diff --git a/.gitattributes b/.gitattributes
index e3ffd343db..c61ca25cd2 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -15,6 +15,7 @@ App.config text eol=crlf
*.cmd text eol=crlf
*.snippet text eol=crlf
*.manifest text eol=crlf
+*.licenseheader text eol=crlf
# Check out with lf (UNIX) line endings
*.sh text eol=lf
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/.github/ISSUE_TEMPLATE/bug-issues.md b/.github/ISSUE_TEMPLATE/bug-issues.md
index 8d85c92fec..c8c41e5a78 100644
--- a/.github/ISSUE_TEMPLATE/bug-issues.md
+++ b/.github/ISSUE_TEMPLATE/bug-issues.md
@@ -1,14 +1,11 @@
---
name: Bug Report
-about: For issues regarding encountered game bugs
+about: Issues regarding encountered bugs.
---
-
-
-
-**Describe your problem:**
+**Describe the bug:**
**Screenshots or videos showing encountered issue:**
-**osu!lazer version:**
+**osu!lazer version:**
-**Logs:**
\ No newline at end of file
+**Logs:**
diff --git a/.github/ISSUE_TEMPLATE/crash-issues.md b/.github/ISSUE_TEMPLATE/crash-issues.md
index 849f042c1f..8ad27e9e31 100644
--- a/.github/ISSUE_TEMPLATE/crash-issues.md
+++ b/.github/ISSUE_TEMPLATE/crash-issues.md
@@ -1,16 +1,13 @@
---
name: Crash Report
-about: For issues regarding game crashes or permanent freezes
+about: Issues regarding crashes or permanent freezes.
---
-
-
-
-**Describe your problem:**
+**Describe the crash:**
**Screenshots or videos showing encountered issue:**
-**osu!lazer version:**
+**osu!lazer version:**
-**Logs:**
+**Logs:**
-**Computer Specifications:**
\ No newline at end of file
+**Computer Specifications:**
diff --git a/.github/ISSUE_TEMPLATE/feature-request-issues.md b/.github/ISSUE_TEMPLATE/feature-request-issues.md
index 73c4f37a3e..54c4ff94e5 100644
--- a/.github/ISSUE_TEMPLATE/feature-request-issues.md
+++ b/.github/ISSUE_TEMPLATE/feature-request-issues.md
@@ -1,10 +1,7 @@
---
name: Feature Request
-about: Let us know what you would like to see in the game!
+about: Features you would like to see in the game!
---
+**Describe the new feature:**
-
-
-**Describe the feature:**
-
-**Proposal designs of the feature:**
+**Proposal designs of the feature:**
diff --git a/.github/ISSUE_TEMPLATE/missing-for-live-issues.md b/.github/ISSUE_TEMPLATE/missing-for-live-issues.md
index ae3cf20a8c..5822da9c65 100644
--- a/.github/ISSUE_TEMPLATE/missing-for-live-issues.md
+++ b/.github/ISSUE_TEMPLATE/missing-for-live-issues.md
@@ -1,10 +1,7 @@
---
name: Missing for Live
-about: Let us know the features you need which are available in osu-stable but not lazer
+about: Features which are available in osu!stable but not yet in osu!lazer.
---
+**Describe the missing feature:**
-
-
-**Describe the feature:**
-
-**Designs:**
+**Proposal designs of the feature:**
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
deleted file mode 100644
index 221e4746cb..0000000000
--- a/.github/pull_request_template.md
+++ /dev/null
@@ -1,8 +0,0 @@
-Add any details pertaining to developers above the break.
-
-- [ ] Depends on #PR
-- Closes #ISSUE
-
----
-
-Add a sentence or two describing this change in plain english. This will be displayed on the [changelog](https://osu.ppy.sh/home/changelog). A single screenshot or short gif is also welcomed.
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index f95a04e517..0e2850a01c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,8 +11,10 @@
*.userprefs
### Cake ###
-tools/*
-!tools/cakebuild.csproj
+tools/**
+build/tools/**
+
+fastlane/report.xml
# Build results
bin/[Dd]ebug/
diff --git a/.gitmodules b/.gitmodules
index f1c4f5d172..e69de29bb2 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +0,0 @@
-[submodule "osu-resources"]
- path = osu-resources
- url = https://github.com/ppy/osu-resources
\ No newline at end of file
diff --git a/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__catch_.xml b/.idea/.idea.osu/.idea/runConfigurations/CatchRuleset__Tests_.xml
similarity index 67%
rename from .idea/.idea.osu/.idea/runConfigurations/RulesetTests__catch_.xml
rename to .idea/.idea.osu/.idea/runConfigurations/CatchRuleset__Tests_.xml
index 1c988fe6fd..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 67%
rename from .idea/.idea.osu/.idea/runConfigurations/RulesetTests__mania_.xml
rename to .idea/.idea.osu/.idea/runConfigurations/ManiaRuleset__Tests_.xml
index d7bb0f90f1..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 67%
rename from .idea/.idea.osu/.idea/runConfigurations/RulesetTests__osu__.xml
rename to .idea/.idea.osu/.idea/runConfigurations/OsuRuleset__Tests_.xml
index 997ac6b078..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 67%
rename from .idea/.idea.osu/.idea/runConfigurations/RulesetTests__taiko_.xml
rename to .idea/.idea.osu/.idea/runConfigurations/TaikoRuleset__Tests_.xml
index b7a070174c..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 344301d4a7..7ac6bb745d 100644
--- a/.idea/.idea.osu/.idea/runConfigurations/osu_.xml
+++ b/.idea/.idea.osu/.idea/runConfigurations/osu_.xml
@@ -1,17 +1,20 @@
-
-
+
+
+
-
-
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.osu/.idea/runConfigurations/VisualTests.xml b/.idea/.idea.osu/.idea/runConfigurations/osu___Tests_.xml
similarity index 66%
rename from .idea/.idea.osu/.idea/runConfigurations/VisualTests.xml
rename to .idea/.idea.osu/.idea/runConfigurations/osu___Tests_.xml
index bf5a1f64e0..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 e9b8d6f397..57ff3e6b43 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -1,53 +1,18 @@
{
"version": "0.2.0",
- "configurations": [
- {
- "name": "VisualTests (Debug)",
- "type": "coreclr",
- "request": "launch",
- "program": "dotnet",
- "args": [
- "${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.1/osu.Game.Tests.dll"
- ],
- "cwd": "${workspaceRoot}",
- "preLaunchTask": "Build tests (Debug)",
- "linux": {
- "env": {
- "LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.1:${env:LD_LIBRARY_PATH}"
- }
- },
- "console": "internalConsole"
- },
- {
- "name": "VisualTests (Release)",
- "type": "coreclr",
- "request": "launch",
- "program": "dotnet",
- "args": [
- "${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp2.1/osu.Game.Tests.dll"
- ],
- "cwd": "${workspaceRoot}",
- "preLaunchTask": "Build tests (Release)",
- "linux": {
- "env": {
- "LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp2.1:${env:LD_LIBRARY_PATH}"
- }
- },
- "console": "internalConsole"
- },
- {
+ "configurations": [{
"name": "osu! (Debug)",
"type": "coreclr",
"request": "launch",
"program": "dotnet",
"args": [
- "${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.1/osu!.dll"
+ "${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.2/osu!.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build osu! (Debug)",
"linux": {
"env": {
- "LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.1:${env:LD_LIBRARY_PATH}"
+ "LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.2:${env:LD_LIBRARY_PATH}"
}
},
"console": "internalConsole"
@@ -58,16 +23,135 @@
"request": "launch",
"program": "dotnet",
"args": [
- "${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.1/osu!.dll"
+ "${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.2/osu!.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build osu! (Release)",
"linux": {
"env": {
- "LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.1:${env:LD_LIBRARY_PATH}"
+ "LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.2:${env:LD_LIBRARY_PATH}"
}
},
"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",
+ "request": "launch",
+ "program": "${workspaceRoot}/build/tools/Cake.CoreCLR/0.30.0/Cake.dll",
+ "args": [
+ "${workspaceRoot}/build/build.cake",
+ "--debug",
+ "--verbosity=diagnostic"
+ ],
+ "cwd": "${workspaceRoot}/build",
+ "stopAtEntry": true,
+ "externalConsole": false
}
]
-}
+}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 188f20b69f..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",
@@ -11,7 +10,6 @@
"build",
"--no-restore",
"osu.Desktop",
- "/p:TargetFramework=netcoreapp2.1",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
@@ -27,7 +25,6 @@
"build",
"--no-restore",
"osu.Desktop",
- "/p:TargetFramework=netcoreapp2.1",
"/p:Configuration=Release",
"/p:GenerateFullPaths=true",
"/m",
@@ -44,7 +41,6 @@
"build",
"--no-restore",
"osu.Game.Tests",
- "/p:TargetFramework=netcoreapp2.1",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
@@ -60,7 +56,6 @@
"build",
"--no-restore",
"osu.Game.Tests",
- "/p:TargetFramework=netcoreapp2.1",
"/p:Configuration=Release",
"/p:GenerateFullPaths=true",
"/m",
@@ -70,11 +65,42 @@
"problemMatcher": "$msCompile"
},
{
- "label": "Restore (netcoreapp2.1)",
+ "label": "Build tournament tests (Debug)",
"type": "shell",
"command": "dotnet",
"args": [
- "restore"
+ "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",
+ "command": "dotnet",
+ "args": [
+ "restore",
+ "osu.sln"
],
"problemMatcher": []
}
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000000..cdd3a6b349
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,6 @@
+source "https://rubygems.org"
+
+gem "fastlane"
+
+plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
+eval_gemfile(plugins_path) if File.exist?(plugins_path)
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 0000000000..17c0db12e7
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,173 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ CFPropertyList (3.0.0)
+ addressable (2.6.0)
+ public_suffix (>= 2.0.2, < 4.0)
+ atomos (0.1.3)
+ babosa (1.0.2)
+ claide (1.0.2)
+ colored (1.2)
+ colored2 (3.1.2)
+ commander-fastlane (4.4.6)
+ highline (~> 1.7.2)
+ declarative (0.0.10)
+ declarative-option (0.1.0)
+ digest-crc (0.4.1)
+ domain_name (0.5.20180417)
+ unf (>= 0.0.5, < 1.0.0)
+ dotenv (2.7.1)
+ emoji_regex (1.0.1)
+ excon (0.62.0)
+ faraday (0.15.4)
+ multipart-post (>= 1.2, < 3)
+ faraday-cookie_jar (0.0.6)
+ faraday (>= 0.7.4)
+ http-cookie (~> 1.0.0)
+ faraday_middleware (0.13.1)
+ faraday (>= 0.7.4, < 1.0)
+ fastimage (2.1.5)
+ fastlane (2.117.0)
+ CFPropertyList (>= 2.3, < 4.0.0)
+ addressable (>= 2.3, < 3.0.0)
+ babosa (>= 1.0.2, < 2.0.0)
+ bundler (>= 1.12.0, < 3.0.0)
+ colored
+ commander-fastlane (>= 4.4.6, < 5.0.0)
+ dotenv (>= 2.1.1, < 3.0.0)
+ emoji_regex (>= 0.1, < 2.0)
+ excon (>= 0.45.0, < 1.0.0)
+ faraday (~> 0.9)
+ faraday-cookie_jar (~> 0.0.6)
+ faraday_middleware (~> 0.9)
+ fastimage (>= 2.1.0, < 3.0.0)
+ gh_inspector (>= 1.1.2, < 2.0.0)
+ google-api-client (>= 0.21.2, < 0.24.0)
+ google-cloud-storage (>= 1.15.0, < 2.0.0)
+ highline (>= 1.7.2, < 2.0.0)
+ json (< 3.0.0)
+ mini_magick (~> 4.5.1)
+ multi_json
+ multi_xml (~> 0.5)
+ multipart-post (~> 2.0.0)
+ plist (>= 3.1.0, < 4.0.0)
+ public_suffix (~> 2.0.0)
+ rubyzip (>= 1.2.2, < 2.0.0)
+ security (= 0.1.3)
+ simctl (~> 1.6.3)
+ slack-notifier (>= 2.0.0, < 3.0.0)
+ terminal-notifier (>= 1.6.2, < 2.0.0)
+ terminal-table (>= 1.4.5, < 2.0.0)
+ tty-screen (>= 0.6.3, < 1.0.0)
+ tty-spinner (>= 0.8.0, < 1.0.0)
+ word_wrap (~> 1.0.0)
+ xcodeproj (>= 1.6.0, < 2.0.0)
+ xcpretty (~> 0.3.0)
+ xcpretty-travis-formatter (>= 0.0.3)
+ fastlane-plugin-clean_testflight_testers (0.2.0)
+ fastlane-plugin-souyuz (0.8.1)
+ souyuz (>= 0.8.1)
+ fastlane-plugin-xamarin (0.6.3)
+ gh_inspector (1.1.3)
+ google-api-client (0.23.9)
+ addressable (~> 2.5, >= 2.5.1)
+ googleauth (>= 0.5, < 0.7.0)
+ httpclient (>= 2.8.1, < 3.0)
+ mime-types (~> 3.0)
+ representable (~> 3.0)
+ retriable (>= 2.0, < 4.0)
+ signet (~> 0.9)
+ google-cloud-core (1.3.0)
+ google-cloud-env (~> 1.0)
+ google-cloud-env (1.0.5)
+ faraday (~> 0.11)
+ google-cloud-storage (1.16.0)
+ digest-crc (~> 0.4)
+ google-api-client (~> 0.23)
+ google-cloud-core (~> 1.2)
+ googleauth (>= 0.6.2, < 0.10.0)
+ googleauth (0.6.7)
+ faraday (~> 0.12)
+ jwt (>= 1.4, < 3.0)
+ memoist (~> 0.16)
+ multi_json (~> 1.11)
+ os (>= 0.9, < 2.0)
+ signet (~> 0.7)
+ highline (1.7.10)
+ http-cookie (1.0.3)
+ domain_name (~> 0.5)
+ httpclient (2.8.3)
+ json (2.2.0)
+ jwt (2.1.0)
+ memoist (0.16.0)
+ mime-types (3.2.2)
+ mime-types-data (~> 3.2015)
+ mime-types-data (3.2018.0812)
+ mini_magick (4.5.1)
+ mini_portile2 (2.4.0)
+ multi_json (1.13.1)
+ multi_xml (0.6.0)
+ multipart-post (2.0.0)
+ nanaimo (0.2.6)
+ naturally (2.2.0)
+ nokogiri (1.10.1)
+ mini_portile2 (~> 2.4.0)
+ os (1.0.0)
+ plist (3.5.0)
+ public_suffix (2.0.5)
+ representable (3.0.4)
+ declarative (< 0.1.0)
+ declarative-option (< 0.2.0)
+ uber (< 0.2.0)
+ retriable (3.1.2)
+ rouge (2.0.7)
+ rubyzip (1.2.2)
+ security (0.1.3)
+ signet (0.11.0)
+ addressable (~> 2.3)
+ faraday (~> 0.9)
+ jwt (>= 1.5, < 3.0)
+ multi_json (~> 1.10)
+ simctl (1.6.5)
+ CFPropertyList
+ naturally
+ slack-notifier (2.3.2)
+ souyuz (0.8.1)
+ fastlane (>= 2.29.0)
+ highline (~> 1.7)
+ nokogiri (~> 1.7)
+ terminal-notifier (1.8.0)
+ terminal-table (1.8.0)
+ unicode-display_width (~> 1.1, >= 1.1.1)
+ tty-cursor (0.6.1)
+ tty-screen (0.6.5)
+ tty-spinner (0.9.0)
+ tty-cursor (~> 0.6.0)
+ uber (0.1.0)
+ unf (0.1.4)
+ unf_ext
+ unf_ext (0.0.7.5)
+ unicode-display_width (1.4.1)
+ word_wrap (1.0.0)
+ xcodeproj (1.8.1)
+ CFPropertyList (>= 2.3.3, < 4.0)
+ atomos (~> 0.1.3)
+ claide (>= 1.0.2, < 2.0)
+ colored2 (~> 3.1)
+ nanaimo (~> 0.2.6)
+ xcpretty (0.3.0)
+ rouge (~> 2.0.7)
+ xcpretty-travis-formatter (1.0.0)
+ xcpretty (~> 0.2, >= 0.0.7)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ fastlane
+ fastlane-plugin-clean_testflight_testers
+ fastlane-plugin-souyuz
+ fastlane-plugin-xamarin
+
+BUNDLED WITH
+ 2.0.1
diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md
deleted file mode 100644
index 2bff304fba..0000000000
--- a/ISSUE_TEMPLATE.md
+++ /dev/null
@@ -1,11 +0,0 @@
-osu!lazer is currently still under heavy development!
-
-Please ensure that you are making an issue for one of the following:
-
-- A bug with currently implemented features (not features that don't exist)
-- A feature you are considering adding, so we can collaborate on feedback and design.
-- Discussions about technical design decisions
-
-If your issue qualifies, replace this text with a detailed description of your issue with as much relevant information as you can provide.
-
-Screenshots and log files are highly welcomed.
\ No newline at end of file
diff --git a/LICENCE b/LICENCE
index a11a7ce75b..21c6a7090f 100644
--- a/LICENCE
+++ b/LICENCE
@@ -1,4 +1,4 @@
-Copyright (c) 2007-2018 ppy Pty Ltd .
+Copyright (c) 2019 ppy Pty Ltd .
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index baaba22726..55f2eebec9 100644
--- a/README.md
+++ b/README.md
@@ -1,37 +1,94 @@
-# 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)
+# 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)
Rhythm is just a *click* away. The future of [osu!](https://osu.ppy.sh) and the beginning of an open era! Commonly known by the codename "osu!lazer". Pew pew.
-# Status
+## Status
This project is still heavily under development, but is in a state where users are encouraged to try it out and keep it installed alongside the stable osu! client. It will continue to evolve over the coming months and hopefully bring some new unique features to the table.
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.
-# Requirements
+Detailed changelogs are published on the [official osu! site](https://osu.ppy.sh/home/changelog).
-- A desktop platform with the [.NET Core SDK 2.1](https://www.microsoft.com/net/learn/get-started) or higher installed.
-- When working with the codebase, we recommend using an IDE with intellisense and syntax highlighting, such as [Visual Studio Community Edition](https://www.visualstudio.com/) (Windows), [Visual Studio Code](https://code.visualstudio.com/) (with the C# plugin installed) or [Jetbrains Rider](https://www.jetbrains.com/rider/) (commercial).
+## Requirements
-# Building and running
+- A desktop platform with the [.NET Core SDK 2.2](https://www.microsoft.com/net/learn/get-started) or higher installed.
+- When working with the codebase, we recommend using an IDE with intellisense and syntax highlighting, such as [Visual Studio 2017+](https://visualstudio.microsoft.com/vs/), [Jetbrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/).
+- Note that there are **[additional requirements for Windows 7 and Windows 8.1](https://docs.microsoft.com/en-us/dotnet/core/windows-prerequisites?tabs=netcore2x)** which you may need to manually install if your operating system is not up-to-date.
-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 (download and run the install executable for your platform).
+## Running osu!
-Clone the repository including submodules
+### Releases
-`git clone --recurse-submodules https://github.com/ppy/osu`
+![](https://puu.sh/DCmvA/f6a74f5fbb.png)
-Build and run
+If you are not interested in developing the game, you can still consume our [binary releases](https://github.com/ppy/osu/releases).
-- Using Visual Studio 2017, Rider or Visual Studio Code (configurations are included)
-- From command line using `dotnet run --project osu.Desktop`. When building for non-development purposes, add `-c Release` to gain higher performance.
-- To run with code analysis, instead use `powershell ./build.ps1` or `build.sh`. This is currently only supported under windows due to [resharper cli shortcomings](https://youtrack.jetbrains.com/issue/RSRP-410004). Alternative, you can install resharper or use rider to get inline support in your IDE of choice.
+**Latest build:**
-Note: If you run from command line under linux, you will need to prefix the output folder to your `LD_LIBRARY_PATH`. See `.vscode/launch.json` for an example
+| [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) |
+| ------------- | ------------- |
-If you run into issues building you may need to restore nuget packages (commonly via `dotnet restore`). Visual Studio Code users must run `Restore` task from debug tab before attempt to build.
+- **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.
-# Contributing
+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:
+
+```shell
+git clone https://github.com/ppy/osu
+cd osu
+```
+
+To update the source code to the latest commit, run the following command inside the `osu` directory:
+
+```shell
+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](#contributing).
+
+> Visual Studio Code users must run the `Restore` task before any build attempt.
+
+You can also build and run osu! from the command-line with a single command:
+
+```shell
+dotnet run --project osu.Desktop
+```
+
+If you are not interested in debugging osu!, you can add `-c Release` to gain performance. In this case, you must replace `Debug` with `Release` in any commands mentioned in this document.
+
+If the build fails, try to restore nuget packages with `dotnet restore`.
+
+#### A note for Linux users
+
+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 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:
+
+```shell
+LD_LIBRARY_PATH="$(pwd)/osu.Desktop/bin/Debug/netcoreapp2.2" dotnet run --project osu.Desktop
+```
+
+### Testing with resource/framework modifications
+
+Sometimes it may be necessary to cross-test changes in [osu-resources](https://github.com/ppy/osu-resources) or [osu-framework](https://github.com/ppy/osu-framework). This can be achieved by running some commands as documented on the [osu-resources](https://github.com/ppy/osu-resources/wiki/Testing-local-resources-checkout-with-other-projects) and [osu-framework](https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects) wiki pages.
+
+### Code analysis
+
+Code analysis can be run with `powershell ./build.ps1` or `build.sh`. This is currently only supported under windows due to [resharper cli shortcomings](https://youtrack.jetbrains.com/issue/RSRP-410004). Alternatively, you can install resharper or use rider to get inline support in your IDE of choice.
+
+## Contributing
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.
@@ -41,7 +98,7 @@ Contributions can be made via pull requests to this repository. We hope to credi
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.
-# Licence
+## Licence
The osu! client code and framework are licensed under the [MIT licence](https://opensource.org/licenses/MIT). Please see [the licence file](LICENCE) for more information. [tl;dr](https://tldrlegal.com/license/mit-license) you can do whatever you want as long as you include the original copyright and license notice in any copy of the software/source.
diff --git a/appveyor.yml b/appveyor.yml
index 1f485485da..4dcaa7b45e 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,6 +1,6 @@
clone_depth: 1
version: '{branch}-{build}'
-image: Visual Studio 2017
+image: Previous Visual Studio 2017
test: off
install:
- cmd: git submodule update --init --recursive --depth=5
diff --git a/build.ps1 b/build.ps1
index 9968673c90..c6a0bf6d4a 100644
--- a/build.ps1
+++ b/build.ps1
@@ -41,27 +41,28 @@ Param(
[switch]$ShowDescription,
[Alias("WhatIf", "Noop")]
[switch]$DryRun,
- [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
+ [Parameter(Position = 0, Mandatory = $false, ValueFromRemainingArguments = $true)]
[string[]]$ScriptArgs
)
Write-Host "Preparing to run build script..."
# Determine the script root for resolving other paths.
-if(!$PSScriptRoot){
+if(!$PSScriptRoot) {
$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
}
# Resolve the paths for resources used for debugging.
-$TOOLS_DIR = Join-Path $PSScriptRoot "tools"
-$CAKE_CSPROJ = Join-Path $TOOLS_DIR "cakebuild.csproj"
+$BUILD_DIR = Join-Path $PSScriptRoot "build"
+$TOOLS_DIR = Join-Path $BUILD_DIR "tools"
+$CAKE_CSPROJ = Join-Path $BUILD_DIR "cakebuild.csproj"
# Install the required tools locally.
Write-Host "Restoring cake tools..."
Invoke-Expression "dotnet restore `"$CAKE_CSPROJ`" --packages `"$TOOLS_DIR`"" | Out-Null
# Find the Cake executable
-$CAKE_EXECUTABLE = (Get-ChildItem -Path ./tools/cake.coreclr/ -Filter Cake.dll -Recurse).FullName
+$CAKE_EXECUTABLE = (Get-ChildItem -Path "$TOOLS_DIR/cake.coreclr/" -Filter Cake.dll -Recurse).FullName
# Build Cake arguments
$cakeArguments = @("$Script");
@@ -75,5 +76,7 @@ $cakeArguments += $ScriptArgs
# Start Cake
Write-Host "Running build script..."
+Push-Location -Path $BUILD_DIR
Invoke-Expression "dotnet `"$CAKE_EXECUTABLE`" $cakeArguments"
+Pop-Location
exit $LASTEXITCODE
diff --git a/build.sh b/build.sh
index caf1702f41..8f1ef5b455 100755
--- a/build.sh
+++ b/build.sh
@@ -6,12 +6,13 @@
echo "Preparing to run build script..."
+cd build
SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
TOOLS_DIR=$SCRIPT_DIR/tools
CAKE_BINARY_PATH=$TOOLS_DIR/"cake.coreclr"
SCRIPT="build.cake"
-CAKE_CSPROJ=$TOOLS_DIR/"cakebuild.csproj"
+CAKE_CSPROJ=$SCRIPT_DIR/"cakebuild.csproj"
# Parse arguments.
CAKE_ARGUMENTS=()
diff --git a/build.cake b/build/build.cake
similarity index 68%
rename from build.cake
rename to build/build.cake
index bc7dfafb8c..1d2588de49 100644
--- a/build.cake
+++ b/build/build.cake
@@ -1,6 +1,7 @@
#addin "nuget:?package=CodeFileSanity&version=0.0.21"
-#addin "nuget:?package=JetBrains.ReSharper.CommandLineTools&version=2018.2.2"
+#addin "nuget:?package=JetBrains.ReSharper.CommandLineTools&version=2019.1.1"
#tool "nuget:?package=NVika.MSBuild&version=1.0.1"
+var nVikaToolPath = GetFiles("./tools/NVika.MSBuild.*/tools/NVika.exe").First();
///////////////////////////////////////////////////////////////////////////////
// ARGUMENTS
@@ -9,30 +10,24 @@
var target = Argument("target", "Build");
var configuration = Argument("configuration", "Release");
-var osuSolution = new FilePath("./osu.sln");
+var rootDirectory = new DirectoryPath("..");
+var solution = rootDirectory.CombineWithFilePath("osu.sln");
///////////////////////////////////////////////////////////////////////////////
// TASKS
///////////////////////////////////////////////////////////////////////////////
-Task("Restore")
- .Does(() => {
- DotNetCoreRestore(osuSolution.FullPath);
- });
-
Task("Compile")
- .IsDependentOn("Restore")
.Does(() => {
- DotNetCoreBuild(osuSolution.FullPath, new DotNetCoreBuildSettings {
+ DotNetCoreBuild(solution.FullPath, new DotNetCoreBuildSettings {
Configuration = configuration,
- NoRestore = true,
});
});
Task("Test")
.IsDependentOn("Compile")
.Does(() => {
- var testAssemblies = GetFiles("**/*.Tests/bin/**/*.Tests.dll");
+ var testAssemblies = GetFiles(rootDirectory + "/**/*.Tests/bin/**/*.Tests.dll");
DotNetCoreVSTest(testAssemblies, new DotNetCoreVSTestSettings {
Logger = AppVeyor.IsRunningOnAppVeyor ? "Appveyor" : $"trx",
@@ -46,20 +41,20 @@ Task("InspectCode")
.WithCriteria(IsRunningOnWindows())
.IsDependentOn("Compile")
.Does(() => {
- var nVikaToolPath = GetFiles("./tools/NVika.MSBuild.*/tools/NVika.exe").First();
-
- InspectCode(osuSolution, new InspectCodeSettings {
+ InspectCode(solution, new InspectCodeSettings {
CachesHome = "inspectcode",
OutputFile = "inspectcodereport.xml",
});
- StartProcess(nVikaToolPath, @"parsereport ""inspectcodereport.xml"" --treatwarningsaserrors");
+ int returnCode = StartProcess(nVikaToolPath, $@"parsereport ""inspectcodereport.xml"" --treatwarningsaserrors");
+ if (returnCode != 0)
+ throw new Exception($"inspectcode failed with return code {returnCode}");
});
Task("CodeFileSanity")
.Does(() => {
ValidateCodeSanity(new ValidateCodeSanitySettings {
- RootDirectory = ".",
+ RootDirectory = rootDirectory.FullPath,
IsAppveyorBuild = AppVeyor.IsRunningOnAppVeyor
});
});
diff --git a/tools/cakebuild.csproj b/build/cakebuild.csproj
similarity index 100%
rename from tools/cakebuild.csproj
rename to build/cakebuild.csproj
diff --git a/fastlane/Appfile b/fastlane/Appfile
new file mode 100644
index 0000000000..083de66985
--- /dev/null
+++ b/fastlane/Appfile
@@ -0,0 +1,2 @@
+app_identifier("sh.ppy.osulazer") # The bundle identifier of your app
+apple_id("apple-dev@ppy.sh") # Your Apple email address
diff --git a/fastlane/Fastfile b/fastlane/Fastfile
new file mode 100644
index 0000000000..48c16caf0f
--- /dev/null
+++ b/fastlane/Fastfile
@@ -0,0 +1,65 @@
+update_fastlane
+
+default_platform(:ios)
+
+platform :ios do
+ lane :testflight_prune_dry do
+ clean_testflight_testers(days_of_inactivity:45, dry_run: true)
+ end
+
+ # Specify a custom number for what's "inactive"
+ lane :testflight_prune do
+ clean_testflight_testers(days_of_inactivity: 45) # 120 days, so about 4 months
+ end
+
+ lane :update_version do |options|
+ options[:plist_path] = '../osu.iOS/Info.plist'
+ app_version(options)
+ end
+
+ desc 'Deploy to testflight'
+ lane :beta do |options|
+ update_version(options)
+
+ provision(
+ type: 'appstore'
+ )
+
+ build(
+ build_configuration: 'Release',
+ build_platform: 'iPhone'
+ )
+
+ client = HTTPClient.new
+ changelog = client.get_content 'https://gist.githubusercontent.com/peppy/ab89c29dcc0dce95f39eb218e8fad197/raw'
+ changelog.gsub!('$BUILD_ID', options[:build])
+
+ pilot(
+ wait_processing_interval: 1800,
+ changelog: changelog,
+ ipa: './osu.iOS/bin/iPhone/Release/osu.iOS.ipa'
+ )
+ end
+
+ desc 'Compile the project'
+ lane :build do
+ nuget_restore(
+ project_path: 'osu.iOS.sln'
+ )
+
+ souyuz(
+ platform: "ios",
+ build_target: "osu_iOS",
+ plist_path: "../osu.iOS/Info.plist"
+ )
+ end
+
+ desc 'Install provisioning profiles using match'
+ lane :provision do |options|
+ if Helper.is_ci?
+ options[:readonly] = true
+ end
+
+ match(options)
+ end
+end
diff --git a/fastlane/Matchfile b/fastlane/Matchfile
new file mode 100644
index 0000000000..40c974b09e
--- /dev/null
+++ b/fastlane/Matchfile
@@ -0,0 +1 @@
+git_url('https://github.com/peppy/apple-certificates')
diff --git a/fastlane/Pluginfile b/fastlane/Pluginfile
new file mode 100644
index 0000000000..9f4f47f213
--- /dev/null
+++ b/fastlane/Pluginfile
@@ -0,0 +1,7 @@
+# Autogenerated by fastlane
+#
+# Ensure this file is checked in to source control!
+
+gem 'fastlane-plugin-clean_testflight_testers'
+gem 'fastlane-plugin-souyuz'
+gem 'fastlane-plugin-xamarin'
diff --git a/fastlane/README.md b/fastlane/README.md
new file mode 100644
index 0000000000..53bbc62cae
--- /dev/null
+++ b/fastlane/README.md
@@ -0,0 +1,54 @@
+fastlane documentation
+================
+# Installation
+
+Make sure you have the latest version of the Xcode command line tools installed:
+
+```
+xcode-select --install
+```
+
+Install _fastlane_ using
+```
+[sudo] gem install fastlane -NV
+```
+or alternatively using `brew cask install fastlane`
+
+# Available Actions
+## iOS
+### ios testflight_prune_dry
+```
+fastlane ios testflight_prune_dry
+```
+
+### ios testflight_prune
+```
+fastlane ios testflight_prune
+```
+
+### ios update_version
+```
+fastlane ios update_version
+```
+
+### ios beta
+```
+fastlane ios beta
+```
+Deploy to testflight
+### ios build
+```
+fastlane ios build
+```
+Compile the project
+### ios provision
+```
+fastlane ios provision
+```
+Install provisioning profiles using match
+
+----
+
+This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run.
+More information about fastlane can be found on [fastlane.tools](https://fastlane.tools).
+The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
diff --git a/osu-resources b/osu-resources
deleted file mode 160000
index 694cb03f19..0000000000
--- a/osu-resources
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 694cb03f19c93106ed0f2593f3e506e835fb652a
diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs
index 93fd3935c6..975b7f9f5a 100644
--- a/osu.Desktop/OsuGameDesktop.cs
+++ b/osu.Desktop/OsuGameDesktop.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.IO;
@@ -7,20 +7,23 @@ 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;
using Microsoft.Win32;
using osu.Desktop.Updater;
using osu.Framework;
+using osu.Framework.Logging;
using osu.Framework.Platform.Windows;
+using osu.Framework.Screens;
+using osu.Game.Screens.Menu;
namespace osu.Desktop
{
internal class OsuGameDesktop : OsuGame
{
private readonly bool noVersionOverlay;
+ private VersionManager versionManager;
public OsuGameDesktop(string[] args = null)
: base(args)
@@ -32,12 +35,15 @@ namespace osu.Desktop
{
try
{
- return new StableStorage();
+ if (Host is DesktopGameHost desktopHost)
+ return new StableStorage(desktopHost);
}
- catch
+ catch (Exception e)
{
- return null;
+ Logger.Error(e, "Error while searching for stable install");
}
+
+ return null;
}
protected override void LoadComplete()
@@ -46,10 +52,10 @@ namespace osu.Desktop
if (!noVersionOverlay)
{
- LoadComponentAsync(new VersionManager { Depth = int.MinValue }, v =>
+ LoadComponentAsync(versionManager = new VersionManager { Depth = int.MinValue }, v =>
{
Add(v);
- v.State = Visibility.Visible;
+ v.Show();
});
if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows)
@@ -59,11 +65,28 @@ namespace osu.Desktop
}
}
+ protected override void ScreenChanged(IScreen lastScreen, IScreen newScreen)
+ {
+ base.ScreenChanged(lastScreen, newScreen);
+
+ switch (newScreen)
+ {
+ case Intro _:
+ case MainMenu _:
+ versionManager?.Show();
+ break;
+
+ default:
+ versionManager?.Hide();
+ break;
+ }
+ }
+
public override void SetHost(GameHost host)
{
base.SetHost(host);
- var desktopWindow = host.Window as DesktopGameWindow;
- if (desktopWindow != null)
+
+ if (host.Window is DesktopGameWindow desktopWindow)
{
desktopWindow.CursorState |= CursorState.Hidden;
@@ -76,7 +99,7 @@ namespace osu.Desktop
private void fileDrop(object sender, FileDropEventArgs e)
{
- var filePaths = new[] { e.FileName };
+ var filePaths = e.FileNames;
var firstExtension = Path.GetExtension(filePaths.First());
@@ -119,8 +142,8 @@ namespace osu.Desktop
return null;
}
- public StableStorage()
- : base(string.Empty, null)
+ public StableStorage(DesktopGameHost host)
+ : base(string.Empty, host)
{
}
}
diff --git a/osu.Desktop/Overlays/VersionManager.cs b/osu.Desktop/Overlays/VersionManager.cs
index f31bba1e1e..1f1d2cea5f 100644
--- a/osu.Desktop/Overlays/VersionManager.cs
+++ b/osu.Desktop/Overlays/VersionManager.cs
@@ -1,20 +1,18 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using osu.Framework.Allocation;
+using osu.Framework.Development;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
-using osu.Framework.Platform;
using osu.Game;
using osu.Game.Configuration;
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;
@@ -25,15 +23,13 @@ namespace osu.Desktop.Overlays
private OsuConfigManager config;
private OsuGameBase game;
private NotificationOverlay notificationOverlay;
- private GameHost host;
[BackgroundDependencyLoader]
- private void load(NotificationOverlay notification, OsuColour colours, TextureStore textures, OsuGameBase game, OsuConfigManager config, GameHost host)
+ private void load(NotificationOverlay notification, OsuColour colours, TextureStore textures, OsuGameBase game, OsuConfigManager config)
{
notificationOverlay = notification;
this.config = config;
this.game = game;
- this.host = host;
AutoSizeAxes = Axes.Both;
Anchor = Anchor.BottomCentre;
@@ -60,12 +56,12 @@ namespace osu.Desktop.Overlays
{
new OsuSpriteText
{
- Font = @"Exo2.0-Bold",
+ Font = OsuFont.GetFont(weight: FontWeight.Bold),
Text = game.Name
},
new OsuSpriteText
{
- Colour = DebugUtils.IsDebug ? colours.Red : Color4.White,
+ Colour = DebugUtils.IsDebugBuild ? colours.Red : Color4.White,
Text = game.Version
},
}
@@ -74,9 +70,8 @@ namespace osu.Desktop.Overlays
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
- TextSize = 12,
+ Font = OsuFont.Numeric.With(size: 12),
Colour = colours.Yellow,
- Font = @"Venera",
Text = @"Development Build"
},
new Sprite
@@ -96,43 +91,49 @@ namespace osu.Desktop.Overlays
var version = game.Version;
var lastVersion = config.Get(OsuSetting.Version);
+
if (game.IsDeployedBuild && version != lastVersion)
{
config.Set(OsuSetting.Version, version);
// only show a notification if we've previously saved a version to the config file (ie. not the first run).
if (!string.IsNullOrEmpty(lastVersion))
- notificationOverlay.Post(new UpdateCompleteNotification(version, host.OpenUrlExternally));
+ notificationOverlay.Post(new UpdateCompleteNotification(version));
}
}
private class UpdateCompleteNotification : SimpleNotification
{
- public UpdateCompleteNotification(string version, Action openUrl = null)
+ private readonly string version;
+
+ public UpdateCompleteNotification(string version)
{
+ this.version = version;
Text = $"You are now running osu!lazer {version}.\nClick to see what's new!";
- Icon = FontAwesome.fa_check_square;
- Activated = delegate
- {
- openUrl?.Invoke($"https://osu.ppy.sh/home/changelog/lazer/{version}");
- return true;
- };
}
[BackgroundDependencyLoader]
- private void load(OsuColour colours)
+ private void load(OsuColour colours, ChangelogOverlay changelog)
{
+ Icon = FontAwesome.Solid.CheckSquare;
IconBackgound.Colour = colours.BlueDark;
+
+ Activated = delegate
+ {
+ changelog.ShowBuild(OsuGameBase.CLIENT_STREAM_NAME, version);
+ return true;
+ };
}
}
protected override void PopIn()
{
- this.FadeIn(1000);
+ this.FadeIn(1400, Easing.OutQuint);
}
protected override void PopOut()
{
+ this.FadeOut(500, Easing.OutQuint);
}
}
}
diff --git a/osu.Desktop/Program.cs b/osu.Desktop/Program.cs
index 257155478f..cb488fea52 100644
--- a/osu.Desktop/Program.cs
+++ b/osu.Desktop/Program.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.IO;
@@ -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
{
@@ -31,6 +32,7 @@ namespace osu.Desktop
var importer = new ArchiveImportIPCChannel(host);
// Restore the cwd so relative paths given at the command line work correctly
Directory.SetCurrentDirectory(cwd);
+
foreach (var file in args)
{
Console.WriteLine(@"Importing {0}", file);
@@ -45,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/SimpleUpdateManager.cs b/osu.Desktop/Updater/SimpleUpdateManager.cs
index 6c363422f7..5184791de1 100644
--- a/osu.Desktop/Updater/SimpleUpdateManager.cs
+++ b/osu.Desktop/Updater/SimpleUpdateManager.cs
@@ -1,17 +1,16 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.Collections.Generic;
-using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json;
using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
using osu.Framework.IO.Network;
using osu.Framework.Platform;
using osu.Game;
-using osu.Game.Graphics;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
@@ -41,24 +40,32 @@ namespace osu.Desktop.Updater
private async void checkForUpdateAsync()
{
- var releases = new JsonWebRequest("https://api.github.com/repos/ppy/osu/releases/latest");
- await releases.PerformAsync();
-
- var latest = releases.ResponseObject;
-
- if (latest.TagName != version)
+ try
{
- notificationOverlay.Post(new SimpleNotification
+ var releases = new JsonWebRequest("https://api.github.com/repos/ppy/osu/releases/latest");
+
+ await releases.PerformAsync();
+
+ var latest = releases.ResponseObject;
+
+ if (latest.TagName != version)
{
- Text = $"A newer release of osu! has been found ({version} → {latest.TagName}).\n\n"
- + "Click here to download the new version, which can be installed over the top of your existing installation",
- Icon = FontAwesome.fa_upload,
- Activated = () =>
+ notificationOverlay.Post(new SimpleNotification
{
- host.OpenUrlExternally(getBestUrl(latest));
- return true;
- }
- });
+ Text = $"A newer release of osu! has been found ({version} → {latest.TagName}).\n\n"
+ + "Click here to download the new version, which can be installed over the top of your existing installation",
+ Icon = FontAwesome.Solid.Upload,
+ Activated = () =>
+ {
+ host.OpenUrlExternally(getBestUrl(latest));
+ return true;
+ }
+ });
+ }
+ }
+ catch
+ {
+ // we shouldn't crash on a web failure. or any failure for the matter.
}
}
@@ -69,10 +76,11 @@ namespace osu.Desktop.Updater
switch (RuntimeInfo.OS)
{
case RuntimeInfo.Platform.Windows:
- bestAsset = release.Assets?.FirstOrDefault(f => f.Name.EndsWith(".exe"));
+ bestAsset = release.Assets?.Find(f => f.Name.EndsWith(".exe"));
break;
+
case RuntimeInfo.Platform.MacOsx:
- bestAsset = release.Assets?.FirstOrDefault(f => f.Name.EndsWith(".app.zip"));
+ bestAsset = release.Assets?.Find(f => f.Name.EndsWith(".app.zip"));
break;
}
diff --git a/osu.Desktop/Updater/SquirrelUpdateManager.cs b/osu.Desktop/Updater/SquirrelUpdateManager.cs
index 19383d617f..69064a40cb 100644
--- a/osu.Desktop/Updater/SquirrelUpdateManager.cs
+++ b/osu.Desktop/Updater/SquirrelUpdateManager.cs
@@ -1,14 +1,13 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
-using System.IO;
-using System.Reflection;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Shapes;
+using osu.Framework.Graphics.Sprites;
using osu.Framework.Logging;
using osu.Game;
using osu.Game.Graphics;
@@ -26,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)
@@ -47,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
{
@@ -87,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!");
}
}
@@ -101,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);
}
@@ -135,8 +128,8 @@ namespace osu.Desktop.Updater
Text = @"Update ready to install. Click to restart!",
Activated = () =>
{
- updateManager.PrepareUpdate();
- game.GracefullyExit();
+ updateManager.PrepareUpdateAsync()
+ .ContinueWith(_ => Schedule(() => game.GracefullyExit()));
return true;
}
};
@@ -158,7 +151,7 @@ namespace osu.Desktop.Updater
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
- Icon = FontAwesome.fa_upload,
+ Icon = FontAwesome.Solid.Upload,
Colour = Color4.White,
Size = new Vector2(20),
}
@@ -168,23 +161,19 @@ namespace osu.Desktop.Updater
private class SquirrelLogger : Splat.ILogger, IDisposable
{
- private readonly string path;
- private readonly object locker = new object();
public LogLevel Level { get; set; } = LogLevel.Info;
- public SquirrelLogger()
- {
- var file = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "SquirrelSetupUpdater.log");
- if (File.Exists(file)) File.Delete(file);
- path = file;
- }
+ private Logger logger;
public void Write(string message, LogLevel logLevel)
{
if (logLevel < Level)
return;
- lock (locker) File.AppendAllText(path, message + "\r\n");
+ if (logger == null)
+ logger = Logger.GetLogger("updater");
+
+ logger.Add(message);
}
public void Dispose()
diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj
index 09bfdc67d4..8c9e1f279f 100644
--- a/osu.Desktop/osu.Desktop.csproj
+++ b/osu.Desktop/osu.Desktop.csproj
@@ -1,7 +1,7 @@
- netcoreapp2.1
+ netcoreapp2.2
WinExe
AnyCPU
true
@@ -17,19 +17,19 @@
osu.Desktop.Program
+
-
-
-
-
+
+
+
diff --git a/osu.Desktop/osu.nuspec b/osu.Desktop/osu.nuspec
index cdd232a9b2..a26b35fcd5 100644
--- a/osu.Desktop/osu.nuspec
+++ b/osu.Desktop/osu.nuspec
@@ -12,7 +12,7 @@
click the circles. to the beat.
click the circles.
testing
- Copyright ppy Pty Ltd 2007-2018
+ Copyright (c) 2019 ppy Pty Ltd
en-AU
diff --git a/osu.Game.Rulesets.Catch.Tests.iOS/AppDelegate.cs b/osu.Game.Rulesets.Catch.Tests.iOS/AppDelegate.cs
new file mode 100644
index 0000000000..39fe3dac25
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests.iOS/AppDelegate.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 Foundation;
+using osu.Framework.iOS;
+using osu.Game.Tests;
+
+namespace osu.Game.Rulesets.Catch.Tests.iOS
+{
+ [Register("AppDelegate")]
+ public class AppDelegate : GameAppDelegate
+ {
+ protected override Framework.Game CreateGame() => new OsuTestBrowser();
+ }
+}
diff --git a/osu.Game.Rulesets.Catch.Tests.iOS/Application.cs b/osu.Game.Rulesets.Catch.Tests.iOS/Application.cs
new file mode 100644
index 0000000000..44817c1304
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests.iOS/Application.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 UIKit;
+
+namespace osu.Game.Rulesets.Catch.Tests.iOS
+{
+ public class Application
+ {
+ public static void Main(string[] args)
+ {
+ UIApplication.Main(args, null, "AppDelegate");
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch.Tests.iOS/Entitlements.plist b/osu.Game.Rulesets.Catch.Tests.iOS/Entitlements.plist
new file mode 100644
index 0000000000..9ae599370b
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests.iOS/Entitlements.plist
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/osu.Game.Rulesets.Catch.Tests.iOS/Info.plist b/osu.Game.Rulesets.Catch.Tests.iOS/Info.plist
new file mode 100644
index 0000000000..5115746cbb
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests.iOS/Info.plist
@@ -0,0 +1,36 @@
+
+
+
+
+ CFBundleName
+ osu.Game.Rulesets.Catch.Tests.iOS
+ CFBundleIdentifier
+ ppy.osu-Game-Rulesets-Catch-Tests-iOS
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1.0
+ LSRequiresIPhoneOS
+
+ MinimumOSVersion
+ 10.0
+ UIDeviceFamily
+
+ 1
+ 2
+
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ XSAppIconAssets
+ Assets.xcassets/AppIcon.appiconset
+
+
diff --git a/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj b/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj
new file mode 100644
index 0000000000..37e7c45a4e
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj
@@ -0,0 +1,45 @@
+
+
+
+
+ Debug
+ iPhoneSimulator
+ {4004C7B7-1A62-43F1-9DF2-52450FA67E70}
+ Exe
+ osu.Game.Rulesets.Catch.Tests
+ osu.Game.Rulesets.Catch.Tests.iOS
+
+
+
+
+
+
+ libbass.a
+ PreserveNewest
+
+
+ libbass_fx.a
+ PreserveNewest
+
+
+ Linker.xml
+
+
+
+
+ %(RecursiveDir)%(Filename)%(Extension)
+
+
+
+
+ {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}
+ osu.Game
+
+
+ {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}
+ osu.Game.Rulesets.Catch
+
+
+
+
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Catch.Tests/.vscode/launch.json b/osu.Game.Rulesets.Catch.Tests/.vscode/launch.json
index da9344b6a2..5dfaf5ec39 100644
--- a/osu.Game.Rulesets.Catch.Tests/.vscode/launch.json
+++ b/osu.Game.Rulesets.Catch.Tests/.vscode/launch.json
@@ -7,7 +7,7 @@
"request": "launch",
"program": "dotnet",
"args": [
- "${workspaceRoot}/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Catch.Tests.dll"
+ "${workspaceRoot}/bin/Debug/netcoreapp2.2/osu.Game.Rulesets.Catch.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug)",
@@ -20,7 +20,7 @@
"request": "launch",
"program": "dotnet",
"args": [
- "${workspaceRoot}/bin/Release/netcoreapp2.1/osu.Game.Rulesets.Catch.Tests.dll"
+ "${workspaceRoot}/bin/Release/netcoreapp2.2/osu.Game.Rulesets.Catch.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release)",
diff --git a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs
index 162624da57..e45ed8c6f4 100644
--- a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs
+++ b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
@@ -21,6 +21,7 @@ namespace osu.Game.Rulesets.Catch.Tests
[TestCase("basic")]
[TestCase("spinner")]
[TestCase("spinner-and-circles")]
+ [TestCase("slider")]
public new void Test(string name)
{
base.Test(name);
@@ -33,13 +34,18 @@ namespace osu.Game.Rulesets.Catch.Tests
case JuiceStream stream:
foreach (var nested in stream.NestedHitObjects)
yield return new ConvertValue((CatchHitObject)nested);
+
break;
+
case BananaShower shower:
foreach (var nested in shower.NestedHitObjects)
yield return new ConvertValue((CatchHitObject)nested);
+
break;
+
default:
yield return new ConvertValue((CatchHitObject)hitObject);
+
break;
}
}
diff --git a/osu.Game.Rulesets.Catch.Tests/CatchDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchDifficultyCalculatorTest.cs
new file mode 100644
index 0000000000..51fe0b035d
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests/CatchDifficultyCalculatorTest.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 NUnit.Framework;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.Difficulty;
+using osu.Game.Rulesets.Difficulty;
+using osu.Game.Tests.Beatmaps;
+
+namespace osu.Game.Rulesets.Catch.Tests
+{
+ public class CatchDifficultyCalculatorTest : DifficultyCalculatorTest
+ {
+ protected override string ResourceAssembly => "osu.Game.Rulesets.Catch";
+
+ [TestCase(4.2058561036909863d, "diffcalc-test")]
+ public void Test(double expected, string name)
+ => base.Test(expected, name);
+
+ protected override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new CatchDifficultyCalculator(new CatchRuleset(), beatmap);
+
+ protected override Ruleset CreateRuleset() => new CatchRuleset();
+ }
+}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseCatchPlayer.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseCatchPlayer.cs
deleted file mode 100644
index a2c886f1f3..0000000000
--- a/osu.Game.Rulesets.Catch.Tests/TestCaseCatchPlayer.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using NUnit.Framework;
-
-namespace osu.Game.Rulesets.Catch.Tests
-{
- [TestFixture]
- public class TestCaseCatchPlayer : Game.Tests.Visual.TestCasePlayer
- {
- public TestCaseCatchPlayer() : base(new CatchRuleset())
- {
- }
- }
-}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseHyperDash.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseHyperDash.cs
deleted file mode 100644
index 14487b2c7f..0000000000
--- a/osu.Game.Rulesets.Catch.Tests/TestCaseHyperDash.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using NUnit.Framework;
-using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Catch.Objects;
-
-namespace osu.Game.Rulesets.Catch.Tests
-{
- [TestFixture]
- public class TestCaseHyperDash : Game.Tests.Visual.TestCasePlayer
- {
- public TestCaseHyperDash()
- : base(new CatchRuleset())
- {
- }
-
- protected override IBeatmap CreateBeatmap(Ruleset ruleset)
- {
- var beatmap = new Beatmap { BeatmapInfo = { Ruleset = ruleset.RulesetInfo } };
-
-
- for (int i = 0; i < 512; i++)
- if (i % 5 < 3)
- beatmap.HitObjects.Add(new Fruit { X = i % 10 < 5 ? 0.02f : 0.98f, StartTime = i * 100, NewCombo = i % 8 == 0 });
-
- return beatmap;
- }
- }
-}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs
similarity index 74%
rename from osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs
rename to osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs
index fc3809fae4..ab3c040b4e 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.Linq;
using osu.Game.Beatmaps;
@@ -13,21 +13,21 @@ using osuTK;
namespace osu.Game.Rulesets.Catch.Tests
{
- public class TestCaseAutoJuiceStream : TestCasePlayer
+ public class TestSceneAutoJuiceStream : PlayerTestScene
{
- public TestCaseAutoJuiceStream()
+ public TestSceneAutoJuiceStream()
: base(new CatchRuleset())
{
}
- 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
}
};
@@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Catch.Tests
protected override Player CreatePlayer(Ruleset ruleset)
{
- Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
+ Mods.Value = Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray();
return base.CreatePlayer(ruleset);
}
}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseBananaShower.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs
similarity index 68%
rename from osu.Game.Rulesets.Catch.Tests/TestCaseBananaShower.cs
rename to osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs
index b5cf0e3d1d..0ad72412fc 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestCaseBananaShower.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
@@ -8,11 +8,12 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Objects.Drawable;
using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Catch.Tests
{
[TestFixture]
- public class TestCaseBananaShower : Game.Tests.Visual.TestCasePlayer
+ public class TestSceneBananaShower : PlayerTestScene
{
public override IReadOnlyList RequiredTypes => new[]
{
@@ -20,22 +21,22 @@ namespace osu.Game.Rulesets.Catch.Tests
typeof(DrawableBananaShower),
typeof(CatchRuleset),
- typeof(CatchRulesetContainer),
+ typeof(DrawableCatchRuleset),
};
- public TestCaseBananaShower()
+ public TestSceneBananaShower()
: base(new CatchRuleset())
{
}
- 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/TestSceneCatchPlayer.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayer.cs
new file mode 100644
index 0000000000..9836a7811a
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayer.cs
@@ -0,0 +1,17 @@
+// 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.Tests.Visual;
+
+namespace osu.Game.Rulesets.Catch.Tests
+{
+ [TestFixture]
+ public class TestSceneCatchPlayer : PlayerTestScene
+ {
+ public TestSceneCatchPlayer()
+ : base(new CatchRuleset())
+ {
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseCatchStacker.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchStacker.cs
similarity index 63%
rename from osu.Game.Rulesets.Catch.Tests/TestCaseCatchStacker.cs
rename to osu.Game.Rulesets.Catch.Tests/TestSceneCatchStacker.cs
index 8a90b48180..9ce46ad6ba 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestCaseCatchStacker.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchStacker.cs
@@ -1,32 +1,32 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Catch.Tests
{
[TestFixture]
- public class TestCaseCatchStacker : Game.Tests.Visual.TestCasePlayer
+ public class TestSceneCatchStacker : PlayerTestScene
{
- public TestCaseCatchStacker()
+ public TestSceneCatchStacker()
: base(new CatchRuleset())
{
}
- 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
}
};
-
for (int i = 0; i < 512; i++)
beatmap.HitObjects.Add(new Fruit { X = 0.5f + i / 2048f * (i % 10 - 5), StartTime = i * 100, NewCombo = i % 8 == 0 });
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/TestCaseCatcherArea.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs
similarity index 86%
rename from osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs
rename to osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs
index 25f7ca108d..3ae6886c31 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
@@ -13,7 +13,7 @@ using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Catch.Tests
{
[TestFixture]
- public class TestCaseCatcherArea : OsuTestCase
+ public class TestSceneCatcherArea : OsuTestScene
{
private RulesetInfo catchRuleset;
private TestCatcherArea catcherArea;
@@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Catch.Tests
typeof(CatcherArea),
};
- public TestCaseCatcherArea()
+ public TestSceneCatcherArea()
{
AddSliderStep("CircleSize", 0, 8, 5, createCatcher);
AddToggleStep("Hyperdash", t => catcherArea.ToggleHyperDash(t));
diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseFruitObjects.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs
similarity index 90%
rename from osu.Game.Rulesets.Catch.Tests/TestCaseFruitObjects.cs
rename to osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs
index 7b6773ad58..44517382f7 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestCaseFruitObjects.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
@@ -15,7 +15,7 @@ using osuTK;
namespace osu.Game.Rulesets.Catch.Tests
{
[TestFixture]
- public class TestCaseFruitObjects : OsuTestCase
+ public class TestSceneFruitObjects : OsuTestScene
{
public override IReadOnlyList RequiredTypes => new[]
{
@@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Catch.Tests
typeof(Pulp),
};
- public TestCaseFruitObjects()
+ public TestSceneFruitObjects()
{
Add(new GridContainer
{
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs
new file mode 100644
index 0000000000..a603d96201
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs
@@ -0,0 +1,47 @@
+// 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.Rulesets.Catch.Objects;
+using osu.Game.Tests.Visual;
+
+namespace osu.Game.Rulesets.Catch.Tests
+{
+ [TestFixture]
+ public class TestSceneHyperDash : PlayerTestScene
+ {
+ public TestSceneHyperDash()
+ : base(new CatchRuleset())
+ {
+ }
+
+ [Test]
+ public void TestHyperDash()
+ {
+ AddAssert("First note is hyperdash", () => Beatmap.Value.Beatmap.HitObjects[0] is Fruit f && f.HyperDash);
+ }
+
+ protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
+ {
+ var beatmap = new Beatmap
+ {
+ BeatmapInfo =
+ {
+ Ruleset = ruleset,
+ BaseDifficulty = new BeatmapDifficulty { CircleSize = 3.6f }
+ }
+ };
+
+ // Should produce a hyper-dash
+ beatmap.HitObjects.Add(new Fruit { StartTime = 816, X = 308 / 512f, NewCombo = true });
+ beatmap.HitObjects.Add(new Fruit { StartTime = 1008, X = 56 / 512f, });
+
+ for (int i = 0; i < 512; i++)
+ if (i % 5 < 3)
+ beatmap.HitObjects.Add(new Fruit { X = i % 10 < 5 ? 0.02f : 0.98f, StartTime = 2000 + i * 100, NewCombo = i % 8 == 0 });
+
+ return beatmap;
+ }
+ }
+}
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 b76f591239..265ecb7688 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,14 +2,14 @@
-
-
-
+
+
+
WinExe
- netcoreapp2.1
+ netcoreapp2.2
diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmap.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmap.cs
index 5b4af6ea8a..18cc300ff9 100644
--- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmap.cs
+++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmap.cs
@@ -1,10 +1,10 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.Collections.Generic;
using System.Linq;
+using osu.Framework.Graphics.Sprites;
using osu.Game.Beatmaps;
-using osu.Game.Graphics;
using osu.Game.Rulesets.Catch.Objects;
namespace osu.Game.Rulesets.Catch.Beatmaps
@@ -23,19 +23,19 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
{
Name = @"Fruit Count",
Content = fruits.ToString(),
- Icon = FontAwesome.fa_circle_o
+ Icon = FontAwesome.Regular.Circle
},
new BeatmapStatistic
{
Name = @"Juice Stream Count",
Content = juiceStreams.ToString(),
- Icon = FontAwesome.fa_circle
+ Icon = FontAwesome.Regular.Circle
},
new BeatmapStatistic
{
Name = @"Banana Shower Count",
Content = bananaShowers.ToString(),
- Icon = FontAwesome.fa_circle
+ Icon = FontAwesome.Regular.Circle
}
};
}
diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs
index c3dc9499c2..0d9a663b9f 100644
--- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs
+++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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;
using osu.Game.Rulesets.Catch.Objects;
diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
index 22c1180c09..645cb5701a 100644
--- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
+++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
@@ -31,6 +31,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
initialiseHyperDash((List)Beatmap.HitObjects);
int index = 0;
+
foreach (var obj in Beatmap.HitObjects.OfType())
{
obj.IndexInBeatmap = index++;
@@ -56,7 +57,9 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
rng.Next(); // osu!stable retrieved a random banana rotation
rng.Next(); // osu!stable retrieved a random banana colour
}
+
break;
+
case JuiceStream juiceStream:
foreach (var nested in juiceStream.NestedHitObjects)
{
@@ -67,6 +70,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
rng.Next(); // osu!stable retrieved a random droplet rotation
hitObject.X = MathHelper.Clamp(hitObject.X, 0, 1);
}
+
break;
}
}
@@ -98,9 +102,10 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
CatchHitObject nextObject = objectWithDroplets[i + 1];
int thisDirection = nextObject.X > currentObject.X ? 1 : -1;
- double timeToNext = nextObject.StartTime - currentObject.StartTime;
+ double timeToNext = nextObject.StartTime - currentObject.StartTime - 1000f / 60f / 4; // 1/4th of a frame of grace time, taken from osu-stable
double distanceToNext = Math.Abs(nextObject.X - currentObject.X) - (lastDirection == thisDirection ? lastExcess : halfCatcherWidth);
float distanceToHyper = (float)(timeToNext * CatcherArea.Catcher.BASE_SPEED - distanceToNext);
+
if (distanceToHyper < 0)
{
currentObject.HyperDashTarget = nextObject;
diff --git a/osu.Game.Rulesets.Catch/CatchInputManager.cs b/osu.Game.Rulesets.Catch/CatchInputManager.cs
index 4f976bb7b2..021d7a7efe 100644
--- a/osu.Game.Rulesets.Catch/CatchInputManager.cs
+++ b/osu.Game.Rulesets.Catch/CatchInputManager.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.ComponentModel;
using osu.Framework.Input.Bindings;
@@ -19,8 +19,10 @@ namespace osu.Game.Rulesets.Catch
{
[Description("Move left")]
MoveLeft,
+
[Description("Move right")]
MoveRight,
+
[Description("Engage dash")]
Dash,
}
diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs
index 1f1d2475f6..ea9f225cc1 100644
--- a/osu.Game.Rulesets.Catch/CatchRuleset.cs
+++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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;
using osu.Game.Graphics;
@@ -9,19 +9,22 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
using System.Collections.Generic;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Bindings;
+using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Replays;
using osu.Game.Rulesets.Replays.Types;
using osu.Game.Beatmaps.Legacy;
using osu.Game.Rulesets.Catch.Beatmaps;
using osu.Game.Rulesets.Catch.Difficulty;
using osu.Game.Rulesets.Difficulty;
+using osu.Game.Scoring;
namespace osu.Game.Rulesets.Catch
{
public class CatchRuleset : Ruleset
{
- public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap) => new CatchRulesetContainer(this, beatmap);
+ public override DrawableRuleset CreateDrawableRulesetWith(WorkingBeatmap beatmap, IReadOnlyList mods) => new DrawableCatchRuleset(this, beatmap, mods);
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new CatchBeatmapConverter(beatmap);
public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new CatchBeatmapProcessor(beatmap);
@@ -84,6 +87,7 @@ namespace osu.Game.Rulesets.Catch
new CatchModNoFail(),
new MultiMod(new CatchModHalfTime(), new CatchModDaycore())
};
+
case ModType.DifficultyIncrease:
return new Mod[]
{
@@ -93,12 +97,20 @@ namespace osu.Game.Rulesets.Catch
new CatchModHidden(),
new CatchModFlashlight(),
};
+
case ModType.Automation:
return new Mod[]
{
new MultiMod(new CatchModAutoplay(), new ModCinema()),
new CatchModRelax(),
};
+
+ case ModType.Fun:
+ return new Mod[]
+ {
+ new MultiMod(new ModWindUp(), new ModWindDown())
+ };
+
default:
return new Mod[] { };
}
@@ -108,10 +120,12 @@ namespace osu.Game.Rulesets.Catch
public override string ShortName => "fruits";
- public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o };
+ public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.RulesetCatch };
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new CatchDifficultyCalculator(this, beatmap);
+ public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new CatchPerformanceCalculator(this, beatmap, score);
+
public override int? LegacyID => 2;
public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new CatchReplayFrame();
diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs
index f6535380c8..75f5b18607 100644
--- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs
+++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs
@@ -1,8 +1,7 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Difficulty;
-using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Difficulty
{
@@ -10,10 +9,5 @@ namespace osu.Game.Rulesets.Catch.Difficulty
{
public double ApproachRate;
public int MaxCombo;
-
- public CatchDifficultyAttributes(Mod[] mods, double starRating)
- : base(mods, starRating)
- {
- }
}
}
diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs
index a763989750..44e1a8e5cc 100644
--- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs
+++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs
@@ -1,149 +1,91 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Difficulty;
-using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Catch.Difficulty.Preprocessing;
+using osu.Game.Rulesets.Catch.Difficulty.Skills;
+using osu.Game.Rulesets.Catch.Mods;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Rulesets.Difficulty;
+using osu.Game.Rulesets.Difficulty.Preprocessing;
+using osu.Game.Rulesets.Difficulty.Skills;
+using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Difficulty
{
public class CatchDifficultyCalculator : DifficultyCalculator
{
-
- ///
- /// In milliseconds. For difficulty calculation we will only look at the highest strain value in each time interval of size STRAIN_STEP.
- /// This is to eliminate higher influence of stream over aim by simply having more HitObjects with high strain.
- /// The higher this value, the less strains there will be, indirectly giving long beatmaps an advantage.
- ///
- private const double strain_step = 750;
-
- ///
- /// The weighting of each strain value decays to this number * it's previous value
- ///
- private const double decay_weight = 0.94;
-
private const double star_scaling_factor = 0.145;
+ protected override int SectionLength => 750;
+
public CatchDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
: base(ruleset, beatmap)
{
}
- protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate)
+ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
{
- if (!beatmap.HitObjects.Any())
- return new CatchDifficultyAttributes(mods, 0);
-
- var catcher = new CatcherArea.Catcher(beatmap.BeatmapInfo.BaseDifficulty);
- float halfCatchWidth = catcher.CatchWidth * 0.5f;
-
- var difficultyHitObjects = new List();
-
- foreach (var hitObject in beatmap.HitObjects)
- {
- switch (hitObject)
- {
- // We want to only consider fruits that contribute to the combo. Droplets are addressed as accuracy and spinners are not relevant for "skill" calculations.
- case Fruit fruit:
- difficultyHitObjects.Add(new CatchDifficultyHitObject(fruit, halfCatchWidth));
- break;
- case JuiceStream _:
- difficultyHitObjects.AddRange(hitObject.NestedHitObjects.OfType().Where(o => !(o is TinyDroplet)).Select(o => new CatchDifficultyHitObject(o, halfCatchWidth)));
- break;
- }
- }
-
- difficultyHitObjects.Sort((a, b) => a.BaseHitObject.StartTime.CompareTo(b.BaseHitObject.StartTime));
-
- if (!calculateStrainValues(difficultyHitObjects, timeRate))
- return new CatchDifficultyAttributes(mods, 0);
+ if (beatmap.HitObjects.Count == 0)
+ 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) / timeRate;
- double starRating = Math.Sqrt(calculateDifficulty(difficultyHitObjects, timeRate)) * star_scaling_factor;
+ double preempt = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / clockRate;
- return new CatchDifficultyAttributes(mods, starRating)
+ return new CatchDifficultyAttributes
{
+ 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 = difficultyHitObjects.Count
+ MaxCombo = beatmap.HitObjects.Count(h => h is Fruit) + beatmap.HitObjects.OfType().SelectMany(j => j.NestedHitObjects).Count(h => !(h is TinyDroplet)),
+ Skills = skills
};
}
- private bool calculateStrainValues(List objects, double timeRate)
+ protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate)
{
- CatchDifficultyHitObject lastObject = null;
+ float halfCatchWidth;
- if (!objects.Any()) return false;
-
- // Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment.
- foreach (var currentObject in objects)
+ using (var catcher = new CatcherArea.Catcher(beatmap.BeatmapInfo.BaseDifficulty))
{
+ halfCatchWidth = catcher.CatchWidth * 0.5f;
+ halfCatchWidth *= 0.8f; // We're only using 80% of the catcher's width to simulate imperfect gameplay.
+ }
+
+ CatchHitObject lastObject = null;
+
+ // In 2B beatmaps, it is possible that a normal Fruit is placed in the middle of a JuiceStream.
+ foreach (var hitObject in beatmap.HitObjects
+ .SelectMany(obj => obj is JuiceStream stream ? stream.NestedHitObjects : new[] { obj })
+ .Cast()
+ .OrderBy(x => x.StartTime))
+ {
+ // We want to only consider fruits that contribute to the combo.
+ if (hitObject is BananaShower || hitObject is TinyDroplet)
+ continue;
+
if (lastObject != null)
- currentObject.CalculateStrains(lastObject, timeRate);
+ yield return new CatchDifficultyHitObject(hitObject, lastObject, clockRate, halfCatchWidth);
- lastObject = currentObject;
+ lastObject = hitObject;
}
-
- return true;
}
- private double calculateDifficulty(List objects, double timeRate)
+ protected override Skill[] CreateSkills(IBeatmap beatmap) => new Skill[]
{
- // The strain step needs to be adjusted for the algorithm to be considered equal with speed changing mods
- double actualStrainStep = strain_step * timeRate;
+ new Movement(),
+ };
- // Find the highest strain value within each strain step
- var highestStrains = new List();
- double intervalEndTime = actualStrainStep;
- double maximumStrain = 0; // We need to keep track of the maximum strain in the current interval
-
- CatchDifficultyHitObject previousHitObject = null;
- foreach (CatchDifficultyHitObject hitObject in objects)
- {
- // While we are beyond the current interval push the currently available maximum to our strain list
- while (hitObject.BaseHitObject.StartTime > intervalEndTime)
- {
- highestStrains.Add(maximumStrain);
-
- // The maximum strain of the next interval is not zero by default! We need to take the last hitObject we encountered, take its strain and apply the decay
- // until the beginning of the next interval.
- if (previousHitObject == null)
- {
- maximumStrain = 0;
- }
- else
- {
- double decay = Math.Pow(CatchDifficultyHitObject.DECAY_BASE, (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000);
- maximumStrain = previousHitObject.Strain * decay;
- }
-
- // Go to the next time interval
- intervalEndTime += actualStrainStep;
- }
-
- // Obtain maximum strain
- maximumStrain = Math.Max(hitObject.Strain, maximumStrain);
-
- previousHitObject = hitObject;
- }
-
- // Build the weighted sum over the highest strains for each interval
- double difficulty = 0;
- double weight = 1;
- highestStrains.Sort((a, b) => b.CompareTo(a)); // Sort from highest to lowest strain.
-
- foreach (double strain in highestStrains)
- {
- difficulty += weight * strain;
- weight *= decay_weight;
- }
-
- return difficulty;
- }
+ protected override Mod[] DifficultyAdjustmentMods => new Mod[]
+ {
+ new CatchModDoubleTime(),
+ new CatchModHalfTime(),
+ new CatchModHardRock(),
+ new CatchModEasy(),
+ };
}
}
diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs
deleted file mode 100644
index bd7796ed91..0000000000
--- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System;
-using osu.Game.Rulesets.Catch.Objects;
-using osu.Game.Rulesets.Catch.UI;
-using osuTK;
-
-namespace osu.Game.Rulesets.Catch.Difficulty
-{
- public class CatchDifficultyHitObject
- {
- internal static readonly double DECAY_BASE = 0.20;
- private const float normalized_hitobject_radius = 41.0f;
- private const float absolute_player_positioning_error = 16f;
- private readonly float playerPositioningError;
-
- internal CatchHitObject BaseHitObject;
-
- ///
- /// Measures jump difficulty. CtB doesn't have something like button pressing speed or accuracy
- ///
- internal double Strain = 1;
-
- ///
- /// This is required to keep track of lazy player movement (always moving only as far as necessary)
- /// Without this quick repeat sliders / weirdly shaped streams might become ridiculously overrated
- ///
- internal float PlayerPositionOffset;
- internal float LastMovement;
-
- internal float NormalizedPosition;
- internal float ActualNormalizedPosition => NormalizedPosition + PlayerPositionOffset;
-
- internal CatchDifficultyHitObject(CatchHitObject baseHitObject, float catcherWidthHalf)
- {
- BaseHitObject = baseHitObject;
-
- // We will scale everything by this factor, so we can assume a uniform CircleSize among beatmaps.
- float scalingFactor = normalized_hitobject_radius / catcherWidthHalf;
-
- playerPositioningError = absolute_player_positioning_error; // * scalingFactor;
- NormalizedPosition = baseHitObject.X * CatchPlayfield.BASE_WIDTH * scalingFactor;
- }
-
- private const double direction_change_bonus = 12.5;
- internal void CalculateStrains(CatchDifficultyHitObject previousHitObject, double timeRate)
- {
- // Rather simple, but more specialized things are inherently inaccurate due to the big difference playstyles and opinions make.
- // See Taiko feedback thread.
- double timeElapsed = (BaseHitObject.StartTime - previousHitObject.BaseHitObject.StartTime) / timeRate;
- double decay = Math.Pow(DECAY_BASE, timeElapsed / 1000);
-
- // Update new position with lazy movement.
- PlayerPositionOffset =
- MathHelper.Clamp(
- previousHitObject.ActualNormalizedPosition,
- NormalizedPosition - (normalized_hitobject_radius - playerPositioningError),
- NormalizedPosition + (normalized_hitobject_radius - playerPositioningError)) // Obtain new lazy position, but be stricter by allowing for an error of a certain degree of the player.
- - NormalizedPosition; // Subtract HitObject position to obtain offset
-
- LastMovement = DistanceTo(previousHitObject);
- double addition = spacingWeight(LastMovement);
-
- if (NormalizedPosition < previousHitObject.NormalizedPosition)
- {
- LastMovement = -LastMovement;
- }
-
- CatchHitObject previousHitCircle = previousHitObject.BaseHitObject;
-
- double additionBonus = 0;
- double sqrtTime = Math.Sqrt(Math.Max(timeElapsed, 25));
-
- // Direction changes give an extra point!
- if (Math.Abs(LastMovement) > 0.1)
- {
- if (Math.Abs(previousHitObject.LastMovement) > 0.1 && Math.Sign(LastMovement) != Math.Sign(previousHitObject.LastMovement))
- {
- double bonus = direction_change_bonus / sqrtTime;
-
- // Weight bonus by how
- double bonusFactor = Math.Min(playerPositioningError, Math.Abs(LastMovement)) / playerPositioningError;
-
- // We want time to play a role twice here!
- addition += bonus * bonusFactor;
-
- // Bonus for tougher direction switches and "almost" hyperdashes at this point
- if (previousHitCircle != null && previousHitCircle.DistanceToHyperDash <= 10.0f / CatchPlayfield.BASE_WIDTH)
- {
- additionBonus += 0.3 * bonusFactor;
- }
- }
-
- // Base bonus for every movement, giving some weight to streams.
- addition += 7.5 * Math.Min(Math.Abs(LastMovement), normalized_hitobject_radius * 2) / (normalized_hitobject_radius * 6) / sqrtTime;
- }
-
- // Bonus for "almost" hyperdashes at corner points
- if (previousHitCircle != null && previousHitCircle.DistanceToHyperDash <= 10.0f / CatchPlayfield.BASE_WIDTH)
- {
- if (!previousHitCircle.HyperDash)
- {
- additionBonus += 1.0;
- }
- else
- {
- // After a hyperdash we ARE in the correct position. Always!
- PlayerPositionOffset = 0;
- }
-
- addition *= 1.0 + additionBonus * ((10 - previousHitCircle.DistanceToHyperDash * CatchPlayfield.BASE_WIDTH) / 10);
- }
-
- addition *= 850.0 / Math.Max(timeElapsed, 25);
-
- Strain = previousHitObject.Strain * decay + addition;
- }
-
- private static double spacingWeight(float distance)
- {
- return Math.Pow(distance, 1.3) / 500;
- }
-
- internal float DistanceTo(CatchDifficultyHitObject other)
- {
- return Math.Abs(ActualNormalizedPosition - other.ActualNormalizedPosition);
- }
- }
-}
diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs
new file mode 100644
index 0000000000..5a640f6d1a
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs
@@ -0,0 +1,104 @@
+// 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.Beatmaps;
+using osu.Game.Rulesets.Difficulty;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Scoring;
+using osu.Game.Scoring;
+using osu.Game.Scoring.Legacy;
+using osuTK;
+
+namespace osu.Game.Rulesets.Catch.Difficulty
+{
+ public class CatchPerformanceCalculator : PerformanceCalculator
+ {
+ protected new CatchDifficultyAttributes Attributes => (CatchDifficultyAttributes)base.Attributes;
+
+ private Mod[] mods;
+
+ private int fruitsHit;
+ private int ticksHit;
+ private int tinyTicksHit;
+ private int tinyTicksMissed;
+ private int misses;
+
+ public CatchPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, ScoreInfo score)
+ : base(ruleset, beatmap, score)
+ {
+ }
+
+ public override double Calculate(Dictionary categoryDifficulty = null)
+ {
+ mods = Score.Mods;
+
+ var legacyScore = Score as LegacyScoreInfo;
+
+ fruitsHit = legacyScore?.Count300 ?? Score.Statistics[HitResult.Perfect];
+ ticksHit = legacyScore?.Count100 ?? 0;
+ tinyTicksHit = legacyScore?.Count50 ?? 0;
+ tinyTicksMissed = legacyScore?.CountKatu ?? 0;
+ misses = Score.Statistics[HitResult.Miss];
+
+ // Don't count scores made with supposedly unranked mods
+ if (mods.Any(m => !m.Ranked))
+ return 0;
+
+ // We are heavily relying on aim in catch the beat
+ double value = Math.Pow(5.0f * Math.Max(1.0f, Attributes.StarRating / 0.0049f) - 4.0f, 2.0f) / 100000.0f;
+
+ // Longer maps are worth more. "Longer" means how many hits there are which can contribute to combo
+ int numTotalHits = totalComboHits();
+
+ // Longer maps are worth more
+ float lengthBonus =
+ 0.95f + 0.4f * Math.Min(1.0f, numTotalHits / 3000.0f) +
+ (numTotalHits > 3000 ? (float)Math.Log10(numTotalHits / 3000.0f) * 0.5f : 0.0f);
+
+ // Longer maps are worth more
+ value *= lengthBonus;
+
+ // Penalize misses exponentially. This mainly fixes tag4 maps and the likes until a per-hitobject solution is available
+ value *= Math.Pow(0.97f, misses);
+
+ // Combo scaling
+ float beatmapMaxCombo = Attributes.MaxCombo;
+ if (beatmapMaxCombo > 0)
+ value *= Math.Min(Math.Pow(Attributes.MaxCombo, 0.8f) / Math.Pow(beatmapMaxCombo, 0.8f), 1.0f);
+
+ float approachRate = (float)Attributes.ApproachRate;
+ float approachRateFactor = 1.0f;
+ if (approachRate > 9.0f)
+ approachRateFactor += 0.1f * (approachRate - 9.0f); // 10% for each AR above 9
+ else if (approachRate < 8.0f)
+ approachRateFactor += 0.025f * (8.0f - approachRate); // 2.5% for each AR below 8
+
+ value *= approachRateFactor;
+
+ if (mods.Any(m => m is ModHidden))
+ // Hiddens gives nothing on max approach rate, and more the lower it is
+ value *= 1.05f + 0.075f * (10.0f - Math.Min(10.0f, approachRate)); // 7.5% for each AR below 10
+
+ if (mods.Any(m => m is ModFlashlight))
+ // Apply length bonus again if flashlight is on simply because it becomes a lot harder on longer maps.
+ value *= 1.35f * lengthBonus;
+
+ // Scale the aim value with accuracy _slightly_
+ value *= Math.Pow(accuracy(), 5.5f);
+
+ // Custom multipliers for NoFail. SpunOut is not applicable.
+ if (mods.Any(m => m is ModNoFail))
+ value *= 0.90f;
+
+ return value;
+ }
+
+ private float accuracy() => totalHits() == 0 ? 0 : MathHelper.Clamp((float)totalSuccessfulHits() / totalHits(), 0f, 1f);
+ private int totalHits() => tinyTicksHit + ticksHit + fruitsHit + misses + tinyTicksMissed;
+ private int totalSuccessfulHits() => tinyTicksHit + ticksHit + fruitsHit;
+ private int totalComboHits() => misses + ticksHit + fruitsHit;
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Difficulty/Preprocessing/CatchDifficultyHitObject.cs b/osu.Game.Rulesets.Catch/Difficulty/Preprocessing/CatchDifficultyHitObject.cs
new file mode 100644
index 0000000000..24e526ed19
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Difficulty/Preprocessing/CatchDifficultyHitObject.cs
@@ -0,0 +1,41 @@
+// 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.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Rulesets.Difficulty.Preprocessing;
+using osu.Game.Rulesets.Objects;
+
+namespace osu.Game.Rulesets.Catch.Difficulty.Preprocessing
+{
+ public class CatchDifficultyHitObject : DifficultyHitObject
+ {
+ private const float normalized_hitobject_radius = 41.0f;
+
+ public new CatchHitObject BaseObject => (CatchHitObject)base.BaseObject;
+
+ public new CatchHitObject LastObject => (CatchHitObject)base.LastObject;
+
+ public readonly float NormalizedPosition;
+ public readonly float LastNormalizedPosition;
+
+ ///
+ /// Milliseconds elapsed since the start time of the previous , with a minimum of 25ms.
+ ///
+ public readonly double StrainTime;
+
+ public CatchDifficultyHitObject(HitObject hitObject, HitObject lastObject, double clockRate, float halfCatcherWidth)
+ : base(hitObject, lastObject, clockRate)
+ {
+ // We will scale everything by this factor, so we can assume a uniform CircleSize among beatmaps.
+ var scalingFactor = normalized_hitobject_radius / halfCatcherWidth;
+
+ NormalizedPosition = BaseObject.X * CatchPlayfield.BASE_WIDTH * scalingFactor;
+ LastNormalizedPosition = LastObject.X * CatchPlayfield.BASE_WIDTH * scalingFactor;
+
+ // Every strain interval is hard capped at the equivalent of 600 BPM streaming speed as a safety measure
+ StrainTime = Math.Max(25, DeltaTime);
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs b/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs
new file mode 100644
index 0000000000..d146153294
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs
@@ -0,0 +1,85 @@
+// 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.Game.Rulesets.Catch.Difficulty.Preprocessing;
+using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Rulesets.Difficulty.Preprocessing;
+using osu.Game.Rulesets.Difficulty.Skills;
+using osuTK;
+
+namespace osu.Game.Rulesets.Catch.Difficulty.Skills
+{
+ public class Movement : Skill
+ {
+ private const float absolute_player_positioning_error = 16f;
+ private const float normalized_hitobject_radius = 41.0f;
+ private const double direction_change_bonus = 12.5;
+
+ protected override double SkillMultiplier => 850;
+ protected override double StrainDecayBase => 0.2;
+
+ protected override double DecayWeight => 0.94;
+
+ private float? lastPlayerPosition;
+ private float lastDistanceMoved;
+
+ protected override double StrainValueOf(DifficultyHitObject current)
+ {
+ var catchCurrent = (CatchDifficultyHitObject)current;
+
+ if (lastPlayerPosition == null)
+ lastPlayerPosition = catchCurrent.LastNormalizedPosition;
+
+ float playerPosition = MathHelper.Clamp(
+ lastPlayerPosition.Value,
+ catchCurrent.NormalizedPosition - (normalized_hitobject_radius - absolute_player_positioning_error),
+ catchCurrent.NormalizedPosition + (normalized_hitobject_radius - absolute_player_positioning_error)
+ );
+
+ float distanceMoved = playerPosition - lastPlayerPosition.Value;
+
+ double distanceAddition = Math.Pow(Math.Abs(distanceMoved), 1.3) / 500;
+ double sqrtStrain = Math.Sqrt(catchCurrent.StrainTime);
+
+ double bonus = 0;
+
+ // Direction changes give an extra point!
+ if (Math.Abs(distanceMoved) > 0.1)
+ {
+ if (Math.Abs(lastDistanceMoved) > 0.1 && Math.Sign(distanceMoved) != Math.Sign(lastDistanceMoved))
+ {
+ double bonusFactor = Math.Min(absolute_player_positioning_error, Math.Abs(distanceMoved)) / absolute_player_positioning_error;
+
+ distanceAddition += direction_change_bonus / sqrtStrain * bonusFactor;
+
+ // Bonus for tougher direction switches and "almost" hyperdashes at this point
+ if (catchCurrent.LastObject.DistanceToHyperDash <= 10 / CatchPlayfield.BASE_WIDTH)
+ bonus = 0.3 * bonusFactor;
+ }
+
+ // Base bonus for every movement, giving some weight to streams.
+ distanceAddition += 7.5 * Math.Min(Math.Abs(distanceMoved), normalized_hitobject_radius * 2) / (normalized_hitobject_radius * 6) / sqrtStrain;
+ }
+
+ // Bonus for "almost" hyperdashes at corner points
+ if (catchCurrent.LastObject.DistanceToHyperDash <= 10.0f / CatchPlayfield.BASE_WIDTH)
+ {
+ if (!catchCurrent.LastObject.HyperDash)
+ bonus += 1.0;
+ else
+ {
+ // After a hyperdash we ARE in the correct position. Always!
+ playerPosition = catchCurrent.NormalizedPosition;
+ }
+
+ distanceAddition *= 1.0 + bonus * ((10 - catchCurrent.LastObject.DistanceToHyperDash * CatchPlayfield.BASE_WIDTH) / 10);
+ }
+
+ lastPlayerPosition = playerPosition;
+ lastDistanceMoved = distanceMoved;
+
+ return distanceAddition / catchCurrent.StrainTime;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchBananaJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchBananaJudgement.cs
index f38009263f..374dd50c11 100644
--- a/osu.Game.Rulesets.Catch/Judgements/CatchBananaJudgement.cs
+++ b/osu.Game.Rulesets.Catch/Judgements/CatchBananaJudgement.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
@@ -16,19 +16,21 @@ namespace osu.Game.Rulesets.Catch.Judgements
{
default:
return 0;
+
case HitResult.Perfect:
return 1100;
}
}
- protected override float HealthIncreaseFor(HitResult result)
+ protected override double HealthIncreaseFor(HitResult result)
{
switch (result)
{
default:
return 0;
+
case HitResult.Perfect:
- return 8;
+ return 0.008;
}
}
diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchDropletJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchDropletJudgement.cs
index 0df2305339..f1399bb5c0 100644
--- a/osu.Game.Rulesets.Catch/Judgements/CatchDropletJudgement.cs
+++ b/osu.Game.Rulesets.Catch/Judgements/CatchDropletJudgement.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Scoring;
@@ -13,19 +13,21 @@ namespace osu.Game.Rulesets.Catch.Judgements
{
default:
return 0;
+
case HitResult.Perfect:
return 30;
}
}
- protected override float HealthIncreaseFor(HitResult result)
+ protected override double HealthIncreaseFor(HitResult result)
{
switch (result)
{
default:
- return 0;
+ return base.HealthIncreaseFor(result);
+
case HitResult.Perfect:
- return 7;
+ return 0.007;
}
}
}
diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs
index 8a51867899..8fd9ac92ba 100644
--- a/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs
+++ b/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Types;
@@ -17,34 +17,24 @@ namespace osu.Game.Rulesets.Catch.Judgements
{
default:
return 0;
+
case HitResult.Perfect:
return 300;
}
}
- ///
- /// Retrieves the numeric health increase of a .
- ///
- /// The to find the numeric health increase for.
- /// The numeric health increase of .
- protected virtual float HealthIncreaseFor(HitResult result)
+ protected override double HealthIncreaseFor(HitResult result)
{
switch (result)
{
default:
- return 0;
+ return -0.02;
+
case HitResult.Perfect:
- return 10.2f;
+ return 0.01;
}
}
- ///
- /// Retrieves the numeric health increase of a .
- ///
- /// The to find the numeric health increase for.
- /// The numeric health increase of .
- public float HealthIncreaseFor(JudgementResult result) => HealthIncreaseFor(result.Type);
-
///
/// Whether fruit on the platter should explode or drop.
/// Note that this is only checked if the owning object is also
diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchTinyDropletJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchTinyDropletJudgement.cs
index 8b77351027..3829b5e94f 100644
--- a/osu.Game.Rulesets.Catch/Judgements/CatchTinyDropletJudgement.cs
+++ b/osu.Game.Rulesets.Catch/Judgements/CatchTinyDropletJudgement.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Scoring;
@@ -15,19 +15,21 @@ namespace osu.Game.Rulesets.Catch.Judgements
{
default:
return 0;
+
case HitResult.Perfect:
return 10;
}
}
- protected override float HealthIncreaseFor(HitResult result)
+ protected override double HealthIncreaseFor(HitResult result)
{
switch (result)
{
default:
return 0;
+
case HitResult.Perfect:
- return 4;
+ return 0.004;
}
}
}
diff --git a/osu.Game.Rulesets.Catch/MathUtils/FastRandom.cs b/osu.Game.Rulesets.Catch/MathUtils/FastRandom.cs
index 5b3835755a..b3605b013b 100644
--- a/osu.Game.Rulesets.Catch/MathUtils/FastRandom.cs
+++ b/osu.Game.Rulesets.Catch/MathUtils/FastRandom.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
@@ -33,11 +33,11 @@ namespace osu.Game.Rulesets.Catch.MathUtils
/// The random value.
public uint NextUInt()
{
- uint t = _x ^ _x << 11;
+ uint t = _x ^ (_x << 11);
_x = _y;
_y = _z;
_z = _w;
- return _w = _w ^ _w >> 19 ^ t ^ t >> 8;
+ return _w = _w ^ (_w >> 19) ^ t ^ (t >> 8);
}
///
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs b/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs
index 5ed563614a..692e63fa69 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs
@@ -1,24 +1,21 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Replays;
using osu.Game.Rulesets.Mods;
-using osu.Game.Rulesets.Scoring;
+using osu.Game.Scoring;
using osu.Game.Users;
namespace osu.Game.Rulesets.Catch.Mods
{
public class CatchModAutoplay : ModAutoplay
{
- protected override Score CreateReplayScore(Beatmap beatmap)
+ public override Score CreateReplayScore(IBeatmap beatmap) => new Score
{
- return new Score
- {
- User = new User { Username = "osu!salad!" },
- Replay = new CatchAutoGenerator(beatmap).Generate(),
- };
- }
+ ScoreInfo = new ScoreInfo { User = new User { Username = "osu!salad!" } },
+ Replay = new CatchAutoGenerator(beatmap).Generate(),
+ };
}
}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModDaycore.cs b/osu.Game.Rulesets.Catch/Mods/CatchModDaycore.cs
index 6d4caef8d2..cae19e9468 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModDaycore.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModDaycore.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModDoubleTime.cs b/osu.Game.Rulesets.Catch/Mods/CatchModDoubleTime.cs
index dcf417c405..178909387f 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModDoubleTime.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModDoubleTime.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModEasy.cs b/osu.Game.Rulesets.Catch/Mods/CatchModEasy.cs
index d20a2ec727..a82d0af102 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModEasy.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModEasy.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs
index 9cfba0236a..71268d899d 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs
@@ -1,6 +1,7 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI;
@@ -20,10 +21,10 @@ namespace osu.Game.Rulesets.Catch.Mods
private CatchPlayfield playfield;
- public override void ApplyToRulesetContainer(RulesetContainer rulesetContainer)
+ public override void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
{
- playfield = (CatchPlayfield)rulesetContainer.Playfield;
- base.ApplyToRulesetContainer(rulesetContainer);
+ playfield = (CatchPlayfield)drawableRuleset.Playfield;
+ base.ApplyToDrawableRuleset(drawableRuleset);
}
private class CatchFlashlight : Flashlight
@@ -55,9 +56,9 @@ namespace osu.Game.Rulesets.Catch.Mods
return default_flashlight_size;
}
- protected override void OnComboChange(int newCombo)
+ protected override void OnComboChange(ValueChangedEvent e)
{
- this.TransformTo(nameof(FlashlightSize), new Vector2(0, getSizeFor(newCombo)), FLASHLIGHT_FADE_DURATION);
+ this.TransformTo(nameof(FlashlightSize), new Vector2(0, getSizeFor(e.NewValue)), FLASHLIGHT_FADE_DURATION);
}
protected override string FragmentShader => "CircularFlashlight";
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModHalfTime.cs b/osu.Game.Rulesets.Catch/Mods/CatchModHalfTime.cs
index 4e48de454f..ce06b841aa 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModHalfTime.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModHalfTime.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs b/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs
index 8e19c0614a..060e51e31d 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.MathUtils;
using osu.Game.Rulesets.Catch.Objects;
@@ -15,77 +15,107 @@ namespace osu.Game.Rulesets.Catch.Mods
public override double ScoreMultiplier => 1.12;
public override bool Ranked => true;
- private float lastStartX;
- private int lastStartTime;
+ private float? lastPosition;
+ private double lastStartTime;
public void ApplyToHitObject(HitObject hitObject)
{
+ if (hitObject is JuiceStream stream)
+ {
+ lastPosition = stream.EndX;
+ lastStartTime = stream.EndTime;
+ return;
+ }
+
+ if (!(hitObject is Fruit))
+ return;
+
var catchObject = (CatchHitObject)hitObject;
float position = catchObject.X;
- int startTime = (int)hitObject.StartTime;
+ double startTime = hitObject.StartTime;
- if (lastStartX == 0)
+ if (lastPosition == null)
{
- lastStartX = position;
+ lastPosition = position;
lastStartTime = startTime;
+
return;
}
- float diff = lastStartX - position;
- int timeDiff = startTime - lastStartTime;
+ float positionDiff = position - lastPosition.Value;
+ double timeDiff = startTime - lastStartTime;
if (timeDiff > 1000)
{
- lastStartX = position;
+ lastPosition = position;
lastStartTime = startTime;
return;
}
- if (diff == 0)
+ if (positionDiff == 0)
{
- bool right = RNG.NextBool();
-
- float rand = Math.Min(20, (float)RNG.NextDouble(0, timeDiff / 4d)) / CatchPlayfield.BASE_WIDTH;
-
- if (right)
- {
- if (position + rand <= 1)
- position += rand;
- else
- position -= rand;
- }
- else
- {
- if (position - rand >= 0)
- position -= rand;
- else
- position += rand;
- }
-
+ applyRandomOffset(ref position, timeDiff / 4d);
catchObject.X = position;
-
return;
}
- if (Math.Abs(diff) < timeDiff / 3d)
- {
- if (diff > 0)
- {
- if (position - diff > 0)
- position -= diff;
- }
- else
- {
- if (position - diff < 1)
- position -= diff;
- }
- }
+ if (Math.Abs(positionDiff * CatchPlayfield.BASE_WIDTH) < timeDiff / 3d)
+ applyOffset(ref position, positionDiff);
catchObject.X = position;
- lastStartX = position;
+ lastPosition = position;
lastStartTime = startTime;
}
+
+ ///
+ /// Applies a random offset in a random direction to a position, ensuring that the final position remains within the boundary of the playfield.
+ ///
+ /// The position which the offset should be applied to.
+ /// The maximum offset, cannot exceed 20px.
+ private void applyRandomOffset(ref float position, double maxOffset)
+ {
+ bool right = RNG.NextBool();
+ float rand = Math.Min(20, (float)RNG.NextDouble(0, Math.Max(0, maxOffset))) / CatchPlayfield.BASE_WIDTH;
+
+ if (right)
+ {
+ // Clamp to the right bound
+ if (position + rand <= 1)
+ position += rand;
+ else
+ position -= rand;
+ }
+ else
+ {
+ // Clamp to the left bound
+ if (position - rand >= 0)
+ position -= rand;
+ else
+ position += rand;
+ }
+ }
+
+ ///
+ /// Applies an offset to a position, ensuring that the final position remains within the boundary of the playfield.
+ ///
+ /// The position which the offset should be applied to.
+ /// The amount to offset by.
+ private void applyOffset(ref float position, float amount)
+ {
+ if (amount > 0)
+ {
+ // Clamp to the right bound
+ if (position + amount < 1)
+ position += amount;
+ }
+ else
+ {
+ // Clamp to the left bound
+ if (position + amount > 0)
+ position += amount;
+ }
+ }
}
}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs b/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs
index f2716f351e..9990b01427 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModNightcore.cs b/osu.Game.Rulesets.Catch/Mods/CatchModNightcore.cs
index 687db172cf..da2edcee44 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModNightcore.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModNightcore.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModNoFail.cs b/osu.Game.Rulesets.Catch/Mods/CatchModNoFail.cs
index 914419438d..3c02646e99 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModNoFail.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModNoFail.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModPerfect.cs b/osu.Game.Rulesets.Catch/Mods/CatchModPerfect.cs
index de00ff31ce..fb92399102 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModPerfect.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModPerfect.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs
index 8bf9f32572..0454bc969d 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModSuddenDeath.cs b/osu.Game.Rulesets.Catch/Mods/CatchModSuddenDeath.cs
index 71461cfc40..68e01391ce 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModSuddenDeath.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModSuddenDeath.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Catch/Objects/Banana.cs b/osu.Game.Rulesets.Catch/Objects/Banana.cs
index e1af4c1075..0b3d1d23e0 100644
--- a/osu.Game.Rulesets.Catch/Objects/Banana.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Banana.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Judgements;
diff --git a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
index 25af7e4bdf..6d44e4660e 100644
--- a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
+++ b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Objects.Types;
diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
index 0c50dae9fb..2153b8dc85 100644
--- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
+++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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;
using osu.Game.Beatmaps.ControlPoints;
diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitWindows.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitWindows.cs
new file mode 100644
index 0000000000..837662f5fe
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Objects/CatchHitWindows.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.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Scoring;
+
+namespace osu.Game.Rulesets.Catch.Objects
+{
+ public class CatchHitWindows : HitWindows
+ {
+ public override bool IsHitResultAllowed(HitResult result)
+ {
+ switch (result)
+ {
+ case HitResult.Perfect:
+ case HitResult.Miss:
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBanana.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBanana.cs
index 8756a5178f..5afdb14888 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBanana.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBanana.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Catch.Objects.Drawable
{
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBananaShower.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBananaShower.cs
index 697fab85c9..42646851d7 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBananaShower.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBananaShower.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Linq;
@@ -13,17 +13,17 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
private readonly Container bananaContainer;
- public DrawableBananaShower(BananaShower s, Func> getVisualRepresentation = null)
+ public DrawableBananaShower(BananaShower s, Func> createDrawableRepresentation = null)
: base(s)
{
RelativeSizeAxes = Axes.X;
Origin = Anchor.BottomLeft;
X = 0;
- InternalChild = bananaContainer = new Container { RelativeSizeAxes = Axes.Both };
+ AddInternal(bananaContainer = new Container { RelativeSizeAxes = Axes.Both });
foreach (var b in s.NestedHitObjects.Cast())
- AddNested(getVisualRepresentation?.Invoke(b));
+ AddNested(createDrawableRepresentation?.Invoke(b));
}
protected override void AddNested(DrawableHitObject h)
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
index 2db252ebc6..2f8ccec48b 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using osuTK;
@@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
base.SkinChanged(skin, allowFallback);
if (HitObject is IHasComboInformation combo)
- AccentColour = skin.GetValue(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
+ AccentColour = skin.GetValue(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
}
private const float preempt = 1000;
@@ -84,6 +84,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
case ArmedState.Miss:
this.FadeOut(250).RotateTo(Rotation * 2, 250, Easing.Out).Expire();
break;
+
case ArmedState.Hit:
this.FadeOut().Expire();
break;
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs
index a896d13132..9cabdc3dd9 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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;
@@ -26,15 +26,12 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
[BackgroundDependencyLoader]
private void load()
{
- InternalChild = pulp = new Pulp
- {
- Size = Size
- };
+ AddInternal(pulp = new Pulp { Size = Size });
}
public override Color4 AccentColour
{
- get { return base.AccentColour; }
+ get => base.AccentColour;
set
{
base.AccentColour = value;
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
index 4bd50f29f6..77407def54 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
@@ -1,11 +1,12 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
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.MathUtils;
using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
@@ -42,7 +43,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
// todo: this should come from the skin.
AccentColour = colourForRepresentation(HitObject.VisualRepresentation);
- InternalChildren = new[]
+ AddRangeInternal(new[]
{
createPulp(HitObject.VisualRepresentation),
border = new Circle
@@ -70,7 +71,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
}
}
},
- };
+ });
if (HitObject.HyperDash)
{
@@ -105,6 +106,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
default:
return new Container();
+
case FruitVisualRepresentation.Raspberry:
return new Container
{
@@ -143,6 +145,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
},
}
};
+
case FruitVisualRepresentation.Pineapple:
return new Container
{
@@ -181,6 +184,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
},
}
};
+
case FruitVisualRepresentation.Pear:
return new Container
{
@@ -213,6 +217,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
},
}
};
+
case FruitVisualRepresentation.Grape:
return new Container
{
@@ -245,6 +250,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
},
}
};
+
case FruitVisualRepresentation.Banana:
return new Container
{
@@ -282,19 +288,25 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
default:
case FruitVisualRepresentation.Pear:
return new Color4(17, 136, 170, 255);
+
case FruitVisualRepresentation.Grape:
return new Color4(204, 102, 0, 255);
+
case FruitVisualRepresentation.Raspberry:
return new Color4(121, 9, 13, 255);
+
case FruitVisualRepresentation.Pineapple:
return new Color4(102, 136, 0, 255);
+
case FruitVisualRepresentation.Banana:
switch (RNG.Next(0, 3))
{
default:
return new Color4(255, 240, 0, 255);
+
case 1:
return new Color4(255, 192, 0, 255);
+
case 2:
return new Color4(214, 221, 28, 255);
}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs
index e66852c5c2..9e5e9f6a04 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Linq;
@@ -13,17 +13,17 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
private readonly Container dropletContainer;
- public DrawableJuiceStream(JuiceStream s, Func> getVisualRepresentation = null)
+ public DrawableJuiceStream(JuiceStream s, Func> createDrawableRepresentation = null)
: base(s)
{
RelativeSizeAxes = Axes.Both;
Origin = Anchor.BottomLeft;
X = 0;
- InternalChild = dropletContainer = new Container { RelativeSizeAxes = Axes.Both, };
+ AddInternal(dropletContainer = new Container { RelativeSizeAxes = Axes.Both, });
foreach (var o in s.NestedHitObjects.Cast())
- AddNested(getVisualRepresentation?.Invoke(o));
+ AddNested(createDrawableRepresentation?.Invoke(o));
}
protected override void AddNested(DrawableHitObject h)
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableTinyDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableTinyDroplet.cs
index 2f167121aa..d41aea1e7b 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableTinyDroplet.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableTinyDroplet.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
using osuTK;
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs
index f21c14f076..b9b6d5b924 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs
@@ -1,9 +1,9 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Color4Extensions;
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osuTK.Graphics;
@@ -23,9 +23,10 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces
}
private Color4 accentColour;
+
public Color4 AccentColour
{
- get { return accentColour; }
+ get => accentColour;
set
{
accentColour = value;
diff --git a/osu.Game.Rulesets.Catch/Objects/Droplet.cs b/osu.Game.Rulesets.Catch/Objects/Droplet.cs
index 8b54922959..7b0bb3f0ae 100644
--- a/osu.Game.Rulesets.Catch/Objects/Droplet.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Droplet.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Judgements;
diff --git a/osu.Game.Rulesets.Catch/Objects/Fruit.cs b/osu.Game.Rulesets.Catch/Objects/Fruit.cs
index 2c2cd013c3..6f0423b420 100644
--- a/osu.Game.Rulesets.Catch/Objects/Fruit.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Fruit.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Judgements;
diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
index d8bd3e0edc..0952e8981a 100644
--- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
+++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
@@ -1,7 +1,6 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Audio;
@@ -25,6 +24,11 @@ namespace osu.Game.Rulesets.Catch.Objects
public double Velocity;
public double TickDistance;
+ ///
+ /// The length of one span of this .
+ ///
+ public double SpanDuration => Duration / this.SpanCount();
+
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
@@ -41,93 +45,68 @@ namespace osu.Game.Rulesets.Catch.Objects
protected override void CreateNestedHitObjects()
{
base.CreateNestedHitObjects();
- createTicks();
- }
- private void createTicks()
- {
- if (TickDistance == 0)
- return;
-
- var length = Path.Distance;
- var tickDistance = Math.Min(TickDistance, length);
- var spanDuration = length / Velocity;
-
- var minDistanceFromEnd = Velocity * 0.01;
-
- AddNested(new Fruit
+ var tickSamples = Samples.Select(s => new HitSampleInfo
{
- Samples = Samples,
- StartTime = StartTime,
- X = X
- });
+ Bank = s.Bank,
+ Name = @"slidertick",
+ Volume = s.Volume
+ }).ToList();
- double lastDropletTime = StartTime;
+ SliderEventDescriptor? lastEvent = null;
- for (int span = 0; span < this.SpanCount(); span++)
+ foreach (var e in SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset))
{
- var spanStartTime = StartTime + span * spanDuration;
- var reversed = span % 2 == 1;
-
- for (double d = 0; d <= length; d += tickDistance)
+ // generate tiny droplets since the last point
+ if (lastEvent != null)
{
- var timeProgress = d / length;
- var distanceProgress = reversed ? 1 - timeProgress : timeProgress;
+ double sinceLastTick = e.Time - lastEvent.Value.Time;
- double time = spanStartTime + timeProgress * spanDuration;
-
- if (LegacyLastTickOffset != null)
+ if (sinceLastTick > 80)
{
- // If we're the last tick, apply the legacy offset
- if (span == this.SpanCount() - 1 && d + tickDistance > length)
- time = Math.Max(StartTime + Duration / 2, time - LegacyLastTickOffset.Value);
- }
+ double timeBetweenTiny = sinceLastTick;
+ while (timeBetweenTiny > 100)
+ timeBetweenTiny /= 2;
- double tinyTickInterval = time - lastDropletTime;
- while (tinyTickInterval > 100)
- tinyTickInterval /= 2;
-
- for (double t = lastDropletTime + tinyTickInterval; t < time; t += tinyTickInterval)
- {
- double progress = reversed ? 1 - (t - spanStartTime) / spanDuration : (t - spanStartTime) / spanDuration;
-
- AddNested(new TinyDroplet
+ for (double t = timeBetweenTiny; t < sinceLastTick; t += timeBetweenTiny)
{
- StartTime = t,
- X = X + Path.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH,
- Samples = new List(Samples.Select(s => new SampleInfo
+ AddNested(new TinyDroplet
{
- Bank = s.Bank,
- Name = @"slidertick",
- Volume = s.Volume
- }))
- });
+ Samples = tickSamples,
+ StartTime = t + lastEvent.Value.Time,
+ X = X + Path.PositionAt(
+ lastEvent.Value.PathProgress + (t / sinceLastTick) * (e.PathProgress - lastEvent.Value.PathProgress)).X / CatchPlayfield.BASE_WIDTH,
+ });
+ }
}
-
- if (d > minDistanceFromEnd && Math.Abs(d - length) > minDistanceFromEnd)
- {
- AddNested(new Droplet
- {
- StartTime = time,
- X = X + Path.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH,
- Samples = new List(Samples.Select(s => new SampleInfo
- {
- Bank = s.Bank,
- Name = @"slidertick",
- Volume = s.Volume
- }))
- });
- }
-
- lastDropletTime = time;
}
- AddNested(new Fruit
+ // this also includes LegacyLastTick and this is used for TinyDroplet generation above.
+ // this means that the final segment of TinyDroplets are increasingly mistimed where LegacyLastTickOffset is being applied.
+ lastEvent = e;
+
+ switch (e.Type)
{
- Samples = Samples,
- StartTime = spanStartTime + spanDuration,
- X = X + Path.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH
- });
+ case SliderEventType.Tick:
+ AddNested(new Droplet
+ {
+ Samples = tickSamples,
+ StartTime = e.Time,
+ X = X + Path.PositionAt(e.PathProgress).X / CatchPlayfield.BASE_WIDTH,
+ });
+ break;
+
+ case SliderEventType.Head:
+ case SliderEventType.Tail:
+ case SliderEventType.Repeat:
+ AddNested(new Fruit
+ {
+ Samples = Samples,
+ StartTime = e.Time,
+ X = X + Path.PositionAt(e.PathProgress).X / CatchPlayfield.BASE_WIDTH,
+ });
+ break;
+ }
}
}
@@ -147,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/Objects/TinyDroplet.cs b/osu.Game.Rulesets.Catch/Objects/TinyDroplet.cs
index 39f1cadad5..1bf160b5a6 100644
--- a/osu.Game.Rulesets.Catch/Objects/TinyDroplet.cs
+++ b/osu.Game.Rulesets.Catch/Objects/TinyDroplet.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Judgements;
diff --git a/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs b/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs
index 045d0824c6..dba76eef49 100644
--- a/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs
+++ b/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.Runtime.CompilerServices;
@@ -9,3 +9,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")]
diff --git a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs
index 23b620248f..8dd00756f2 100644
--- a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs
+++ b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs
@@ -1,25 +1,28 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Linq;
using osu.Framework.MathUtils;
using osu.Game.Beatmaps;
+using osu.Game.Replays;
+using osu.Game.Rulesets.Catch.Beatmaps;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Replays;
-using osu.Game.Users;
namespace osu.Game.Rulesets.Catch.Replays
{
- internal class CatchAutoGenerator : AutoGenerator
+ internal class CatchAutoGenerator : AutoGenerator
{
public const double RELEASE_DELAY = 20;
- public CatchAutoGenerator(Beatmap beatmap)
+ public new CatchBeatmap Beatmap => (CatchBeatmap)base.Beatmap;
+
+ public CatchAutoGenerator(IBeatmap beatmap)
: base(beatmap)
{
- Replay = new Replay { User = new User { Username = @"Autoplay" } };
+ Replay = new Replay();
}
protected Replay Replay;
@@ -40,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;
@@ -56,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/Replays/CatchFramedReplayInputHandler.cs b/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs
index f05eb31454..103aa6c3f1 100644
--- a/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs
+++ b/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs
@@ -1,9 +1,11 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.Collections.Generic;
+using System.Diagnostics;
using osu.Framework.Input.StateChanges;
using osu.Framework.MathUtils;
+using osu.Game.Replays;
using osu.Game.Rulesets.Replays;
namespace osu.Game.Rulesets.Catch.Replays
@@ -21,10 +23,14 @@ namespace osu.Game.Rulesets.Catch.Replays
{
get
{
- if (!HasFrames)
+ var frame = CurrentFrame;
+
+ if (frame == null)
return null;
- return Interpolation.ValueAt(CurrentTime, CurrentFrame.Position, NextFrame.Position, CurrentFrame.Time, NextFrame.Time);
+ Debug.Assert(CurrentTime != null);
+
+ return NextFrame != null ? Interpolation.ValueAt(CurrentTime.Value, frame.Position, NextFrame.Position, frame.Time, NextFrame.Time) : frame.Position;
}
}
diff --git a/osu.Game.Rulesets.Catch/Replays/CatchReplayFrame.cs b/osu.Game.Rulesets.Catch/Replays/CatchReplayFrame.cs
index d5c5eb844a..1e88b35c3b 100644
--- a/osu.Game.Rulesets.Catch/Replays/CatchReplayFrame.cs
+++ b/osu.Game.Rulesets.Catch/Replays/CatchReplayFrame.cs
@@ -1,10 +1,10 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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;
+using osu.Game.Replays.Legacy;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Replays;
-using osu.Game.Rulesets.Replays.Legacy;
using osu.Game.Rulesets.Replays.Types;
namespace osu.Game.Rulesets.Catch.Replays
diff --git a/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/diffcalc-test.osu b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/diffcalc-test.osu
new file mode 100644
index 0000000000..ebad654404
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/diffcalc-test.osu
@@ -0,0 +1,138 @@
+osu file format v14
+
+[General]
+StackLeniency: 0.3
+Mode: 2
+
+[Difficulty]
+CircleSize:4
+OverallDifficulty:7
+ApproachRate:8.3
+SliderMultiplier:1.6
+SliderTickRate:1
+
+[TimingPoints]
+500,500,4,2,1,50,1,0
+34500,-50,4,2,1,50,0,0
+
+[HitObjects]
+// fruits spaced 1/1 beat apart
+32,128,0,5,0,0:0:0:0:
+96,128,500,1,0,0:0:0:0:
+160,128,1000,1,0,0:0:0:0:
+224,128,1500,1,0,0:0:0:0:
+288,128,2000,1,0,0:0:0:0:
+352,128,2500,1,0,0:0:0:0:
+416,128,3000,1,0,0:0:0:0:
+480,128,3500,1,0,0:0:0:0:
+
+// fruits spaced 1/2 beat apart
+32,160,4500,1,0,0:0:0:0:
+64,160,4750,1,0,0:0:0:0:
+96,160,5000,1,0,0:0:0:0:
+128,160,5250,1,0,0:0:0:0:
+160,160,5500,1,0,0:0:0:0:
+192,160,5750,1,0,0:0:0:0:
+224,160,6000,1,0,0:0:0:0:
+256,160,6250,1,0,0:0:0:0:
+288,160,6500,1,0,0:0:0:0:
+
+// fruits spaced 1/4 beat apart
+96,128,7500,1,0,0:0:0:0:
+128,128,7625,1,0,0:0:0:0:
+160,128,7750,1,0,0:0:0:0:
+192,128,7875,1,0,0:0:0:0:
+224,128,8000,1,0,0:0:0:0:
+256,128,8125,1,0,0:0:0:0:
+288,128,8250,1,0,0:0:0:0:
+320,128,8375,1,0,0:0:0:0:
+352,128,8500,1,0,0:0:0:0:
+
+// fruit hyperdashes, spaced 1/2 beat apart
+32,160,9500,1,0,0:0:0:0:
+480,160,9750,1,0,0:0:0:0:
+32,160,10000,1,0,0:0:0:0:
+480,160,10250,1,0,0:0:0:0:
+32,160,10500,1,0,0:0:0:0:
+480,160,10750,1,0,0:0:0:0:
+32,160,11000,1,0,0:0:0:0:
+
+// fruit hyperdashes, spaced 1/4 beat apart
+32,192,12000,1,0,0:0:0:0:
+480,192,12125,1,0,0:0:0:0:
+32,192,12250,1,0,0:0:0:0:
+480,192,12375,1,0,0:0:0:0:
+32,192,12500,1,0,0:0:0:0:
+480,192,12625,1,0,0:0:0:0:
+32,192,12750,1,0,0:0:0:0:
+480,192,12875,1,0,0:0:0:0:
+32,192,13000,1,0,0:0:0:0:
+
+// stream + hyperdash + stream, spaced 1/4 beat apart
+32,192,14000,1,0,0:0:0:0:
+64,192,14125,1,0,0:0:0:0:
+96,192,14250,1,0,0:0:0:0:
+128,192,14375,1,0,0:0:0:0:
+480,192,14500,1,0,0:0:0:0:
+448,192,14625,1,0,0:0:0:0:
+416,192,14750,1,0,0:0:0:0:
+384,192,14875,1,0,0:0:0:0:
+32,192,15000,1,0,0:0:0:0:
+
+// basic sliders
+32,192,16000,2,0,L|192:192,1,160
+224,192,17000,2,0,L|384:192,1,160
+416,192,17875,2,0,L|480:192,1,40
+
+// slider hyperdashes, spaced 1/4 beat apart
+32,192,19000,2,0,L|128:192,1,80
+480,192,19375,2,0,L|384:192,1,80
+352,192,19750,2,0,L|256:192,1,80
+0,192,20125,2,0,L|128:192,1,120
+
+// stream + slider hyperdashes, spaced 1/4 beat apart
+32,192,21500,1,0,0:0:0:0:
+64,192,21625,1,0,0:0:0:0:
+96,192,21750,1,0,0:0:0:0:
+512,192,21875,2,0,L|320:192,1,160
+320,192,22500,1,0,0:0:0:0:
+288,192,22625,1,0,0:0:0:0:
+256,192,22750,1,0,0:0:0:0:
+0,192,22875,2,0,L|64:192,1,40
+
+// streams, spaced 1/4 beat apart
+64,192,24000,1,0,0:0:0:0:
+160,192,24125,1,0,0:0:0:0:
+64,192,24250,1,0,0:0:0:0:
+160,192,24375,1,0,0:0:0:0:
+64,192,24500,1,0,0:0:0:0:
+160,192,24625,1,0,0:0:0:0:
+64,192,24750,1,0,0:0:0:0:
+160,192,24875,1,0,0:0:0:0:
+64,192,25000,1,0,0:0:0:0:
+160,192,25125,1,0,0:0:0:0:
+64,192,25250,1,0,0:0:0:0:
+160,192,25375,1,0,0:0:0:0:
+64,192,25500,1,0,0:0:0:0:
+
+// stream + spinner combo, spaced 1/4 beat apart
+256,192,26500,12,0,27000,0:0:0:0:
+128,192,27250,5,0,0:0:0:0:
+128,192,27375,1,0,0:0:0:0:
+160,192,27500,1,0,0:0:0:0:
+192,192,27625,1,0,0:0:0:0:
+256,192,27750,12,0,28500,0:0:0:0:
+192,192,28625,5,0,0:0:0:0:
+224,192,28750,1,0,0:0:0:0:
+256,192,28875,1,0,0:0:0:0:
+256,192,29000,1,0,0:0:0:0:
+256,192,29125,12,0,29500,0:0:0:0:
+
+// long slow slider
+0,192,30500,6,0,B|480:192|480:192|0:192,2,960
+
+// long fast slider
+0,192,37500,6,0,B|480:192|480:192|0:192,2,960
+
+// long hyperdash slider
+0,192,41500,2,0,P|544:192|544:192,5,480
diff --git a/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider-expected-conversion.json b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider-expected-conversion.json
new file mode 100644
index 0000000000..58c52b6867
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider-expected-conversion.json
@@ -0,0 +1 @@
+{"Mappings":[{"StartTime":19184.0,"Objects":[{"StartTime":19184.0,"Position":320.0},{"StartTime":19263.0,"Position":311.730255},{"StartTime":19343.0,"Position":324.6205},{"StartTime":19423.0,"Position":343.0907},{"StartTime":19503.0,"Position":372.2917},{"StartTime":19582.0,"Position":385.194733},{"StartTime":19662.0,"Position":379.0426},{"StartTime":19742.0,"Position":385.1066},{"StartTime":19822.0,"Position":391.624664},{"StartTime":19919.0,"Position":386.27832},{"StartTime":20016.0,"Position":380.117035},{"StartTime":20113.0,"Position":381.664154},{"StartTime":20247.0,"Position":370.872864}]}]}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider.osu b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider.osu
new file mode 100644
index 0000000000..d48b2d7769
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider.osu
@@ -0,0 +1,18 @@
+osu file format v14
+
+[General]
+Mode: 2
+
+[Difficulty]
+HPDrainRate:3
+CircleSize:2
+OverallDifficulty:4
+ApproachRate:4
+SliderMultiplier:0.9
+SliderTickRate:1
+
+[TimingPoints]
+35.4473684210527,638.298947368422,4,2,1,60,1,0
+
+[HitObjects]
+320,176,19184,2,8,P|384:168|368:232,1,150
diff --git a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs
index 403cedde8c..99b22b2d56 100644
--- a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs
+++ b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs
@@ -1,11 +1,10 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Judgements;
+using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
@@ -13,8 +12,8 @@ namespace osu.Game.Rulesets.Catch.Scoring
{
public class CatchScoreProcessor : ScoreProcessor
{
- public CatchScoreProcessor(RulesetContainer rulesetContainer)
- : base(rulesetContainer)
+ public CatchScoreProcessor(DrawableRuleset drawableRuleset)
+ : base(drawableRuleset)
{
}
@@ -27,21 +26,18 @@ namespace osu.Game.Rulesets.Catch.Scoring
hpDrainRate = beatmap.BeatmapInfo.BaseDifficulty.DrainRate;
}
- private const double harshness = 0.01;
-
- protected override void ApplyResult(JudgementResult result)
+ protected override double HealthAdjustmentFactorFor(JudgementResult result)
{
- base.ApplyResult(result);
-
- if (result.Type == HitResult.Miss)
+ switch (result.Type)
{
- if (!result.Judgement.IsBonus)
- Health.Value -= hpDrainRate * (harshness * 2);
- return;
- }
+ case HitResult.Miss:
+ return hpDrainRate;
- if (result.Judgement is CatchJudgement catchJudgement)
- Health.Value += Math.Max(catchJudgement.HealthIncreaseFor(result) - hpDrainRate, 0) * harshness;
+ default:
+ return 10.2 - hpDrainRate; // Award less HP as drain rate is increased
+ }
}
+
+ public override HitWindows CreateHitWindows() => new CatchHitWindows();
}
}
diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
index 0697a72325..b6d8cf9cbe 100644
--- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using osu.Framework.Graphics;
@@ -10,7 +10,6 @@ using osu.Game.Rulesets.Catch.Objects.Drawable;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI.Scrolling;
-using osuTK;
namespace osu.Game.Rulesets.Catch.UI
{
@@ -20,33 +19,24 @@ namespace osu.Game.Rulesets.Catch.UI
internal readonly CatcherArea CatcherArea;
- public CatchPlayfield(BeatmapDifficulty difficulty, Func> getVisualRepresentation)
+ public CatchPlayfield(BeatmapDifficulty difficulty, Func> createDrawableRepresentation)
{
Container explodingFruitContainer;
- Anchor = Anchor.TopCentre;
- Origin = Anchor.TopCentre;
-
- Size = new Vector2(0.86f); // matches stable's vertical offset for catcher plate
-
- InternalChild = new PlayfieldAdjustmentContainer
+ InternalChildren = new Drawable[]
{
- RelativeSizeAxes = Axes.Both,
- Children = new Drawable[]
+ explodingFruitContainer = new Container
{
- explodingFruitContainer = new Container
- {
- RelativeSizeAxes = Axes.Both,
- },
- CatcherArea = new CatcherArea(difficulty)
- {
- GetVisualRepresentation = getVisualRepresentation,
- ExplodingFruitTarget = explodingFruitContainer,
- Anchor = Anchor.BottomLeft,
- Origin = Anchor.TopLeft,
- },
- HitObjectContainer
- }
+ RelativeSizeAxes = Axes.Both,
+ },
+ CatcherArea = new CatcherArea(difficulty)
+ {
+ CreateDrawableRepresentation = createDrawableRepresentation,
+ ExplodingFruitTarget = explodingFruitContainer,
+ Anchor = Anchor.BottomLeft,
+ Origin = Anchor.TopLeft,
+ },
+ HitObjectContainer
};
}
diff --git a/osu.Game.Rulesets.Catch/UI/PlayfieldAdjustmentContainer.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs
similarity index 69%
rename from osu.Game.Rulesets.Catch/UI/PlayfieldAdjustmentContainer.cs
rename to osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs
index fa1a7ee868..b8d3dc9017 100644
--- a/osu.Game.Rulesets.Catch/UI/PlayfieldAdjustmentContainer.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs
@@ -1,19 +1,25 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Game.Rulesets.UI;
using osuTK;
namespace osu.Game.Rulesets.Catch.UI
{
- public class PlayfieldAdjustmentContainer : Container
+ public class CatchPlayfieldAdjustmentContainer : PlayfieldAdjustmentContainer
{
protected override Container Content => content;
private readonly Container content;
- public PlayfieldAdjustmentContainer()
+ public CatchPlayfieldAdjustmentContainer()
{
+ Anchor = Anchor.TopCentre;
+ Origin = Anchor.TopCentre;
+
+ Size = new Vector2(0.86f); // matches stable's vertical offset for catcher plate
+
InternalChild = new Container
{
Anchor = Anchor.Centre,
diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
index 3637fe0c36..0b06e958e6 100644
--- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
@@ -1,13 +1,11 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
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;
@@ -25,15 +23,15 @@ namespace osu.Game.Rulesets.Catch.UI
{
public class CatcherArea : Container
{
- public const float CATCHER_SIZE = 100;
+ public const float CATCHER_SIZE = 106.75f;
protected internal readonly Catcher MovableCatcher;
- public Func> GetVisualRepresentation;
+ public Func> CreateDrawableRepresentation;
public Container ExplodingFruitTarget
{
- set { MovableCatcher.ExplodingFruitTarget = value; }
+ set => MovableCatcher.ExplodingFruitTarget = value;
}
public CatcherArea(BeatmapDifficulty difficulty = null)
@@ -60,12 +58,12 @@ namespace osu.Game.Rulesets.Catch.UI
if (lastPlateableFruit.IsLoaded)
action();
else
- lastPlateableFruit.OnLoadComplete = _ => action();
+ lastPlateableFruit.OnLoadComplete += _ => action();
}
if (result.IsHit && fruit.CanBePlated)
{
- var caughtFruit = (DrawableCatchHitObject)GetVisualRepresentation?.Invoke(fruit.HitObject);
+ var caughtFruit = (DrawableCatchHitObject)CreateDrawableRepresentation?.Invoke(fruit.HitObject);
if (caughtFruit == null) return;
@@ -141,7 +139,7 @@ namespace osu.Game.Rulesets.Catch.UI
[BackgroundDependencyLoader]
private void load()
{
- Children = new Drawable[]
+ Children = new[]
{
caughtFruit = new Container
{
@@ -158,7 +156,7 @@ namespace osu.Game.Rulesets.Catch.UI
protected bool Dashing
{
- get { return dashing; }
+ get => dashing;
set
{
if (value == dashing) return;
@@ -176,7 +174,7 @@ namespace osu.Game.Rulesets.Catch.UI
///
protected bool Trail
{
- get { return trail; }
+ get => trail;
set
{
if (value == trail) return;
@@ -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.
@@ -292,6 +290,7 @@ namespace osu.Game.Rulesets.Catch.UI
const float hyper_dash_transition_length = 180;
bool previouslyHyperDashing = HyperDashing;
+
if (modifier <= 1 || X == targetPosition)
{
hyperDashModifier = 1;
@@ -325,9 +324,11 @@ namespace osu.Game.Rulesets.Catch.UI
case CatchAction.MoveLeft:
currentDirection--;
return true;
+
case CatchAction.MoveRight:
currentDirection++;
return true;
+
case CatchAction.Dash:
Dashing = true;
return true;
@@ -343,9 +344,11 @@ namespace osu.Game.Rulesets.Catch.UI
case CatchAction.MoveLeft:
currentDirection++;
return true;
+
case CatchAction.MoveRight:
currentDirection--;
return true;
+
case CatchAction.Dash:
Dashing = false;
return true;
@@ -374,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();
@@ -439,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.Catch/UI/CatchRulesetContainer.cs b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs
similarity index 61%
rename from osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs
rename to osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs
index ef1bb7767f..f48b84e344 100644
--- a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs
+++ b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs
@@ -1,30 +1,32 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.Collections.Generic;
using osu.Framework.Input;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Input.Handlers;
+using osu.Game.Replays;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Objects.Drawable;
using osu.Game.Rulesets.Catch.Replays;
using osu.Game.Rulesets.Catch.Scoring;
+using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
-using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling;
namespace osu.Game.Rulesets.Catch.UI
{
- public class CatchRulesetContainer : ScrollingRulesetContainer
+ public class DrawableCatchRuleset : DrawableScrollingRuleset
{
protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Constant;
protected override bool UserScrollSpeedAdjustment => false;
- public CatchRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap)
- : base(ruleset, beatmap)
+ public DrawableCatchRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList mods)
+ : base(ruleset, beatmap, mods)
{
Direction.Value = ScrollingDirection.Down;
TimeRange.Value = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450);
@@ -34,24 +36,31 @@ namespace osu.Game.Rulesets.Catch.UI
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay);
- protected override Playfield CreatePlayfield() => new CatchPlayfield(Beatmap.BeatmapInfo.BaseDifficulty, GetVisualRepresentation);
+ protected override Playfield CreatePlayfield() => new CatchPlayfield(Beatmap.BeatmapInfo.BaseDifficulty, CreateDrawableRepresentation);
- public override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo);
+ public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new CatchPlayfieldAdjustmentContainer();
- public override DrawableHitObject GetVisualRepresentation(CatchHitObject h)
+ protected override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo);
+
+ public override DrawableHitObject CreateDrawableRepresentation(CatchHitObject h)
{
switch (h)
{
case Banana banana:
return new DrawableBanana(banana);
+
case Fruit fruit:
return new DrawableFruit(fruit);
+
case JuiceStream stream:
- return new DrawableJuiceStream(stream, GetVisualRepresentation);
+ return new DrawableJuiceStream(stream, CreateDrawableRepresentation);
+
case BananaShower shower:
- return new DrawableBananaShower(shower, GetVisualRepresentation);
+ return new DrawableBananaShower(shower, CreateDrawableRepresentation);
+
case TinyDroplet tiny:
return new DrawableTinyDroplet(tiny);
+
case Droplet droplet:
return new DrawableDroplet(droplet);
}
diff --git a/osu.Game.Rulesets.Mania.Tests.iOS/AppDelegate.cs b/osu.Game.Rulesets.Mania.Tests.iOS/AppDelegate.cs
new file mode 100644
index 0000000000..9cd1e47023
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests.iOS/AppDelegate.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 Foundation;
+using osu.Framework.iOS;
+using osu.Game.Tests;
+
+namespace osu.Game.Rulesets.Mania.Tests.iOS
+{
+ [Register("AppDelegate")]
+ public class AppDelegate : GameAppDelegate
+ {
+ protected override Framework.Game CreateGame() => new OsuTestBrowser();
+ }
+}
diff --git a/osu.Game.Rulesets.Mania.Tests.iOS/Application.cs b/osu.Game.Rulesets.Mania.Tests.iOS/Application.cs
new file mode 100644
index 0000000000..d47ac4643f
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests.iOS/Application.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 UIKit;
+
+namespace osu.Game.Rulesets.Mania.Tests.iOS
+{
+ public class Application
+ {
+ public static void Main(string[] args)
+ {
+ UIApplication.Main(args, null, "AppDelegate");
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania.Tests.iOS/Entitlements.plist b/osu.Game.Rulesets.Mania.Tests.iOS/Entitlements.plist
new file mode 100644
index 0000000000..9ae599370b
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests.iOS/Entitlements.plist
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/osu.Game.Rulesets.Mania.Tests.iOS/Info.plist b/osu.Game.Rulesets.Mania.Tests.iOS/Info.plist
new file mode 100644
index 0000000000..8780204d5b
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests.iOS/Info.plist
@@ -0,0 +1,36 @@
+
+
+
+
+ CFBundleName
+ osu.Game.Rulesets.Mania.Tests.iOS
+ CFBundleIdentifier
+ ppy.osu-Game-Rulesets-Mania-Tests-iOS
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1.0
+ LSRequiresIPhoneOS
+
+ MinimumOSVersion
+ 10.0
+ UIDeviceFamily
+
+ 1
+ 2
+
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ XSAppIconAssets
+ Assets.xcassets/AppIcon.appiconset
+
+
diff --git a/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj b/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj
new file mode 100644
index 0000000000..24abccb19d
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj
@@ -0,0 +1,45 @@
+
+
+
+
+ Debug
+ iPhoneSimulator
+ {39FD990E-B6CE-4B2A-999F-BC008CF2C64C}
+ Exe
+ osu.Game.Rulesets.Mania.Tests
+ osu.Game.Rulesets.Mania.Tests.iOS
+
+
+
+
+
+
+ libbass.a
+ PreserveNewest
+
+
+ libbass_fx.a
+ PreserveNewest
+
+
+ Linker.xml
+
+
+
+
+ %(RecursiveDir)%(Filename)%(Extension)
+
+
+
+
+ {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}
+ osu.Game
+
+
+ {48F4582B-7687-4621-9CBE-5C24197CB536}
+ osu.Game.Rulesets.Mania
+
+
+
+
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Mania.Tests/.vscode/launch.json b/osu.Game.Rulesets.Mania.Tests/.vscode/launch.json
index c781b0e64e..492f894484 100644
--- a/osu.Game.Rulesets.Mania.Tests/.vscode/launch.json
+++ b/osu.Game.Rulesets.Mania.Tests/.vscode/launch.json
@@ -7,7 +7,7 @@
"request": "launch",
"program": "dotnet",
"args": [
- "${workspaceRoot}/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Mania.Tests.dll"
+ "${workspaceRoot}/bin/Debug/netcoreapp2.2/osu.Game.Rulesets.Mania.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug)",
@@ -20,7 +20,7 @@
"request": "launch",
"program": "dotnet",
"args": [
- "${workspaceRoot}/bin/Release/netcoreapp2.1/osu.Game.Rulesets.Mania.Tests.dll"
+ "${workspaceRoot}/bin/Release/netcoreapp2.2/osu.Game.Rulesets.Mania.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release)",
diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs b/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs
index 58f2ab7747..6b95975059 100644
--- a/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs
+++ b/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
@@ -40,29 +40,29 @@ namespace osu.Game.Rulesets.Mania.Tests
protected override Ruleset CreateRuleset() => new ManiaRuleset();
}
- public class ManiaConvertMapping : ConvertMapping, IEquatable
- {
- public uint RandomW;
- public uint RandomX;
- public uint RandomY;
- public uint RandomZ;
+ public class ManiaConvertMapping : ConvertMapping, IEquatable
+ {
+ public uint RandomW;
+ public uint RandomX;
+ public uint RandomY;
+ public uint RandomZ;
- public ManiaConvertMapping()
- {
- }
+ public ManiaConvertMapping()
+ {
+ }
- public ManiaConvertMapping(IBeatmapConverter converter)
- {
- var maniaConverter = (ManiaBeatmapConverter)converter;
- RandomW = maniaConverter.Random.W;
- RandomX = maniaConverter.Random.X;
- RandomY = maniaConverter.Random.Y;
- RandomZ = maniaConverter.Random.Z;
- }
+ public ManiaConvertMapping(IBeatmapConverter converter)
+ {
+ var maniaConverter = (ManiaBeatmapConverter)converter;
+ RandomW = maniaConverter.Random.W;
+ RandomX = maniaConverter.Random.X;
+ RandomY = maniaConverter.Random.Y;
+ RandomZ = maniaConverter.Random.Z;
+ }
- public bool Equals(ManiaConvertMapping other) => other != null && RandomW == other.RandomW && RandomX == other.RandomX && RandomY == other.RandomY && RandomZ == other.RandomZ;
- public override bool Equals(ConvertMapping other) => base.Equals(other) && Equals(other as ManiaConvertMapping);
- }
+ public bool Equals(ManiaConvertMapping other) => other != null && RandomW == other.RandomW && RandomX == other.RandomX && RandomY == other.RandomY && RandomZ == other.RandomZ;
+ public override bool Equals(ConvertMapping other) => base.Equals(other) && Equals(other as ManiaConvertMapping);
+ }
public struct ConvertValue : IEquatable
{
diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Mania.Tests/ManiaDifficultyCalculatorTest.cs
new file mode 100644
index 0000000000..2c36e81190
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests/ManiaDifficultyCalculatorTest.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 NUnit.Framework;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Difficulty;
+using osu.Game.Rulesets.Mania.Difficulty;
+using osu.Game.Tests.Beatmaps;
+
+namespace osu.Game.Rulesets.Mania.Tests
+{
+ public class ManiaDifficultyCalculatorTest : DifficultyCalculatorTest
+ {
+ protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
+
+ [TestCase(2.3683365342338796d, "diffcalc-test")]
+ public void Test(double expected, string name)
+ => base.Test(expected, name);
+
+ protected override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new ManiaDifficultyCalculator(new ManiaRuleset(), beatmap);
+
+ protected override Ruleset CreateRuleset() => new ManiaRuleset();
+ }
+}
diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaInputTestCase.cs b/osu.Game.Rulesets.Mania.Tests/ManiaInputTestScene.cs
similarity index 83%
rename from osu.Game.Rulesets.Mania.Tests/ManiaInputTestCase.cs
rename to osu.Game.Rulesets.Mania.Tests/ManiaInputTestScene.cs
index 75c8fc7e79..909d0d45c6 100644
--- a/osu.Game.Rulesets.Mania.Tests/ManiaInputTestCase.cs
+++ b/osu.Game.Rulesets.Mania.Tests/ManiaInputTestScene.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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;
@@ -8,12 +8,12 @@ using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Mania.Tests
{
- public abstract class ManiaInputTestCase : OsuTestCase
+ public abstract class ManiaInputTestScene : OsuTestScene
{
private readonly Container content;
protected override Container Content => content ?? base.Content;
- protected ManiaInputTestCase(int keys)
+ protected ManiaInputTestScene(int keys)
{
base.Content.Add(content = new LocalInputManager(keys));
}
diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaPlacementBlueprintTestScene.cs b/osu.Game.Rulesets.Mania.Tests/ManiaPlacementBlueprintTestScene.cs
new file mode 100644
index 0000000000..4b3786c30a
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests/ManiaPlacementBlueprintTestScene.cs
@@ -0,0 +1,58 @@
+// 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.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Timing;
+using osu.Game.Rulesets.Mania.Edit;
+using osu.Game.Rulesets.Mania.Objects.Drawables;
+using osu.Game.Rulesets.Mania.UI;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.UI.Scrolling;
+using osu.Game.Tests.Visual;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Rulesets.Mania.Tests
+{
+ [Cached(Type = typeof(IManiaHitObjectComposer))]
+ public abstract class ManiaPlacementBlueprintTestScene : PlacementBlueprintTestScene, IManiaHitObjectComposer
+ {
+ private readonly Column column;
+
+ [Cached(typeof(IReadOnlyList))]
+ private IReadOnlyList mods { get; set; } = Array.Empty();
+
+ protected ManiaPlacementBlueprintTestScene()
+ {
+ Add(column = new Column(0)
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ AccentColour = Color4.OrangeRed,
+ Clock = new FramedClock(new StopwatchClock()), // No scroll
+ });
+ }
+
+ protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
+ {
+ var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
+
+ dependencies.CacheAs(((ScrollingTestContainer)HitObjectContainer).ScrollingInfo);
+
+ return dependencies;
+ }
+
+ protected override Container CreateHitObjectContainer() => new ScrollingTestContainer(ScrollingDirection.Down) { RelativeSizeAxes = Axes.Both };
+
+ protected override void AddHitObject(DrawableHitObject hitObject) => column.Add((DrawableManiaHitObject)hitObject);
+
+ public Column ColumnAt(Vector2 screenSpacePosition) => column;
+
+ public int TotalColumns => 1;
+ }
+}
diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaSelectionBlueprintTestScene.cs b/osu.Game.Rulesets.Mania.Tests/ManiaSelectionBlueprintTestScene.cs
new file mode 100644
index 0000000000..b598893e8c
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests/ManiaSelectionBlueprintTestScene.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 osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Timing;
+using osu.Game.Rulesets.Mania.Edit;
+using osu.Game.Rulesets.Mania.UI;
+using osu.Game.Tests.Visual;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Rulesets.Mania.Tests
+{
+ [Cached(Type = typeof(IManiaHitObjectComposer))]
+ public abstract class ManiaSelectionBlueprintTestScene : SelectionBlueprintTestScene, IManiaHitObjectComposer
+ {
+ [Cached(Type = typeof(IAdjustableClock))]
+ private readonly IAdjustableClock clock = new StopwatchClock();
+
+ private readonly Column column;
+
+ protected ManiaSelectionBlueprintTestScene()
+ {
+ Add(column = new Column(0)
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ AccentColour = Color4.OrangeRed,
+ Clock = new FramedClock(new StopwatchClock()), // No scroll
+ });
+ }
+
+ public Column ColumnAt(Vector2 screenSpacePosition) => column;
+
+ public int TotalColumns => 1;
+ }
+}
diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseAutoGeneration.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs
similarity index 97%
rename from osu.Game.Rulesets.Mania.Tests/TestCaseAutoGeneration.cs
rename to osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs
index bab3a4db32..20ac5eaa39 100644
--- a/osu.Game.Rulesets.Mania.Tests/TestCaseAutoGeneration.cs
+++ b/osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.Linq;
using NUnit.Framework;
@@ -12,7 +12,7 @@ using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Mania.Tests
{
[TestFixture]
- public class TestCaseAutoGeneration : OsuTestCase
+ public class TestSceneAutoGeneration : OsuTestScene
{
[Test]
public void TestSingleNote()
diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs
similarity index 85%
rename from osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs
rename to osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs
index 9bdb5ec1b2..d94a986dae 100644
--- a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs
+++ b/osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
@@ -13,6 +13,7 @@ using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mania.UI.Components;
+using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Tests.Visual;
using osuTK;
@@ -21,7 +22,7 @@ using osuTK.Graphics;
namespace osu.Game.Rulesets.Mania.Tests
{
[TestFixture]
- public class TestCaseColumn : ManiaInputTestCase
+ public class TestSceneColumn : ManiaInputTestScene
{
public override IReadOnlyList RequiredTypes => new[]
{
@@ -31,9 +32,12 @@ namespace osu.Game.Rulesets.Mania.Tests
typeof(ColumnHitObjectArea)
};
+ [Cached(typeof(IReadOnlyList))]
+ private IReadOnlyList mods { get; set; } = Array.Empty();
+
private readonly List columns = new List();
- public TestCaseColumn()
+ public TestSceneColumn()
: base(2)
{
}
@@ -49,8 +53,8 @@ namespace osu.Game.Rulesets.Mania.Tests
Spacing = new Vector2(20, 0),
Children = new[]
{
- createColumn(ScrollingDirection.Up, ManiaAction.Key1),
- createColumn(ScrollingDirection.Down, ManiaAction.Key2)
+ createColumn(ScrollingDirection.Up, ManiaAction.Key1, 0),
+ createColumn(ScrollingDirection.Down, ManiaAction.Key2, 1)
}
};
}
@@ -85,9 +89,9 @@ namespace osu.Game.Rulesets.Mania.Tests
}
}
- private Drawable createColumn(ScrollingDirection direction, ManiaAction action)
+ private Drawable createColumn(ScrollingDirection direction, ManiaAction action, int index)
{
- var column = new Column
+ var column = new Column(index)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseEditor.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneEditor.cs
similarity index 61%
rename from osu.Game.Rulesets.Mania.Tests/TestCaseEditor.cs
rename to osu.Game.Rulesets.Mania.Tests/TestSceneEditor.cs
index 6c0f931cda..7ed886be49 100644
--- a/osu.Game.Rulesets.Mania.Tests/TestCaseEditor.cs
+++ b/osu.Game.Rulesets.Mania.Tests/TestSceneEditor.cs
@@ -1,9 +1,9 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using osu.Framework.Allocation;
-using osu.Framework.Configuration;
+using osu.Framework.Bindables;
using osu.Game.Rulesets.Mania.Configuration;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Tests.Visual;
@@ -11,11 +11,11 @@ using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Mania.Tests
{
[TestFixture]
- public class TestCaseEditor : EditorTestCase
+ public class TestSceneEditor : EditorTestScene
{
private readonly Bindable direction = new Bindable();
- public TestCaseEditor()
+ public TestSceneEditor()
: base(new ManiaRuleset())
{
AddStep("upwards scroll", () => direction.Value = ManiaScrollingDirection.Up);
@@ -25,8 +25,8 @@ namespace osu.Game.Rulesets.Mania.Tests
[BackgroundDependencyLoader]
private void load(RulesetConfigCache configCache)
{
- var config = (ManiaConfigManager)configCache.GetConfigFor(Ruleset.Value.CreateInstance());
- config.BindWith(ManiaSetting.ScrollDirection, direction);
+ var config = (ManiaRulesetConfigManager)configCache.GetConfigFor(Ruleset.Value.CreateInstance());
+ config.BindWith(ManiaRulesetSetting.ScrollDirection, direction);
}
}
}
diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNotePlacementBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNotePlacementBlueprint.cs
new file mode 100644
index 0000000000..b4332264b9
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNotePlacementBlueprint.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.Rulesets.Edit;
+using osu.Game.Rulesets.Mania.Edit.Blueprints;
+using osu.Game.Rulesets.Mania.Objects;
+using osu.Game.Rulesets.Mania.Objects.Drawables;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Objects.Drawables;
+
+namespace osu.Game.Rulesets.Mania.Tests
+{
+ public class TestSceneHoldNotePlacementBlueprint : ManiaPlacementBlueprintTestScene
+ {
+ protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableHoldNote((HoldNote)hitObject);
+ protected override PlacementBlueprint CreateBlueprint() => new HoldNotePlacementBlueprint();
+ }
+}
diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseHoldNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs
similarity index 86%
rename from osu.Game.Rulesets.Mania.Tests/TestCaseHoldNoteSelectionBlueprint.cs
rename to osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs
index 993f7520e8..04c5724f93 100644
--- a/osu.Game.Rulesets.Mania.Tests/TestCaseHoldNoteSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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;
@@ -15,14 +15,14 @@ using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Mania.Tests
{
- public class TestCaseHoldNoteSelectionBlueprint : SelectionBlueprintTestCase
+ public class TestSceneHoldNoteSelectionBlueprint : ManiaSelectionBlueprintTestScene
{
private readonly DrawableHoldNote drawableObject;
protected override Container Content => content ?? base.Content;
private readonly Container content;
- public TestCaseHoldNoteSelectionBlueprint()
+ public TestSceneHoldNoteSelectionBlueprint()
{
var holdNote = new HoldNote { Column = 0, Duration = 1000 };
holdNote.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneNotePlacementBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneNotePlacementBlueprint.cs
new file mode 100644
index 0000000000..d7b539a2a0
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests/TestSceneNotePlacementBlueprint.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.Rulesets.Edit;
+using osu.Game.Rulesets.Mania.Edit.Blueprints;
+using osu.Game.Rulesets.Mania.Objects;
+using osu.Game.Rulesets.Mania.Objects.Drawables;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Objects.Drawables;
+
+namespace osu.Game.Rulesets.Mania.Tests
+{
+ public class TestSceneNotePlacementBlueprint : ManiaPlacementBlueprintTestScene
+ {
+ protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableNote((Note)hitObject);
+ protected override PlacementBlueprint CreateBlueprint() => new NotePlacementBlueprint();
+ }
+}
diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs
similarity index 80%
rename from osu.Game.Rulesets.Mania.Tests/TestCaseNoteSelectionBlueprint.cs
rename to osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs
index 67370be66c..6bb344f977 100644
--- a/osu.Game.Rulesets.Mania.Tests/TestCaseNoteSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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;
@@ -15,14 +15,14 @@ using osuTK;
namespace osu.Game.Rulesets.Mania.Tests
{
- public class TestCaseNoteSelectionBlueprint : SelectionBlueprintTestCase
+ public class TestSceneNoteSelectionBlueprint : ManiaSelectionBlueprintTestScene
{
private readonly DrawableNote drawableObject;
protected override Container Content => content ?? base.Content;
private readonly Container content;
- public TestCaseNoteSelectionBlueprint()
+ public TestSceneNoteSelectionBlueprint()
{
var note = new Note { Column = 0 };
note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseNotes.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneNotes.cs
similarity index 94%
rename from osu.Game.Rulesets.Mania.Tests/TestCaseNotes.cs
rename to osu.Game.Rulesets.Mania.Tests/TestSceneNotes.cs
index 6344aee6bd..b2613a59d5 100644
--- a/osu.Game.Rulesets.Mania.Tests/TestCaseNotes.cs
+++ b/osu.Game.Rulesets.Mania.Tests/TestSceneNotes.cs
@@ -1,19 +1,20 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
-using osu.Framework.Configuration;
+using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
-using osu.Framework.Graphics.Sprites;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Objects.Drawables;
@@ -26,7 +27,7 @@ using osuTK.Graphics;
namespace osu.Game.Rulesets.Mania.Tests
{
[TestFixture]
- public class TestCaseNotes : OsuTestCase
+ public class TestSceneNotes : OsuTestScene
{
public override IReadOnlyList RequiredTypes => new[]
{
@@ -137,11 +138,11 @@ namespace osu.Game.Rulesets.Mania.Tests
content = new Container { RelativeSizeAxes = Axes.Both }
}
},
- new SpriteText
+ new OsuSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
- TextSize = 14,
+ Font = OsuFont.GetFont(size: 14),
Text = description
}
}
@@ -167,11 +168,13 @@ namespace osu.Game.Rulesets.Mania.Tests
foreach (var nested in obj.NestedHitObjects)
{
double finalPosition = (nested.HitObject.StartTime - obj.HitObject.StartTime) / endTime.Duration;
+
switch (direction)
{
case ScrollingDirection.Up:
nested.Y = (float)(finalPosition * content.DrawHeight);
break;
+
case ScrollingDirection.Down:
nested.Y = (float)(-finalPosition * content.DrawHeight);
break;
diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs
similarity index 91%
rename from osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs
rename to osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs
index 7acc37cb67..395e6daf0a 100644
--- a/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs
+++ b/osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs
@@ -1,6 +1,7 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
@@ -13,6 +14,7 @@ using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.UI;
+using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Tests.Visual;
using osuTK;
@@ -20,15 +22,18 @@ using osuTK;
namespace osu.Game.Rulesets.Mania.Tests
{
[TestFixture]
- public class TestCaseStage : ManiaInputTestCase
+ public class TestSceneStage : ManiaInputTestScene
{
private const int columns = 4;
+ [Cached(typeof(IReadOnlyList))]
+ private IReadOnlyList mods { get; set; } = Array.Empty();
+
private readonly List stages = new List();
private FillFlowContainer fill;
- public TestCaseStage()
+ public TestSceneStage()
: base(columns)
{
}
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 98ad086c66..dbade6ff8d 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,14 +2,14 @@
-
-
-
+
+
+
WinExe
- netcoreapp2.1
+ netcoreapp2.2
diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmap.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmap.cs
index ad5f8e447d..dc24a344e9 100644
--- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmap.cs
+++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmap.cs
@@ -1,10 +1,10 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.Collections.Generic;
using System.Linq;
+using osu.Framework.Graphics.Sprites;
using osu.Game.Beatmaps;
-using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.UI;
@@ -42,13 +42,13 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
{
Name = @"Note Count",
Content = notes.ToString(),
- Icon = FontAwesome.fa_circle_o
+ Icon = FontAwesome.Regular.Circle
},
new BeatmapStatistic
{
Name = @"Hold Note Count",
Content = holdnotes.ToString(),
- Icon = FontAwesome.fa_circle
+ Icon = FontAwesome.Regular.Circle
},
};
}
diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs
index 2770a6ff5b..e10602312e 100644
--- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs
+++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mania.Objects;
using System;
@@ -27,6 +27,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) };
public int TargetColumns;
+ public bool Dual;
public readonly bool IsForCurrentRuleset;
// Internal for testing purposes
@@ -45,7 +46,15 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
var roundedOverallDifficulty = Math.Round(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty);
if (IsForCurrentRuleset)
+ {
TargetColumns = (int)Math.Max(1, roundedCircleSize);
+
+ if (TargetColumns >= 10)
+ {
+ TargetColumns = TargetColumns / 2;
+ Dual = true;
+ }
+ }
else
{
float percentSliderOrSpinner = (float)beatmap.HitObjects.Count(h => h is IHasEndTime) / beatmap.HitObjects.Count;
@@ -70,14 +79,22 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
return base.ConvertBeatmap(original);
}
- protected override Beatmap CreateBeatmap() => beatmap = new ManiaBeatmap(new StageDefinition { Columns = TargetColumns });
+ protected override Beatmap CreateBeatmap()
+ {
+ beatmap = new ManiaBeatmap(new StageDefinition { Columns = TargetColumns });
+
+ if (Dual)
+ beatmap.Stages.Add(new StageDefinition { Columns = TargetColumns });
+
+ return beatmap;
+ }
protected override IEnumerable ConvertHitObject(HitObject original, IBeatmap beatmap)
{
- var maniaOriginal = original as ManiaHitObject;
- if (maniaOriginal != null)
+ if (original is ManiaHitObject maniaOriginal)
{
yield return maniaOriginal;
+
yield break;
}
@@ -92,6 +109,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
private readonly List prevNoteTimes = new List(max_notes_for_density);
private double density = int.MaxValue;
+
private void computeDensity(double newNoteTime)
{
if (prevNoteTimes.Count == max_notes_for_density)
@@ -104,6 +122,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
private double lastTime;
private Vector2 lastPosition;
private PatternType lastStair = PatternType.Stair;
+
private void recordNote(double time, Vector2 position)
{
lastTime = time;
@@ -180,7 +199,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
foreach (var obj in newPattern.HitObjects)
yield return obj;
-
}
}
@@ -237,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 635004d2f6..ea418eedb4 100644
--- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs
+++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
@@ -65,6 +65,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
if (originalPattern.HitObjects.Count() == 1)
{
yield return originalPattern;
+
yield break;
}
@@ -135,6 +136,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{
if (convertType.HasFlag(PatternType.LowProbability))
return generateNRandomNotes(HitObject.StartTime, 0.78, 0.3, 0);
+
return generateNRandomNotes(HitObject.StartTime, 0.85, 0.36, 0.03);
}
@@ -142,6 +144,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{
if (convertType.HasFlag(PatternType.LowProbability))
return generateNRandomNotes(HitObject.StartTime, 0.43, 0.08, 0);
+
return generateNRandomNotes(HitObject.StartTime, 0.56, 0.18, 0);
}
@@ -149,11 +152,13 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{
if (convertType.HasFlag(PatternType.LowProbability))
return generateNRandomNotes(HitObject.StartTime, 0.3, 0, 0);
+
return generateNRandomNotes(HitObject.StartTime, 0.37, 0.08, 0);
}
if (convertType.HasFlag(PatternType.LowProbability))
return generateNRandomNotes(HitObject.StartTime, 0.17, 0, 0);
+
return generateNRandomNotes(HitObject.StartTime, 0.27, 0, 0);
}
@@ -174,6 +179,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
int usableColumns = TotalColumns - RandomStart - PreviousPattern.ColumnWithObjects;
int nextColumn = GetRandomColumn();
+
for (int i = 0; i < Math.Min(usableColumns, noteCount); i++)
{
// Find available column
@@ -212,6 +218,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
nextColumn = FindAvailableColumn(nextColumn, PreviousPattern);
int lastColumn = nextColumn;
+
for (int i = 0; i < noteCount; i++)
{
addToPattern(pattern, nextColumn, startTime, startTime);
@@ -294,6 +301,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
int interval = Random.Next(1, TotalColumns - (legacy ? 1 : 0));
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
+
for (int i = 0; i <= spanCount; i++)
{
addToPattern(pattern, nextColumn, startTime, startTime);
@@ -336,16 +344,19 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
p3 = 0;
p4 = 0;
break;
+
case 3:
p2 = Math.Min(p2, 0.1);
p3 = 0;
p4 = 0;
break;
+
case 4:
p2 = Math.Min(p2, 0.3);
p3 = Math.Min(p3, 0.04);
p4 = 0;
break;
+
case 5:
p2 = Math.Min(p2, 0.34);
p3 = Math.Min(p3, 0.1);
@@ -353,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);
@@ -432,9 +443,10 @@ 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();
+
for (int i = 0; i <= spanCount; i++)
{
if (!(ignoreHead && startTime == HitObject.StartTime))
@@ -460,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 775a4145e6..b3be08e1f7 100644
--- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs
+++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.Collections.Generic;
using osu.Game.Rulesets.Mania.MathUtils;
@@ -35,12 +35,14 @@ 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;
+
case 8:
addToPattern(pattern, FindAvailableColumn(GetRandomColumn(), PreviousPattern), generateHold);
break;
+
default:
if (TotalColumns > 0)
addToPattern(pattern, GetRandomColumn(), generateHold);
@@ -70,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 8463e209e4..decd159ee9 100644
--- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs
+++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
@@ -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;
}
}
@@ -116,10 +116,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
}
if (convertType.HasFlag(PatternType.Cycle) && PreviousPattern.HitObjects.Count() == 1
- // If we convert to 7K + 1, let's not overload the special key
- && (TotalColumns != 8 || lastColumn != 0)
- // Make sure the last column was not the centre column
- && (TotalColumns % 2 == 0 || lastColumn != TotalColumns / 2))
+ // If we convert to 7K + 1, let's not overload the special key
+ && (TotalColumns != 8 || lastColumn != 0)
+ // Make sure the last column was not the centre column
+ && (TotalColumns % 2 == 0 || lastColumn != TotalColumns / 2))
{
// Generate a new pattern by cycling backwards (similar to Reverse but for only one hit object)
int column = RandomStart + TotalColumns - lastColumn - 1;
@@ -172,6 +172,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
return pattern = generateRandomPatternWithMirrored(0.12, 0.38, 0.12);
if (ConversionDifficulty > 4)
return pattern = generateRandomPatternWithMirrored(0.12, 0.17, 0);
+
return pattern = generateRandomPatternWithMirrored(0.12, 0, 0);
}
@@ -179,6 +180,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{
if (convertType.HasFlag(PatternType.LowProbability))
return pattern = generateRandomPattern(0.78, 0.42, 0, 0);
+
return pattern = generateRandomPattern(1, 0.62, 0, 0);
}
@@ -186,6 +188,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{
if (convertType.HasFlag(PatternType.LowProbability))
return pattern = generateRandomPattern(0.35, 0.08, 0, 0);
+
return pattern = generateRandomPattern(0.52, 0.15, 0, 0);
}
@@ -193,6 +196,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{
if (convertType.HasFlag(PatternType.LowProbability))
return pattern = generateRandomPattern(0.18, 0, 0, 0);
+
return pattern = generateRandomPattern(0.45, 0, 0, 0);
}
@@ -229,6 +233,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
noteCount = Math.Min(noteCount, TotalColumns - RandomStart - PreviousPattern.ColumnWithObjects);
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
+
for (int i = 0; i < noteCount; i++)
{
nextColumn = allowStacking
@@ -250,6 +255,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
}
else
last = GetRandomColumn();
+
return last;
}
}
@@ -257,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.
@@ -298,6 +304,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
int columnLimit = (TotalColumns % 2 == 0 ? TotalColumns : TotalColumns - 1) / 2;
int nextColumn = GetRandomColumn(upperBound: columnLimit);
+
for (int i = 0; i < noteCount; i++)
{
nextColumn = FindAvailableColumn(nextColumn, upperBound: columnLimit, patterns: pattern);
@@ -335,18 +342,21 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
p4 = 0;
p5 = 0;
break;
+
case 3:
p2 = Math.Min(p2, 0.1);
p3 = 0;
p4 = 0;
p5 = 0;
break;
+
case 4:
p2 = Math.Min(p2, 0.23);
p3 = Math.Min(p3, 0.04);
p4 = 0;
p5 = 0;
break;
+
case 5:
p3 = Math.Min(p3, 0.15);
p4 = Math.Min(p4, 0.03);
@@ -354,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);
@@ -379,20 +389,24 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
p2 = 0;
p3 = 0;
break;
+
case 3:
centreProbability = Math.Min(centreProbability, 0.03);
p2 = 0;
p3 = 0;
break;
+
case 4:
centreProbability = 0;
p2 = Math.Min(p2 * 2, 0.2);
p3 = 0;
break;
+
case 5:
centreProbability = Math.Min(centreProbability, 0.03);
p3 = 0;
break;
+
case 6:
centreProbability = 0;
p2 = Math.Min(p2 * 2, 0.5);
diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs
index f412e127c5..fba52dfc32 100644
--- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs
+++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Linq;
@@ -87,6 +87,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
return 4;
if (val >= 1 - p3)
return 3;
+
return val >= 1 - p2 ? 2 : 1;
}
@@ -157,6 +158,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
// Ensure that we have at least one free column, so that an endless loop is avoided
bool hasValidColumns = false;
+
for (int i = lowerBound.Value; i < upperBound.Value; i++)
{
hasValidColumns = isValid(i);
diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternType.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternType.cs
index 2eba2d5843..a3cd455886 100644
--- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternType.cs
+++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternType.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
@@ -12,51 +12,63 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
internal enum PatternType
{
None = 0,
+
///
/// Keep the same as last row.
///
ForceStack = 1 << 0,
+
///
/// Keep different from last row.
///
ForceNotStack = 1 << 1,
+
///
/// Keep as single note at its original position.
///
KeepSingle = 1 << 2,
+
///
/// Use a lower random value.
///
LowProbability = 1 << 3,
+
///
/// Reserved.
///
Alternate = 1 << 4,
+
///
/// Ignore the repeat count.
///
ForceSigSlider = 1 << 5,
+
///
/// Convert slider to circle.
///
ForceNotSlider = 1 << 6,
+
///
/// Notes gathered together.
///
Gathered = 1 << 7,
Mirror = 1 << 8,
+
///
/// Change 0 -> 6.
///
Reverse = 1 << 9,
+
///
/// 1 -> 5 -> 1 -> 5 like reverse.
///
Cycle = 1 << 10,
+
///
/// Next note will be at column + 1.
///
Stair = 1 << 11,
+
///
/// Next note will be at column - 1.
///
diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Pattern.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Pattern.cs
index 32d2d096b2..f095a0ffce 100644
--- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Pattern.cs
+++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Pattern.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.Collections.Generic;
using System.Linq;
diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs
index a42d57cdd1..71b3f6ecf2 100644
--- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs
+++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
diff --git a/osu.Game.Rulesets.Mania/Beatmaps/StageDefinition.cs b/osu.Game.Rulesets.Mania/Beatmaps/StageDefinition.cs
index afec607a7c..dff7cb72ce 100644
--- a/osu.Game.Rulesets.Mania/Beatmaps/StageDefinition.cs
+++ b/osu.Game.Rulesets.Mania/Beatmaps/StageDefinition.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mania.UI;
diff --git a/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs b/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs
deleted file mode 100644
index 1c9e1e4c73..0000000000
--- a/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Framework.Configuration.Tracking;
-using osu.Game.Configuration;
-using osu.Game.Rulesets.Configuration;
-using osu.Game.Rulesets.Mania.UI;
-
-namespace osu.Game.Rulesets.Mania.Configuration
-{
- public class ManiaConfigManager : RulesetConfigManager
- {
- public ManiaConfigManager(SettingsStore settings, RulesetInfo ruleset, int? variant = null)
- : base(settings, ruleset, variant)
- {
- }
-
- protected override void InitialiseDefaults()
- {
- base.InitialiseDefaults();
-
- Set(ManiaSetting.ScrollTime, 2250.0, 50.0, 10000.0, 50.0);
- Set(ManiaSetting.ScrollDirection, ManiaScrollingDirection.Down);
- }
-
- public override TrackedSettings CreateTrackedSettings() => new TrackedSettings
- {
- new TrackedSetting(ManiaSetting.ScrollTime, v => new SettingDescription(v, "Scroll Time", $"{v}ms"))
- };
- }
-
- public enum ManiaSetting
- {
- ScrollTime,
- ScrollDirection
- }
-}
diff --git a/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs b/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs
new file mode 100644
index 0000000000..b591f9da22
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs
@@ -0,0 +1,37 @@
+// 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.Configuration.Tracking;
+using osu.Game.Configuration;
+using osu.Game.Rulesets.Configuration;
+using osu.Game.Rulesets.Mania.UI;
+
+namespace osu.Game.Rulesets.Mania.Configuration
+{
+ public class ManiaRulesetConfigManager : RulesetConfigManager
+ {
+ public ManiaRulesetConfigManager(SettingsStore settings, RulesetInfo ruleset, int? variant = null)
+ : base(settings, ruleset, variant)
+ {
+ }
+
+ protected override void InitialiseDefaults()
+ {
+ base.InitialiseDefaults();
+
+ Set(ManiaRulesetSetting.ScrollTime, 2250.0, 50.0, 10000.0, 50.0);
+ Set(ManiaRulesetSetting.ScrollDirection, ManiaScrollingDirection.Down);
+ }
+
+ public override TrackedSettings CreateTrackedSettings() => new TrackedSettings
+ {
+ new TrackedSetting(ManiaRulesetSetting.ScrollTime, v => new SettingDescription(v, "Scroll Time", $"{v}ms"))
+ };
+ }
+
+ public enum ManiaRulesetSetting
+ {
+ ScrollTime,
+ ScrollDirection
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs
index c7f6890b93..3ff665d2c8 100644
--- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs
+++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs
@@ -1,18 +1,12 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Difficulty;
-using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Mania.Difficulty
{
public class ManiaDifficultyAttributes : DifficultyAttributes
{
public double GreatHitWindow;
-
- public ManiaDifficultyAttributes(Mod[] mods, double starRating)
- : base(mods, starRating)
- {
- }
}
}
diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs
index 7b4d4b12ed..4a9c22d339 100644
--- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs
+++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs
@@ -1,34 +1,24 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Difficulty;
+using osu.Game.Rulesets.Difficulty.Preprocessing;
+using osu.Game.Rulesets.Difficulty.Skills;
using osu.Game.Rulesets.Mania.Beatmaps;
+using osu.Game.Rulesets.Mania.Difficulty.Preprocessing;
+using osu.Game.Rulesets.Mania.Difficulty.Skills;
using osu.Game.Rulesets.Mania.Mods;
-using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Mania.Difficulty
{
- internal class ManiaDifficultyCalculator : DifficultyCalculator
+ public class ManiaDifficultyCalculator : DifficultyCalculator
{
private const double star_scaling_factor = 0.018;
- ///
- /// In milliseconds. For difficulty calculation we will only look at the highest strain value in each time interval of size strain_step.
- /// This is to eliminate higher influence of stream over aim by simply having more HitObjects with high strain.
- /// The higher this value, the less strains there will be, indirectly giving long beatmaps an advantage.
- ///
- private const double strain_step = 400;
-
- ///
- /// The weighting of each strain value decays to this number * it's previous value
- ///
- private const double decay_weight = 0.9;
-
private readonly bool isForCurrentRuleset;
public ManiaDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
@@ -37,109 +27,71 @@ namespace osu.Game.Rulesets.Mania.Difficulty
isForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.Equals(ruleset.RulesetInfo);
}
- protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate)
+ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
{
- if (!beatmap.HitObjects.Any())
- return new ManiaDifficultyAttributes(mods, 0);
+ if (beatmap.HitObjects.Count == 0)
+ return new ManiaDifficultyAttributes { Mods = mods, Skills = skills };
- var difficultyHitObjects = new List();
-
- int columnCount = ((ManiaBeatmap)beatmap).TotalColumns;
-
- // Sort DifficultyHitObjects by StartTime of the HitObjects - just to make sure.
- // Note: Stable sort is done so that the ordering of hitobjects with equal start times doesn't change
- difficultyHitObjects.AddRange(beatmap.HitObjects.Select(h => new ManiaHitObjectDifficulty((ManiaHitObject)h, columnCount)).OrderBy(h => h.BaseHitObject.StartTime));
-
- if (!calculateStrainValues(difficultyHitObjects, timeRate))
- return new DifficultyAttributes(mods, 0);
-
-
- double starRating = calculateDifficulty(difficultyHitObjects, timeRate) * star_scaling_factor;
-
- return new ManiaDifficultyAttributes(mods, starRating)
+ return new ManiaDifficultyAttributes
{
- // Todo: This int cast is temporary to achieve 1:1 results with osu!stable, and should be remoevd in the future
- GreatHitWindow = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / timeRate
+ StarRating = difficultyValue(skills) * star_scaling_factor,
+ 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
};
}
- private bool calculateStrainValues(List objects, double timeRate)
+ private double difficultyValue(Skill[] skills)
{
- // Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment.
- using (var hitObjectsEnumerator = objects.GetEnumerator())
+ // Preprocess the strains to find the maximum overall + individual (aggregate) strain from each section
+ var overall = skills.OfType().Single();
+ var aggregatePeaks = new List(Enumerable.Repeat(0.0, overall.StrainPeaks.Count));
+
+ foreach (var individual in skills.OfType())
{
- if (!hitObjectsEnumerator.MoveNext())
- return false;
-
- ManiaHitObjectDifficulty current = hitObjectsEnumerator.Current;
-
- // First hitObject starts at strain 1. 1 is the default for strain values, so we don't need to set it here. See DifficultyHitObject.
- while (hitObjectsEnumerator.MoveNext())
+ for (int i = 0; i < individual.StrainPeaks.Count; i++)
{
- var next = hitObjectsEnumerator.Current;
- next?.CalculateStrains(current, timeRate);
- current = next;
+ double aggregate = individual.StrainPeaks[i] + overall.StrainPeaks[i];
+
+ if (aggregate > aggregatePeaks[i])
+ aggregatePeaks[i] = aggregate;
}
-
- return true;
- }
- }
-
- private double calculateDifficulty(List objects, double timeRate)
- {
- double actualStrainStep = strain_step * timeRate;
-
- // Find the highest strain value within each strain step
- List highestStrains = new List();
- double intervalEndTime = actualStrainStep;
- double maximumStrain = 0; // We need to keep track of the maximum strain in the current interval
-
- ManiaHitObjectDifficulty previousHitObject = null;
- foreach (var hitObject in objects)
- {
- // While we are beyond the current interval push the currently available maximum to our strain list
- while (hitObject.BaseHitObject.StartTime > intervalEndTime)
- {
- highestStrains.Add(maximumStrain);
-
- // The maximum strain of the next interval is not zero by default! We need to take the last hitObject we encountered, take its strain and apply the decay
- // until the beginning of the next interval.
- if (previousHitObject == null)
- {
- maximumStrain = 0;
- }
- else
- {
- double individualDecay = Math.Pow(ManiaHitObjectDifficulty.INDIVIDUAL_DECAY_BASE, (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000);
- double overallDecay = Math.Pow(ManiaHitObjectDifficulty.OVERALL_DECAY_BASE, (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000);
- maximumStrain = previousHitObject.IndividualStrain * individualDecay + previousHitObject.OverallStrain * overallDecay;
- }
-
- // Go to the next time interval
- intervalEndTime += actualStrainStep;
- }
-
- // Obtain maximum strain
- double strain = hitObject.IndividualStrain + hitObject.OverallStrain;
- maximumStrain = Math.Max(strain, maximumStrain);
-
- previousHitObject = hitObject;
}
- // Build the weighted sum over the highest strains for each interval
+ aggregatePeaks.Sort((a, b) => b.CompareTo(a)); // Sort from highest to lowest strain.
+
double difficulty = 0;
double weight = 1;
- highestStrains.Sort((a, b) => b.CompareTo(a)); // Sort from highest to lowest strain.
- foreach (double strain in highestStrains)
+ // Difficulty is the weighted sum of the highest strains from every section.
+ foreach (double strain in aggregatePeaks)
{
- difficulty += weight * strain;
- weight *= decay_weight;
+ difficulty += strain * weight;
+ weight *= 0.9;
}
return difficulty;
}
+ protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate)
+ {
+ for (int i = 1; i < beatmap.HitObjects.Count; i++)
+ yield return new ManiaDifficultyHitObject(beatmap.HitObjects[i], beatmap.HitObjects[i - 1], clockRate);
+ }
+
+ protected override Skill[] CreateSkills(IBeatmap beatmap)
+ {
+ int columnCount = ((ManiaBeatmap)beatmap).TotalColumns;
+
+ var skills = new List { new Overall(columnCount) };
+
+ for (int i = 0; i < columnCount; i++)
+ skills.Add(new Individual(i, columnCount));
+
+ return skills.ToArray();
+ }
+
protected override Mod[] DifficultyAdjustmentMods
{
get
diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs
index 1f26bda1b2..b99bddee96 100644
--- a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs
+++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
@@ -8,6 +8,7 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
+using osu.Game.Scoring;
namespace osu.Game.Rulesets.Mania.Difficulty
{
@@ -27,7 +28,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty
private int countMeh;
private int countMiss;
- public ManiaPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, Score score)
+ public ManiaPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, ScoreInfo score)
: base(ruleset, beatmap, score)
{
}
@@ -113,8 +114,8 @@ namespace osu.Game.Rulesets.Mania.Difficulty
// Lots of arbitrary values from testing.
// Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution
double accuracyValue = Math.Max(0.0, 0.2 - (Attributes.GreatHitWindow - 34) * 0.006667)
- * strainValue
- * Math.Pow(Math.Max(0.0, scaledScore - 960000) / 40000, 1.1);
+ * strainValue
+ * Math.Pow(Math.Max(0.0, scaledScore - 960000) / 40000, 1.1);
// Bonus for many hitcircles - it's harder to keep good accuracy up for longer
// accuracyValue *= Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3));
diff --git a/osu.Game.Rulesets.Mania/Difficulty/Preprocessing/ManiaDifficultyHitObject.cs b/osu.Game.Rulesets.Mania/Difficulty/Preprocessing/ManiaDifficultyHitObject.cs
new file mode 100644
index 0000000000..29ba934e9f
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Difficulty/Preprocessing/ManiaDifficultyHitObject.cs
@@ -0,0 +1,19 @@
+// 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.Rulesets.Difficulty.Preprocessing;
+using osu.Game.Rulesets.Mania.Objects;
+using osu.Game.Rulesets.Objects;
+
+namespace osu.Game.Rulesets.Mania.Difficulty.Preprocessing
+{
+ public class ManiaDifficultyHitObject : DifficultyHitObject
+ {
+ public new ManiaHitObject BaseObject => (ManiaHitObject)base.BaseObject;
+
+ public ManiaDifficultyHitObject(HitObject hitObject, HitObject lastObject, double clockRate)
+ : base(hitObject, lastObject, clockRate)
+ {
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Difficulty/Skills/Individual.cs b/osu.Game.Rulesets.Mania/Difficulty/Skills/Individual.cs
new file mode 100644
index 0000000000..059cd39641
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Difficulty/Skills/Individual.cs
@@ -0,0 +1,47 @@
+// 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.Game.Rulesets.Difficulty.Preprocessing;
+using osu.Game.Rulesets.Difficulty.Skills;
+using osu.Game.Rulesets.Mania.Difficulty.Preprocessing;
+using osu.Game.Rulesets.Mania.Objects;
+
+namespace osu.Game.Rulesets.Mania.Difficulty.Skills
+{
+ public class Individual : Skill
+ {
+ protected override double SkillMultiplier => 1;
+ protected override double StrainDecayBase => 0.125;
+
+ private readonly double[] holdEndTimes;
+
+ private readonly int column;
+
+ public Individual(int column, int columnCount)
+ {
+ this.column = column;
+
+ holdEndTimes = new double[columnCount];
+ }
+
+ protected override double StrainValueOf(DifficultyHitObject current)
+ {
+ var maniaCurrent = (ManiaDifficultyHitObject)current;
+ var endTime = (maniaCurrent.BaseObject as HoldNote)?.EndTime ?? maniaCurrent.BaseObject.StartTime;
+
+ try
+ {
+ if (maniaCurrent.BaseObject.Column != column)
+ return 0;
+
+ // We give a slight bonus if something is held meanwhile
+ return holdEndTimes.Any(t => t > endTime) ? 2.5 : 2;
+ }
+ finally
+ {
+ holdEndTimes[maniaCurrent.BaseObject.Column] = endTime;
+ }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Difficulty/Skills/Overall.cs b/osu.Game.Rulesets.Mania/Difficulty/Skills/Overall.cs
new file mode 100644
index 0000000000..ed25173d38
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Difficulty/Skills/Overall.cs
@@ -0,0 +1,56 @@
+// 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.Rulesets.Difficulty.Preprocessing;
+using osu.Game.Rulesets.Difficulty.Skills;
+using osu.Game.Rulesets.Mania.Difficulty.Preprocessing;
+using osu.Game.Rulesets.Mania.Objects;
+
+namespace osu.Game.Rulesets.Mania.Difficulty.Skills
+{
+ public class Overall : Skill
+ {
+ protected override double SkillMultiplier => 1;
+ protected override double StrainDecayBase => 0.3;
+
+ private readonly double[] holdEndTimes;
+
+ private readonly int columnCount;
+
+ public Overall(int columnCount)
+ {
+ this.columnCount = columnCount;
+
+ holdEndTimes = new double[columnCount];
+ }
+
+ protected override double StrainValueOf(DifficultyHitObject current)
+ {
+ var maniaCurrent = (ManiaDifficultyHitObject)current;
+ var endTime = (maniaCurrent.BaseObject as HoldNote)?.EndTime ?? maniaCurrent.BaseObject.StartTime;
+
+ double holdFactor = 1.0; // Factor in case something else is held
+ double holdAddition = 0; // Addition to the current note in case it's a hold and has to be released awkwardly
+
+ for (int i = 0; i < columnCount; i++)
+ {
+ // If there is at least one other overlapping end or note, then we get an addition, buuuuuut...
+ if (current.BaseObject.StartTime < holdEndTimes[i] && endTime > holdEndTimes[i])
+ holdAddition = 1.0;
+
+ // ... this addition only is valid if there is _no_ other note with the same ending.
+ // Releasing multiple notes at the same time is just as easy as releasing one
+ if (endTime == holdEndTimes[i])
+ holdAddition = 0;
+
+ // We give a slight bonus if something is held meanwhile
+ if (holdEndTimes[i] > endTime)
+ holdFactor = 1.25;
+ }
+
+ holdEndTimes[maniaCurrent.BaseObject.Column] = endTime;
+
+ return (1 + holdAddition) * holdFactor;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditBodyPiece.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditBodyPiece.cs
new file mode 100644
index 0000000000..b99a1157f3
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditBodyPiece.cs
@@ -0,0 +1,21 @@
+// 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.Graphics;
+using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
+
+namespace osu.Game.Rulesets.Mania.Edit.Blueprints.Components
+{
+ public class EditBodyPiece : BodyPiece
+ {
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ AccentColour = colours.Yellow;
+
+ Background.Alpha = 0.5f;
+ Foreground.Alpha = 0;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditNotePiece.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditNotePiece.cs
index 424ff1118c..6f85fd9167 100644
--- a/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditNotePiece.cs
+++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditNotePiece.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Containers;
diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs
new file mode 100644
index 0000000000..26115311f7
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs
@@ -0,0 +1,74 @@
+// 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.Framework.Input.Events;
+using osu.Game.Rulesets.Mania.Edit.Blueprints.Components;
+using osu.Game.Rulesets.Mania.Objects;
+using osuTK;
+
+namespace osu.Game.Rulesets.Mania.Edit.Blueprints
+{
+ public class HoldNotePlacementBlueprint : ManiaPlacementBlueprint
+ {
+ private readonly EditBodyPiece bodyPiece;
+ private readonly EditNotePiece headPiece;
+ private readonly EditNotePiece tailPiece;
+
+ public HoldNotePlacementBlueprint()
+ : base(new HoldNote())
+ {
+ RelativeSizeAxes = Axes.Both;
+
+ InternalChildren = new Drawable[]
+ {
+ bodyPiece = new EditBodyPiece { Origin = Anchor.TopCentre },
+ headPiece = new EditNotePiece { Origin = Anchor.Centre },
+ tailPiece = new EditNotePiece { Origin = Anchor.Centre }
+ };
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+
+ if (Column != null)
+ {
+ headPiece.Y = PositionAt(HitObject.StartTime);
+ tailPiece.Y = PositionAt(HitObject.EndTime);
+ }
+
+ var topPosition = new Vector2(headPiece.DrawPosition.X, Math.Min(headPiece.DrawPosition.Y, tailPiece.DrawPosition.Y));
+ var bottomPosition = new Vector2(headPiece.DrawPosition.X, Math.Max(headPiece.DrawPosition.Y, tailPiece.DrawPosition.Y));
+
+ bodyPiece.Position = topPosition;
+ bodyPiece.Width = headPiece.Width;
+ bodyPiece.Height = (bottomPosition - topPosition).Y;
+ }
+
+ private double originalStartTime;
+
+ protected override bool OnMouseMove(MouseMoveEvent e)
+ {
+ base.OnMouseMove(e);
+
+ if (PlacementBegun)
+ {
+ var endTime = TimeAt(e.ScreenSpaceMousePosition);
+
+ HitObject.StartTime = endTime < originalStartTime ? endTime : originalStartTime;
+ HitObject.Duration = Math.Abs(endTime - originalStartTime);
+ }
+ else
+ {
+ headPiece.Width = tailPiece.Width = SnappedWidth;
+ headPiece.X = tailPiece.X = SnappedMousePosition.X;
+
+ originalStartTime = HitObject.StartTime = TimeAt(e.ScreenSpaceMousePosition);
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs
index afeb0a585e..d64c5dbc6a 100644
--- a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs
@@ -1,8 +1,8 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Configuration;
+using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Game.Graphics;
@@ -49,7 +49,6 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
base.Update();
Size = HitObject.DrawSize + new Vector2(0, HitObject.Tail.DrawHeight);
- Position = Parent.ToLocalSpace(HitObject.ScreenSpaceDrawQuad.TopLeft);
// This is a side-effect of not matching the hitobject's anchors/origins, which is kinda hard to do
// When scrolling upwards our origin is already at the top of the head note (which is the intended location),
diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs
new file mode 100644
index 0000000000..d3779e2e18
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs
@@ -0,0 +1,118 @@
+// 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.Input;
+using osu.Framework.Input.Events;
+using osu.Game.Rulesets.Edit;
+using osu.Game.Rulesets.Mania.Objects;
+using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
+using osu.Game.Rulesets.Mania.UI;
+using osu.Game.Rulesets.UI.Scrolling;
+using osuTK;
+
+namespace osu.Game.Rulesets.Mania.Edit.Blueprints
+{
+ public abstract class ManiaPlacementBlueprint : PlacementBlueprint,
+ IRequireHighFrequencyMousePosition // the playfield could be moving behind us
+ where T : ManiaHitObject
+ {
+ protected new T HitObject => (T)base.HitObject;
+
+ protected Column Column;
+
+ ///
+ /// The current mouse position, snapped to the closest column.
+ ///
+ protected Vector2 SnappedMousePosition { get; private set; }
+
+ ///
+ /// The width of the closest column to the current mouse position.
+ ///
+ protected float SnappedWidth { get; private set; }
+
+ [Resolved]
+ private IManiaHitObjectComposer composer { get; set; }
+
+ [Resolved]
+ private IScrollingInfo scrollingInfo { get; set; }
+
+ protected ManiaPlacementBlueprint(T hitObject)
+ : base(hitObject)
+ {
+ RelativeSizeAxes = Axes.None;
+ }
+
+ protected override bool OnMouseDown(MouseDownEvent e)
+ {
+ if (Column == null)
+ return base.OnMouseDown(e);
+
+ HitObject.StartTime = TimeAt(e.ScreenSpaceMousePosition);
+ HitObject.Column = Column.Index;
+
+ BeginPlacement();
+ return true;
+ }
+
+ protected override bool OnMouseUp(MouseUpEvent e)
+ {
+ EndPlacement();
+ return base.OnMouseUp(e);
+ }
+
+ protected override bool OnMouseMove(MouseMoveEvent e)
+ {
+ if (!PlacementBegun)
+ Column = ColumnAt(e.ScreenSpaceMousePosition);
+
+ if (Column == null) return false;
+
+ SnappedWidth = Column.DrawWidth;
+
+ // Snap to the column
+ var parentPos = Parent.ToLocalSpace(Column.ToScreenSpace(new Vector2(Column.DrawWidth / 2, 0)));
+ SnappedMousePosition = new Vector2(parentPos.X, e.MousePosition.Y);
+ return true;
+ }
+
+ protected double TimeAt(Vector2 screenSpacePosition)
+ {
+ if (Column == null)
+ return 0;
+
+ var hitObjectContainer = Column.HitObjectContainer;
+
+ // If we're scrolling downwards, a position of 0 is actually further away from the hit target
+ // so we need to flip the vertical coordinate in the hitobject container's space
+ var hitObjectPos = Column.HitObjectContainer.ToLocalSpace(applyPositionOffset(screenSpacePosition, false)).Y;
+ if (scrollingInfo.Direction.Value == ScrollingDirection.Down)
+ hitObjectPos = hitObjectContainer.DrawHeight - hitObjectPos;
+
+ return scrollingInfo.Algorithm.TimeAt(hitObjectPos,
+ EditorClock.CurrentTime,
+ scrollingInfo.TimeRange.Value,
+ hitObjectContainer.DrawHeight);
+ }
+
+ protected float PositionAt(double time)
+ {
+ var pos = scrollingInfo.Algorithm.PositionAt(time,
+ EditorClock.CurrentTime,
+ scrollingInfo.TimeRange.Value,
+ Column.HitObjectContainer.DrawHeight);
+
+ return applyPositionOffset(Column.HitObjectContainer.ToSpaceOfOtherDrawable(new Vector2(0, pos), Parent), true).Y;
+ }
+
+ protected Column ColumnAt(Vector2 screenSpacePosition)
+ => composer.ColumnAt(applyPositionOffset(screenSpacePosition, false));
+
+ private Vector2 applyPositionOffset(Vector2 position, bool reverse)
+ {
+ position.Y += (scrollingInfo.Direction.Value == ScrollingDirection.Up && !reverse ? -1 : 1) * NotePiece.NOTE_HEIGHT / 2;
+ return position;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs
index 53f9dd8752..d3c12b1944 100644
--- a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs
@@ -1,23 +1,80 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Input.Events;
+using osu.Framework.Timing;
using osu.Game.Rulesets.Edit;
+using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.UI.Scrolling;
+using osuTK;
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
{
public class ManiaSelectionBlueprint : SelectionBlueprint
{
+ public Vector2 ScreenSpaceDragPosition { get; private set; }
+ public Vector2 DragPosition { get; private set; }
+
+ protected new DrawableManiaHitObject HitObject => (DrawableManiaHitObject)base.HitObject;
+
+ protected IClock EditorClock { get; private set; }
+
+ [Resolved]
+ private IScrollingInfo scrollingInfo { get; set; }
+
+ [Resolved]
+ private IManiaHitObjectComposer composer { get; set; }
+
public ManiaSelectionBlueprint(DrawableHitObject hitObject)
: base(hitObject)
{
RelativeSizeAxes = Axes.None;
}
- public override void AdjustPosition(DragEvent dragEvent)
+ [BackgroundDependencyLoader]
+ private void load(IAdjustableClock clock)
{
+ EditorClock = clock;
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+
+ Position = Parent.ToLocalSpace(HitObject.ToScreenSpace(Vector2.Zero));
+ }
+
+ protected override bool OnMouseDown(MouseDownEvent e)
+ {
+ ScreenSpaceDragPosition = e.ScreenSpaceMousePosition;
+ DragPosition = HitObject.ToLocalSpace(e.ScreenSpaceMousePosition);
+
+ return base.OnMouseDown(e);
+ }
+
+ protected override bool OnDrag(DragEvent e)
+ {
+ var result = base.OnDrag(e);
+
+ ScreenSpaceDragPosition = e.ScreenSpaceMousePosition;
+ DragPosition = HitObject.ToLocalSpace(e.ScreenSpaceMousePosition);
+
+ return result;
+ }
+
+ public override void Show()
+ {
+ HitObject.AlwaysAlive = true;
+ base.Show();
+ }
+
+ public override void Hide()
+ {
+ HitObject.AlwaysAlive = false;
+ base.Hide();
}
}
}
diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/NotePlacementBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/NotePlacementBlueprint.cs
new file mode 100644
index 0000000000..32c6a6fd07
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/NotePlacementBlueprint.cs
@@ -0,0 +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 osu.Framework.Graphics;
+using osu.Game.Rulesets.Mania.Edit.Blueprints.Components;
+using osu.Game.Rulesets.Mania.Objects;
+
+namespace osu.Game.Rulesets.Mania.Edit.Blueprints
+{
+ public class NotePlacementBlueprint : ManiaPlacementBlueprint
+ {
+ public NotePlacementBlueprint()
+ : base(new Note())
+ {
+ Origin = Anchor.Centre;
+
+ AutoSizeAxes = Axes.Y;
+
+ InternalChild = new EditNotePiece { RelativeSizeAxes = Axes.X };
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+
+ Width = SnappedWidth;
+ Position = SnappedMousePosition;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs
index 7df7924c51..d345b14e84 100644
--- a/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mania.Edit.Blueprints.Components;
@@ -20,7 +20,6 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
base.Update();
Size = HitObject.DrawSize;
- Position = Parent.ToLocalSpace(HitObject.ScreenSpaceDrawQuad.TopLeft);
}
}
}
diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs b/osu.Game.Rulesets.Mania/Edit/DrawableManiaEditRuleset.cs
similarity index 55%
rename from osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs
rename to osu.Game.Rulesets.Mania/Edit/DrawableManiaEditRuleset.cs
index f605ad0a22..e5f379f608 100644
--- a/osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs
+++ b/osu.Game.Rulesets.Mania/Edit/DrawableManiaEditRuleset.cs
@@ -1,21 +1,23 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.Collections.Generic;
using osu.Framework.Graphics;
using osuTK;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.UI;
+using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling;
namespace osu.Game.Rulesets.Mania.Edit
{
- public class ManiaEditRulesetContainer : ManiaRulesetContainer
+ public class DrawableManiaEditRuleset : DrawableManiaRuleset
{
public new IScrollingInfo ScrollingInfo => base.ScrollingInfo;
- public ManiaEditRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap)
- : base(ruleset, beatmap)
+ public DrawableManiaEditRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList mods)
+ : base(ruleset, beatmap, mods)
{
}
diff --git a/osu.Game.Rulesets.Mania/Edit/HoldNoteCompositionTool.cs b/osu.Game.Rulesets.Mania/Edit/HoldNoteCompositionTool.cs
new file mode 100644
index 0000000000..295bf417c4
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Edit/HoldNoteCompositionTool.cs
@@ -0,0 +1,19 @@
+// 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.Rulesets.Edit;
+using osu.Game.Rulesets.Edit.Tools;
+using osu.Game.Rulesets.Mania.Edit.Blueprints;
+
+namespace osu.Game.Rulesets.Mania.Edit
+{
+ public class HoldNoteCompositionTool : HitObjectCompositionTool
+ {
+ public HoldNoteCompositionTool()
+ : base("Hold")
+ {
+ }
+
+ public override PlacementBlueprint CreatePlacementBlueprint() => new HoldNotePlacementBlueprint();
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Edit/IManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/IManiaHitObjectComposer.cs
new file mode 100644
index 0000000000..f64bab1fae
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Edit/IManiaHitObjectComposer.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.Rulesets.Mania.UI;
+using osuTK;
+
+namespace osu.Game.Rulesets.Mania.Edit
+{
+ public interface IManiaHitObjectComposer
+ {
+ Column ColumnAt(Vector2 screenSpacePosition);
+
+ int TotalColumns { get; }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaEditPlayfield.cs b/osu.Game.Rulesets.Mania/Edit/ManiaEditPlayfield.cs
index e7bc526471..a42f793a77 100644
--- a/osu.Game.Rulesets.Mania/Edit/ManiaEditPlayfield.cs
+++ b/osu.Game.Rulesets.Mania/Edit/ManiaEditPlayfield.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.UI;
diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs
index 3531b81e68..2729621ab3 100644
--- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs
+++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs
@@ -1,7 +1,6 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools;
@@ -11,33 +10,55 @@ using osu.Game.Rulesets.Objects.Drawables;
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Game.Rulesets.Mania.Edit.Blueprints;
+using osu.Game.Rulesets.Mania.UI;
+using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
+using osu.Game.Screens.Edit.Compose.Components;
+using osuTK;
namespace osu.Game.Rulesets.Mania.Edit
{
- public class ManiaHitObjectComposer : HitObjectComposer
+ [Cached(Type = typeof(IManiaHitObjectComposer))]
+ public class ManiaHitObjectComposer : HitObjectComposer, IManiaHitObjectComposer
{
+ protected new DrawableManiaEditRuleset DrawableRuleset { get; private set; }
+
public ManiaHitObjectComposer(Ruleset ruleset)
: base(ruleset)
{
}
+ ///
+ /// Retrieves the column that intersects a screen-space position.
+ ///
+ /// The screen-space position.
+ /// The column which intersects with .
+ public Column ColumnAt(Vector2 screenSpacePosition) => DrawableRuleset.GetColumnByPosition(screenSpacePosition);
+
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
=> dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
- protected override RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap)
+ public int TotalColumns => ((ManiaPlayfield)DrawableRuleset.Playfield).TotalColumns;
+
+ protected override DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList mods)
{
- var rulesetContainer = new ManiaEditRulesetContainer(ruleset, beatmap);
+ DrawableRuleset = new DrawableManiaEditRuleset(ruleset, beatmap, mods);
// This is the earliest we can cache the scrolling info to ourselves, before masks are added to the hierarchy and inject it
- dependencies.CacheAs(rulesetContainer.ScrollingInfo);
+ dependencies.CacheAs(DrawableRuleset.ScrollingInfo);
- return rulesetContainer;
+ return DrawableRuleset;
}
- protected override IReadOnlyList CompositionTools => Array.Empty();
+ protected override IReadOnlyList CompositionTools => new HitObjectCompositionTool[]
+ {
+ new NoteCompositionTool(),
+ new HoldNoteCompositionTool()
+ };
+
+ public override SelectionHandler CreateSelectionHandler() => new ManiaSelectionHandler();
public override SelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject)
{
@@ -45,6 +66,7 @@ namespace osu.Game.Rulesets.Mania.Edit
{
case DrawableNote note:
return new NoteSelectionBlueprint(note);
+
case DrawableHoldNote holdNote:
return new HoldNoteSelectionBlueprint(holdNote);
}
diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs
new file mode 100644
index 0000000000..6f49c7f0c4
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.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.Linq;
+using osu.Framework.Allocation;
+using osu.Framework.Input.Events;
+using osu.Framework.Timing;
+using osu.Game.Rulesets.Edit;
+using osu.Game.Rulesets.Mania.Edit.Blueprints;
+using osu.Game.Rulesets.Mania.Objects;
+using osu.Game.Rulesets.UI;
+using osu.Game.Rulesets.UI.Scrolling;
+using osu.Game.Screens.Edit.Compose.Components;
+using osuTK;
+
+namespace osu.Game.Rulesets.Mania.Edit
+{
+ public class ManiaSelectionHandler : SelectionHandler
+ {
+ [Resolved]
+ private IScrollingInfo scrollingInfo { get; set; }
+
+ [Resolved]
+ private IManiaHitObjectComposer composer { get; set; }
+
+ private IClock editorClock;
+
+ [BackgroundDependencyLoader]
+ private void load(IAdjustableClock clock)
+ {
+ editorClock = clock;
+ }
+
+ public override void HandleDrag(SelectionBlueprint blueprint, DragEvent dragEvent)
+ {
+ adjustOrigins((ManiaSelectionBlueprint)blueprint);
+ performDragMovement(dragEvent);
+ performColumnMovement(dragEvent);
+
+ base.HandleDrag(blueprint, dragEvent);
+ }
+
+ ///
+ /// Ensures that the position of hitobjects remains centred to the mouse position.
+ /// E.g. The hitobject position will change if the editor scrolls while a hitobject is dragged.
+ ///
+ /// The that received the drag event.
+ private void adjustOrigins(ManiaSelectionBlueprint reference)
+ {
+ var referenceParent = (HitObjectContainer)reference.HitObject.Parent;
+
+ float offsetFromReferenceOrigin = reference.DragPosition.Y - reference.HitObject.OriginPosition.Y;
+ float targetPosition = referenceParent.ToLocalSpace(reference.ScreenSpaceDragPosition).Y - offsetFromReferenceOrigin;
+
+ // Flip the vertical coordinate space when scrolling downwards
+ if (scrollingInfo.Direction.Value == ScrollingDirection.Down)
+ targetPosition = targetPosition - referenceParent.DrawHeight;
+
+ float movementDelta = targetPosition - reference.HitObject.Position.Y;
+
+ foreach (var b in SelectedBlueprints.OfType())
+ b.HitObject.Y += movementDelta;
+ }
+
+ private void performDragMovement(DragEvent dragEvent)
+ {
+ foreach (var b in SelectedBlueprints)
+ {
+ var hitObject = b.HitObject;
+
+ var objectParent = (HitObjectContainer)hitObject.Parent;
+
+ // Using the hitobject position is required since AdjustPosition can be invoked multiple times per frame
+ // without the position having been updated by the parenting ScrollingHitObjectContainer
+ hitObject.Y += dragEvent.Delta.Y;
+
+ float targetPosition;
+
+ // If we're scrolling downwards, a position of 0 is actually further away from the hit target
+ // so we need to flip the vertical coordinate in the hitobject container's space
+ if (scrollingInfo.Direction.Value == ScrollingDirection.Down)
+ targetPosition = -hitObject.Position.Y;
+ else
+ targetPosition = hitObject.Position.Y;
+
+ objectParent.Remove(hitObject);
+
+ hitObject.HitObject.StartTime = scrollingInfo.Algorithm.TimeAt(targetPosition,
+ editorClock.CurrentTime,
+ scrollingInfo.TimeRange.Value,
+ objectParent.DrawHeight);
+
+ objectParent.Add(hitObject);
+ }
+ }
+
+ private void performColumnMovement(DragEvent dragEvent)
+ {
+ var lastColumn = composer.ColumnAt(dragEvent.ScreenSpaceLastMousePosition);
+ var currentColumn = composer.ColumnAt(dragEvent.ScreenSpaceMousePosition);
+ if (lastColumn == null || currentColumn == null)
+ return;
+
+ int columnDelta = currentColumn.Index - lastColumn.Index;
+ if (columnDelta == 0)
+ return;
+
+ int minColumn = int.MaxValue;
+ int maxColumn = int.MinValue;
+
+ foreach (var obj in SelectedHitObjects.OfType())
+ {
+ if (obj.Column < minColumn)
+ minColumn = obj.Column;
+ if (obj.Column > maxColumn)
+ maxColumn = obj.Column;
+ }
+
+ columnDelta = MathHelper.Clamp(columnDelta, -minColumn, composer.TotalColumns - 1 - maxColumn);
+
+ foreach (var obj in SelectedHitObjects.OfType())
+ obj.Column += columnDelta;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Edit/Masks/ManiaSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Masks/ManiaSelectionBlueprint.cs
index 81a2728ad4..30b0f09a94 100644
--- a/osu.Game.Rulesets.Mania/Edit/Masks/ManiaSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Mania/Edit/Masks/ManiaSelectionBlueprint.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Edit;
diff --git a/osu.Game.Rulesets.Mania/Edit/NoteCompositionTool.cs b/osu.Game.Rulesets.Mania/Edit/NoteCompositionTool.cs
new file mode 100644
index 0000000000..50b5f9a8fe
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Edit/NoteCompositionTool.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.Game.Rulesets.Edit;
+using osu.Game.Rulesets.Edit.Tools;
+using osu.Game.Rulesets.Mania.Edit.Blueprints;
+using osu.Game.Rulesets.Mania.Objects;
+
+namespace osu.Game.Rulesets.Mania.Edit
+{
+ public class NoteCompositionTool : HitObjectCompositionTool
+ {
+ public NoteCompositionTool()
+ : base(nameof(Note))
+ {
+ }
+
+ public override PlacementBlueprint CreatePlacementBlueprint() => new NotePlacementBlueprint();
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Judgements/HoldNoteJudgement.cs b/osu.Game.Rulesets.Mania/Judgements/HoldNoteJudgement.cs
index 9055e48a4c..e8b48768a1 100644
--- a/osu.Game.Rulesets.Mania/Judgements/HoldNoteJudgement.cs
+++ b/osu.Game.Rulesets.Mania/Judgements/HoldNoteJudgement.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Scoring;
diff --git a/osu.Game.Rulesets.Mania/Judgements/HoldNoteTickJudgement.cs b/osu.Game.Rulesets.Mania/Judgements/HoldNoteTickJudgement.cs
index 6eb5a79200..b9c6e3a7f7 100644
--- a/osu.Game.Rulesets.Mania/Judgements/HoldNoteTickJudgement.cs
+++ b/osu.Game.Rulesets.Mania/Judgements/HoldNoteTickJudgement.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Scoring;
@@ -10,5 +10,17 @@ namespace osu.Game.Rulesets.Mania.Judgements
public override bool AffectsCombo => false;
protected override int NumericResultFor(HitResult result) => 20;
+
+ protected override double HealthIncreaseFor(HitResult result)
+ {
+ switch (result)
+ {
+ case HitResult.Miss:
+ return 0;
+
+ default:
+ return 0.040;
+ }
+ }
}
}
diff --git a/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs b/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs
index 4e0649c708..0e4c811945 100644
--- a/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs
+++ b/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
@@ -14,16 +14,47 @@ namespace osu.Game.Rulesets.Mania.Judgements
{
default:
return 0;
+
case HitResult.Meh:
return 50;
+
case HitResult.Ok:
return 100;
+
case HitResult.Good:
return 200;
+
case HitResult.Great:
case HitResult.Perfect:
return 300;
}
}
+
+ protected override double HealthIncreaseFor(HitResult result)
+ {
+ switch (result)
+ {
+ case HitResult.Miss:
+ return -0.125;
+
+ case HitResult.Meh:
+ return 0.005;
+
+ case HitResult.Ok:
+ return 0.010;
+
+ case HitResult.Good:
+ return 0.035;
+
+ case HitResult.Great:
+ return 0.055;
+
+ case HitResult.Perfect:
+ return 0.065;
+
+ default:
+ return 0;
+ }
+ }
}
}
diff --git a/osu.Game.Rulesets.Mania/ManiaInputManager.cs b/osu.Game.Rulesets.Mania/ManiaInputManager.cs
index 61356d96dc..292990fd7e 100644
--- a/osu.Game.Rulesets.Mania/ManiaInputManager.cs
+++ b/osu.Game.Rulesets.Mania/ManiaInputManager.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.ComponentModel;
using osu.Framework.Input.Bindings;
@@ -19,6 +19,7 @@ namespace osu.Game.Rulesets.Mania
{
[Description("Special 1")]
Special1 = 1,
+
[Description("Special 2")]
Special2,
@@ -26,38 +27,55 @@ namespace osu.Game.Rulesets.Mania
// above at a later time, without breaking replays/configs.
[Description("Key 1")]
Key1 = 10,
+
[Description("Key 2")]
Key2,
+
[Description("Key 3")]
Key3,
+
[Description("Key 4")]
Key4,
+
[Description("Key 5")]
Key5,
+
[Description("Key 6")]
Key6,
+
[Description("Key 7")]
Key7,
+
[Description("Key 8")]
Key8,
+
[Description("Key 9")]
Key9,
+
[Description("Key 10")]
Key10,
+
[Description("Key 11")]
Key11,
+
[Description("Key 12")]
Key12,
+
[Description("Key 13")]
Key13,
+
[Description("Key 14")]
Key14,
+
[Description("Key 15")]
Key15,
+
[Description("Key 16")]
Key16,
+
[Description("Key 17")]
Key17,
+
[Description("Key 18")]
Key18,
}
diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs
index 19e89c8ec5..d83033f9c6 100644
--- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs
+++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using osu.Game.Beatmaps;
@@ -10,8 +10,10 @@ using osu.Game.Rulesets.UI;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Bindings;
using osu.Game.Graphics;
+using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Replays;
using osu.Game.Rulesets.Replays.Types;
using osu.Game.Beatmaps.Legacy;
@@ -24,15 +26,15 @@ using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Configuration;
using osu.Game.Rulesets.Mania.Difficulty;
using osu.Game.Rulesets.Mania.Edit;
-using osu.Game.Rulesets.Scoring;
+using osu.Game.Scoring;
namespace osu.Game.Rulesets.Mania
{
public class ManiaRuleset : Ruleset
{
- public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap) => new ManiaRulesetContainer(this, beatmap);
+ public override DrawableRuleset CreateDrawableRulesetWith(WorkingBeatmap beatmap, IReadOnlyList mods) => new DrawableManiaRuleset(this, beatmap, mods);
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap);
- public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, Score score) => new ManiaPerformanceCalculator(this, beatmap, score);
+ public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new ManiaPerformanceCalculator(this, beatmap, score);
public override HitObjectComposer CreateHitObjectComposer() => new ManiaHitObjectComposer(this);
@@ -115,6 +117,7 @@ namespace osu.Game.Rulesets.Mania
new ManiaModNoFail(),
new MultiMod(new ManiaModHalfTime(), new ManiaModDaycore()),
};
+
case ModType.DifficultyIncrease:
return new Mod[]
{
@@ -124,6 +127,7 @@ namespace osu.Game.Rulesets.Mania
new MultiMod(new ManiaModFadeIn(), new ManiaModHidden()),
new ManiaModFlashlight(),
};
+
case ModType.Conversion:
return new Mod[]
{
@@ -140,11 +144,19 @@ namespace osu.Game.Rulesets.Mania
new ManiaModDualStages(),
new ManiaModMirror(),
};
+
case ModType.Automation:
return new Mod[]
{
new MultiMod(new ManiaModAutoplay(), new ModCinema()),
};
+
+ case ModType.Fun:
+ return new Mod[]
+ {
+ new MultiMod(new ModWindUp(), new ModWindDown())
+ };
+
default:
return new Mod[] { };
}
@@ -154,7 +166,7 @@ namespace osu.Game.Rulesets.Mania
public override string ShortName => "mania";
- public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_mania_o };
+ public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.RulesetMania };
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new ManiaDifficultyCalculator(this, beatmap);
@@ -162,7 +174,7 @@ namespace osu.Game.Rulesets.Mania
public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new ManiaReplayFrame();
- public override IRulesetConfigManager CreateConfig(SettingsStore settings) => new ManiaConfigManager(settings, RulesetInfo);
+ public override IRulesetConfigManager CreateConfig(SettingsStore settings) => new ManiaRulesetConfigManager(settings, RulesetInfo);
public override RulesetSettingsSubsection CreateSettings() => new ManiaSettingsSubsection(this);
@@ -207,6 +219,7 @@ namespace osu.Game.Rulesets.Mania
SpecialAction = ManiaAction.Special1,
NormalActionStart = ManiaAction.Key1,
}.GenerateKeyBindingsFor(variant, out _);
+
case PlayfieldType.Dual:
int keys = getDualStageKeyCount(variant);
@@ -264,6 +277,7 @@ namespace osu.Game.Rulesets.Mania
{
default:
return $"{variant}K";
+
case PlayfieldType.Dual:
{
var keys = getDualStageKeyCount(variant);
@@ -330,12 +344,12 @@ namespace osu.Game.Rulesets.Mania
for (int i = LeftKeys.Length - columns / 2; i < LeftKeys.Length; i++)
bindings.Add(new KeyBinding(LeftKeys[i], currentNormalAction++));
- for (int i = 0; i < columns / 2; i++)
- bindings.Add(new KeyBinding(RightKeys[i], currentNormalAction++));
-
if (columns % 2 == 1)
bindings.Add(new KeyBinding(SpecialKey, SpecialAction));
+ for (int i = 0; i < columns / 2; i++)
+ bindings.Add(new KeyBinding(RightKeys[i], currentNormalAction++));
+
nextNormalAction = currentNormalAction;
return bindings;
}
@@ -349,6 +363,7 @@ namespace osu.Game.Rulesets.Mania
/// Number of columns in this stage lies at (item - Single).
///
Single = 0,
+
///
/// Columns are grouped into two stages.
/// Overall number of columns lies at (item - Dual), further computation is required for
diff --git a/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs b/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs
index 783142fadc..2ebfd0cfc1 100644
--- a/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs
+++ b/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs
@@ -1,8 +1,9 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.UserInterface;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets.Mania.Configuration;
using osu.Game.Rulesets.Mania.UI;
@@ -21,14 +22,26 @@ namespace osu.Game.Rulesets.Mania
[BackgroundDependencyLoader]
private void load()
{
+ var config = (ManiaRulesetConfigManager)Config;
+
Children = new Drawable[]
{
new SettingsEnumDropdown
{
LabelText = "Scrolling direction",
- Bindable = ((ManiaConfigManager)Config).GetBindable(ManiaSetting.ScrollDirection)
- }
+ Bindable = config.GetBindable(ManiaRulesetSetting.ScrollDirection)
+ },
+ new SettingsSlider
+ {
+ LabelText = "Scroll speed",
+ Bindable = config.GetBindable(ManiaRulesetSetting.ScrollTime)
+ },
};
}
+
+ private class TimeSlider : OsuSliderBar
+ {
+ public override string TooltipText => Current.Value.ToString("N0") + "ms";
+ }
}
}
diff --git a/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs b/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs
index 785cd5ab06..a9cd7f2476 100644
--- a/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs
+++ b/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
@@ -37,11 +37,11 @@ namespace osu.Game.Rulesets.Mania.MathUtils
/// The random value.
public uint NextUInt()
{
- uint t = X ^ X << 11;
+ uint t = X ^ (X << 11);
X = Y;
Y = Z;
Z = W;
- return W = W ^ W >> 19 ^ t ^ t >> 8;
+ return W = W ^ (W >> 19) ^ t ^ (t >> 8);
}
///
diff --git a/osu.Game.Rulesets.Mania/Mods/IPlayfieldTypeMod.cs b/osu.Game.Rulesets.Mania/Mods/IPlayfieldTypeMod.cs
index e08c9aa2a8..410386c9d5 100644
--- a/osu.Game.Rulesets.Mania/Mods/IPlayfieldTypeMod.cs
+++ b/osu.Game.Rulesets.Mania/Mods/IPlayfieldTypeMod.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaKeyMod.cs b/osu.Game.Rulesets.Mania/Mods/ManiaKeyMod.cs
index 6d91c03c13..13fdd74113 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaKeyMod.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaKeyMod.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Linq;
@@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public abstract class ManiaKeyMod : Mod, IApplicableToBeatmapConverter
{
- public override string ShortenedName => Name;
+ public override string Acronym => Name;
public abstract int KeyCount { get; }
public override ModType Type => ModType.Conversion;
public override double ScoreMultiplier => 1; // TODO: Implement the mania key mod score multiplier
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModAutoplay.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModAutoplay.cs
index 89792956bb..c05e979e9a 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModAutoplay.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModAutoplay.cs
@@ -1,25 +1,22 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Replays;
using osu.Game.Rulesets.Mods;
-using osu.Game.Rulesets.Scoring;
+using osu.Game.Scoring;
using osu.Game.Users;
namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModAutoplay : ModAutoplay
{
- protected override Score CreateReplayScore(Beatmap beatmap)
+ public override Score CreateReplayScore(IBeatmap beatmap) => new Score
{
- return new Score
- {
- User = new User { Username = "osu!topus!" },
- Replay = new ManiaAutoGenerator((ManiaBeatmap)beatmap).Generate(),
- };
- }
+ ScoreInfo = new ScoreInfo { User = new User { Username = "osu!topus!" } },
+ Replay = new ManiaAutoGenerator((ManiaBeatmap)beatmap).Generate(),
+ };
}
}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModDaycore.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModDaycore.cs
index 506879bb96..bec0a6a1d3 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModDaycore.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModDaycore.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModDoubleTime.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModDoubleTime.cs
index bd93f0db38..a302f95966 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModDoubleTime.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModDoubleTime.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs
index 4790a77cc0..c78bf72979 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs
@@ -1,18 +1,16 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.Collections.Generic;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Beatmaps;
-using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Mania.Mods
{
- public class ManiaModDualStages : Mod, IPlayfieldTypeMod, IApplicableToBeatmapConverter, IApplicableToBeatmap
+ public class ManiaModDualStages : Mod, IPlayfieldTypeMod, IApplicableToBeatmapConverter
{
public override string Name => "Dual Stages";
- public override string ShortenedName => "DS";
+ public override string Acronym => "DS";
public override string Description => @"Double the stages, double the fun!";
public override ModType Type => ModType.Conversion;
public override double ScoreMultiplier => 1;
@@ -29,24 +27,7 @@ namespace osu.Game.Rulesets.Mania.Mods
if (isForCurrentRuleset)
return;
- mbc.TargetColumns *= 2;
- }
-
- public void ApplyToBeatmap(Beatmap beatmap)
- {
- if (isForCurrentRuleset)
- return;
-
- var maniaBeatmap = (ManiaBeatmap)beatmap;
-
- var newDefinitions = new List();
- foreach (var existing in maniaBeatmap.Stages)
- {
- newDefinitions.Add(new StageDefinition { Columns = existing.Columns / 2 });
- newDefinitions.Add(new StageDefinition { Columns = existing.Columns / 2 });
- }
-
- maniaBeatmap.Stages = newDefinitions;
+ mbc.Dual = true;
}
public PlayfieldType PlayfieldType => PlayfieldType.Dual;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModEasy.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModEasy.cs
index 8c85846ed1..ff77df0ae0 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModEasy.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModEasy.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs
index 73942cbb53..39185e6a57 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs
@@ -1,7 +1,8 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
+using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mods;
@@ -11,8 +12,8 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModFadeIn : Mod
{
public override string Name => "Fade In";
- public override string ShortenedName => "FI";
- public override FontAwesome Icon => FontAwesome.fa_osu_mod_hidden;
+ public override string Acronym => "FI";
+ public override IconUsage Icon => OsuIcon.ModHidden;
public override ModType Type => ModType.DifficultyIncrease;
public override string Description => @"Keys appear out of nowhere!";
public override double ScoreMultiplier => 1;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs
index cd84483eb9..6893e1e73b 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs
@@ -1,7 +1,8 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
+using osu.Framework.Bindables;
using osu.Framework.Caching;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Objects;
@@ -51,7 +52,7 @@ namespace osu.Game.Rulesets.Mania.Mods
}
}
- protected override void OnComboChange(int newCombo)
+ protected override void OnComboChange(ValueChangedEvent e)
{
}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHalfTime.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHalfTime.cs
index 978554362d..014954dd60 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModHalfTime.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHalfTime.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHardRock.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHardRock.cs
index 7b766cab85..d9de06a811 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModHardRock.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHardRock.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs
index 9bc2502a8f..66b90984b4 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using osu.Game.Rulesets.Mania.Objects;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey1.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey1.cs
index c2a4ed444f..948979505c 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey1.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey1.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mania.Mods
{
@@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override int KeyCount => 1;
public override string Name => "One Key";
- public override string ShortenedName => "1K";
+ public override string Acronym => "1K";
public override string Description => @"Play with one key.";
}
}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey2.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey2.cs
index 3d78ad449b..de91902ca8 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey2.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey2.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mania.Mods
{
@@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override int KeyCount => 2;
public override string Name => "Two Keys";
- public override string ShortenedName => "2K";
+ public override string Acronym => "2K";
public override string Description => @"Play with two keys.";
}
}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey3.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey3.cs
index a96375a81d..8575a96bde 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey3.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey3.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mania.Mods
{
@@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override int KeyCount => 3;
public override string Name => "Three Keys";
- public override string ShortenedName => "3K";
+ public override string Acronym => "3K";
public override string Description => @"Play with three keys.";
}
}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey4.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey4.cs
index 2bd3d08648..54ea3afa07 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey4.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey4.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mania.Mods
{
@@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override int KeyCount => 4;
public override string Name => "Four Keys";
- public override string ShortenedName => "4K";
+ public override string Acronym => "4K";
public override string Description => @"Play with four keys.";
}
}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey5.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey5.cs
index e59b2d6e59..e9a9bba5bd 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey5.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey5.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mania.Mods
{
@@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override int KeyCount => 5;
public override string Name => "Five Keys";
- public override string ShortenedName => "5K";
+ public override string Acronym => "5K";
public override string Description => @"Play with five keys.";
}
}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey6.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey6.cs
index 6a05317f46..b9606d1cb5 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey6.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey6.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mania.Mods
{
@@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override int KeyCount => 6;
public override string Name => "Six Keys";
- public override string ShortenedName => "6K";
+ public override string Acronym => "6K";
public override string Description => @"Play with six keys.";
}
}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey7.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey7.cs
index 7280c345b8..b80d794085 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey7.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey7.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mania.Mods
{
@@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override int KeyCount => 7;
public override string Name => "Seven Keys";
- public override string ShortenedName => "7K";
+ public override string Acronym => "7K";
public override string Description => @"Play with seven keys.";
}
}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey8.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey8.cs
index dddef0fa9d..3462d634a4 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey8.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey8.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mania.Mods
{
@@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override int KeyCount => 8;
public override string Name => "Eight Keys";
- public override string ShortenedName => "8K";
+ public override string Acronym => "8K";
public override string Description => @"Play with eight keys.";
}
}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey9.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey9.cs
index 4ef38503a4..83c505c048 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey9.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey9.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mania.Mods
{
@@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override int KeyCount => 9;
public override string Name => "Nine Keys";
- public override string ShortenedName => "9K";
+ public override string Acronym => "9K";
public override string Description => @"Play with nine keys.";
}
}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs
index 847b0037f1..17f4098420 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs
@@ -1,28 +1,28 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.IEnumerableExtensions;
using osu.Game.Rulesets.Mania.Objects;
-using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mods;
-using osu.Game.Rulesets.UI;
using System.Linq;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Mania.Beatmaps;
namespace osu.Game.Rulesets.Mania.Mods
{
- public class ManiaModMirror : Mod, IApplicableToRulesetContainer
+ public class ManiaModMirror : Mod, IApplicableToBeatmap
{
public override string Name => "Mirror";
- public override string ShortenedName => "MR";
+ public override string Acronym => "MR";
public override ModType Type => ModType.Conversion;
public override double ScoreMultiplier => 1;
public override bool Ranked => true;
- public void ApplyToRulesetContainer(RulesetContainer rulesetContainer)
+ public void ApplyToBeatmap(Beatmap beatmap)
{
- var availableColumns = ((ManiaRulesetContainer)rulesetContainer).Beatmap.TotalColumns;
+ var availableColumns = ((ManiaBeatmap)beatmap).TotalColumns;
- rulesetContainer.Objects.OfType().ForEach(h => h.Column = availableColumns - 1 - h.Column);
+ beatmap.HitObjects.OfType().ForEach(h => h.Column = availableColumns - 1 - h.Column);
}
}
}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModNightcore.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModNightcore.cs
index b3e73be4ee..2d94fb6af5 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModNightcore.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModNightcore.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModNoFail.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModNoFail.cs
index c22549bfc7..e8988be548 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModNoFail.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModNoFail.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModPerfect.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModPerfect.cs
index abada804fb..2e22e23dbd 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModPerfect.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModPerfect.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs
index 0915b80742..ba16140644 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs
@@ -1,32 +1,33 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.Linq;
using osu.Framework.Extensions.IEnumerableExtensions;
+using osu.Framework.Graphics.Sprites;
using osu.Framework.MathUtils;
+using osu.Game.Beatmaps;
using osu.Game.Graphics;
+using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
-using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mods;
-using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mania.Mods
{
- public class ManiaModRandom : Mod, IApplicableToRulesetContainer
+ public class ManiaModRandom : Mod, IApplicableToBeatmap
{
public override string Name => "Random";
- public override string ShortenedName => "RD";
+ public override string Acronym => "RD";
public override ModType Type => ModType.Conversion;
- public override FontAwesome Icon => FontAwesome.fa_osu_dice;
+ public override IconUsage Icon => OsuIcon.Dice;
public override string Description => @"Shuffle around the keys!";
public override double ScoreMultiplier => 1;
- public void ApplyToRulesetContainer(RulesetContainer rulesetContainer)
+ public void ApplyToBeatmap(Beatmap beatmap)
{
- var availableColumns = ((ManiaRulesetContainer)rulesetContainer).Beatmap.TotalColumns;
+ var availableColumns = ((ManiaBeatmap)beatmap).TotalColumns;
var shuffledColumns = Enumerable.Range(0, availableColumns).OrderBy(item => RNG.Next()).ToList();
- rulesetContainer.Objects.OfType().ForEach(h => h.Column = shuffledColumns[h.Column]);
+ beatmap.HitObjects.OfType().ForEach(h => h.Column = shuffledColumns[h.Column]);
}
}
}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModSuddenDeath.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModSuddenDeath.cs
index 05843b3af8..ecc343ecaa 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModSuddenDeath.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModSuddenDeath.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Mania/Objects/BarLine.cs b/osu.Game.Rulesets.Mania/Objects/BarLine.cs
index 0ceb10cc89..4c644a8f09 100644
--- a/osu.Game.Rulesets.Mania/Objects/BarLine.cs
+++ b/osu.Game.Rulesets.Mania/Objects/BarLine.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.ControlPoints;
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs
index cf718ebdb0..9c3197504f 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
using osuTK;
using osu.Framework.Graphics;
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
index 5fcc71a039..9368af987d 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
@@ -1,7 +1,8 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.Linq;
+using osu.Framework.Bindables;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
@@ -42,7 +43,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{
RelativeSizeAxes = Axes.X;
- InternalChildren = new Drawable[]
+ AddRangeInternal(new Drawable[]
{
bodyPiece = new BodyPiece
{
@@ -66,7 +67,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre
}
- };
+ });
foreach (var tick in tickContainer)
AddNested(tick);
@@ -75,16 +76,16 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
AddNested(Tail);
}
- protected override void OnDirectionChanged(ScrollingDirection direction)
+ protected override void OnDirectionChanged(ValueChangedEvent e)
{
- base.OnDirectionChanged(direction);
+ base.OnDirectionChanged(e);
- bodyPiece.Anchor = bodyPiece.Origin = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft;
+ bodyPiece.Anchor = bodyPiece.Origin = e.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft;
}
public override Color4 AccentColour
{
- get { return base.AccentColour; }
+ get => base.AccentColour;
set
{
base.AccentColour = value;
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs
index 3e014ec35c..9a29273282 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using osuTK;
@@ -7,6 +7,7 @@ using osuTK.Graphics;
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.Game.Rulesets.Scoring;
@@ -33,7 +34,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
RelativeSizeAxes = Axes.X;
Size = new Vector2(1);
- InternalChildren = new[]
+ AddRangeInternal(new[]
{
glowContainer = new CircularContainer
{
@@ -51,12 +52,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
}
}
}
- };
+ });
}
public override Color4 AccentColour
{
- get { return base.AccentColour; }
+ get => base.AccentColour;
set
{
base.AccentColour = value;
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs
index 8c96c6dfe7..0873f753be 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs
@@ -1,9 +1,9 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Configuration;
+using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI.Scrolling;
@@ -12,6 +12,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{
public abstract class DrawableManiaHitObject : DrawableHitObject
{
+ ///
+ /// Whether this should always remain alive.
+ ///
+ internal bool AlwaysAlive;
+
///
/// The which causes this to be hit.
///
@@ -34,9 +39,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
Direction.BindValueChanged(OnDirectionChanged, true);
}
- protected virtual void OnDirectionChanged(ScrollingDirection direction)
+ protected override bool ShouldBeAlive => AlwaysAlive || base.ShouldBeAlive;
+
+ protected virtual void OnDirectionChanged(ValueChangedEvent e)
{
- Anchor = Origin = direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre;
+ Anchor = Origin = e.NewValue == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre;
}
}
@@ -58,6 +65,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
case ArmedState.Miss:
this.FadeOut(150, Easing.In).Expire();
break;
+
case ArmedState.Hit:
this.FadeOut(150, Easing.OutQuint).Expire();
break;
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs
index 423712b026..afd7777861 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs
@@ -1,10 +1,11 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Extensions.Color4Extensions;
using osuTK.Graphics;
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Effects;
using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.Scoring;
@@ -28,19 +29,19 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
CornerRadius = 5;
Masking = true;
- InternalChild = headPiece = new NotePiece();
+ AddInternal(headPiece = new NotePiece());
}
- protected override void OnDirectionChanged(ScrollingDirection direction)
+ protected override void OnDirectionChanged(ValueChangedEvent e)
{
- base.OnDirectionChanged(direction);
+ base.OnDirectionChanged(e);
- headPiece.Anchor = headPiece.Origin = direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre;
+ headPiece.Anchor = headPiece.Origin = e.NewValue == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre;
}
public override Color4 AccentColour
{
- get { return base.AccentColour; }
+ get => base.AccentColour;
set
{
base.AccentColour = value;
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs
index 4e5bcf64e7..8102718edf 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using osu.Framework.Caching;
@@ -7,6 +7,7 @@ using osuTK.Graphics;
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.Game.Graphics;
@@ -15,12 +16,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
///
/// Represents length-wise portion of a hold note.
///
- internal class BodyPiece : Container, IHasAccentColour
+ public class BodyPiece : Container, IHasAccentColour
{
private readonly Container subtractionLayer;
- private readonly Drawable background;
- private readonly BufferedContainer foreground;
+ protected readonly Drawable Background;
+ protected readonly BufferedContainer Foreground;
private readonly BufferedContainer subtractionContainer;
public BodyPiece()
@@ -29,8 +30,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
Children = new[]
{
- background = new Box { RelativeSizeAxes = Axes.Both },
- foreground = new BufferedContainer
+ Background = new Box { RelativeSizeAxes = Axes.Both },
+ Foreground = new BufferedContainer
{
Blending = BlendingMode.Additive,
RelativeSizeAxes = Axes.Both,
@@ -77,11 +78,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
public Color4 AccentColour
{
- get { return accentColour; }
+ get => accentColour;
set
{
if (accentColour == value)
return;
+
accentColour = value;
updateAccentColour();
@@ -90,7 +92,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
public bool Hitting
{
- get { return hitting; }
+ get => hitting;
set
{
hitting = value;
@@ -123,7 +125,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
Radius = DrawWidth
};
- foreground.ForceRedraw();
+ Foreground.ForceRedraw();
subtractionContainer.ForceRedraw();
subtractionCache.Validate();
@@ -137,18 +139,19 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
if (!IsLoaded)
return;
- foreground.Colour = AccentColour.Opacity(0.5f);
- background.Colour = AccentColour.Opacity(0.7f);
+ Foreground.Colour = AccentColour.Opacity(0.5f);
+ Background.Colour = AccentColour.Opacity(0.7f);
const float animation_length = 50;
- foreground.ClearTransforms(false, nameof(foreground.Colour));
+ Foreground.ClearTransforms(false, nameof(Foreground.Colour));
+
if (hitting)
{
// wait for the next sync point
double synchronisedOffset = animation_length * 2 - Time.Current % (animation_length * 2);
- using (foreground.BeginDelayedSequence(synchronisedOffset))
- foreground.FadeColour(AccentColour.Lighten(0.2f), animation_length).Then().FadeColour(foreground.Colour, animation_length).Loop();
+ using (Foreground.BeginDelayedSequence(synchronisedOffset))
+ Foreground.FadeColour(AccentColour.Lighten(0.2f), animation_length).Then().FadeColour(Foreground.Colour, animation_length).Loop();
}
subtractionCache.Invalidate();
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/GlowPiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/GlowPiece.cs
index 3a524bfc90..1d25a0c966 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/GlowPiece.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/GlowPiece.cs
@@ -1,9 +1,10 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osuTK.Graphics;
@@ -35,13 +36,15 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
}
private Color4 accentColour;
+
public Color4 AccentColour
{
- get { return accentColour; }
+ get => accentColour;
set
{
if (accentColour == value)
return;
+
accentColour = value;
updateGlow();
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/LaneGlowPiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/LaneGlowPiece.cs
index 8325cb8ac0..9e0307c5c2 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/LaneGlowPiece.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/LaneGlowPiece.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
using osuTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
@@ -78,8 +78,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
public Color4 AccentColour
{
- get { return Colour; }
- set { Colour = value; }
+ get => Colour;
+ set => Colour = value;
}
}
}
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs
index 26d5a7f188..bb33693783 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs
@@ -1,8 +1,8 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Configuration;
+using osu.Framework.Bindables;
using osuTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
@@ -49,20 +49,22 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
private void load(IScrollingInfo scrollingInfo)
{
direction.BindTo(scrollingInfo.Direction);
- direction.BindValueChanged(direction =>
+ direction.BindValueChanged(dir =>
{
- colouredBox.Anchor = colouredBox.Origin = direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre;
+ colouredBox.Anchor = colouredBox.Origin = dir.NewValue == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre;
}, true);
}
private Color4 accentColour;
+
public Color4 AccentColour
{
- get { return accentColour; }
+ get => accentColour;
set
{
if (accentColour == value)
return;
+
accentColour = value;
colouredBox.Colour = AccentColour.Lighten(0.9f);
diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs
index 77562bb4c2..5e9f46d9c7 100644
--- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs
+++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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;
using osu.Game.Beatmaps.ControlPoints;
@@ -17,9 +17,10 @@ namespace osu.Game.Rulesets.Mania.Objects
public double EndTime => StartTime + Duration;
private double duration;
+
public double Duration
{
- get { return duration; }
+ get => duration;
set
{
duration = value;
@@ -29,7 +30,7 @@ namespace osu.Game.Rulesets.Mania.Objects
public override double StartTime
{
- get { return base.StartTime; }
+ get => base.StartTime;
set
{
base.StartTime = value;
@@ -40,7 +41,7 @@ namespace osu.Game.Rulesets.Mania.Objects
public override int Column
{
- get { return base.Column; }
+ get => base.Column;
set
{
base.Column = value;
diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs b/osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs
index 05959a31c0..c133ee73b1 100644
--- a/osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs
+++ b/osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Judgements;
diff --git a/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs
index e183098a51..70720a926b 100644
--- a/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs
+++ b/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs
@@ -1,6 +1,7 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Game.Rulesets.Mania.Objects.Types;
using osu.Game.Rulesets.Objects;
@@ -8,7 +9,13 @@ namespace osu.Game.Rulesets.Mania.Objects
{
public abstract class ManiaHitObject : HitObject, IHasColumn
{
- public virtual int Column { get; set; }
+ public readonly Bindable ColumnBindable = new Bindable();
+
+ public virtual int Column
+ {
+ get => ColumnBindable.Value;
+ set => ColumnBindable.Value = value;
+ }
protected override HitWindows CreateHitWindows() => new ManiaHitWindows();
}
diff --git a/osu.Game.Rulesets.Mania/Objects/ManiaHitObjectDifficulty.cs b/osu.Game.Rulesets.Mania/Objects/ManiaHitObjectDifficulty.cs
deleted file mode 100644
index 390d2b0218..0000000000
--- a/osu.Game.Rulesets.Mania/Objects/ManiaHitObjectDifficulty.cs
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Game.Rulesets.Objects.Types;
-using System;
-
-namespace osu.Game.Rulesets.Mania.Objects
-{
- internal class ManiaHitObjectDifficulty
- {
- ///
- /// Factor by how much individual / overall strain decays per second.
- ///
- ///
- /// These values are results of tweaking a lot and taking into account general feedback.
- ///
- internal const double INDIVIDUAL_DECAY_BASE = 0.125;
- internal const double OVERALL_DECAY_BASE = 0.30;
-
- internal ManiaHitObject BaseHitObject;
-
- private readonly int beatmapColumnCount;
-
-
- private readonly double endTime;
- private readonly double[] heldUntil;
-
- ///
- /// Measures jacks or more generally: repeated presses of the same button
- ///
- private readonly double[] individualStrains;
-
- internal double IndividualStrain
- {
- get
- {
- return individualStrains[BaseHitObject.Column];
- }
-
- set
- {
- individualStrains[BaseHitObject.Column] = value;
- }
- }
-
- ///
- /// Measures note density in a way
- ///
- internal double OverallStrain = 1;
-
- public ManiaHitObjectDifficulty(ManiaHitObject baseHitObject, int columnCount)
- {
- BaseHitObject = baseHitObject;
-
- endTime = (baseHitObject as IHasEndTime)?.EndTime ?? baseHitObject.StartTime;
-
- beatmapColumnCount = columnCount;
- heldUntil = new double[beatmapColumnCount];
- individualStrains = new double[beatmapColumnCount];
-
- for (int i = 0; i < beatmapColumnCount; ++i)
- {
- individualStrains[i] = 0;
- heldUntil[i] = 0;
- }
- }
-
- internal void CalculateStrains(ManiaHitObjectDifficulty previousHitObject, double timeRate)
- {
- // TODO: Factor in holds
- double timeElapsed = (BaseHitObject.StartTime - previousHitObject.BaseHitObject.StartTime) / timeRate;
- double individualDecay = Math.Pow(INDIVIDUAL_DECAY_BASE, timeElapsed / 1000);
- double overallDecay = Math.Pow(OVERALL_DECAY_BASE, timeElapsed / 1000);
-
- double holdFactor = 1.0; // Factor to all additional strains in case something else is held
- double holdAddition = 0; // Addition to the current note in case it's a hold and has to be released awkwardly
-
- // Fill up the heldUntil array
- for (int i = 0; i < beatmapColumnCount; ++i)
- {
- heldUntil[i] = previousHitObject.heldUntil[i];
-
- // If there is at least one other overlapping end or note, then we get an addition, buuuuuut...
- if (BaseHitObject.StartTime < heldUntil[i] && endTime > heldUntil[i])
- {
- holdAddition = 1.0;
- }
-
- // ... this addition only is valid if there is _no_ other note with the same ending. Releasing multiple notes at the same time is just as easy as releasing 1
- if (endTime == heldUntil[i])
- {
- holdAddition = 0;
- }
-
- // We give a slight bonus to everything if something is held meanwhile
- if (heldUntil[i] > endTime)
- {
- holdFactor = 1.25;
- }
-
- // Decay individual strains
- individualStrains[i] = previousHitObject.individualStrains[i] * individualDecay;
- }
-
- heldUntil[BaseHitObject.Column] = endTime;
-
- // Increase individual strain in own column
- IndividualStrain += 2.0 * holdFactor;
-
- OverallStrain = previousHitObject.OverallStrain * overallDecay + (1.0 + holdAddition) * holdFactor;
- }
- }
-}
diff --git a/osu.Game.Rulesets.Mania/Objects/ManiaHitWindows.cs b/osu.Game.Rulesets.Mania/Objects/ManiaHitWindows.cs
index 063b626af1..5f2ceab48b 100644
--- a/osu.Game.Rulesets.Mania/Objects/ManiaHitWindows.cs
+++ b/osu.Game.Rulesets.Mania/Objects/ManiaHitWindows.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.Collections.Generic;
using osu.Game.Beatmaps;
@@ -13,18 +13,17 @@ namespace osu.Game.Rulesets.Mania.Objects
private static readonly IReadOnlyDictionary base_ranges = new Dictionary
{
{ HitResult.Perfect, (44.8, 38.8, 27.8) },
- { HitResult.Great, (128, 98, 68 ) },
+ { HitResult.Great, (128, 98, 68) },
{ HitResult.Good, (194, 164, 134) },
{ HitResult.Ok, (254, 224, 194) },
{ HitResult.Meh, (302, 272, 242) },
{ HitResult.Miss, (376, 346, 316) },
};
+ public override bool IsHitResultAllowed(HitResult result) => true;
+
public override void SetDifficulty(double difficulty)
{
- AllowsPerfect = true;
- AllowsOk = true;
-
Perfect = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Perfect]);
Great = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Great]);
Good = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Good]);
diff --git a/osu.Game.Rulesets.Mania/Objects/Note.cs b/osu.Game.Rulesets.Mania/Objects/Note.cs
index 42877649d2..0035960c63 100644
--- a/osu.Game.Rulesets.Mania/Objects/Note.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Note.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Judgements;
diff --git a/osu.Game.Rulesets.Mania/Objects/TailNote.cs b/osu.Game.Rulesets.Mania/Objects/TailNote.cs
index 9de542bcd3..5a30fd6a12 100644
--- a/osu.Game.Rulesets.Mania/Objects/TailNote.cs
+++ b/osu.Game.Rulesets.Mania/Objects/TailNote.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Judgements;
diff --git a/osu.Game.Rulesets.Mania/Objects/Types/IHasColumn.cs b/osu.Game.Rulesets.Mania/Objects/Types/IHasColumn.cs
index 44a79de7db..1ea3138828 100644
--- a/osu.Game.Rulesets.Mania/Objects/Types/IHasColumn.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Types/IHasColumn.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Mania.Objects.Types
{
diff --git a/osu.Game.Rulesets.Mania/Properties/AssemblyInfo.cs b/osu.Game.Rulesets.Mania/Properties/AssemblyInfo.cs
index 76ccfe324b..f3ea6c7b71 100644
--- a/osu.Game.Rulesets.Mania/Properties/AssemblyInfo.cs
+++ b/osu.Game.Rulesets.Mania/Properties/AssemblyInfo.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.Runtime.CompilerServices;
@@ -9,3 +9,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")]
diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs
index 0eef540d97..e5669816fa 100644
--- a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs
+++ b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs
@@ -1,17 +1,16 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.Collections.Generic;
using System.Linq;
+using osu.Game.Replays;
using osu.Game.Rulesets.Mania.Beatmaps;
-using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Replays;
-using osu.Game.Users;
namespace osu.Game.Rulesets.Mania.Replays
{
- internal class ManiaAutoGenerator : AutoGenerator
+ internal class ManiaAutoGenerator : AutoGenerator
{
public const double RELEASE_DELAY = 20;
@@ -22,13 +21,14 @@ namespace osu.Game.Rulesets.Mania.Replays
public ManiaAutoGenerator(ManiaBeatmap beatmap)
: base(beatmap)
{
- Replay = new Replay { User = new User { Username = @"Autoplay" } };
+ Replay = new Replay();
columnActions = new ManiaAction[Beatmap.TotalColumns];
var normalAction = ManiaAction.Key1;
var specialAction = ManiaAction.Special1;
int totalCounter = 0;
+
foreach (var stage in Beatmap.Stages)
{
for (int i = 0; i < stage.Columns; i++)
@@ -52,6 +52,7 @@ namespace osu.Game.Rulesets.Mania.Replays
var pointGroups = generateActionPoints().GroupBy(a => a.Time).OrderBy(g => g.First().Time);
var actions = new List();
+
foreach (var group in pointGroups)
{
foreach (var point in group)
@@ -61,6 +62,7 @@ namespace osu.Game.Rulesets.Mania.Replays
case HitPoint _:
actions.Add(columnActions[point.Column]);
break;
+
case ReleasePoint _:
actions.Remove(columnActions[point.Column]);
break;
diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs b/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs
index ea239bf80f..899718b77e 100644
--- a/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs
+++ b/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs
@@ -1,9 +1,10 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.Collections.Generic;
using System.Linq;
using osu.Framework.Input.StateChanges;
+using osu.Game.Replays;
using osu.Game.Rulesets.Replays;
namespace osu.Game.Rulesets.Mania.Replays
@@ -17,6 +18,6 @@ namespace osu.Game.Rulesets.Mania.Replays
protected override bool IsImportant(ManiaReplayFrame frame) => frame.Actions.Any();
- public override List GetPendingInputs() => new List { new ReplayState { PressedActions = CurrentFrame.Actions } };
+ public override List GetPendingInputs() => new List { new ReplayState { PressedActions = CurrentFrame?.Actions ?? new List() } };
}
}
diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs b/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs
index bc9fd6e06f..f7277d3669 100644
--- a/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs
+++ b/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs
@@ -1,11 +1,11 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.Collections.Generic;
using osu.Game.Beatmaps;
+using osu.Game.Replays.Legacy;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Replays;
-using osu.Game.Rulesets.Replays.Legacy;
using osu.Game.Rulesets.Replays.Types;
namespace osu.Game.Rulesets.Mania.Replays
@@ -39,6 +39,7 @@ namespace osu.Game.Rulesets.Mania.Replays
int activeColumns = (int)(legacyFrame.MouseX ?? 0);
int counter = 0;
+
while (activeColumns > 0)
{
var isSpecial = stage.IsSpecialColumn(counter);
diff --git a/osu.Game.Rulesets.Mania/Resources/Testing/Beatmaps/diffcalc-test.osu b/osu.Game.Rulesets.Mania/Resources/Testing/Beatmaps/diffcalc-test.osu
new file mode 100644
index 0000000000..4c877c6193
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Resources/Testing/Beatmaps/diffcalc-test.osu
@@ -0,0 +1,180 @@
+osu file format v14
+
+[General]
+Mode: 3
+
+[Difficulty]
+CircleSize:4
+OverallDifficulty:7
+ApproachRate:8.3
+SliderMultiplier:1.6
+SliderTickRate:1
+
+[TimingPoints]
+500,500,4,2,1,50,1,0
+37500,-50,4,2,1,50,0,0
+41500,-25,4,2,1,50,0,0
+
+[HitObjects]
+// jacks spaced 1/1 beat apart
+64,192,0,1,0,0:0:0:0:
+64,192,500,1,0,0:0:0:0:
+64,192,1000,1,0,0:0:0:0:
+64,192,1500,1,0,0:0:0:0:
+64,192,2000,1,0,0:0:0:0:
+64,192,2500,1,0,0:0:0:0:
+
+// jacks spaced 1/2 beat apart
+64,192,3500,1,0,0:0:0:0:
+64,192,3750,1,0,0:0:0:0:
+64,192,4000,1,0,0:0:0:0:
+64,192,4250,1,0,0:0:0:0:
+64,192,4500,1,0,0:0:0:0:
+64,192,4750,1,0,0:0:0:0:
+64,192,5000,1,0,0:0:0:0:
+64,192,6000,1,0,0:0:0:0:
+
+// doubles jacks spaced 1/2 beat apart
+192,192,6000,1,0,0:0:0:0:
+64,192,6250,1,0,0:0:0:0:
+192,192,6250,1,0,0:0:0:0:
+64,192,6500,1,0,0:0:0:0:
+192,192,6500,1,0,0:0:0:0:
+64,192,6750,1,0,0:0:0:0:
+192,192,6750,1,0,0:0:0:0:
+64,192,7000,1,0,0:0:0:0:
+192,192,7000,1,0,0:0:0:0:
+64,192,7250,1,0,0:0:0:0:
+192,192,7250,1,0,0:0:0:0:
+64,192,7500,1,0,0:0:0:0:
+192,192,7500,1,0,0:0:0:0:
+
+// trill spaced 1/2 beat apart
+64,192,8500,1,0,0:0:0:0:
+192,192,8750,1,0,0:0:0:0:
+64,192,9000,1,0,0:0:0:0:
+192,192,9250,1,0,0:0:0:0:
+64,192,9500,1,0,0:0:0:0:
+192,192,9750,1,0,0:0:0:0:
+64,192,10000,1,0,0:0:0:0:
+192,192,10250,1,0,0:0:0:0:
+64,192,10500,1,0,0:0:0:0:
+
+// stair spaced 1/4 apart
+64,192,11500,1,0,0:0:0:0:
+192,192,11625,1,0,0:0:0:0:
+320,192,11750,1,0,0:0:0:0:
+448,192,11875,1,0,0:0:0:0:
+320,192,12000,1,0,0:0:0:0:
+192,192,12125,1,0,0:0:0:0:
+64,192,12250,1,0,0:0:0:0:
+192,192,12375,1,0,0:0:0:0:
+320,192,12500,1,0,0:0:0:0:
+448,192,12625,1,0,0:0:0:0:
+
+// jumpstreams?
+64,192,13500,1,0,0:0:0:0:
+192,192,13625,1,0,0:0:0:0:
+320,192,13750,1,0,0:0:0:0:
+448,192,13875,1,0,0:0:0:0:
+320,192,14000,1,0,0:0:0:0:
+192,192,14000,1,0,0:0:0:0:
+64,192,14125,1,0,0:0:0:0:
+192,192,14250,1,0,0:0:0:0:
+320,192,14250,1,0,0:0:0:0:
+448,192,14250,1,0,0:0:0:0:
+64,192,14375,1,0,0:0:0:0:
+64,192,14500,1,0,0:0:0:0:
+320,192,14625,1,0,0:0:0:0:
+448,192,14625,1,0,0:0:0:0:
+192,192,14625,1,0,0:0:0:0:
+192,192,14750,1,0,0:0:0:0:
+64,192,14875,1,0,0:0:0:0:
+192,192,15000,1,0,0:0:0:0:
+320,192,15125,1,0,0:0:0:0:
+448,192,15125,1,0,0:0:0:0:
+
+// double... jumps?
+64,192,16000,1,0,0:0:0:0:
+64,192,16250,1,0,0:0:0:0:
+192,192,16250,1,0,0:0:0:0:
+192,192,16500,1,0,0:0:0:0:
+320,192,16500,1,0,0:0:0:0:
+320,192,16750,1,0,0:0:0:0:
+448,192,16750,1,0,0:0:0:0:
+448,192,17000,1,0,0:0:0:0:
+
+// notes alongside hold
+64,192,18000,128,0,18500:0:0:0:0:
+192,192,18000,1,0,0:0:0:0:
+192,192,18250,1,0,0:0:0:0:
+192,192,18500,1,0,0:0:0:0:
+
+// notes overlapping hold
+64,192,19500,1,0,0:0:0:0:
+192,192,19625,128,0,20875:0:0:0:0:
+64,192,19750,1,0,0:0:0:0:
+64,192,20000,1,0,0:0:0:0:
+64,192,20250,1,0,0:0:0:0:
+64,192,20500,1,0,0:0:0:0:
+64,192,20750,1,0,0:0:0:0:
+64,192,21000,1,0,0:0:0:0:
+
+// simultaneous holds
+64,192,22000,128,0,23000:0:0:0:0:
+192,192,22000,128,0,23000:0:0:0:0:
+320,192,22000,128,0,23000:0:0:0:0:
+448,192,22000,128,0,23000:0:0:0:0:
+
+// hold stairs
+64,192,24500,128,0,25500:0:0:0:0:
+192,192,24625,128,0,25375:0:0:0:0:
+320,192,24750,128,0,25250:0:0:0:0:
+448,192,24875,128,0,25125:0:0:0:0:
+448,192,25375,128,0,26375:0:0:0:0:
+320,192,25500,128,0,26250:0:0:0:0:
+192,192,25625,128,0,26125:0:0:0:0:
+64,192,25750,128,0,26000:0:0:0:0:
+
+// quads
+64,192,26500,1,0,0:0:0:0:
+64,192,27500,1,0,0:0:0:0:
+192,192,27500,1,0,0:0:0:0:
+320,192,27500,1,0,0:0:0:0:
+448,192,27500,1,0,0:0:0:0:
+64,192,27750,1,0,0:0:0:0:
+192,192,27750,1,0,0:0:0:0:
+320,192,27750,1,0,0:0:0:0:
+448,192,27750,1,0,0:0:0:0:
+64,192,28000,1,0,0:0:0:0:
+192,192,28000,1,0,0:0:0:0:
+320,192,28000,1,0,0:0:0:0:
+448,192,28000,1,0,0:0:0:0:
+64,192,28250,1,0,0:0:0:0:
+192,192,28250,1,0,0:0:0:0:
+320,192,28250,1,0,0:0:0:0:
+448,192,28250,1,0,0:0:0:0:
+64,192,28500,1,0,0:0:0:0:
+192,192,28500,1,0,0:0:0:0:
+320,192,28500,1,0,0:0:0:0:
+448,192,28500,1,0,0:0:0:0:
+
+// double-trills
+64,192,29500,1,0,0:0:0:0:
+192,192,29500,1,0,0:0:0:0:
+320,192,29625,1,0,0:0:0:0:
+448,192,29625,1,0,0:0:0:0:
+64,192,29750,1,0,0:0:0:0:
+192,192,29750,1,0,0:0:0:0:
+320,192,29875,1,0,0:0:0:0:
+448,192,29875,1,0,0:0:0:0:
+64,192,30000,1,0,0:0:0:0:
+192,192,30000,1,0,0:0:0:0:
+320,192,30125,1,0,0:0:0:0:
+448,192,30125,1,0,0:0:0:0:
+64,192,30250,1,0,0:0:0:0:
+192,192,30250,1,0,0:0:0:0:
+320,192,30375,1,0,0:0:0:0:
+448,192,30375,1,0,0:0:0:0:
+64,192,30500,1,0,0:0:0:0:
+192,192,30500,1,0,0:0:0:0:
diff --git a/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs b/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs
index 12b32c46ee..5caf08fb1e 100644
--- a/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs
+++ b/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs
@@ -1,10 +1,10 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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;
using osu.Game.Rulesets.Judgements;
-using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Mania.Objects;
+using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
@@ -27,36 +27,6 @@ namespace osu.Game.Rulesets.Mania.Scoring
///
private const double hp_multiplier_max = 1;
- ///
- /// The default BAD hit HP increase.
- ///
- private const double hp_increase_bad = 0.005;
-
- ///
- /// The default OK hit HP increase.
- ///
- private const double hp_increase_ok = 0.010;
-
- ///
- /// The default GOOD hit HP increase.
- ///
- private const double hp_increase_good = 0.035;
-
- ///
- /// The default tick hit HP increase.
- ///
- private const double hp_increase_tick = 0.040;
-
- ///
- /// The default GREAT hit HP increase.
- ///
- private const double hp_increase_great = 0.055;
-
- ///
- /// The default PERFECT hit HP increase.
- ///
- private const double hp_increase_perfect = 0.065;
-
///
/// The MISS HP multiplier at OD = 0.
///
@@ -72,11 +42,6 @@ namespace osu.Game.Rulesets.Mania.Scoring
///
private const double hp_multiplier_miss_max = 1;
- ///
- /// The default MISS HP increase.
- ///
- private const double hp_increase_miss = -0.125;
-
///
/// The MISS HP multiplier. This is multiplied to the miss hp increase.
///
@@ -87,12 +52,8 @@ namespace osu.Game.Rulesets.Mania.Scoring
///
private double hpMultiplier = 1;
- public ManiaScoreProcessor()
- {
- }
-
- public ManiaScoreProcessor(RulesetContainer rulesetContainer)
- : base(rulesetContainer)
+ public ManiaScoreProcessor(DrawableRuleset drawableRuleset)
+ : base(drawableRuleset)
{
}
@@ -121,41 +82,9 @@ namespace osu.Game.Rulesets.Mania.Scoring
}
}
- protected override void ApplyResult(JudgementResult result)
- {
- base.ApplyResult(result);
+ protected override double HealthAdjustmentFactorFor(JudgementResult result)
+ => result.Type == HitResult.Miss ? hpMissMultiplier : hpMultiplier;
- bool isTick = result.Judgement is HoldNoteTickJudgement;
-
- if (isTick)
- {
- if (result.IsHit)
- Health.Value += hpMultiplier * hp_increase_tick;
- }
- else
- {
- switch (result.Type)
- {
- case HitResult.Miss:
- Health.Value += hpMissMultiplier * hp_increase_miss;
- break;
- case HitResult.Meh:
- Health.Value += hpMultiplier * hp_increase_bad;
- break;
- case HitResult.Ok:
- Health.Value += hpMultiplier * hp_increase_ok;
- break;
- case HitResult.Good:
- Health.Value += hpMultiplier * hp_increase_good;
- break;
- case HitResult.Great:
- Health.Value += hpMultiplier * hp_increase_great;
- break;
- case HitResult.Perfect:
- Health.Value += hpMultiplier * hp_increase_perfect;
- break;
- }
- }
- }
+ public override HitWindows CreateHitWindows() => new ManiaHitWindows();
}
}
diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs
index 2f456f7479..c59bed4ea7 100644
--- a/osu.Game.Rulesets.Mania/UI/Column.cs
+++ b/osu.Game.Rulesets.Mania/UI/Column.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.Linq;
using osuTK.Graphics;
@@ -8,11 +8,12 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Framework.Allocation;
-using osu.Framework.Configuration;
+using osu.Framework.Bindables;
using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.UI.Components;
using osu.Game.Rulesets.UI.Scrolling;
+using osuTK;
namespace osu.Game.Rulesets.Mania.UI
{
@@ -21,6 +22,11 @@ namespace osu.Game.Rulesets.Mania.UI
private const float column_width = 45;
private const float special_column_width = 70;
+ ///
+ /// The index of this column as part of the whole playfield.
+ ///
+ public readonly int Index;
+
public readonly Bindable Action = new Bindable();
private readonly ColumnBackground background;
@@ -30,8 +36,10 @@ namespace osu.Game.Rulesets.Mania.UI
internal readonly Container TopLevelContainer;
private readonly Container explosionContainer;
- public Column()
+ public Column(int index)
{
+ Index = index;
+
RelativeSizeAxes = Axes.Y;
Width = column_width;
@@ -74,28 +82,30 @@ namespace osu.Game.Rulesets.Mania.UI
TopLevelContainer.Add(explosionContainer.CreateProxy());
- Direction.BindValueChanged(d =>
+ Direction.BindValueChanged(dir =>
{
hitTargetContainer.Padding = new MarginPadding
{
- Top = d == ScrollingDirection.Up ? ManiaStage.HIT_TARGET_POSITION : 0,
- Bottom = d == ScrollingDirection.Down ? ManiaStage.HIT_TARGET_POSITION : 0,
+ Top = dir.NewValue == ScrollingDirection.Up ? ManiaStage.HIT_TARGET_POSITION : 0,
+ Bottom = dir.NewValue == ScrollingDirection.Down ? ManiaStage.HIT_TARGET_POSITION : 0,
};
- keyArea.Anchor = keyArea.Origin= d == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft;
+ keyArea.Anchor = keyArea.Origin = dir.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft;
}, true);
}
public override Axes RelativeSizeAxes => Axes.Y;
private bool isSpecial;
+
public bool IsSpecial
{
- get { return isSpecial; }
+ get => isSpecial;
set
{
if (isSpecial == value)
return;
+
isSpecial = value;
Width = isSpecial ? special_column_width : column_width;
@@ -103,13 +113,15 @@ namespace osu.Game.Rulesets.Mania.UI
}
private Color4 accentColour;
+
public Color4 AccentColour
{
- get { return accentColour; }
+ get => accentColour;
set
{
if (accentColour == value)
return;
+
accentColour = value;
background.AccentColour = value;
@@ -137,9 +149,18 @@ namespace osu.Game.Rulesets.Mania.UI
HitObjectContainer.Add(hitObject);
}
+ public override bool Remove(DrawableHitObject h)
+ {
+ if (!base.Remove(h))
+ return false;
+
+ h.OnNewResult -= OnNewResult;
+ return true;
+ }
+
internal void OnNewResult(DrawableHitObject judgedObject, JudgementResult result)
{
- if (!result.IsHit || !judgedObject.DisplayResult || !DisplayJudgements)
+ if (!result.IsHit || !judgedObject.DisplayResult || !DisplayJudgements.Value)
return;
explosionContainer.Add(new HitExplosion(judgedObject)
@@ -150,7 +171,7 @@ namespace osu.Game.Rulesets.Mania.UI
public bool OnPressed(ManiaAction action)
{
- if (action != Action)
+ if (action != Action.Value)
return false;
var nextObject =
@@ -165,5 +186,9 @@ namespace osu.Game.Rulesets.Mania.UI
}
public bool OnReleased(ManiaAction action) => false;
+
+ public override bool ReceivePositionalInputAt(Vector2 screenSpacePos)
+ // This probably shouldn't exist as is, but the columns in the stage are separated by a 1px border
+ => DrawRectangle.Inflate(new Vector2(ManiaStage.COLUMN_SPACING / 2, 0)).Contains(ToLocalSpace(screenSpacePos));
}
}
diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs
index 6aef158205..b4e29ae9f9 100644
--- a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs
+++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs
@@ -1,8 +1,8 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Configuration;
+using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
@@ -48,9 +48,9 @@ namespace osu.Game.Rulesets.Mania.UI.Components
};
direction.BindTo(scrollingInfo.Direction);
- direction.BindValueChanged(direction =>
+ direction.BindValueChanged(dir =>
{
- backgroundOverlay.Anchor = backgroundOverlay.Origin = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft;
+ backgroundOverlay.Anchor = backgroundOverlay.Origin = dir.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft;
updateColours();
}, true);
}
@@ -70,6 +70,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components
{
if (accentColour == value)
return;
+
accentColour = value;
updateColours();
diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs
index f158d5be07..a0d713067d 100644
--- a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs
+++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs
@@ -1,11 +1,12 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Configuration;
+using osu.Framework.Bindables;
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.Game.Graphics;
using osu.Game.Rulesets.UI;
@@ -49,9 +50,9 @@ namespace osu.Game.Rulesets.Mania.UI.Components
private void load(IScrollingInfo scrollingInfo)
{
direction.BindTo(scrollingInfo.Direction);
- direction.BindValueChanged(direction =>
+ direction.BindValueChanged(dir =>
{
- Anchor anchor = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft;
+ Anchor anchor = dir.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft;
hitTargetBar.Anchor = hitTargetBar.Origin = anchor;
hitTargetLine.Anchor = hitTargetLine.Origin = anchor;
@@ -73,6 +74,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components
{
if (accentColour == value)
return;
+
accentColour = value;
updateColours();
diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs
index 228e81fef3..85880222d7 100644
--- a/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs
+++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs
@@ -1,12 +1,13 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Configuration;
+using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Bindings;
using osu.Game.Graphics;
@@ -64,11 +65,11 @@ namespace osu.Game.Rulesets.Mania.UI.Components
};
direction.BindTo(scrollingInfo.Direction);
- direction.BindValueChanged(direction =>
+ direction.BindValueChanged(dir =>
{
gradient.Colour = ColourInfo.GradientVertical(
- direction == ScrollingDirection.Up ? Color4.Black : Color4.Black.Opacity(0),
- direction == ScrollingDirection.Up ? Color4.Black.Opacity(0) : Color4.Black);
+ dir.NewValue == ScrollingDirection.Up ? Color4.Black : Color4.Black.Opacity(0),
+ dir.NewValue == ScrollingDirection.Up ? Color4.Black.Opacity(0) : Color4.Black);
}, true);
}
@@ -87,6 +88,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components
{
if (accentColour == value)
return;
+
accentColour = value;
updateColours();
diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs
index f78cfefab8..8797f014df 100644
--- a/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs
+++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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;
@@ -19,25 +19,18 @@ namespace osu.Game.Rulesets.Mania.UI
private void load()
{
if (JudgementText != null)
- JudgementText.TextSize = 25;
+ JudgementText.Font = JudgementText.Font.With(size: 25);
}
- protected override void LoadComplete()
+ protected override double FadeInDuration => 50;
+
+ protected override void ApplyHitAnimations()
{
- base.LoadComplete();
+ JudgementBody.ScaleTo(0.8f);
+ JudgementBody.ScaleTo(1, 250, Easing.OutElastic);
- this.FadeInFromZero(50, Easing.OutQuint);
-
- if (Result.IsHit)
- {
- JudgementBody.ScaleTo(0.8f);
- JudgementBody.ScaleTo(1, 250, Easing.OutElastic);
-
- JudgementBody.Delay(50).ScaleTo(0.75f, 250);
- this.Delay(50).FadeOut(200);
- }
-
- Expire();
+ JudgementBody.Delay(FadeInDuration).ScaleTo(0.75f, 250);
+ this.Delay(FadeInDuration).FadeOut(200);
}
}
}
diff --git a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs
similarity index 61%
rename from osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs
rename to osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs
index 321dd4e1cb..c8aeda8fe4 100644
--- a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs
+++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs
@@ -1,45 +1,47 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
-using osu.Framework.Configuration;
+using osu.Framework.Bindables;
using osu.Framework.Extensions.IEnumerableExtensions;
-using osu.Framework.Graphics;
using osu.Framework.Input;
using osu.Framework.MathUtils;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Input.Handlers;
+using osu.Game.Replays;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Configuration;
-using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Replays;
using osu.Game.Rulesets.Mania.Scoring;
+using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types;
-using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling;
+using osuTK;
namespace osu.Game.Rulesets.Mania.UI
{
- public class ManiaRulesetContainer : ScrollingRulesetContainer
+ public class DrawableManiaRuleset : DrawableScrollingRuleset
{
+ protected new ManiaPlayfield Playfield => (ManiaPlayfield)base.Playfield;
+
public new ManiaBeatmap Beatmap => (ManiaBeatmap)base.Beatmap;
public IEnumerable BarLines;
- protected new ManiaConfigManager Config => (ManiaConfigManager)base.Config;
+ protected new ManiaRulesetConfigManager Config => (ManiaRulesetConfigManager)base.Config;
private readonly Bindable configDirection = new Bindable();
- public ManiaRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap)
- : base(ruleset, beatmap)
+ public DrawableManiaRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList mods)
+ : base(ruleset, beatmap, mods)
{
// Generate the bar lines
double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue;
@@ -55,6 +57,7 @@ namespace osu.Game.Rulesets.Mania.UI
double endTime = i < timingPoints.Count - 1 ? timingPoints[i + 1].Time - point.BeatLength : lastObjectTime + point.BeatLength * (int)point.TimeSignature;
int index = 0;
+
for (double t = timingPoints[i].Time; Precision.DefinitelyBigger(endTime, t); t += point.BeatLength, index++)
{
barLines.Add(new BarLine
@@ -74,32 +77,39 @@ namespace osu.Game.Rulesets.Mania.UI
{
BarLines.ForEach(Playfield.Add);
- Config.BindWith(ManiaSetting.ScrollDirection, configDirection);
- configDirection.BindValueChanged(v => Direction.Value = (ScrollingDirection)v, true);
+ Config.BindWith(ManiaRulesetSetting.ScrollDirection, configDirection);
+ configDirection.BindValueChanged(direction => Direction.Value = (ScrollingDirection)direction.NewValue, true);
- Config.BindWith(ManiaSetting.ScrollTime, TimeRange);
+ Config.BindWith(ManiaRulesetSetting.ScrollTime, TimeRange);
}
- protected override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.Stages)
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- };
+ ///
+ /// Retrieves the column that intersects a screen-space position.
+ ///
+ /// The screen-space position.
+ /// The column which intersects with .
+ public Column GetColumnByPosition(Vector2 screenSpacePosition) => Playfield.GetColumnByPosition(screenSpacePosition);
+
+ public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new ManiaPlayfieldAdjustmentContainer();
+
+ protected override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.Stages);
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this);
- public override int Variant => (int)(Mods.OfType().FirstOrDefault()?.PlayfieldType ?? PlayfieldType.Single) + Beatmap.TotalColumns;
+ public override int Variant => (int)(Beatmap.Stages.Count == 1 ? PlayfieldType.Single : PlayfieldType.Dual) + Beatmap.TotalColumns;
- public override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, Variant);
+ protected override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, Variant);
- public override DrawableHitObject GetVisualRepresentation(ManiaHitObject h)
+ public override DrawableHitObject CreateDrawableRepresentation(ManiaHitObject h)
{
switch (h)
{
case HoldNote holdNote:
return new DrawableHoldNote(holdNote);
+
case Note note:
return new DrawableNote(note);
+
default:
return null;
}
diff --git a/osu.Game.Rulesets.Mania/UI/HitExplosion.cs b/osu.Game.Rulesets.Mania/UI/HitExplosion.cs
index 817b60d14a..0ec1fc38d2 100644
--- a/osu.Game.Rulesets.Mania/UI/HitExplosion.cs
+++ b/osu.Game.Rulesets.Mania/UI/HitExplosion.cs
@@ -1,9 +1,10 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
using osuTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.MathUtils;
using osu.Game.Rulesets.Mania.Objects.Drawables;
diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs
index 85d1c0c4b0..5ab07416a6 100644
--- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs
+++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs
@@ -1,10 +1,11 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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 System;
using System.Collections.Generic;
+using System.Linq;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Objects.Drawables;
@@ -17,6 +18,8 @@ namespace osu.Game.Rulesets.Mania.UI
{
private readonly List stages = new List();
+ public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => stages.Any(s => s.ReceivePositionalInputAt(screenSpacePos));
+
public ManiaPlayfield(List stageDefinitions)
{
if (stageDefinitions == null)
@@ -25,8 +28,6 @@ namespace osu.Game.Rulesets.Mania.UI
if (stageDefinitions.Count <= 0)
throw new ArgumentException("Can't have zero or fewer stages.");
- Size = new Vector2(1, 0.8f);
-
GridContainer playfieldGrid;
AddInternal(playfieldGrid = new GridContainer
{
@@ -37,6 +38,7 @@ namespace osu.Game.Rulesets.Mania.UI
var normalColumnAction = ManiaAction.Key1;
var specialColumnAction = ManiaAction.Special1;
int firstColumnIndex = 0;
+
for (int i = 0; i < stageDefinitions.Count; i++)
{
var newStage = new ManiaStage(firstColumnIndex, stageDefinitions[i], ref normalColumnAction, ref specialColumnAction);
@@ -52,11 +54,46 @@ namespace osu.Game.Rulesets.Mania.UI
public override void Add(DrawableHitObject h) => getStageByColumn(((ManiaHitObject)h.HitObject).Column).Add(h);
+ public override bool Remove(DrawableHitObject h) => getStageByColumn(((ManiaHitObject)h.HitObject).Column).Remove(h);
+
public void Add(BarLine barline) => stages.ForEach(s => s.Add(barline));
+ ///
+ /// Retrieves a column from a screen-space position.
+ ///
+ /// The screen-space position.
+ /// The column which the lies in.
+ public Column GetColumnByPosition(Vector2 screenSpacePosition)
+ {
+ Column found = null;
+
+ foreach (var stage in stages)
+ {
+ foreach (var column in stage.Columns)
+ {
+ if (column.ReceivePositionalInputAt(screenSpacePosition))
+ {
+ found = column;
+ break;
+ }
+ }
+
+ if (found != null)
+ break;
+ }
+
+ return found;
+ }
+
+ ///
+ /// Retrieves the total amount of columns across all stages in this playfield.
+ ///
+ public int TotalColumns => stages.Sum(s => s.Columns.Count);
+
private ManiaStage getStageByColumn(int column)
{
int sum = 0;
+
foreach (var stage in stages)
{
sum = sum + stage.Columns.Count;
diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfieldAdjustmentContainer.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfieldAdjustmentContainer.cs
new file mode 100644
index 0000000000..d893a3fdde
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfieldAdjustmentContainer.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;
+using osu.Game.Rulesets.UI;
+using osuTK;
+
+namespace osu.Game.Rulesets.Mania.UI
+{
+ public class ManiaPlayfieldAdjustmentContainer : PlayfieldAdjustmentContainer
+ {
+ public ManiaPlayfieldAdjustmentContainer()
+ {
+ Anchor = Anchor.Centre;
+ Origin = Anchor.Centre;
+
+ Size = new Vector2(1, 0.8f);
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/UI/ManiaScrollingDirection.cs b/osu.Game.Rulesets.Mania/UI/ManiaScrollingDirection.cs
index 0fc9c1920a..98165fedeb 100644
--- a/osu.Game.Rulesets.Mania/UI/ManiaScrollingDirection.cs
+++ b/osu.Game.Rulesets.Mania/UI/ManiaScrollingDirection.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.UI.Scrolling;
diff --git a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs
index 73c080ffba..a28de7ea58 100644
--- a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs
+++ b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
@@ -25,6 +25,8 @@ namespace osu.Game.Rulesets.Mania.UI
///
public class ManiaStage : ScrollingPlayfield
{
+ public const float COLUMN_SPACING = 1;
+
public const float HIT_TARGET_POSITION = 50;
public IReadOnlyList Columns => columnFlow.Children;
@@ -40,6 +42,8 @@ namespace osu.Game.Rulesets.Mania.UI
private List normalColumnColours = new List();
private Color4 specialColumnColour;
+ public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Columns.Any(c => c.ReceivePositionalInputAt(screenSpacePos));
+
private readonly int firstColumnIndex;
public ManiaStage(int firstColumnIndex, StageDefinition definition, ref ManiaAction normalColumnStartAction, ref ManiaAction specialColumnStartAction)
@@ -84,8 +88,8 @@ namespace osu.Game.Rulesets.Mania.UI
RelativeSizeAxes = Axes.Y,
AutoSizeAxes = Axes.X,
Direction = FillDirection.Horizontal,
- Padding = new MarginPadding { Left = 1, Right = 1 },
- Spacing = new Vector2(1, 0)
+ Padding = new MarginPadding { Left = COLUMN_SPACING, Right = COLUMN_SPACING },
+ Spacing = new Vector2(COLUMN_SPACING, 0)
},
}
},
@@ -123,7 +127,7 @@ namespace osu.Game.Rulesets.Mania.UI
for (int i = 0; i < definition.Columns; i++)
{
var isSpecial = definition.IsSpecialColumn(i);
- var column = new Column
+ var column = new Column(firstColumnIndex + i)
{
IsSpecial = isSpecial,
Action = { Value = isSpecial ? specialColumnStartAction++ : normalColumnStartAction++ }
@@ -132,12 +136,12 @@ namespace osu.Game.Rulesets.Mania.UI
AddColumn(column);
}
- Direction.BindValueChanged(d =>
+ Direction.BindValueChanged(dir =>
{
barLineContainer.Padding = new MarginPadding
{
- Top = d == ScrollingDirection.Up ? HIT_TARGET_POSITION : 0,
- Bottom = d == ScrollingDirection.Down ? HIT_TARGET_POSITION : 0,
+ Top = dir.NewValue == ScrollingDirection.Up ? HIT_TARGET_POSITION : 0,
+ Bottom = dir.NewValue == ScrollingDirection.Down ? HIT_TARGET_POSITION : 0,
};
}, true);
}
@@ -152,16 +156,36 @@ namespace osu.Game.Rulesets.Mania.UI
public override void Add(DrawableHitObject h)
{
var maniaObject = (ManiaHitObject)h.HitObject;
- int columnIndex = maniaObject.Column - firstColumnIndex;
- Columns.ElementAt(columnIndex).Add(h);
+
+ int columnIndex = -1;
+
+ maniaObject.ColumnBindable.BindValueChanged(_ =>
+ {
+ if (columnIndex != -1)
+ Columns.ElementAt(columnIndex).Remove(h);
+
+ columnIndex = maniaObject.Column - firstColumnIndex;
+ Columns.ElementAt(columnIndex).Add(h);
+ }, true);
+
h.OnNewResult += OnNewResult;
}
+ public override bool Remove(DrawableHitObject h)
+ {
+ var maniaObject = (ManiaHitObject)h.HitObject;
+ int columnIndex = maniaObject.Column - firstColumnIndex;
+ Columns.ElementAt(columnIndex).Remove(h);
+
+ h.OnNewResult -= OnNewResult;
+ return true;
+ }
+
public void Add(BarLine barline) => base.Add(new DrawableBarLine(barline));
internal void OnNewResult(DrawableHitObject judgedObject, JudgementResult result)
{
- if (!judgedObject.DisplayResult || !DisplayJudgements)
+ if (!judgedObject.DisplayResult || !DisplayJudgements.Value)
return;
judgements.Clear();
diff --git a/osu.Game.Rulesets.Osu.Tests.iOS/AppDelegate.cs b/osu.Game.Rulesets.Osu.Tests.iOS/AppDelegate.cs
new file mode 100644
index 0000000000..01e635f09c
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests.iOS/AppDelegate.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 Foundation;
+using osu.Framework.iOS;
+using osu.Game.Tests;
+
+namespace osu.Game.Rulesets.Osu.Tests.iOS
+{
+ [Register("AppDelegate")]
+ public class AppDelegate : GameAppDelegate
+ {
+ protected override Framework.Game CreateGame() => new OsuTestBrowser();
+ }
+}
diff --git a/osu.Game.Rulesets.Osu.Tests.iOS/Application.cs b/osu.Game.Rulesets.Osu.Tests.iOS/Application.cs
new file mode 100644
index 0000000000..7a0797a909
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests.iOS/Application.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 UIKit;
+
+namespace osu.Game.Rulesets.Osu.Tests.iOS
+{
+ public class Application
+ {
+ public static void Main(string[] args)
+ {
+ UIApplication.Main(args, null, "AppDelegate");
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu.Tests.iOS/Entitlements.plist b/osu.Game.Rulesets.Osu.Tests.iOS/Entitlements.plist
new file mode 100644
index 0000000000..9ae599370b
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests.iOS/Entitlements.plist
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/osu.Game.Rulesets.Osu.Tests.iOS/Info.plist b/osu.Game.Rulesets.Osu.Tests.iOS/Info.plist
new file mode 100644
index 0000000000..f79215cf54
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests.iOS/Info.plist
@@ -0,0 +1,36 @@
+
+
+
+
+ CFBundleName
+ osu.Game.Rulesets.Osu.Tests.iOS
+ CFBundleIdentifier
+ ppy.osu-Game-Rulesets-Osu-Tests-iOS
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1.0
+ LSRequiresIPhoneOS
+
+ MinimumOSVersion
+ 10.0
+ UIDeviceFamily
+
+ 1
+ 2
+
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ XSAppIconAssets
+ Assets.xcassets/AppIcon.appiconset
+
+
diff --git a/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj b/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj
new file mode 100644
index 0000000000..9930a166e3
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj
@@ -0,0 +1,45 @@
+
+
+
+
+ Debug
+ iPhoneSimulator
+ {6653CA6F-DB06-4604-A3FD-762E25C2AF96}
+ Exe
+ osu.Game.Rulesets.Osu.Tests
+ osu.Game.Rulesets.Osu.Tests.iOS
+
+
+
+
+
+
+ libbass.a
+ PreserveNewest
+
+
+ libbass_fx.a
+ PreserveNewest
+
+
+ Linker.xml
+
+
+
+
+ %(RecursiveDir)%(Filename)%(Extension)
+
+
+
+
+ {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}
+ osu.Game
+
+
+ {C92A607B-1FDD-4954-9F92-03FF547D9080}
+ osu.Game.Rulesets.Osu
+
+
+
+
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Osu.Tests/.vscode/launch.json b/osu.Game.Rulesets.Osu.Tests/.vscode/launch.json
index fe3ecbec47..ed03e99b9b 100644
--- a/osu.Game.Rulesets.Osu.Tests/.vscode/launch.json
+++ b/osu.Game.Rulesets.Osu.Tests/.vscode/launch.json
@@ -7,7 +7,7 @@
"request": "launch",
"program": "dotnet",
"args": [
- "${workspaceRoot}/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Osu.Tests.dll"
+ "${workspaceRoot}/bin/Debug/netcoreapp2.2/osu.Game.Rulesets.Osu.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug)",
@@ -20,7 +20,7 @@
"request": "launch",
"program": "dotnet",
"args": [
- "${workspaceRoot}/bin/Release/netcoreapp2.1/osu.Game.Rulesets.Osu.Tests.dll"
+ "${workspaceRoot}/bin/Release/netcoreapp2.2/osu.Game.Rulesets.Osu.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release)",
diff --git a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs
index 3a551bbbcf..f98d63e6c7 100644
--- a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs
+++ b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
@@ -33,9 +33,12 @@ namespace osu.Game.Rulesets.Osu.Tests
case Slider slider:
foreach (var nested in slider.NestedHitObjects)
yield return createConvertValue(nested);
+
break;
+
default:
yield return createConvertValue(hitObject);
+
break;
}
diff --git a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs
new file mode 100644
index 0000000000..e55dc1f902
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.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 NUnit.Framework;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Difficulty;
+using osu.Game.Rulesets.Osu.Difficulty;
+using osu.Game.Tests.Beatmaps;
+
+namespace osu.Game.Rulesets.Osu.Tests
+{
+ [TestFixture]
+ public class OsuDifficultyCalculatorTest : DifficultyCalculatorTest
+ {
+ protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
+
+ [TestCase(6.931145117263422, "diffcalc-test")]
+ public void Test(double expected, string name)
+ => base.Test(expected, name);
+
+ protected override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new OsuDifficultyCalculator(new OsuRuleset(), beatmap);
+
+ protected override Ruleset CreateRuleset() => new OsuRuleset();
+ }
+}
diff --git a/osu.Game.Rulesets.Osu.Tests/StackingTest.cs b/osu.Game.Rulesets.Osu.Tests/StackingTest.cs
index 579cb77084..e8b99e86f9 100644
--- a/osu.Game.Rulesets.Osu.Tests/StackingTest.cs
+++ b/osu.Game.Rulesets.Osu.Tests/StackingTest.cs
@@ -1,11 +1,13 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.IO;
using System.Linq;
using System.Text;
using NUnit.Framework;
using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Tests.Beatmaps;
using Decoder = osu.Game.Beatmaps.Formats.Decoder;
@@ -22,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Tests
using (var reader = new StreamReader(stream))
{
var beatmap = Decoder.GetDecoder(reader).Decode(reader);
- var converted = new TestWorkingBeatmap(beatmap).GetPlayableBeatmap(new OsuRuleset().RulesetInfo);
+ var converted = new TestWorkingBeatmap(beatmap).GetPlayableBeatmap(new OsuRuleset().RulesetInfo, Array.Empty());
var objects = converted.HitObjects.ToList();
diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseEditor.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseEditor.cs
deleted file mode 100644
index f2525ad555..0000000000
--- a/osu.Game.Rulesets.Osu.Tests/TestCaseEditor.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using NUnit.Framework;
-using osu.Game.Tests.Visual;
-
-namespace osu.Game.Rulesets.Osu.Tests
-{
- [TestFixture]
- public class TestCaseEditor : EditorTestCase
- {
- public TestCaseEditor()
- : base(new OsuRuleset())
- {
- }
- }
-}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneEditor.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneEditor.cs
new file mode 100644
index 0000000000..4aca34bf64
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneEditor.cs
@@ -0,0 +1,17 @@
+// 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.Tests.Visual;
+
+namespace osu.Game.Rulesets.Osu.Tests
+{
+ [TestFixture]
+ public class TestSceneEditor : EditorTestScene
+ {
+ public TestSceneEditor()
+ : base(new OsuRuleset())
+ {
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseGameplayCursor.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs
similarity index 52%
rename from osu.Game.Rulesets.Osu.Tests/TestCaseGameplayCursor.cs
rename to osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs
index 472da88e1f..1b1cfa89c0 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestCaseGameplayCursor.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
@@ -9,25 +9,26 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Cursor;
using osu.Game.Graphics.Cursor;
using osu.Game.Rulesets.Osu.UI.Cursor;
+using osu.Game.Rulesets.UI;
using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Osu.Tests
{
[TestFixture]
- public class TestCaseGameplayCursor : OsuTestCase, IProvideCursor
+ public class TestSceneGameplayCursor : OsuTestScene, IProvideCursor
{
- private GameplayCursor cursor;
+ private GameplayCursorContainer cursorContainer;
- public override IReadOnlyList RequiredTypes => new [] { typeof(CursorTrail) };
+ public override IReadOnlyList RequiredTypes => new[] { typeof(CursorTrail) };
- public CursorContainer Cursor => cursor;
+ public CursorContainer Cursor => cursorContainer;
public bool ProvidingUserCursor => true;
[BackgroundDependencyLoader]
private void load()
{
- Add(cursor = new GameplayCursor { RelativeSizeAxes = Axes.Both });
+ Add(cursorContainer = new OsuCursorContainer { RelativeSizeAxes = Axes.Both });
}
}
}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircle.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs
similarity index 89%
rename from osu.Game.Rulesets.Osu.Tests/TestCaseHitCircle.cs
rename to osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs
index 1c1a027411..d44a0cd841 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircle.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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;
@@ -19,7 +19,7 @@ using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Tests
{
[TestFixture]
- public class TestCaseHitCircle : OsuTestCase
+ public class TestSceneHitCircle : OsuTestScene
{
public override IReadOnlyList RequiredTypes => new[]
{
@@ -30,9 +30,8 @@ namespace osu.Game.Rulesets.Osu.Tests
protected override Container Content => content;
private int depthIndex;
- protected readonly List Mods = new List();
- public TestCaseHitCircle()
+ public TestSceneHitCircle()
{
base.Content.Add(content = new OsuInputManager(new RulesetInfo { ID = 0 }));
@@ -68,7 +67,7 @@ namespace osu.Game.Rulesets.Osu.Tests
Depth = depthIndex++
};
- foreach (var mod in Mods.OfType())
+ foreach (var mod in Mods.Value.OfType())
mod.ApplyToDrawableHitObjects(new[] { drawable });
Add(drawable);
@@ -89,7 +88,8 @@ namespace osu.Game.Rulesets.Osu.Tests
{
private readonly bool auto;
- public TestDrawableHitCircle(HitCircle h, bool auto) : base(h)
+ public TestDrawableHitCircle(HitCircle h, bool auto)
+ : base(h)
{
this.auto = auto;
}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleHidden.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleHidden.cs
similarity index 52%
rename from osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleHidden.cs
rename to osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleHidden.cs
index 68c35faca4..55c6b22146 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleHidden.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleHidden.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
@@ -10,13 +10,13 @@ using osu.Game.Rulesets.Osu.Mods;
namespace osu.Game.Rulesets.Osu.Tests
{
[TestFixture]
- public class TestCaseHitCircleHidden : TestCaseHitCircle
+ public class TestSceneHitCircleHidden : TestSceneHitCircle
{
public override IReadOnlyList RequiredTypes => base.RequiredTypes.Concat(new[] { typeof(OsuModHidden) }).ToList();
- public TestCaseHitCircleHidden()
+ public TestSceneHitCircleHidden()
{
- Mods.Add(new OsuModHidden());
+ Mods.Value = new[] { new OsuModHidden() };
}
}
}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs
new file mode 100644
index 0000000000..399cf22599
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs
@@ -0,0 +1,37 @@
+// 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.Rulesets.Osu.Objects;
+using osu.Game.Tests.Visual;
+using osuTK;
+
+namespace osu.Game.Rulesets.Osu.Tests
+{
+ [TestFixture]
+ public class TestSceneHitCircleLongCombo : PlayerTestScene
+ {
+ public TestSceneHitCircleLongCombo()
+ : base(new OsuRuleset())
+ {
+ }
+
+ protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
+ {
+ var beatmap = new Beatmap
+ {
+ BeatmapInfo = new BeatmapInfo
+ {
+ BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 },
+ Ruleset = ruleset
+ }
+ };
+
+ for (int i = 0; i < 512; i++)
+ beatmap.HitObjects.Add(new HitCircle { Position = new Vector2(256, 192), StartTime = i * 100 });
+
+ return beatmap;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCirclePlacementBlueprint.cs
similarity index 70%
rename from osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementBlueprint.cs
rename to osu.Game.Rulesets.Osu.Tests/TestSceneHitCirclePlacementBlueprint.cs
index 313438a337..4c6abc45f7 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementBlueprint.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCirclePlacementBlueprint.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
@@ -11,7 +11,7 @@ using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Osu.Tests
{
- public class TestCaseHitCirclePlacementBlueprint : PlacementBlueprintTestCase
+ public class TestSceneHitCirclePlacementBlueprint : PlacementBlueprintTestScene
{
protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableHitCircle((HitCircle)hitObject);
protected override PlacementBlueprint CreateBlueprint() => new HitCirclePlacementBlueprint();
diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs
similarity index 73%
rename from osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionBlueprint.cs
rename to osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs
index fed62188ab..32043bf5d7 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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;
using osu.Game.Beatmaps.ControlPoints;
@@ -12,11 +12,11 @@ using osuTK;
namespace osu.Game.Rulesets.Osu.Tests
{
- public class TestCaseHitCircleSelectionBlueprint : SelectionBlueprintTestCase
+ public class TestSceneHitCircleSelectionBlueprint : SelectionBlueprintTestScene
{
private readonly DrawableHitCircle drawableObject;
- public TestCaseHitCircleSelectionBlueprint()
+ public TestSceneHitCircleSelectionBlueprint()
{
var hitCircle = new HitCircle { Position = new Vector2(256, 192) };
hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 });
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuFlashlight.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuFlashlight.cs
new file mode 100644
index 0000000000..64e7632b1b
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuFlashlight.cs
@@ -0,0 +1,19 @@
+// 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.Rulesets.Mods;
+using osu.Game.Rulesets.Osu.Mods;
+using osu.Game.Screens.Play;
+
+namespace osu.Game.Rulesets.Osu.Tests
+{
+ public class TestSceneOsuFlashlight : TestSceneOsuPlayer
+ {
+ protected override Player CreatePlayer(Ruleset ruleset)
+ {
+ Mods.Value = new Mod[] { new OsuModAutoplay(), new OsuModFlashlight(), };
+
+ return base.CreatePlayer(ruleset);
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs
new file mode 100644
index 0000000000..0a33b09ba8
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs
@@ -0,0 +1,17 @@
+// 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.Tests.Visual;
+
+namespace osu.Game.Rulesets.Osu.Tests
+{
+ [TestFixture]
+ public class TestSceneOsuPlayer : PlayerTestScene
+ {
+ public TestSceneOsuPlayer()
+ : base(new OsuRuleset())
+ {
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneResumeOverlay.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneResumeOverlay.cs
new file mode 100644
index 0000000000..8e73d6152f
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneResumeOverlay.cs
@@ -0,0 +1,70 @@
+// 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.Cursor;
+using osu.Game.Rulesets.Osu.UI;
+using osu.Game.Screens.Play;
+using osu.Game.Tests.Visual;
+
+namespace osu.Game.Rulesets.Osu.Tests
+{
+ public class TestSceneResumeOverlay : ManualInputManagerTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(OsuResumeOverlay),
+ };
+
+ public TestSceneResumeOverlay()
+ {
+ ManualOsuInputManager osuInputManager;
+ CursorContainer cursor;
+ ResumeOverlay resume;
+
+ bool resumeFired = false;
+
+ Child = osuInputManager = new ManualOsuInputManager(new OsuRuleset().RulesetInfo)
+ {
+ Children = new Drawable[]
+ {
+ cursor = new CursorContainer(),
+ resume = new OsuResumeOverlay
+ {
+ GameplayCursor = cursor
+ },
+ }
+ };
+
+ resume.ResumeAction = () => resumeFired = true;
+
+ AddStep("move mouse to center", () => InputManager.MoveMouseTo(ScreenSpaceDrawQuad.Centre));
+ AddStep("show", () => resume.Show());
+
+ AddStep("move mouse away", () => InputManager.MoveMouseTo(ScreenSpaceDrawQuad.TopLeft));
+ AddStep("click", () => osuInputManager.GameClick());
+ 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.Value == Visibility.Hidden);
+ }
+
+ private class ManualOsuInputManager : OsuInputManager
+ {
+ public ManualOsuInputManager(RulesetInfo ruleset)
+ : base(ruleset)
+ {
+ }
+
+ public void GameClick()
+ {
+ KeyBindingContainer.TriggerPressed(OsuAction.LeftButton);
+ KeyBindingContainer.TriggerReleased(OsuAction.LeftButton);
+ }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseShaking.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneShaking.cs
similarity index 73%
rename from osu.Game.Rulesets.Osu.Tests/TestCaseShaking.cs
rename to osu.Game.Rulesets.Osu.Tests/TestSceneShaking.cs
index 97978cff1e..3d8afd66f4 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestCaseShaking.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneShaking.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.MathUtils;
@@ -7,7 +7,7 @@ using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Tests
{
- public class TestCaseShaking : TestCaseHitCircle
+ public class TestSceneShaking : TestSceneHitCircle
{
public override void Add(Drawable drawable)
{
diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs
similarity index 94%
rename from osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs
rename to osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs
index 1895913917..c5a27205d6 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
@@ -16,6 +16,7 @@ using osuTK.Graphics;
using osu.Game.Rulesets.Mods;
using System.Linq;
using NUnit.Framework;
+using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
@@ -26,7 +27,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
namespace osu.Game.Rulesets.Osu.Tests
{
[TestFixture]
- public class TestCaseSlider : OsuTestCase
+ public class TestSceneSlider : OsuTestScene
{
public override IReadOnlyList RequiredTypes => new[]
{
@@ -43,9 +44,8 @@ namespace osu.Game.Rulesets.Osu.Tests
protected override Container Content => content;
private int depthIndex;
- protected readonly List Mods = new List();
- public TestCaseSlider()
+ public TestSceneSlider()
{
base.Content.Add(content = new OsuInputManager(new RulesetInfo { ID = 0 }));
@@ -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;
}
@@ -291,7 +291,7 @@ namespace osu.Game.Rulesets.Osu.Tests
Depth = depthIndex++
};
- foreach (var mod in Mods.OfType())
+ foreach (var mod in Mods.Value.OfType())
mod.ApplyToDrawableHitObjects(new[] { drawable });
drawable.OnNewResult += onNewResult;
@@ -300,6 +300,7 @@ namespace osu.Game.Rulesets.Osu.Tests
}
private float judgementOffsetDirection = 1;
+
private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
{
var osuObject = judgedObject as DrawableOsuHitObject;
@@ -313,7 +314,7 @@ namespace osu.Game.Rulesets.Osu.Tests
Origin = Anchor.Centre,
Text = result.IsHit ? "Hit!" : "Miss!",
Colour = result.IsHit ? Color4.Green : Color4.Red,
- TextSize = 30,
+ Font = OsuFont.GetFont(size: 30),
Position = osuObject.HitObject.StackedEndPosition + judgementOffsetDirection * new Vector2(0, 45)
});
diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderHidden.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderHidden.cs
similarity index 53%
rename from osu.Game.Rulesets.Osu.Tests/TestCaseSliderHidden.cs
rename to osu.Game.Rulesets.Osu.Tests/TestSceneSliderHidden.cs
index 1c207d1fca..2a9c1d167b 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderHidden.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderHidden.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
@@ -10,13 +10,13 @@ using osu.Game.Rulesets.Osu.Mods;
namespace osu.Game.Rulesets.Osu.Tests
{
[TestFixture]
- public class TestCaseSliderHidden : TestCaseSlider
+ public class TestSceneSliderHidden : TestSceneSlider
{
public override IReadOnlyList RequiredTypes => base.RequiredTypes.Concat(new[] { typeof(OsuModHidden) }).ToList();
- public TestCaseSliderHidden()
+ public TestSceneSliderHidden()
{
- Mods.Add(new OsuModHidden());
+ Mods.Value = new[] { new OsuModHidden() };
}
}
}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderInput.cs
new file mode 100644
index 0000000000..2eb783233a
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderInput.cs
@@ -0,0 +1,363 @@
+// 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.Screens;
+using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Replays;
+using osu.Game.Rulesets.Judgements;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Objects.Types;
+using osu.Game.Rulesets.Osu.Objects;
+using osu.Game.Rulesets.Osu.Objects.Drawables;
+using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
+using osu.Game.Rulesets.Osu.Replays;
+using osu.Game.Rulesets.Replays;
+using osu.Game.Rulesets.Scoring;
+using osu.Game.Scoring;
+using osu.Game.Screens.Play;
+using osu.Game.Tests.Visual;
+using osuTK;
+
+namespace osu.Game.Rulesets.Osu.Tests
+{
+ public class TestSceneSliderInput : RateAdjustedBeatmapTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(SliderBall),
+ typeof(DrawableSlider),
+ typeof(DrawableSliderTick),
+ typeof(DrawableRepeatPoint),
+ typeof(DrawableOsuHitObject),
+ typeof(DrawableSliderHead),
+ typeof(DrawableSliderTail),
+ };
+
+ private const double time_before_slider = 250;
+ private const double time_slider_start = 1500;
+ private const double time_during_slide_1 = 2500;
+ private const double time_during_slide_2 = 3000;
+ private const double time_during_slide_3 = 3500;
+ private const double time_during_slide_4 = 3800;
+
+ private List judgementResults;
+ private bool allJudgedFired;
+
+ ///
+ /// Scenario:
+ /// - Press a key before a slider starts
+ /// - Press the other key on the slider head timed correctly while holding the original key
+ /// - Release the latter pressed key
+ /// Expected Result:
+ /// A passing test case will have the cursor lose tracking on replay frame 3.
+ ///
+ [Test]
+ public void TestInvalidKeyTransfer()
+ {
+ performTest(new List
+ {
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_before_slider },
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton, OsuAction.RightButton }, Time = time_slider_start },
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_during_slide_1 },
+ });
+
+ AddAssert("Tracking lost", assertMidSliderJudgementFail);
+ }
+
+ ///
+ /// Scenario:
+ /// - Press a key on the slider head timed correctly
+ /// - Press the other key in the middle of the slider while holding the original key
+ /// - Release the original key used to hit the slider
+ /// Expected Result:
+ /// A passing test case will have the cursor continue tracking on replay frame 3.
+ ///
+ [Test]
+ public void TestLeftBeforeSliderThenRightThenLettingGoOfLeft()
+ {
+ performTest(new List
+ {
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_slider_start },
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton, OsuAction.RightButton }, Time = time_during_slide_1 },
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.RightButton }, Time = time_during_slide_2 },
+ });
+
+ AddAssert("Tracking retained", assertGreatJudge);
+ }
+
+ ///
+ /// Scenario:
+ /// - Press a key on the slider head timed correctly
+ /// - Press the other key in the middle of the slider while holding the original key
+ /// - Release the new key that was pressed second
+ /// Expected Result:
+ /// A passing test case will have the cursor continue tracking on replay frame 3.
+ ///
+ [Test]
+ public void TestTrackingRetentionLeftRightLeft()
+ {
+ performTest(new List
+ {
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_before_slider },
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton, OsuAction.RightButton }, Time = time_slider_start },
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.RightButton }, Time = time_during_slide_1 },
+ });
+
+ AddAssert("Tracking retained", assertGreatJudge);
+ }
+
+ ///
+ /// Scenario:
+ /// - Press a key before a slider starts
+ /// - Press the other key on the slider head timed correctly while holding the original key
+ /// - Release the key that was held down before the slider started.
+ /// Expected Result:
+ /// A passing test case will have the cursor continue tracking on replay frame 3
+ ///
+ [Test]
+ public void TestTrackingLeftBeforeSliderToRight()
+ {
+ performTest(new List
+ {
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_before_slider },
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton, OsuAction.RightButton }, Time = time_slider_start },
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.RightButton }, Time = time_during_slide_1 },
+ });
+
+ AddAssert("Tracking retained", assertGreatJudge);
+ }
+
+ ///
+ /// Scenario:
+ /// - Press a key before a slider starts
+ /// - Hold the key down throughout the slider without pressing any other buttons.
+ /// Expected Result:
+ /// A passing test case will have the cursor track the slider, but miss the slider head.
+ ///
+ [Test]
+ public void TestTrackingPreclicked()
+ {
+ performTest(new List
+ {
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_before_slider },
+ });
+
+ AddAssert("Tracking retained, sliderhead miss", assertHeadMissTailTracked);
+ }
+
+ ///
+ /// Scenario:
+ /// - Press a key before a slider starts
+ /// - Hold the key down after the slider starts
+ /// - Move the cursor away from the slider body
+ /// - Move the cursor back onto the body
+ /// Expected Result:
+ /// A passing test case will have the cursor track the slider, miss the head, miss the ticks where its outside of the body, and resume tracking when the cursor returns.
+ ///
+ [Test]
+ public void TestTrackingReturnMidSlider()
+ {
+ performTest(new List
+ {
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_slider_start },
+ new OsuReplayFrame { Position = new Vector2(150, 150), Actions = { OsuAction.LeftButton }, Time = time_during_slide_1 },
+ new OsuReplayFrame { Position = new Vector2(200, 200), Actions = { OsuAction.LeftButton }, Time = time_during_slide_2 },
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_during_slide_3 },
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_during_slide_4 },
+ });
+
+ AddAssert("Tracking re-acquired", assertMidSliderJudgements);
+ }
+
+ ///
+ /// Scenario:
+ /// - Press a key before a slider starts
+ /// - Press the other key on the slider head timed correctly while holding the original key
+ /// - Release the key used to hit the slider head
+ /// - While holding the first key, move the cursor away from the slider body
+ /// - Still holding the first key, move the cursor back to the slider body
+ /// Expected Result:
+ /// A passing test case will have the slider not track despite having the cursor return to the slider body.
+ ///
+ [Test]
+ public void TestTrackingReturnMidSliderKeyDownBefore()
+ {
+ performTest(new List
+ {
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_before_slider },
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton, OsuAction.RightButton }, Time = time_slider_start },
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_during_slide_1 },
+ new OsuReplayFrame { Position = new Vector2(200, 200), Actions = { OsuAction.LeftButton }, Time = time_during_slide_2 },
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_during_slide_3 },
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_during_slide_4 },
+ });
+
+ AddAssert("Tracking lost", assertMidSliderJudgementFail);
+ }
+
+ ///
+ /// Scenario:
+ /// - Wait for the slider to reach a mid-point
+ /// - Press a key away from the slider body
+ /// - While holding down the key, move into the slider body
+ /// Expected Result:
+ /// A passing test case will have the slider track the cursor after the cursor enters the slider body.
+ ///
+ [Test]
+ public void TestTrackingMidSlider()
+ {
+ performTest(new List
+ {
+ new OsuReplayFrame { Position = new Vector2(150, 150), Actions = { OsuAction.LeftButton }, Time = time_during_slide_1 },
+ new OsuReplayFrame { Position = new Vector2(200, 200), Actions = { OsuAction.LeftButton }, Time = time_during_slide_2 },
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_during_slide_3 },
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_during_slide_4 },
+ });
+
+ AddAssert("Tracking acquired", assertMidSliderJudgements);
+ }
+
+ ///
+ /// Scenario:
+ /// - Press a key before the slider starts
+ /// - Press another key on the slider head while holding the original key
+ /// - Move out of the slider body while releasing the two pressed keys
+ /// - Move back into the slider body while pressing any key.
+ /// Expected Result:
+ /// A passing test case will have the slider track the cursor after the cursor enters the slider body.
+ ///
+ [Test]
+ public void TestMidSliderTrackingAcquired()
+ {
+ performTest(new List
+ {
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_before_slider },
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton, OsuAction.RightButton }, Time = time_slider_start },
+ new OsuReplayFrame { Position = new Vector2(100, 100), Time = time_during_slide_1 },
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_during_slide_2 },
+ });
+
+ AddAssert("Tracking acquired", assertMidSliderJudgements);
+ }
+
+ [Test]
+ public void TestMidSliderTrackingAcquiredWithMouseDownOutsideSlider()
+ {
+ performTest(new List
+ {
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_before_slider },
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton, OsuAction.RightButton }, Time = time_slider_start },
+ new OsuReplayFrame { Position = new Vector2(100, 100), Actions = { OsuAction.RightButton }, Time = time_during_slide_1 },
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.RightButton }, Time = time_during_slide_2 },
+ });
+
+ AddAssert("Tracking acquired", assertMidSliderJudgements);
+ }
+
+ ///
+ /// Scenario:
+ /// - Press a key on the slider head
+ /// - While holding the key, move outside of the slider body with the cursor
+ /// - Release the key while outside of the slider body
+ /// - Press the key again while outside of the slider body
+ /// - Move back into the slider body while holding the pressed key
+ /// Expected Result:
+ /// A passing test case will have the slider track the cursor after the cursor enters the slider body.
+ ///
+ [Test]
+ public void TestTrackingReleasedValidKey()
+ {
+ performTest(new List
+ {
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_slider_start },
+ new OsuReplayFrame { Position = new Vector2(100, 100), Actions = { OsuAction.LeftButton }, Time = time_during_slide_1 },
+ new OsuReplayFrame { Position = new Vector2(100, 100), Time = time_during_slide_2 },
+ new OsuReplayFrame { Position = new Vector2(100, 100), Actions = { OsuAction.LeftButton }, Time = time_during_slide_3 },
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_during_slide_4 },
+ });
+
+ AddAssert("Tracking acquired", assertMidSliderJudgements);
+ }
+
+ private bool assertGreatJudge() => judgementResults.Last().Type == HitResult.Great;
+
+ private bool assertHeadMissTailTracked() => judgementResults[judgementResults.Count - 2].Type == HitResult.Great && judgementResults.First().Type == HitResult.Miss;
+
+ private bool assertMidSliderJudgements() => judgementResults[judgementResults.Count - 2].Type == HitResult.Great;
+
+ private bool assertMidSliderJudgementFail() => judgementResults[judgementResults.Count - 2].Type == HitResult.Miss;
+
+ private ScoreAccessibleReplayPlayer currentPlayer;
+
+ private void performTest(List frames)
+ {
+ AddStep("load player", () =>
+ {
+ Beatmap.Value = CreateWorkingBeatmap(new Beatmap
+ {
+ HitObjects =
+ {
+ new Slider
+ {
+ StartTime = time_slider_start,
+ Position = new Vector2(0, 0),
+ Path = new SliderPath(PathType.PerfectCurve, new[]
+ {
+ Vector2.Zero,
+ new Vector2(25, 0),
+ }, 25),
+ }
+ },
+ ControlPointInfo =
+ {
+ DifficultyPoints = { new DifficultyControlPoint { SpeedMultiplier = 0.1f } }
+ },
+ BeatmapInfo =
+ {
+ BaseDifficulty = new BeatmapDifficulty { SliderTickRate = 3 },
+ Ruleset = new OsuRuleset().RulesetInfo
+ },
+ });
+
+ var p = new ScoreAccessibleReplayPlayer(new Score { Replay = new Replay { Frames = frames } });
+
+ p.OnLoadComplete += _ =>
+ {
+ p.ScoreProcessor.NewJudgement += result =>
+ {
+ if (currentPlayer == p) judgementResults.Add(result);
+ };
+ p.ScoreProcessor.AllJudged += () =>
+ {
+ if (currentPlayer == p) allJudgedFired = true;
+ };
+ };
+
+ LoadScreen(currentPlayer = p);
+ allJudgedFired = false;
+ judgementResults = new List();
+ });
+
+ AddUntilStep("Beatmap at 0", () => Beatmap.Value.Track.CurrentTime == 0);
+ AddUntilStep("Wait until player is loaded", () => currentPlayer.IsCurrentScreen());
+ AddUntilStep("Wait for all judged", () => allJudgedFired);
+ }
+
+ private class ScoreAccessibleReplayPlayer : ReplayPlayer
+ {
+ public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
+
+ protected override bool PauseOnFocusLost => false;
+
+ public ScoreAccessibleReplayPlayer(Score score)
+ : base(score, false, false)
+ {
+ }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderPlacementBlueprint.cs
similarity index 70%
rename from osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementBlueprint.cs
rename to osu.Game.Rulesets.Osu.Tests/TestSceneSliderPlacementBlueprint.cs
index 1f693ad9f4..0522260150 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementBlueprint.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderPlacementBlueprint.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
@@ -11,7 +11,7 @@ using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Osu.Tests
{
- public class TestCaseSliderPlacementBlueprint : PlacementBlueprintTestCase
+ public class TestSceneSliderPlacementBlueprint : PlacementBlueprintTestScene
{
protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableSlider((Slider)hitObject);
protected override PlacementBlueprint CreateBlueprint() => new SliderPlacementBlueprint();
diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs
similarity index 84%
rename from osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionBlueprint.cs
rename to osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs
index cd07369ccf..8cf5a2f33e 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
@@ -17,7 +17,7 @@ using osuTK;
namespace osu.Game.Rulesets.Osu.Tests
{
- public class TestCaseSliderSelectionBlueprint : SelectionBlueprintTestCase
+ public class TestSceneSliderSelectionBlueprint : SelectionBlueprintTestScene
{
public override IReadOnlyList RequiredTypes => new[]
{
@@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Tests
private readonly DrawableSlider drawableObject;
- public TestCaseSliderSelectionBlueprint()
+ public TestSceneSliderSelectionBlueprint()
{
var slider = new Slider
{
diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinner.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs
similarity index 85%
rename from osu.Game.Rulesets.Osu.Tests/TestCaseSpinner.cs
rename to osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs
index 3b91ea93b8..3ed3f3e981 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinner.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
@@ -18,10 +18,10 @@ using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Osu.Tests
{
[TestFixture]
- public class TestCaseSpinner : OsuTestCase
+ public class TestSceneSpinner : OsuTestScene
{
public override IReadOnlyList RequiredTypes => new[]
-{
+ {
typeof(SpinnerDisc),
typeof(DrawableSpinner),
typeof(DrawableOsuHitObject)
@@ -31,9 +31,8 @@ namespace osu.Game.Rulesets.Osu.Tests
protected override Container Content => content;
private int depthIndex;
- protected readonly List Mods = new List();
- public TestCaseSpinner()
+ public TestSceneSpinner()
{
base.Content.Add(content = new OsuInputManager(new RulesetInfo { ID = 0 }));
@@ -57,7 +56,7 @@ namespace osu.Game.Rulesets.Osu.Tests
Depth = depthIndex++
};
- foreach (var mod in Mods.OfType())
+ foreach (var mod in Mods.Value.OfType())
mod.ApplyToDrawableHitObjects(new[] { drawable });
Add(drawable);
@@ -67,7 +66,8 @@ namespace osu.Game.Rulesets.Osu.Tests
{
private bool auto;
- public TestDrawableSpinner(Spinner s, bool auto) : base(s)
+ public TestDrawableSpinner(Spinner s, bool auto)
+ : base(s)
{
this.auto = auto;
}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerHidden.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerHidden.cs
similarity index 53%
rename from osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerHidden.cs
rename to osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerHidden.cs
index b93a6ed0f1..a0ab1908d6 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerHidden.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerHidden.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
@@ -10,13 +10,13 @@ using osu.Game.Rulesets.Osu.Mods;
namespace osu.Game.Rulesets.Osu.Tests
{
[TestFixture]
- public class TestCaseSpinnerHidden : TestCaseSpinner
+ public class TestSceneSpinnerHidden : TestSceneSpinner
{
public override IReadOnlyList RequiredTypes => base.RequiredTypes.Concat(new[] { typeof(OsuModHidden) }).ToList();
- public TestCaseSpinnerHidden()
+ public TestSceneSpinnerHidden()
{
- Mods.Add(new OsuModHidden());
+ Mods.Value = new[] { new OsuModHidden() };
}
}
}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerPlacementBlueprint.cs
similarity index 70%
rename from osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementBlueprint.cs
rename to osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerPlacementBlueprint.cs
index 9a90be2582..d74d072857 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementBlueprint.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerPlacementBlueprint.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
@@ -11,7 +11,7 @@ using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Osu.Tests
{
- public class TestCaseSpinnerPlacementBlueprint : PlacementBlueprintTestCase
+ public class TestSceneSpinnerPlacementBlueprint : PlacementBlueprintTestScene
{
protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableSpinner((Spinner)hitObject);
diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs
similarity index 83%
rename from osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionBlueprint.cs
rename to osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs
index d7ba5d8105..c5cea76b14 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
@@ -17,7 +17,7 @@ using osuTK;
namespace osu.Game.Rulesets.Osu.Tests
{
- public class TestCaseSpinnerSelectionBlueprint : SelectionBlueprintTestCase
+ public class TestSceneSpinnerSelectionBlueprint : SelectionBlueprintTestScene
{
public override IReadOnlyList RequiredTypes => new[]
{
@@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Tests
private readonly DrawableSpinner drawableSpinner;
- public TestCaseSpinnerSelectionBlueprint()
+ public TestSceneSpinnerSelectionBlueprint()
{
var spinner = new Spinner
{
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 6117812f45..a99a93c3e9 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,14 +2,14 @@
-
-
-
+
+
+
WinExe
- netcoreapp2.1
+ netcoreapp2.2
diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmap.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmap.cs
index 6d90c2a875..491d82b89e 100644
--- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmap.cs
+++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmap.cs
@@ -1,10 +1,10 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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.Collections.Generic;
using System.Linq;
+using osu.Framework.Graphics.Sprites;
using osu.Game.Beatmaps;
-using osu.Game.Graphics;
using osu.Game.Rulesets.Osu.Objects;
namespace osu.Game.Rulesets.Osu.Beatmaps
@@ -23,19 +23,19 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
{
Name = @"Circle Count",
Content = circles.ToString(),
- Icon = FontAwesome.fa_circle_o
+ Icon = FontAwesome.Regular.Circle
},
new BeatmapStatistic
{
Name = @"Slider Count",
Content = sliders.ToString(),
- Icon = FontAwesome.fa_circle
+ Icon = FontAwesome.Regular.Circle
},
new BeatmapStatistic
{
Name = @"Spinner Count",
Content = spinners.ToString(),
- Icon = FontAwesome.fa_circle
+ Icon = FontAwesome.Regular.Circle
}
};
}
diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs
index 510c32fd9f..6a41e93c35 100644
--- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs
+++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
using osuTK;
using osu.Game.Beatmaps;
diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs
index db80948c94..7bb1f42802 100644
--- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs
+++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs
@@ -1,6 +1,7 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects.Types;
@@ -23,60 +24,73 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
var osuBeatmap = (Beatmap)Beatmap;
- // Reset stacking
- foreach (var h in osuBeatmap.HitObjects)
- h.StackHeight = 0;
+ if (osuBeatmap.HitObjects.Count > 0)
+ {
+ // Reset stacking
+ foreach (var h in osuBeatmap.HitObjects)
+ h.StackHeight = 0;
- if (Beatmap.BeatmapInfo.BeatmapVersion >= 6)
- applyStacking(osuBeatmap);
- else
- applyStackingOld(osuBeatmap);
+ if (Beatmap.BeatmapInfo.BeatmapVersion >= 6)
+ applyStacking(osuBeatmap, 0, osuBeatmap.HitObjects.Count - 1);
+ else
+ applyStackingOld(osuBeatmap);
+ }
}
- private void applyStacking(Beatmap beatmap)
+ private void applyStacking(Beatmap beatmap, int startIndex, int endIndex)
{
- // Extend the end index to include objects they are stacked on
- int extendedEndIndex = beatmap.HitObjects.Count - 1;
- for (int i = beatmap.HitObjects.Count - 1; i >= 0; i--)
+ if (startIndex > endIndex) throw new ArgumentOutOfRangeException(nameof(startIndex), $"{nameof(startIndex)} cannot be greater than {nameof(endIndex)}.");
+ if (startIndex < 0) throw new ArgumentOutOfRangeException(nameof(startIndex), $"{nameof(startIndex)} cannot be less than 0.");
+ if (endIndex < 0) throw new ArgumentOutOfRangeException(nameof(endIndex), $"{nameof(endIndex)} cannot be less than 0.");
+
+ int extendedEndIndex = endIndex;
+
+ if (endIndex < beatmap.HitObjects.Count - 1)
{
- int stackBaseIndex = i;
- for (int n = stackBaseIndex + 1; n < beatmap.HitObjects.Count; n++)
+ // Extend the end index to include objects they are stacked on
+ for (int i = endIndex; i >= startIndex; i--)
{
- OsuHitObject stackBaseObject = beatmap.HitObjects[stackBaseIndex];
- if (stackBaseObject is Spinner) break;
+ int stackBaseIndex = i;
- OsuHitObject objectN = beatmap.HitObjects[n];
- if (objectN is Spinner)
- continue;
-
- double endTime = (stackBaseObject as IHasEndTime)?.EndTime ?? stackBaseObject.StartTime;
- double stackThreshold = objectN.TimePreempt * beatmap.BeatmapInfo.StackLeniency;
-
- if (objectN.StartTime - endTime > stackThreshold)
- //We are no longer within stacking range of the next object.
- break;
-
- if (Vector2Extensions.Distance(stackBaseObject.Position, objectN.Position) < stack_distance ||
- stackBaseObject is Slider && Vector2Extensions.Distance(stackBaseObject.EndPosition, objectN.Position) < stack_distance)
+ for (int n = stackBaseIndex + 1; n < beatmap.HitObjects.Count; n++)
{
- stackBaseIndex = n;
+ OsuHitObject stackBaseObject = beatmap.HitObjects[stackBaseIndex];
+ if (stackBaseObject is Spinner) break;
- // HitObjects after the specified update range haven't been reset yet
- objectN.StackHeight = 0;
+ OsuHitObject objectN = beatmap.HitObjects[n];
+ if (objectN is Spinner)
+ continue;
+
+ double endTime = (stackBaseObject as IHasEndTime)?.EndTime ?? stackBaseObject.StartTime;
+ double stackThreshold = objectN.TimePreempt * beatmap.BeatmapInfo.StackLeniency;
+
+ if (objectN.StartTime - endTime > stackThreshold)
+ //We are no longer within stacking range of the next object.
+ break;
+
+ if (Vector2Extensions.Distance(stackBaseObject.Position, objectN.Position) < stack_distance
+ || (stackBaseObject is Slider && Vector2Extensions.Distance(stackBaseObject.EndPosition, objectN.Position) < stack_distance))
+ {
+ stackBaseIndex = n;
+
+ // HitObjects after the specified update range haven't been reset yet
+ objectN.StackHeight = 0;
+ }
}
- }
- if (stackBaseIndex > extendedEndIndex)
- {
- extendedEndIndex = stackBaseIndex;
- if (extendedEndIndex == beatmap.HitObjects.Count - 1)
- break;
+ if (stackBaseIndex > extendedEndIndex)
+ {
+ extendedEndIndex = stackBaseIndex;
+ if (extendedEndIndex == beatmap.HitObjects.Count - 1)
+ break;
+ }
}
}
//Reverse pass for stack calculation.
- int extendedStartIndex = 0;
- for (int i = extendedEndIndex; i > 0; i--)
+ int extendedStartIndex = startIndex;
+
+ for (int i = extendedEndIndex; i > startIndex; i--)
{
int n = i;
/* We should check every note which has not yet got a stack.
@@ -127,6 +141,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
if (objectN is Slider && Vector2Extensions.Distance(objectN.EndPosition, objectI.Position) < stack_distance)
{
int offset = objectI.StackHeight - objectN.StackHeight + 1;
+
for (int j = n + 1; j <= i; j++)
{
//For each object which was declared under this slider, we will offset it to appear *below* the slider end (rather than above).
@@ -155,7 +170,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
/* We have hit the first slider in a possible stack.
* From this point on, we ALWAYS stack positive regardless.
*/
- while (--n >= 0)
+ while (--n >= startIndex)
{
OsuHitObject objectN = beatmap.HitObjects[n];
if (objectN is Spinner) continue;
diff --git a/osu.Game.Rulesets.Osu/Configuration/OsuRulesetConfigManager.cs b/osu.Game.Rulesets.Osu/Configuration/OsuRulesetConfigManager.cs
new file mode 100644
index 0000000000..f76635a932
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/Configuration/OsuRulesetConfigManager.cs
@@ -0,0 +1,31 @@
+// 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.Configuration;
+using osu.Game.Rulesets.Configuration;
+
+namespace osu.Game.Rulesets.Osu.Configuration
+{
+ public class OsuRulesetConfigManager : RulesetConfigManager
+ {
+ public OsuRulesetConfigManager(SettingsStore settings, RulesetInfo ruleset, int? variant = null)
+ : base(settings, ruleset, variant)
+ {
+ }
+
+ protected override void InitialiseDefaults()
+ {
+ base.InitialiseDefaults();
+ Set(OsuRulesetSetting.SnakingInSliders, true);
+ Set(OsuRulesetSetting.SnakingOutSliders, true);
+ Set(OsuRulesetSetting.ShowCursorTrail, true);
+ }
+ }
+
+ public enum OsuRulesetSetting
+ {
+ SnakingInSliders,
+ SnakingOutSliders,
+ ShowCursorTrail
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs
index 2b42eed0c5..6e991a1d08 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs
@@ -1,8 +1,7 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+// 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.Rulesets.Difficulty;
-using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Osu.Difficulty
{
@@ -13,10 +12,5 @@ namespace osu.Game.Rulesets.Osu.Difficulty
public double ApproachRate;
public double OverallDifficulty;
public int MaxCombo;
-
- public OsuDifficultyAttributes(Mod[] mods, double starRating)
- : base(mods, starRating)
- {
- }
}
}
diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
index 8fc2b69267..c197933233 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
@@ -1,10 +1,13 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
+using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Difficulty;
+using osu.Game.Rulesets.Difficulty.Preprocessing;
+using osu.Game.Rulesets.Difficulty.Skills;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
using osu.Game.Rulesets.Osu.Difficulty.Skills;
@@ -15,7 +18,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
{
public class OsuDifficultyCalculator : DifficultyCalculator
{
- private const int section_length = 400;
private const double difficulty_multiplier = 0.0675;
public OsuDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
@@ -23,62 +25,56 @@ namespace osu.Game.Rulesets.Osu.Difficulty
{
}
- protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate)
+ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
{
- if (!beatmap.HitObjects.Any())
- return new OsuDifficultyAttributes(mods, 0);
-
- OsuDifficultyBeatmap difficultyBeatmap = new OsuDifficultyBeatmap(beatmap.HitObjects.Cast().ToList(), timeRate);
- Skill[] skills =
- {
- new Aim(),
- new Speed()
- };
-
- double sectionLength = section_length * timeRate;
-
- // The first object doesn't generate a strain, so we begin with an incremented section end
- double currentSectionEnd = Math.Ceiling(beatmap.HitObjects.First().StartTime / sectionLength) * sectionLength;
-
- foreach (OsuDifficultyHitObject h in difficultyBeatmap)
- {
- while (h.BaseObject.StartTime > currentSectionEnd)
- {
- foreach (Skill s in skills)
- {
- s.SaveCurrentPeak();
- s.StartNewSectionFrom(currentSectionEnd);
- }
-
- currentSectionEnd += sectionLength;
- }
-
- foreach (Skill s in skills)
- s.Process(h);
- }
+ if (beatmap.HitObjects.Count == 0)
+ 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;
double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2;
// Todo: These int casts are temporary to achieve 1:1 results with osu!stable, and should be removed in the future
- double hitWindowGreat = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / timeRate;
- double preempt = (int)BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate;
+ double hitWindowGreat = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / clockRate;
+ double preempt = (int)BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / clockRate;
int maxCombo = beatmap.HitObjects.Count;
// Add the ticks + tail of the slider. 1 is subtracted because the head circle would be counted twice (once for the slider itself in the line above)
maxCombo += beatmap.HitObjects.OfType().Sum(s => s.NestedHitObjects.Count - 1);
- return new OsuDifficultyAttributes(mods, starRating)
+ return new OsuDifficultyAttributes
{
+ StarRating = starRating,
+ Mods = mods,
AimStrain = aimRating,
SpeedStrain = speedRating,
ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
OverallDifficulty = (80 - hitWindowGreat) / 6,
- MaxCombo = maxCombo
+ MaxCombo = maxCombo,
+ Skills = skills
};
}
+ protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate)
+ {
+ // The first jump is formed by the first two hitobjects of the map.
+ // If the map has less than two OsuHitObjects, the enumerator will not return anything.
+ for (int i = 1; i < beatmap.HitObjects.Count; i++)
+ {
+ var lastLast = i > 1 ? beatmap.HitObjects[i - 2] : null;
+ var last = beatmap.HitObjects[i - 1];
+ var current = beatmap.HitObjects[i];
+
+ yield return new OsuDifficultyHitObject(current, lastLast, last, clockRate);
+ }
+ }
+
+ protected override Skill[] CreateSkills(IBeatmap beatmap) => new Skill[]
+ {
+ new Aim(),
+ new Speed()
+ };
+
protected override Mod[] DifficultyAdjustmentMods => new Mod[]
{
new OsuModDoubleTime(),
diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
index b0887ac72b..093081b6a1 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/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;
using System.Collections.Generic;
@@ -10,6 +10,7 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Scoring;
+using osu.Game.Scoring;
namespace osu.Game.Rulesets.Osu.Difficulty
{
@@ -29,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
private int countMeh;
private int countMiss;
- public OsuPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, Score score)
+ public OsuPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, ScoreInfo score)
: base(ruleset, beatmap, score)
{
countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle);
@@ -87,11 +88,16 @@ namespace osu.Game.Rulesets.Osu.Difficulty
private double computeAimValue()
{
- double aimValue = Math.Pow(5.0f * Math.Max(1.0f, Attributes.AimStrain / 0.0675f) - 4.0f, 3.0f) / 100000.0f;
+ double rawAim = Attributes.AimStrain;
+
+ if (mods.Any(m => m is OsuModTouchDevice))
+ rawAim = Math.Pow(rawAim, 0.8);
+
+ double aimValue = Math.Pow(5.0f * Math.Max(1.0f, rawAim / 0.0675f) - 4.0f, 3.0f) / 100000.0f;
// Longer maps are worth more
double lengthBonus = 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) +
- (totalHits > 2000 ? Math.Log10(totalHits / 2000.0f) * 0.5f : 0.0f);
+ (totalHits > 2000 ? Math.Log10(totalHits / 2000.0f) * 0.5f : 0.0f);
aimValue *= lengthBonus;
@@ -103,27 +109,28 @@ namespace osu.Game.Rulesets.Osu.Difficulty
aimValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8f) / Math.Pow(beatmapMaxCombo, 0.8f), 1.0f);
double approachRateFactor = 1.0f;
+
if (Attributes.ApproachRate > 10.33f)
- approachRateFactor += 0.45f * (Attributes.ApproachRate - 10.33f);
+ approachRateFactor += 0.3f * (Attributes.ApproachRate - 10.33f);
else if (Attributes.ApproachRate < 8.0f)
{
- // HD is worth more with lower ar!
- if (mods.Any(h => h is OsuModHidden))
- approachRateFactor += 0.02f * (8.0f - Attributes.ApproachRate);
- else
- approachRateFactor += 0.01f * (8.0f - Attributes.ApproachRate);
+ approachRateFactor += 0.01f * (8.0f - Attributes.ApproachRate);
}
aimValue *= approachRateFactor;
// We want to give more reward for lower AR when it comes to aim and HD. This nerfs high AR and buffs lower AR.
if (mods.Any(h => h is OsuModHidden))
- aimValue *= 1.02 + (11.0f - Attributes.ApproachRate) / 50.0; // Gives a 1.04 bonus for AR10, a 1.06 bonus for AR9, a 1.02 bonus for AR11.
+ aimValue *= 1.0f + 0.04f * (12.0f - Attributes.ApproachRate);
if (mods.Any(h => h is OsuModFlashlight))
{
- // Apply length bonus again if flashlight is on simply because it becomes a lot harder on longer maps.
- aimValue *= 1.45f * lengthBonus;
+ // Apply object-based bonus for flashlight.
+ aimValue *= 1.0f + 0.35f * Math.Min(1.0f, totalHits / 200.0f) +
+ (totalHits > 200
+ ? 0.3f * Math.Min(1.0f, (totalHits - 200) / 300.0f) +
+ (totalHits > 500 ? (totalHits - 500) / 1200.0f : 0.0f)
+ : 0.0f);
}
// Scale the aim value with accuracy _slightly_
@@ -140,7 +147,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
// Longer maps are worth more
speedValue *= 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) +
- (totalHits > 2000 ? Math.Log10(totalHits / 2000.0f) * 0.5f : 0.0f);
+ (totalHits > 2000 ? Math.Log10(totalHits / 2000.0f) * 0.5f : 0.0f);
// Penalize misses exponentially. This mainly fixes tag4 maps and the likes until a per-hitobject solution is available
speedValue *= Math.Pow(0.97f, countMiss);
@@ -149,13 +156,19 @@ namespace osu.Game.Rulesets.Osu.Difficulty
if (beatmapMaxCombo > 0)
speedValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8f) / Math.Pow(beatmapMaxCombo, 0.8f), 1.0f);
+ double approachRateFactor = 1.0f;
+ if (Attributes.ApproachRate > 10.33f)
+ approachRateFactor += 0.3f * (Attributes.ApproachRate - 10.33f);
+
+ speedValue *= approachRateFactor;
+
if (mods.Any(m => m is OsuModHidden))
- speedValue *= 1.18f;
+ speedValue *= 1.0f + 0.04f * (12.0f - Attributes.ApproachRate);
// Scale the speed value with accuracy _slightly_
- speedValue *= 0.5f + accuracy / 2.0f;
+ speedValue *= 0.02f + accuracy;
// It is important to also consider accuracy difficulty when doing that
- speedValue *= 0.98f + Math.Pow(Attributes.OverallDifficulty, 2) / 2500;
+ speedValue *= 0.96f + Math.Pow(Attributes.OverallDifficulty, 2) / 1600;
return speedValue;
}
@@ -183,7 +196,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
accuracyValue *= Math.Min(1.15f, Math.Pow(amountHitObjectsWithAccuracy / 1000.0f, 0.3f));
if (mods.Any(m => m is OsuModHidden))
- accuracyValue *= 1.02f;
+ accuracyValue *= 1.08f;
if (mods.Any(m => m is OsuModFlashlight))
accuracyValue *= 1.02f;
diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyBeatmap.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyBeatmap.cs
deleted file mode 100644
index 24d4677981..0000000000
--- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyBeatmap.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-using osu.Game.Rulesets.Osu.Objects;
-
-namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
-{
- ///
- /// An enumerable container wrapping input as
- /// which contains extra data required for difficulty calculation.
- ///
- public class OsuDifficultyBeatmap : IEnumerable
- {
- private readonly IEnumerator difficultyObjects;
-
- ///
- /// Creates an enumerator, which preprocesses a list of s recieved as input, wrapping them as
- /// which contains extra data required for difficulty calculation.
- ///
- public OsuDifficultyBeatmap(List objects, double timeRate)
- {
- // Sort OsuHitObjects by StartTime - they are not correctly ordered in some cases.
- // This should probably happen before the objects reach the difficulty calculator.
- difficultyObjects = createDifficultyObjectEnumerator(objects.OrderBy(h => h.StartTime).ToList(), timeRate);
- }
-
- ///
- /// Returns an enumerator that enumerates all