diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
new file mode 100644
index 0000000000..6ba6ae82c8
--- /dev/null
+++ b/.config/dotnet-tools.json
@@ -0,0 +1,18 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "cake.tool": {
+ "version": "0.35.0",
+ "commands": [
+ "dotnet-cake"
+ ]
+ },
+ "dotnet-format": {
+ "version": "3.1.37601",
+ "commands": [
+ "dotnet-format"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/.editorconfig b/.editorconfig
index 0dd7ef8ed1..2c000d3881 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -12,16 +12,171 @@ trim_trailing_whitespace = true
#PascalCase for public and protected members
dotnet_naming_style.pascalcase.capitalization = pascal_case
-dotnet_naming_symbols.public_members.applicable_accessibilities = public,internal,protected,protected_internal
-dotnet_naming_symbols.public_members.applicable_kinds = property,method,field,event,delegate
-dotnet_naming_rule.public_members_pascalcase.severity = suggestion
+dotnet_naming_symbols.public_members.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
+dotnet_naming_symbols.public_members.applicable_kinds = property,method,field,event
+dotnet_naming_rule.public_members_pascalcase.severity = error
dotnet_naming_rule.public_members_pascalcase.symbols = public_members
dotnet_naming_rule.public_members_pascalcase.style = pascalcase
#camelCase for private members
dotnet_naming_style.camelcase.capitalization = camel_case
+
dotnet_naming_symbols.private_members.applicable_accessibilities = private
-dotnet_naming_symbols.private_members.applicable_kinds = property,method,field,event,delegate
-dotnet_naming_rule.private_members_camelcase.severity = suggestion
+dotnet_naming_symbols.private_members.applicable_kinds = property,method,field,event
+dotnet_naming_rule.private_members_camelcase.severity = warning
dotnet_naming_rule.private_members_camelcase.symbols = private_members
-dotnet_naming_rule.private_members_camelcase.style = camelcase
\ No newline at end of file
+dotnet_naming_rule.private_members_camelcase.style = camelcase
+
+dotnet_naming_symbols.local_function.applicable_kinds = local_function
+dotnet_naming_rule.local_function_camelcase.severity = warning
+dotnet_naming_rule.local_function_camelcase.symbols = local_function
+dotnet_naming_rule.local_function_camelcase.style = camelcase
+
+#all_lower for private and local constants/static readonlys
+dotnet_naming_style.all_lower.capitalization = all_lower
+dotnet_naming_style.all_lower.word_separator = _
+
+dotnet_naming_symbols.private_constants.applicable_accessibilities = private
+dotnet_naming_symbols.private_constants.required_modifiers = const
+dotnet_naming_symbols.private_constants.applicable_kinds = field
+dotnet_naming_rule.private_const_all_lower.severity = warning
+dotnet_naming_rule.private_const_all_lower.symbols = private_constants
+dotnet_naming_rule.private_const_all_lower.style = all_lower
+
+dotnet_naming_symbols.private_static_readonly.applicable_accessibilities = private
+dotnet_naming_symbols.private_static_readonly.required_modifiers = static,readonly
+dotnet_naming_symbols.private_static_readonly.applicable_kinds = field
+dotnet_naming_rule.private_static_readonly_all_lower.severity = warning
+dotnet_naming_rule.private_static_readonly_all_lower.symbols = private_static_readonly
+dotnet_naming_rule.private_static_readonly_all_lower.style = all_lower
+
+dotnet_naming_symbols.local_constants.applicable_kinds = local
+dotnet_naming_symbols.local_constants.required_modifiers = const
+dotnet_naming_rule.local_const_all_lower.severity = warning
+dotnet_naming_rule.local_const_all_lower.symbols = local_constants
+dotnet_naming_rule.local_const_all_lower.style = all_lower
+
+#ALL_UPPER for non private constants/static readonlys
+dotnet_naming_style.all_upper.capitalization = all_upper
+dotnet_naming_style.all_upper.word_separator = _
+
+dotnet_naming_symbols.public_constants.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
+dotnet_naming_symbols.public_constants.required_modifiers = const
+dotnet_naming_symbols.public_constants.applicable_kinds = field
+dotnet_naming_rule.public_const_all_upper.severity = warning
+dotnet_naming_rule.public_const_all_upper.symbols = public_constants
+dotnet_naming_rule.public_const_all_upper.style = all_upper
+
+dotnet_naming_symbols.public_static_readonly.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
+dotnet_naming_symbols.public_static_readonly.required_modifiers = static,readonly
+dotnet_naming_symbols.public_static_readonly.applicable_kinds = field
+dotnet_naming_rule.public_static_readonly_all_upper.severity = warning
+dotnet_naming_rule.public_static_readonly_all_upper.symbols = public_static_readonly
+dotnet_naming_rule.public_static_readonly_all_upper.style = all_upper
+
+#Roslyn formating options
+
+#Formatting - indentation options
+csharp_indent_case_contents = true
+csharp_indent_case_contents_when_block = false
+csharp_indent_labels = one_less_than_current
+csharp_indent_switch_labels = true
+
+#Formatting - new line options
+csharp_new_line_before_catch = true
+csharp_new_line_before_else = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_open_brace = all
+#csharp_new_line_before_members_in_anonymous_types = true
+#csharp_new_line_before_members_in_object_initializers = true # Currently no effect in VS/dotnet format (16.4), and makes Rider confusing
+csharp_new_line_between_query_expression_clauses = true
+
+#Formatting - organize using options
+dotnet_sort_system_directives_first = true
+
+#Formatting - spacing options
+csharp_space_after_cast = false
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+
+#Formatting - wrapping options
+csharp_preserve_single_line_blocks = true
+csharp_preserve_single_line_statements = true
+
+#Roslyn language styles
+
+#Style - type names
+dotnet_style_predefined_type_for_locals_parameters_members = true:silent
+dotnet_style_predefined_type_for_member_access = true:silent
+csharp_style_var_when_type_is_apparent = true:none
+csharp_style_var_for_built_in_types = true:none
+csharp_style_var_elsewhere = true:silent
+
+#Style - modifiers
+dotnet_style_require_accessibility_modifiers = for_non_interface_members:warning
+csharp_preferred_modifier_order = public,private,protected,internal,new,abstract,virtual,sealed,override,static,readonly,extern,unsafe,volatile,async:warning
+
+#Style - parentheses
+# Skipped because roslyn cannot separate +-*/ with << >>
+
+#Style - expression bodies
+csharp_style_expression_bodied_accessors = true:silent
+csharp_style_expression_bodied_constructors = false:none
+csharp_style_expression_bodied_indexers = true:silent
+csharp_style_expression_bodied_methods = true:silent
+csharp_style_expression_bodied_operators = true:silent
+csharp_style_expression_bodied_properties = true:silent
+
+#Style - expression preferences
+dotnet_style_object_initializer = true:warning
+dotnet_style_collection_initializer = true:warning
+dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning
+dotnet_style_prefer_auto_properties = true:silent
+dotnet_style_prefer_conditional_expression_over_assignment = true:silent
+dotnet_style_prefer_conditional_expression_over_return = true:silent
+dotnet_style_prefer_compound_assignment = true:silent
+
+#Style - null/type checks
+dotnet_style_coalesce_expression = true:warning
+dotnet_style_null_propagation = true:warning
+csharp_style_pattern_matching_over_is_with_cast_check = true:silent
+csharp_style_pattern_matching_over_as_with_null_check = true:silent
+csharp_style_throw_expression = true:silent
+csharp_style_conditional_delegate_call = true:suggestion
+
+#Style - unused
+dotnet_code_quality_unused_parameters = non_public:silent
+csharp_style_unused_value_expression_statement_preference = discard_variable:silent
+csharp_style_unused_value_assignment_preference = discard_variable:silent
+
+#Style - variable declaration
+csharp_style_inlined_variable_declaration = true:silent
+csharp_style_deconstructed_variable_declaration = true:silent
+
+#Style - other C# 7.x features
+csharp_style_expression_bodied_local_functions = true:silent
+dotnet_style_prefer_inferred_tuple_names = true:warning
+csharp_prefer_simple_default_expression = true:warning
+csharp_style_pattern_local_over_anonymous_function = true:silent
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
+
+#Supressing roslyn built-in analyzers
+# Suppress: EC112
+
+#Field can be readonly
+dotnet_diagnostic.IDE0044.severity = silent
+#Private method is unused
+dotnet_diagnostic.IDE0051.severity = silent
+#Private member is unused
+dotnet_diagnostic.IDE0052.severity = silent
+
+#Rules for disposable
+dotnet_diagnostic.IDE0067.severity = none
+dotnet_diagnostic.IDE0068.severity = none
+dotnet_diagnostic.IDE0069.severity = none
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index e60058ab35..e6b5db5904 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,14 +10,8 @@
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
-### Cake ###
-tools/**
-build/tools/**
-
-fastlane/report.xml
-
# Build results
-bin/[Dd]ebug/
+[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
@@ -104,7 +98,6 @@ $tf/
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
-inspectcode
# JustCode is a .NET coding add-in
.JustCode
@@ -254,20 +247,87 @@ paket-files/
# FAKE - F# Make
.fake/
-# JetBrains Rider
-.idea/.idea.osu/.idea/*.xml
-.idea/.idea.osu/.idea/codeStyles/*.xml
-.idea/.idea.osu/.idea/dataSources/*.xml
-.idea/.idea.osu/.idea/dictionaries/*.xml
-.idea/.idea.osu/*.iml
-*.sln.iml
-
-# CodeRush
-.cr/
-
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
-Staging/
+# Cake #
+/tools/**
+/build/tools/**
+/build/temp/**
+
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn. Uncomment if using
+# auto-import.
+.idea/modules.xml
+.idea/*.iml
+.idea/modules
+*.iml
+*.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
+# fastlane
+fastlane/report.xml
+
+# inspectcode
inspectcodereport.xml
+inspectcode
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/.idea/.idea.osu.Desktop/.idea/.name b/.idea/.idea.osu.Desktop/.idea/.name
new file mode 100644
index 0000000000..12bf4aebba
--- /dev/null
+++ b/.idea/.idea.osu.Desktop/.idea/.name
@@ -0,0 +1 @@
+osu.Desktop
\ No newline at end of file
diff --git a/.idea/.idea.osu.Desktop/.idea/codeStyles/codeStyleConfig.xml b/.idea/.idea.osu.Desktop/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000000..a55e7a179b
--- /dev/null
+++ b/.idea/.idea.osu.Desktop/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.osu.Desktop/.idea/dataSources.xml b/.idea/.idea.osu.Desktop/.idea/dataSources.xml
new file mode 100644
index 0000000000..10f8c1c84d
--- /dev/null
+++ b/.idea/.idea.osu.Desktop/.idea/dataSources.xml
@@ -0,0 +1,14 @@
+
+
+
+
+ sqlite.xerial
+ true
+ org.sqlite.JDBC
+ jdbc:sqlite:$USER_HOME$/.local/share/osu/client.db
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.osu.Desktop/.idea/encodings.xml b/.idea/.idea.osu.Desktop/.idea/encodings.xml
new file mode 100644
index 0000000000..15a15b218a
--- /dev/null
+++ b/.idea/.idea.osu.Desktop/.idea/encodings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.osu.Desktop/.idea/indexLayout.xml b/.idea/.idea.osu.Desktop/.idea/indexLayout.xml
new file mode 100644
index 0000000000..27ba142e96
--- /dev/null
+++ b/.idea/.idea.osu.Desktop/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.osu.Desktop/.idea/misc.xml b/.idea/.idea.osu.Desktop/.idea/misc.xml
new file mode 100644
index 0000000000..1d8c84d0af
--- /dev/null
+++ b/.idea/.idea.osu.Desktop/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.osu.Desktop/.idea/modules.xml b/.idea/.idea.osu.Desktop/.idea/modules.xml
new file mode 100644
index 0000000000..fe63f5faf3
--- /dev/null
+++ b/.idea/.idea.osu.Desktop/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.osu.Desktop/.idea/projectSettingsUpdater.xml b/.idea/.idea.osu.Desktop/.idea/projectSettingsUpdater.xml
new file mode 100644
index 0000000000..7515e76054
--- /dev/null
+++ b/.idea/.idea.osu.Desktop/.idea/projectSettingsUpdater.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.osu/.idea/runConfigurations/CatchRuleset__Tests_.xml b/.idea/.idea.osu.Desktop/.idea/runConfigurations/CatchRuleset__Tests_.xml
similarity index 100%
rename from .idea/.idea.osu/.idea/runConfigurations/CatchRuleset__Tests_.xml
rename to .idea/.idea.osu.Desktop/.idea/runConfigurations/CatchRuleset__Tests_.xml
diff --git a/.idea/.idea.osu/.idea/runConfigurations/ManiaRuleset__Tests_.xml b/.idea/.idea.osu.Desktop/.idea/runConfigurations/ManiaRuleset__Tests_.xml
similarity index 100%
rename from .idea/.idea.osu/.idea/runConfigurations/ManiaRuleset__Tests_.xml
rename to .idea/.idea.osu.Desktop/.idea/runConfigurations/ManiaRuleset__Tests_.xml
diff --git a/.idea/.idea.osu/.idea/runConfigurations/OsuRuleset__Tests_.xml b/.idea/.idea.osu.Desktop/.idea/runConfigurations/OsuRuleset__Tests_.xml
similarity index 100%
rename from .idea/.idea.osu/.idea/runConfigurations/OsuRuleset__Tests_.xml
rename to .idea/.idea.osu.Desktop/.idea/runConfigurations/OsuRuleset__Tests_.xml
diff --git a/.idea/.idea.osu/.idea/runConfigurations/TaikoRuleset__Tests_.xml b/.idea/.idea.osu.Desktop/.idea/runConfigurations/TaikoRuleset__Tests_.xml
similarity index 100%
rename from .idea/.idea.osu/.idea/runConfigurations/TaikoRuleset__Tests_.xml
rename to .idea/.idea.osu.Desktop/.idea/runConfigurations/TaikoRuleset__Tests_.xml
diff --git a/.idea/.idea.osu/.idea/runConfigurations/Tournament.xml b/.idea/.idea.osu.Desktop/.idea/runConfigurations/Tournament.xml
similarity index 100%
rename from .idea/.idea.osu/.idea/runConfigurations/Tournament.xml
rename to .idea/.idea.osu.Desktop/.idea/runConfigurations/Tournament.xml
diff --git a/.idea/.idea.osu/.idea/runConfigurations/Tournament__Tests_.xml b/.idea/.idea.osu.Desktop/.idea/runConfigurations/Tournament__Tests_.xml
similarity index 100%
rename from .idea/.idea.osu/.idea/runConfigurations/Tournament__Tests_.xml
rename to .idea/.idea.osu.Desktop/.idea/runConfigurations/Tournament__Tests_.xml
diff --git a/.idea/.idea.osu/.idea/runConfigurations/osu_.xml b/.idea/.idea.osu.Desktop/.idea/runConfigurations/osu_.xml
similarity index 100%
rename from .idea/.idea.osu/.idea/runConfigurations/osu_.xml
rename to .idea/.idea.osu.Desktop/.idea/runConfigurations/osu_.xml
diff --git a/.idea/.idea.osu/.idea/runConfigurations/osu___Tests_.xml b/.idea/.idea.osu.Desktop/.idea/runConfigurations/osu___Tests_.xml
similarity index 100%
rename from .idea/.idea.osu/.idea/runConfigurations/osu___Tests_.xml
rename to .idea/.idea.osu.Desktop/.idea/runConfigurations/osu___Tests_.xml
diff --git a/.idea/.idea.osu.Desktop/.idea/vcs.xml b/.idea/.idea.osu.Desktop/.idea/vcs.xml
new file mode 100644
index 0000000000..3de04b744c
--- /dev/null
+++ b/.idea/.idea.osu.Desktop/.idea/vcs.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.osu/.idea/indexLayout.xml b/.idea/.idea.osu/.idea/indexLayout.xml
new file mode 100644
index 0000000000..27ba142e96
--- /dev/null
+++ b/.idea/.idea.osu/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.osu/.idea/modules.xml b/.idea/.idea.osu/.idea/modules.xml
new file mode 100644
index 0000000000..0360fdbc5e
--- /dev/null
+++ b/.idea/.idea.osu/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.osu/.idea/projectSettingsUpdater.xml b/.idea/.idea.osu/.idea/projectSettingsUpdater.xml
new file mode 100644
index 0000000000..7515e76054
--- /dev/null
+++ b/.idea/.idea.osu/.idea/projectSettingsUpdater.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.osu/.idea/vcs.xml b/.idea/.idea.osu/.idea/vcs.xml
new file mode 100644
index 0000000000..94a25f7f4c
--- /dev/null
+++ b/.idea/.idea.osu/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 70e620bca2..04ff7c1bea 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -100,7 +100,7 @@
"command": "dotnet",
"args": [
"restore",
- "osu.sln"
+ "build/Desktop.proj"
],
"problemMatcher": []
}
diff --git a/osu.Game.props b/Directory.Build.props
similarity index 55%
rename from osu.Game.props
rename to Directory.Build.props
index 1a3c0aec3e..b4baa2833e 100644
--- a/osu.Game.props
+++ b/Directory.Build.props
@@ -1,13 +1,13 @@
- 7.2
+ 7.3
- ..\app.manifest
+ $(MSBuildThisFileDirectory)app.manifest
-
+
osu.licenseheader
@@ -15,10 +15,18 @@
- ppy Pty Ltd
- Copyright (c) 2019 ppy Pty Ltd
NU1701
+
+ ppy Pty Ltd
+ MIT
+ https://github.com/ppy/osu
+ https://github.com/ppy/osu
+ Automated release.
+ ppy Pty Ltd
+ Copyright (c) 2019 ppy Pty Ltd
+ osu game
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 0460e9cbcf..a078265d6c 100644
--- a/README.md
+++ b/README.md
@@ -19,9 +19,9 @@ Detailed changelogs are published on the [official osu! site](https://osu.ppy.sh
## Requirements
- A desktop platform with the [.NET Core SDK 3.0](https://www.microsoft.com/net/learn/get-started) or higher installed.
-- When running on linux, please have a system-wide ffmpeg installation available to support video decoding.
+- When running on Linux, please have a system-wide FFmpeg installation available to support video decoding.
- When running on Windows 7 or 8.1, **[additional prerequisites](https://docs.microsoft.com/en-us/dotnet/core/windows-prerequisites?tabs=netcore2x)** may be required to correctly run .NET Core applications if your operating system is not up-to-date with the latest service packs.
-- 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/).
+- When working with the codebase, we recommend using an IDE with intelligent code completion and syntax highlighting, such as [Visual Studio 2019+](https://visualstudio.microsoft.com/vs/), [JetBrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/).
## Running osu!
@@ -57,7 +57,8 @@ git pull
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.
+- Visual Studio / Rider users should load the project via one of the platform-specific .slnf files, rather than the main .sln. This will allow access to template run configurations.
+- 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:
@@ -67,19 +68,7 @@ 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/netcoreapp3.0" dotnet run --project osu.Desktop
-```
+If the build fails, try to restore NuGet packages with `dotnet restore`.
### Testing with resource/framework modifications
@@ -87,11 +76,11 @@ Sometimes it may be necessary to cross-test changes in [osu-resources](https://g
### 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.
+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.
+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 of 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.
If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu/issues) (especially those with the ["good first issue"](https://github.com/ppy/osu/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) label).
@@ -99,7 +88,7 @@ Before starting, please make sure you are familiar with the [development and tes
Note that while we already have certain standards in place, nothing is set in stone. If you have an issue with the way code is structured; with any libraries we are using; with any processes involved with contributing, *please* bring it up. We welcome all feedback so we can make contributing to this project as pain-free as possible.
-For those interested, we love to reward quality contributions via [bounties](https://docs.google.com/spreadsheets/d/1jNXfj_S3Pb5PErA-czDdC9DUu4IgUbe1Lt8E7CYUJuE/view?&rm=minimal#gid=523803337), paid out via paypal or osu! supporter tags. Don't hesitate to [request a bounty](https://docs.google.com/forms/d/e/1FAIpQLSet_8iFAgPMG526pBZ2Kic6HSh7XPM3fE8xPcnWNkMzINDdYg/viewform) for your work on this project.
+For those interested, we love to reward quality contributions via [bounties](https://docs.google.com/spreadsheets/d/1jNXfj_S3Pb5PErA-czDdC9DUu4IgUbe1Lt8E7CYUJuE/view?&rm=minimal#gid=523803337), paid out via PayPal or osu!supporter tags. Don't hesitate to [request a bounty](https://docs.google.com/forms/d/e/1FAIpQLSet_8iFAgPMG526pBZ2Kic6HSh7XPM3fE8xPcnWNkMzINDdYg/viewform) for your work on this project.
## Licence
diff --git a/appveyor.yml b/appveyor.yml
index f59c0b162d..f911d67c6e 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,6 +1,6 @@
clone_depth: 1
version: '{branch}-{build}'
-image: Visual Studio 2019 Preview
+image: Visual Studio 2019
test: off
build_script:
- cmd: PowerShell -Version 2.0 .\build.ps1
diff --git a/appveyor_deploy.yml b/appveyor_deploy.yml
index 13635b943c..fb7825b31d 100644
--- a/appveyor_deploy.yml
+++ b/appveyor_deploy.yml
@@ -1,6 +1,6 @@
clone_depth: 1
version: '{build}'
-image: Visual Studio 2019 Preview
+image: Visual Studio 2019
test: off
skip_non_tags: true
build_script:
diff --git a/assets/lazer-nuget.png b/assets/lazer-nuget.png
new file mode 100644
index 0000000000..c2a587fdc2
Binary files /dev/null and b/assets/lazer-nuget.png differ
diff --git a/build.ps1 b/build.ps1
index 2dbd10a150..4b3b1f717a 100755
--- a/build.ps1
+++ b/build.ps1
@@ -21,7 +21,7 @@ if ($DryRun) { $cakeArguments += "-dryrun" }
if ($Experimental) { $cakeArguments += "-experimental" }
$cakeArguments += $ScriptArgs
-dotnet tool install Cake.Tool --global --version 0.35.0
+dotnet tool restore
dotnet cake ./build/build.cake --bootstrap
dotnet cake ./build/build.cake $cakeArguments
exit $LASTEXITCODE
\ No newline at end of file
diff --git a/build.sh b/build.sh
index ac6bd877a6..2c22f08574 100755
--- a/build.sh
+++ b/build.sh
@@ -1,5 +1,5 @@
echo "Installing Cake.Tool..."
-dotnet tool install Cake.Tool --global --version 0.35.0
+dotnet tool restore
# Parse arguments.
CAKE_ARGUMENTS=()
diff --git a/build/Desktop.proj b/build/Desktop.proj
new file mode 100644
index 0000000000..b1c6b065e8
--- /dev/null
+++ b/build/Desktop.proj
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build/build.cake b/build/build.cake
index cfdfebee61..274e57ef4e 100644
--- a/build/build.cake
+++ b/build/build.cake
@@ -11,7 +11,9 @@ var target = Argument("target", "Build");
var configuration = Argument("configuration", "Release");
var rootDirectory = new DirectoryPath("..");
-var solution = rootDirectory.CombineWithFilePath("osu.sln");
+var sln = rootDirectory.CombineWithFilePath("osu.sln");
+var desktopBuilds = rootDirectory.CombineWithFilePath("build/Desktop.proj");
+var desktopSlnf = rootDirectory.CombineWithFilePath("osu.Desktop.slnf");
///////////////////////////////////////////////////////////////////////////////
// TASKS
@@ -19,7 +21,7 @@ var solution = rootDirectory.CombineWithFilePath("osu.sln");
Task("Compile")
.Does(() => {
- DotNetCoreBuild(solution.FullPath, new DotNetCoreBuildSettings {
+ DotNetCoreBuild(desktopBuilds.FullPath, new DotNetCoreBuildSettings {
Configuration = configuration,
});
});
@@ -41,7 +43,7 @@ Task("InspectCode")
.WithCriteria(IsRunningOnWindows())
.IsDependentOn("Compile")
.Does(() => {
- InspectCode(solution, new InspectCodeSettings {
+ InspectCode(desktopSlnf, new InspectCodeSettings {
CachesHome = "inspectcode",
OutputFile = "inspectcodereport.xml",
});
@@ -59,8 +61,12 @@ Task("CodeFileSanity")
});
});
+Task("DotnetFormat")
+ .Does(() => DotNetCoreTool(sln.FullPath, "format", "--dry-run --check"));
+
Task("Build")
.IsDependentOn("CodeFileSanity")
+ .IsDependentOn("DotnetFormat")
.IsDependentOn("InspectCode")
.IsDependentOn("Test");
diff --git a/global.json b/global.json
new file mode 100644
index 0000000000..d8b8d14c36
--- /dev/null
+++ b/global.json
@@ -0,0 +1,5 @@
+{
+ "msbuild-sdks": {
+ "Microsoft.Build.Traversal": "2.0.19"
+ }
+}
\ No newline at end of file
diff --git a/osu.Android.props b/osu.Android.props
index 8b31be3f12..6c40dc4812 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -1,13 +1,10 @@
-
- Debug
- AnyCPU
+
bin\$(Configuration)
4
2.0
false
false
- default
Library
512
Off
@@ -15,37 +12,31 @@
Xamarin.Android.Net.AndroidClientHandler
v9.0
false
+ true
+ armeabi-v7a;x86;arm64-v8a
+ true
+ cjk,mideast,other,rare,west
+ SdkOnly
+ prompt
-
+
True
portable
False
DEBUG;TRACE
- prompt
false
false
- SdkOnly
true
false
- cjk,mideast,other,rare,west
- true
- armeabi-v7a;x86;arm64-v8a
- true
-
+
false
None
True
- prompt
true
false
- SdkOnly
False
true
- cjk,mideast,other,rare,west
- true
- armeabi-v7a;x86;arm64-v8a
- true
@@ -62,6 +53,6 @@
-
+
diff --git a/osu.Android.sln b/osu.Android.sln
deleted file mode 100644
index ebf2c55cb4..0000000000
--- a/osu.Android.sln
+++ /dev/null
@@ -1,126 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.28516.95
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game", "osu.Game\osu.Game.csproj", "{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Rulesets.Osu", "osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj", "{C92A607B-1FDD-4954-9F92-03FF547D9080}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Rulesets.Catch", "osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj", "{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Rulesets.Taiko", "osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj", "{F167E17A-7DE6-4AF5-B920-A5112296C695}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Rulesets.Mania", "osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj", "{48F4582B-7687-4621-9CBE-5C24197CB536}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Android", "osu.Android\osu.Android.csproj", "{D1D5F9A8-B40B-40E6-B02F-482D03346D3D}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Catch.Tests.Android", "osu.Game.Rulesets.Catch.Tests.Android\osu.Game.Rulesets.Catch.Tests.Android.csproj", "{C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Mania.Tests.Android", "osu.Game.Rulesets.Mania.Tests.Android\osu.Game.Rulesets.Mania.Tests.Android.csproj", "{531F1092-DB27-445D-AA33-2A77C7187C99}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Osu.Tests.Android", "osu.Game.Rulesets.Osu.Tests.Android\osu.Game.Rulesets.Osu.Tests.Android.csproj", "{90CAB706-39CB-4B93-9629-3218A6FF8E9B}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Taiko.Tests.Android", "osu.Game.Rulesets.Taiko.Tests.Android\osu.Game.Rulesets.Taiko.Tests.Android.csproj", "{3701A0A1-8476-42C6-B5C4-D24129B4A484}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Tests.Android", "osu.Game.Tests.Android\osu.Game.Tests.Android.csproj", "{5CC222DC-5716-4499-B897-DCBDDA4A5CF9}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.Build.0 = Release|Any CPU
- {C92A607B-1FDD-4954-9F92-03FF547D9080}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C92A607B-1FDD-4954-9F92-03FF547D9080}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C92A607B-1FDD-4954-9F92-03FF547D9080}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C92A607B-1FDD-4954-9F92-03FF547D9080}.Release|Any CPU.Build.0 = Release|Any CPU
- {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Release|Any CPU.Build.0 = Release|Any CPU
- {F167E17A-7DE6-4AF5-B920-A5112296C695}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F167E17A-7DE6-4AF5-B920-A5112296C695}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F167E17A-7DE6-4AF5-B920-A5112296C695}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F167E17A-7DE6-4AF5-B920-A5112296C695}.Release|Any CPU.Build.0 = Release|Any CPU
- {48F4582B-7687-4621-9CBE-5C24197CB536}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {48F4582B-7687-4621-9CBE-5C24197CB536}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {48F4582B-7687-4621-9CBE-5C24197CB536}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {48F4582B-7687-4621-9CBE-5C24197CB536}.Release|Any CPU.Build.0 = Release|Any CPU
- {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
- {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Release|Any CPU.Build.0 = Release|Any CPU
- {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Release|Any CPU.Deploy.0 = Release|Any CPU
- {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
- {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Release|Any CPU.Build.0 = Release|Any CPU
- {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Release|Any CPU.Deploy.0 = Release|Any CPU
- {531F1092-DB27-445D-AA33-2A77C7187C99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {531F1092-DB27-445D-AA33-2A77C7187C99}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {531F1092-DB27-445D-AA33-2A77C7187C99}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
- {531F1092-DB27-445D-AA33-2A77C7187C99}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {531F1092-DB27-445D-AA33-2A77C7187C99}.Release|Any CPU.Build.0 = Release|Any CPU
- {531F1092-DB27-445D-AA33-2A77C7187C99}.Release|Any CPU.Deploy.0 = Release|Any CPU
- {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
- {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Release|Any CPU.Build.0 = Release|Any CPU
- {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Release|Any CPU.Deploy.0 = Release|Any CPU
- {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
- {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Release|Any CPU.Build.0 = Release|Any CPU
- {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Release|Any CPU.Deploy.0 = Release|Any CPU
- {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
- {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Release|Any CPU.Build.0 = Release|Any CPU
- {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Release|Any CPU.Deploy.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {671B0BEC-2403-45B0-9357-2C97CC517668}
- EndGlobalSection
- GlobalSection(MonoDevelopProperties) = preSolution
- Policies = $0
- $0.TextStylePolicy = $1
- $1.EolMarker = Windows
- $1.inheritsSet = VisualStudio
- $1.inheritsScope = text/plain
- $1.scope = text/x-csharp
- $0.CSharpFormattingPolicy = $2
- $2.IndentSwitchSection = True
- $2.NewLinesForBracesInProperties = True
- $2.NewLinesForBracesInAccessors = True
- $2.NewLinesForBracesInAnonymousMethods = True
- $2.NewLinesForBracesInControlBlocks = True
- $2.NewLinesForBracesInAnonymousTypes = True
- $2.NewLinesForBracesInObjectCollectionArrayInitializers = True
- $2.NewLinesForBracesInLambdaExpressionBody = True
- $2.NewLineForElse = True
- $2.NewLineForCatch = True
- $2.NewLineForFinally = True
- $2.NewLineForMembersInObjectInit = True
- $2.NewLineForMembersInAnonymousTypes = True
- $2.NewLineForClausesInQuery = True
- $2.SpacingAfterMethodDeclarationName = False
- $2.SpaceAfterMethodCallName = False
- $2.SpaceBeforeOpenSquareBracket = False
- $2.inheritsSet = Mono
- $2.inheritsScope = text/x-csharp
- $2.scope = text/x-csharp
- EndGlobalSection
-EndGlobal
diff --git a/osu.Android.sln.DotSettings b/osu.Android.sln.DotSettings
deleted file mode 100644
index 5a97fc7518..0000000000
--- a/osu.Android.sln.DotSettings
+++ /dev/null
@@ -1,834 +0,0 @@
-
- True
- True
- True
- True
- ExplicitlyExcluded
- ExplicitlyExcluded
- SOLUTION
- HINT
- WARNING
-
- True
- WARNING
- WARNING
- HINT
- HINT
- HINT
- HINT
- WARNING
- WARNING
- WARNING
- HINT
- WARNING
- HINT
- SUGGESTION
- HINT
- HINT
- HINT
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- HINT
- WARNING
- WARNING
- HINT
- WARNING
- WARNING
- DO_NOT_SHOW
- HINT
- WARNING
- DO_NOT_SHOW
- WARNING
- HINT
- HINT
- HINT
- ERROR
- HINT
- HINT
- HINT
- WARNING
- WARNING
- HINT
- DO_NOT_SHOW
- HINT
- HINT
- HINT
- HINT
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- HINT
- HINT
- HINT
- HINT
- HINT
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- HINT
- DO_NOT_SHOW
- DO_NOT_SHOW
- DO_NOT_SHOW
- WARNING
-
- WARNING
- WARNING
- WARNING
- ERROR
- WARNING
- WARNING
- HINT
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- HINT
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- HINT
- DO_NOT_SHOW
- DO_NOT_SHOW
- DO_NOT_SHOW
- WARNING
- WARNING
- HINT
- WARNING
- HINT
- HINT
- HINT
- HINT
- HINT
- HINT
- HINT
-
- HINT
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- HINT
- WARNING
- WARNING
- HINT
- HINT
- WARNING
- <?xml version="1.0" encoding="utf-16"?><Profile name="Code Cleanup (peppy)"><CSArrangeThisQualifier>True</CSArrangeThisQualifier><CSUseVar><BehavourStyle>CAN_CHANGE_TO_EXPLICIT</BehavourStyle><LocalVariableStyle>ALWAYS_EXPLICIT</LocalVariableStyle><ForeachVariableStyle>ALWAYS_EXPLICIT</ForeachVariableStyle></CSUseVar><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName></RegionName></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><CSUpdateFileHeader>True</CSUpdateFileHeader><CSCodeStyleAttributes ArrangeTypeAccessModifier="False" ArrangeTypeMemberAccessModifier="False" SortModifiers="True" RemoveRedundantParentheses="True" AddMissingParentheses="False" ArrangeBraces="False" ArrangeAttributes="False" ArrangeArgumentsStyle="False" /><XAMLCollapseEmptyTags>False</XAMLCollapseEmptyTags><CSFixBuiltinTypeReferences>True</CSFixBuiltinTypeReferences><CSArrangeQualifiers>True</CSArrangeQualifiers></Profile>
- Code Cleanup (peppy)
- Required
- Required
- Required
- Explicit
- ExpressionBody
- ExpressionBody
- True
- NEXT_LINE
- True
- True
- True
- True
- True
- True
- True
- True
- NEXT_LINE
- 1
- 1
- NEXT_LINE
- MULTILINE
- NEXT_LINE
- 1
- 1
- True
- NEXT_LINE
- NEVER
- NEVER
- True
- False
- True
- NEVER
- False
- False
- True
- False
- False
- True
- True
- False
- False
- CHOP_IF_LONG
- True
- 200
- CHOP_IF_LONG
- False
- False
- AABB
- API
- BPM
- GC
- GL
- GLSL
- HID
- HUD
- ID
- IP
- IPC
- LTRB
- MD5
- NS
- OS
- RGB
- RNG
- SHA
- SRGB
- TK
- SS
- PP
- GMT
- QAT
- BNG
- UI
- HINT
- <?xml version="1.0" encoding="utf-16"?>
-<Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns">
- <TypePattern DisplayName="COM interfaces or structs">
- <TypePattern.Match>
- <Or>
- <And>
- <Kind Is="Interface" />
- <Or>
- <HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" />
- <HasAttribute Name="System.Runtime.InteropServices.ComImport" />
- </Or>
- </And>
- <Kind Is="Struct" />
- </Or>
- </TypePattern.Match>
- </TypePattern>
- <TypePattern DisplayName="NUnit Test Fixtures" RemoveRegions="All">
- <TypePattern.Match>
- <And>
- <Kind Is="Class" />
- <HasAttribute Name="NUnit.Framework.TestFixtureAttribute" Inherited="True" />
- </And>
- </TypePattern.Match>
- <Entry DisplayName="Setup/Teardown Methods">
- <Entry.Match>
- <And>
- <Kind Is="Method" />
- <Or>
- <HasAttribute Name="NUnit.Framework.SetUpAttribute" Inherited="True" />
- <HasAttribute Name="NUnit.Framework.TearDownAttribute" Inherited="True" />
- <HasAttribute Name="NUnit.Framework.FixtureSetUpAttribute" Inherited="True" />
- <HasAttribute Name="NUnit.Framework.FixtureTearDownAttribute" Inherited="True" />
- </Or>
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="All other members" />
- <Entry Priority="100" DisplayName="Test Methods">
- <Entry.Match>
- <And>
- <Kind Is="Method" />
- <HasAttribute Name="NUnit.Framework.TestAttribute" />
- </And>
- </Entry.Match>
- <Entry.SortBy>
- <Name />
- </Entry.SortBy>
- </Entry>
- </TypePattern>
- <TypePattern DisplayName="Default Pattern">
- <Group DisplayName="Fields/Properties">
- <Group DisplayName="Public Fields">
- <Entry DisplayName="Constant Fields">
- <Entry.Match>
- <And>
- <Access Is="Public" />
- <Or>
- <Kind Is="Constant" />
- <Readonly />
- <And>
- <Static />
- <Readonly />
- </And>
- </Or>
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Static Fields">
- <Entry.Match>
- <And>
- <Access Is="Public" />
- <Static />
- <Not>
- <Readonly />
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Normal Fields">
- <Entry.Match>
- <And>
- <Access Is="Public" />
- <Not>
- <Or>
- <Static />
- <Readonly />
- </Or>
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Entry DisplayName="Public Properties">
- <Entry.Match>
- <And>
- <Access Is="Public" />
- <Kind Is="Property" />
- </And>
- </Entry.Match>
- </Entry>
- <Group DisplayName="Internal Fields">
- <Entry DisplayName="Constant Fields">
- <Entry.Match>
- <And>
- <Access Is="Internal" />
- <Or>
- <Kind Is="Constant" />
- <Readonly />
- <And>
- <Static />
- <Readonly />
- </And>
- </Or>
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Static Fields">
- <Entry.Match>
- <And>
- <Access Is="Internal" />
- <Static />
- <Not>
- <Readonly />
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Normal Fields">
- <Entry.Match>
- <And>
- <Access Is="Internal" />
- <Not>
- <Or>
- <Static />
- <Readonly />
- </Or>
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Entry DisplayName="Internal Properties">
- <Entry.Match>
- <And>
- <Access Is="Internal" />
- <Kind Is="Property" />
- </And>
- </Entry.Match>
- </Entry>
- <Group DisplayName="Protected Fields">
- <Entry DisplayName="Constant Fields">
- <Entry.Match>
- <And>
- <Access Is="Protected" />
- <Or>
- <Kind Is="Constant" />
- <Readonly />
- <And>
- <Static />
- <Readonly />
- </And>
- </Or>
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Static Fields">
- <Entry.Match>
- <And>
- <Access Is="Protected" />
- <Static />
- <Not>
- <Readonly />
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Normal Fields">
- <Entry.Match>
- <And>
- <Access Is="Protected" />
- <Not>
- <Or>
- <Static />
- <Readonly />
- </Or>
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Entry DisplayName="Protected Properties">
- <Entry.Match>
- <And>
- <Access Is="Protected" />
- <Kind Is="Property" />
- </And>
- </Entry.Match>
- </Entry>
- <Group DisplayName="Private Fields">
- <Entry DisplayName="Constant Fields">
- <Entry.Match>
- <And>
- <Access Is="Private" />
- <Or>
- <Kind Is="Constant" />
- <Readonly />
- <And>
- <Static />
- <Readonly />
- </And>
- </Or>
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Static Fields">
- <Entry.Match>
- <And>
- <Access Is="Private" />
- <Static />
- <Not>
- <Readonly />
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Normal Fields">
- <Entry.Match>
- <And>
- <Access Is="Private" />
- <Not>
- <Or>
- <Static />
- <Readonly />
- </Or>
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Entry DisplayName="Private Properties">
- <Entry.Match>
- <And>
- <Access Is="Private" />
- <Kind Is="Property" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Group DisplayName="Constructor/Destructor">
- <Entry DisplayName="Ctor">
- <Entry.Match>
- <Kind Is="Constructor" />
- </Entry.Match>
- </Entry>
- <Region Name="Disposal">
- <Entry DisplayName="Dtor">
- <Entry.Match>
- <Kind Is="Destructor" />
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Dispose()">
- <Entry.Match>
- <And>
- <Access Is="Public" />
- <Kind Is="Method" />
- <Name Is="Dispose" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Dispose(true)">
- <Entry.Match>
- <And>
- <Access Is="Protected" />
- <Or>
- <Virtual />
- <Override />
- </Or>
- <Kind Is="Method" />
- <Name Is="Dispose" />
- </And>
- </Entry.Match>
- </Entry>
- </Region>
- </Group>
- <Group DisplayName="Methods">
- <Group DisplayName="Public">
- <Entry DisplayName="Static Methods">
- <Entry.Match>
- <And>
- <Access Is="Public" />
- <Static />
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Methods">
- <Entry.Match>
- <And>
- <Access Is="Public" />
- <Not>
- <Static />
- </Not>
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Group DisplayName="Internal">
- <Entry DisplayName="Static Methods">
- <Entry.Match>
- <And>
- <Access Is="Internal" />
- <Static />
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Methods">
- <Entry.Match>
- <And>
- <Access Is="Internal" />
- <Not>
- <Static />
- </Not>
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Group DisplayName="Protected">
- <Entry DisplayName="Static Methods">
- <Entry.Match>
- <And>
- <Access Is="Protected" />
- <Static />
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Methods">
- <Entry.Match>
- <And>
- <Access Is="Protected" />
- <Not>
- <Static />
- </Not>
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Group DisplayName="Private">
- <Entry DisplayName="Static Methods">
- <Entry.Match>
- <And>
- <Access Is="Private" />
- <Static />
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Methods">
- <Entry.Match>
- <And>
- <Access Is="Private" />
- <Not>
- <Static />
- </Not>
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- </Group>
- </TypePattern>
-</Patterns>
- Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
-See the LICENCE file in the repository root for full licence text.
-
- <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" />
- <Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb"><ExtraRule Prefix="_" Suffix="" Style="aaBb" /></Policy>
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Private" Description="private methods"><ElementKinds><Kind Name="ASYNC_METHOD" /><Kind Name="METHOD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></Policy>
- <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Protected, ProtectedInternal, Internal, Public" Description="internal/protected/public methods"><ElementKinds><Kind Name="ASYNC_METHOD" /><Kind Name="METHOD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></Policy>
- <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Private" Description="private properties"><ElementKinds><Kind Name="PROPERTY" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></Policy>
- <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Protected, ProtectedInternal, Internal, Public" Description="internal/protected/public properties"><ElementKinds><Kind Name="PROPERTY" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></Policy>
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
- o!f – Object Initializer: Anchor&Origin
- True
- constant("Centre")
- 0
- True
- True
- 2.0
- InCSharpFile
- ofao
- True
- Anchor = Anchor.$anchor$,
-Origin = Anchor.$anchor$,
- True
- True
- o!f – InternalChildren = []
- True
- True
- 2.0
- InCSharpFile
- ofic
- True
- InternalChildren = new Drawable[]
-{
- $END$
-};
- True
- True
- o!f – new GridContainer { .. }
- True
- True
- 2.0
- InCSharpFile
- ofgc
- True
- new GridContainer
-{
- RelativeSizeAxes = Axes.Both,
- Content = new[]
- {
- new Drawable[] { $END$ },
- new Drawable[] { }
- }
-};
- True
- True
- o!f – new FillFlowContainer { .. }
- True
- True
- 2.0
- InCSharpFile
- offf
- True
- new FillFlowContainer
-{
- RelativeSizeAxes = Axes.Both,
- Direction = FillDirection.Vertical,
- Children = new Drawable[]
- {
- $END$
- }
-},
- True
- True
- o!f – new Container { .. }
- True
- True
- 2.0
- InCSharpFile
- ofcont
- True
- new Container
-{
- RelativeSizeAxes = Axes.Both,
- Children = new Drawable[]
- {
- $END$
- }
-},
- True
- True
- o!f – BackgroundDependencyLoader load()
- True
- True
- 2.0
- InCSharpFile
- ofbdl
- True
- [BackgroundDependencyLoader]
-private void load()
-{
- $END$
-}
- True
- True
- o!f – new Box { .. }
- True
- True
- 2.0
- InCSharpFile
- ofbox
- True
- new Box
-{
- Colour = Color4.Black,
- RelativeSizeAxes = Axes.Both,
-},
- True
- True
- o!f – Children = []
- True
- True
- 2.0
- InCSharpFile
- ofc
- True
- Children = new Drawable[]
-{
- $END$
-};
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
diff --git a/osu.Android.slnf b/osu.Android.slnf
new file mode 100644
index 0000000000..7d90f97eb9
--- /dev/null
+++ b/osu.Android.slnf
@@ -0,0 +1,19 @@
+{
+ "solution": {
+ "path": "osu.sln",
+ "projects": [
+ "osu.Android\\osu.Android.csproj",
+ "osu.Game.Rulesets.Catch.Tests.Android\\osu.Game.Rulesets.Catch.Tests.Android.csproj",
+ "osu.Game.Rulesets.Catch\\osu.Game.Rulesets.Catch.csproj",
+ "osu.Game.Rulesets.Mania.Tests.Android\\osu.Game.Rulesets.Mania.Tests.Android.csproj",
+ "osu.Game.Rulesets.Mania\\osu.Game.Rulesets.Mania.csproj",
+ "osu.Game.Rulesets.Osu.Tests.Android\\osu.Game.Rulesets.Osu.Tests.Android.csproj",
+ "osu.Game.Rulesets.Osu\\osu.Game.Rulesets.Osu.csproj",
+ "osu.Game.Rulesets.Taiko.Tests.Android\\osu.Game.Rulesets.Taiko.Tests.Android.csproj",
+ "osu.Game.Rulesets.Taiko\\osu.Game.Rulesets.Taiko.csproj",
+ "osu.Game.Tests.Android\\osu.Game.Tests.Android.csproj",
+ "osu.Game.Tests\\osu.Game.Tests.csproj",
+ "osu.Game\\osu.Game.csproj"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/osu.Desktop.slnf b/osu.Desktop.slnf
new file mode 100644
index 0000000000..e6b6446f72
--- /dev/null
+++ b/osu.Desktop.slnf
@@ -0,0 +1,20 @@
+{
+ "solution": {
+ "path": "osu.sln",
+ "projects": [
+ "osu.Desktop\\osu.Desktop.csproj",
+ "osu.Game.Rulesets.Catch.Tests\\osu.Game.Rulesets.Catch.Tests.csproj",
+ "osu.Game.Rulesets.Catch\\osu.Game.Rulesets.Catch.csproj",
+ "osu.Game.Rulesets.Mania.Tests\\osu.Game.Rulesets.Mania.Tests.csproj",
+ "osu.Game.Rulesets.Mania\\osu.Game.Rulesets.Mania.csproj",
+ "osu.Game.Rulesets.Osu.Tests\\osu.Game.Rulesets.Osu.Tests.csproj",
+ "osu.Game.Rulesets.Osu\\osu.Game.Rulesets.Osu.csproj",
+ "osu.Game.Rulesets.Taiko.Tests\\osu.Game.Rulesets.Taiko.Tests.csproj",
+ "osu.Game.Rulesets.Taiko\\osu.Game.Rulesets.Taiko.csproj",
+ "osu.Game.Tests\\osu.Game.Tests.csproj",
+ "osu.Game.Tournament.Tests\\osu.Game.Tournament.Tests.csproj",
+ "osu.Game.Tournament\\osu.Game.Tournament.csproj",
+ "osu.Game\\osu.Game.csproj"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj
index 2d1282634f..453cf6f94d 100644
--- a/osu.Desktop/osu.Desktop.csproj
+++ b/osu.Desktop/osu.Desktop.csproj
@@ -1,9 +1,7 @@
-
netcoreapp3.0
WinExe
- AnyCPU
true
click the circles. to the beat.
osu!
@@ -23,13 +21,13 @@
-
+
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
index 7990c35e09..be6044bbd0 100644
--- 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
@@ -1,6 +1,5 @@
-
+
-
Debug
iPhoneSimulator
@@ -33,5 +32,4 @@
-
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs
index 7b8c699f2c..da36673930 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs
@@ -40,8 +40,10 @@ namespace osu.Game.Rulesets.Catch.Tests
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 4b629902cb..1dbe9b39ee 100644
--- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
+++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
@@ -2,7 +2,7 @@
-
+
diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
index 5ab47c1611..58bf811fac 100644
--- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
+++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
@@ -195,10 +195,15 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
{
if (currentObject is Fruit)
objectWithDroplets.Add(currentObject);
+
if (currentObject is JuiceStream)
+ {
foreach (var currentJuiceElement in currentObject.NestedHitObjects)
+ {
if (!(currentJuiceElement is TinyDroplet))
objectWithDroplets.Add((CatchHitObject)currentJuiceElement);
+ }
+ }
}
objectWithDroplets.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime));
diff --git a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
index 6d44e4660e..267e6d12c7 100644
--- a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
+++ b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
@@ -27,11 +27,13 @@ namespace osu.Game.Rulesets.Catch.Objects
return;
for (double i = StartTime; i <= EndTime; i += spacing)
+ {
AddNested(new Banana
{
Samples = Samples,
StartTime = i
});
+ }
}
public double EndTime => StartTime + Duration;
diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj
index 883cac67d1..f24cf1def9 100644
--- a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj
+++ b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj
@@ -1,9 +1,7 @@
-
netstandard2.0
Library
- AnyCPU
true
catch the fruit. to the beat.
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
index 58c2e2aa5a..88ad484bc1 100644
--- 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
@@ -1,6 +1,5 @@
-
+
-
Debug
iPhoneSimulator
@@ -33,5 +32,4 @@
-
\ No newline at end of file
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 30511d672d..8fc4dbfe72 100644
--- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
+++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
@@ -2,7 +2,7 @@
-
+
diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs
index decd159ee9..ada960a78d 100644
--- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs
+++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs
@@ -109,8 +109,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{
// Generate a new pattern by copying the last hit objects in reverse-column order
for (int i = RandomStart; i < TotalColumns; i++)
+ {
if (PreviousPattern.ColumnHasObject(i))
addToPattern(pattern, RandomStart + TotalColumns - i - 1);
+ }
return pattern;
}
@@ -132,8 +134,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{
// Generate a new pattern by placing on the already filled columns
for (int i = RandomStart; i < TotalColumns; i++)
+ {
if (PreviousPattern.ColumnHasObject(i))
addToPattern(pattern, i);
+ }
return pattern;
}
diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteNoteSelectionBlueprint.cs
new file mode 100644
index 0000000000..acce41db6f
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteNoteSelectionBlueprint.cs
@@ -0,0 +1,45 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics;
+using osu.Game.Rulesets.Mania.Edit.Blueprints.Components;
+using osu.Game.Rulesets.Mania.Objects.Drawables;
+
+namespace osu.Game.Rulesets.Mania.Edit.Blueprints
+{
+ public class HoldNoteNoteSelectionBlueprint : ManiaSelectionBlueprint
+ {
+ protected new DrawableHoldNote DrawableObject => (DrawableHoldNote)base.DrawableObject;
+
+ private readonly HoldNotePosition position;
+
+ public HoldNoteNoteSelectionBlueprint(DrawableHoldNote holdNote, HoldNotePosition position)
+ : base(holdNote)
+ {
+ this.position = position;
+ InternalChild = new EditNotePiece { RelativeSizeAxes = Axes.X };
+
+ Select();
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+
+ // Todo: This shouldn't exist, mania should not reference the drawable hitobject directly.
+ if (DrawableObject.IsLoaded)
+ {
+ DrawableNote note = position == HoldNotePosition.Start ? DrawableObject.Head : DrawableObject.Tail;
+
+ Anchor = note.Anchor;
+ Origin = note.Origin;
+
+ Size = note.DrawSize;
+ Position = note.DrawPosition;
+ }
+ }
+
+ // Todo: This is temporary, since the note masks don't do anything special yet. In the future they will handle input.
+ public override bool HandlePositionalInput => false;
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePosition.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePosition.cs
new file mode 100644
index 0000000000..219dad566d
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePosition.cs
@@ -0,0 +1,11 @@
+// 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.Edit.Blueprints
+{
+ public enum HoldNotePosition
+ {
+ Start,
+ End
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs
index 3a9eb1f043..56c0b671a0 100644
--- a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs
@@ -40,8 +40,8 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
InternalChildren = new Drawable[]
{
- new HoldNoteNoteSelectionBlueprint(DrawableObject.Head),
- new HoldNoteNoteSelectionBlueprint(DrawableObject.Tail),
+ new HoldNoteNoteSelectionBlueprint(DrawableObject, HoldNotePosition.Start),
+ new HoldNoteNoteSelectionBlueprint(DrawableObject, HoldNotePosition.End),
new BodyPiece
{
AccentColour = Color4.Transparent,
@@ -54,37 +54,19 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
{
base.Update();
- Size = DrawableObject.DrawSize + new Vector2(0, DrawableObject.Tail.DrawHeight);
+ // Todo: This shouldn't exist, mania should not reference the drawable hitobject directly.
+ if (DrawableObject.IsLoaded)
+ {
+ Size = DrawableObject.DrawSize + new Vector2(0, DrawableObject.Tail.DrawHeight);
- // 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),
- // but when scrolling downwards our origin is at the _bottom_ of the tail note (where we need to be at the _top_ of the tail note)
- if (direction.Value == ScrollingDirection.Down)
- Y -= DrawableObject.Tail.DrawHeight;
+ // 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),
+ // but when scrolling downwards our origin is at the _bottom_ of the tail note (where we need to be at the _top_ of the tail note)
+ if (direction.Value == ScrollingDirection.Down)
+ Y -= DrawableObject.Tail.DrawHeight;
+ }
}
public override Quad SelectionQuad => ScreenSpaceDrawQuad;
-
- private class HoldNoteNoteSelectionBlueprint : NoteSelectionBlueprint
- {
- public HoldNoteNoteSelectionBlueprint(DrawableNote note)
- : base(note)
- {
- Select();
- }
-
- protected override void Update()
- {
- base.Update();
-
- Anchor = DrawableObject.Anchor;
- Origin = DrawableObject.Origin;
-
- Position = DrawableObject.DrawPosition;
- }
-
- // Todo: This is temporary, since the note masks don't do anything special yet. In the future they will handle input.
- public override bool HandlePositionalInput => false;
- }
}
}
diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs
index b83c4aa9aa..2bff33c4cf 100644
--- a/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs
@@ -19,7 +19,9 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
{
base.Update();
- Size = DrawableObject.DrawSize;
+ // Todo: This shouldn't exist, mania should not reference the drawable hitobject directly.
+ if (DrawableObject.IsLoaded)
+ Size = DrawableObject.DrawSize;
}
}
}
diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs
index 732231b0d9..9cdf045b5b 100644
--- a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs
+++ b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs
@@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Mania.Edit
editorClock = clock;
}
- public override void HandleMovement(MoveSelectionEvent moveEvent)
+ public override bool HandleMovement(MoveSelectionEvent moveEvent)
{
var maniaBlueprint = (ManiaSelectionBlueprint)moveEvent.Blueprint;
int lastColumn = maniaBlueprint.DrawableObject.HitObject.Column;
@@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Mania.Edit
performDragMovement(moveEvent);
performColumnMovement(lastColumn, moveEvent);
- base.HandleMovement(moveEvent);
+ return true;
}
///
diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj
index a086da0565..0af200d19b 100644
--- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj
+++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj
@@ -1,9 +1,7 @@
-
netstandard2.0
Library
- AnyCPU
true
smash the keys. to the beat.
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
index c7787bd162..545abcec6c 100644
--- 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
@@ -1,6 +1,5 @@
-
+
-
Debug
iPhoneSimulator
@@ -33,5 +32,4 @@
-
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs
index 685a51d208..46769f65fe 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs
@@ -101,7 +101,11 @@ namespace osu.Game.Rulesets.Osu.Tests
public IBindable GetConfig(TLookup lookup) => throw new NotImplementedException();
- public event Action SourceChanged;
+ public event Action SourceChanged
+ {
+ add { }
+ remove { }
+ }
}
private class MovingCursorInputManager : ManualInputManager
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs
index 433ec6bd25..ac627aa23e 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs
@@ -24,12 +24,14 @@ namespace osu.Game.Rulesets.Osu.Tests
public TestSceneDrawableJudgement()
{
foreach (HitResult result in Enum.GetValues(typeof(HitResult)).OfType().Skip(1))
+ {
AddStep("Show " + result.GetDescription(), () => SetContents(() =>
new DrawableOsuJudgement(new JudgementResult(new HitObject(), new Judgement()) { Type = result }, null)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}));
+ }
}
}
}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneFollowPoints.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneFollowPoints.cs
new file mode 100644
index 0000000000..94ca2d4cd1
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneFollowPoints.cs
@@ -0,0 +1,230 @@
+// 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 NUnit.Framework;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Rulesets.Osu.Objects;
+using osu.Game.Rulesets.Osu.Objects.Drawables;
+using osu.Game.Rulesets.Osu.Objects.Drawables.Connections;
+using osu.Game.Tests.Visual;
+using osuTK;
+
+namespace osu.Game.Rulesets.Osu.Tests
+{
+ public class TestSceneFollowPoints : OsuTestScene
+ {
+ private Container hitObjectContainer;
+ private FollowPointRenderer followPointRenderer;
+
+ [SetUp]
+ public void Setup() => Schedule(() =>
+ {
+ Children = new Drawable[]
+ {
+ hitObjectContainer = new TestHitObjectContainer { RelativeSizeAxes = Axes.Both },
+ followPointRenderer = new FollowPointRenderer { RelativeSizeAxes = Axes.Both }
+ };
+ });
+
+ [Test]
+ public void TestAddObject()
+ {
+ addObjectsStep(() => new OsuHitObject[] { new HitCircle { Position = new Vector2(100, 100) } });
+
+ assertGroups();
+ }
+
+ [Test]
+ public void TestRemoveObject()
+ {
+ addObjectsStep(() => new OsuHitObject[] { new HitCircle { Position = new Vector2(100, 100) } });
+
+ removeObjectStep(() => getObject(0));
+
+ assertGroups();
+ }
+
+ [Test]
+ public void TestAddMultipleObjects()
+ {
+ addMultipleObjectsStep();
+
+ assertGroups();
+ }
+
+ [Test]
+ public void TestRemoveEndObject()
+ {
+ addMultipleObjectsStep();
+
+ removeObjectStep(() => getObject(4));
+
+ assertGroups();
+ }
+
+ [Test]
+ public void TestRemoveStartObject()
+ {
+ addMultipleObjectsStep();
+
+ removeObjectStep(() => getObject(0));
+
+ assertGroups();
+ }
+
+ [Test]
+ public void TestRemoveMiddleObject()
+ {
+ addMultipleObjectsStep();
+
+ removeObjectStep(() => getObject(2));
+
+ assertGroups();
+ }
+
+ [Test]
+ public void TestMoveObject()
+ {
+ addMultipleObjectsStep();
+
+ AddStep("move hitobject", () => getObject(2).HitObject.Position = new Vector2(300, 100));
+
+ assertGroups();
+ }
+
+ [TestCase(0, 0)] // Start -> Start
+ [TestCase(0, 2)] // Start -> Middle
+ [TestCase(0, 5)] // Start -> End
+ [TestCase(2, 0)] // Middle -> Start
+ [TestCase(1, 3)] // Middle -> Middle (forwards)
+ [TestCase(3, 1)] // Middle -> Middle (backwards)
+ [TestCase(4, 0)] // End -> Start
+ [TestCase(4, 2)] // End -> Middle
+ [TestCase(4, 4)] // End -> End
+ public void TestReorderObjects(int startIndex, int endIndex)
+ {
+ addMultipleObjectsStep();
+
+ reorderObjectStep(startIndex, endIndex);
+
+ assertGroups();
+ }
+
+ private void addMultipleObjectsStep() => addObjectsStep(() => new OsuHitObject[]
+ {
+ new HitCircle { Position = new Vector2(100, 100) },
+ new HitCircle { Position = new Vector2(200, 200) },
+ new HitCircle { Position = new Vector2(300, 300) },
+ new HitCircle { Position = new Vector2(400, 400) },
+ new HitCircle { Position = new Vector2(500, 500) },
+ });
+
+ private void addObjectsStep(Func ctorFunc)
+ {
+ AddStep("add hitobjects", () =>
+ {
+ var objects = ctorFunc();
+
+ for (int i = 0; i < objects.Length; i++)
+ {
+ objects[i].StartTime = Time.Current + 1000 + 500 * (i + 1);
+ objects[i].ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
+
+ DrawableOsuHitObject drawableObject = null;
+
+ switch (objects[i])
+ {
+ case HitCircle circle:
+ drawableObject = new DrawableHitCircle(circle);
+ break;
+
+ case Slider slider:
+ drawableObject = new DrawableSlider(slider);
+ break;
+
+ case Spinner spinner:
+ drawableObject = new DrawableSpinner(spinner);
+ break;
+ }
+
+ hitObjectContainer.Add(drawableObject);
+ followPointRenderer.AddFollowPoints(drawableObject);
+ }
+ });
+ }
+
+ private void removeObjectStep(Func getFunc)
+ {
+ AddStep("remove hitobject", () =>
+ {
+ var drawableObject = getFunc?.Invoke();
+
+ hitObjectContainer.Remove(drawableObject);
+ followPointRenderer.RemoveFollowPoints(drawableObject);
+ });
+ }
+
+ private void reorderObjectStep(int startIndex, int endIndex)
+ {
+ AddStep($"move object {startIndex} to {endIndex}", () =>
+ {
+ DrawableOsuHitObject toReorder = getObject(startIndex);
+
+ double targetTime;
+ if (endIndex < hitObjectContainer.Count)
+ targetTime = getObject(endIndex).HitObject.StartTime - 1;
+ else
+ targetTime = getObject(hitObjectContainer.Count - 1).HitObject.StartTime + 1;
+
+ hitObjectContainer.Remove(toReorder);
+ toReorder.HitObject.StartTime = targetTime;
+ hitObjectContainer.Add(toReorder);
+ });
+ }
+
+ private void assertGroups()
+ {
+ AddAssert("has correct group count", () => followPointRenderer.Connections.Count == hitObjectContainer.Count);
+ AddAssert("group endpoints are correct", () =>
+ {
+ for (int i = 0; i < hitObjectContainer.Count; i++)
+ {
+ DrawableOsuHitObject expectedStart = getObject(i);
+ DrawableOsuHitObject expectedEnd = i < hitObjectContainer.Count - 1 ? getObject(i + 1) : null;
+
+ if (getGroup(i).Start != expectedStart)
+ throw new AssertionException($"Object {i} expected to be the start of group {i}.");
+
+ if (getGroup(i).End != expectedEnd)
+ throw new AssertionException($"Object {(expectedEnd == null ? "null" : i.ToString())} expected to be the end of group {i}.");
+ }
+
+ return true;
+ });
+ }
+
+ private DrawableOsuHitObject getObject(int index) => hitObjectContainer[index];
+
+ private FollowPointConnection getGroup(int index) => followPointRenderer.Connections[index];
+
+ private class TestHitObjectContainer : Container
+ {
+ protected override int Compare(Drawable x, Drawable y)
+ {
+ var osuX = (DrawableOsuHitObject)x;
+ var osuY = (DrawableOsuHitObject)y;
+
+ int compare = osuX.HitObject.StartTime.CompareTo(osuY.HitObject.StartTime);
+
+ if (compare == 0)
+ return base.Compare(x, y);
+
+ return compare;
+ }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs
index 95c2810e94..b99cd523ff 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs
@@ -29,8 +29,10 @@ namespace osu.Game.Rulesets.Osu.Tests
};
for (int i = 0; i < 512; i++)
+ {
if (i % 32 < 20)
beatmap.HitObjects.Add(new HitCircle { Position = new Vector2(256, 192), StartTime = i * 100 });
+ }
return beatmap;
}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuDistanceSnapGrid.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuDistanceSnapGrid.cs
index a9a6097182..eff4d919b0 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuDistanceSnapGrid.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuDistanceSnapGrid.cs
@@ -42,11 +42,19 @@ namespace osu.Game.Rulesets.Osu.Tests
[Cached(typeof(IDistanceSnapProvider))]
private readonly SnapProvider snapProvider = new SnapProvider();
- private readonly TestOsuDistanceSnapGrid grid;
+ private TestOsuDistanceSnapGrid grid;
public TestSceneOsuDistanceSnapGrid()
{
editorBeatmap = new EditorBeatmap(new OsuBeatmap());
+ }
+
+ [SetUp]
+ public void Setup() => Schedule(() =>
+ {
+ editorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 1;
+ editorBeatmap.ControlPointInfo.Clear();
+ editorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = beat_length });
Children = new Drawable[]
{
@@ -58,14 +66,6 @@ namespace osu.Game.Rulesets.Osu.Tests
grid = new TestOsuDistanceSnapGrid(new HitCircle { Position = grid_position }),
new SnappingCursorContainer { GetSnapPosition = v => grid.GetSnappedPosition(grid.ToLocalSpace(v)).position }
};
- }
-
- [SetUp]
- public void Setup() => Schedule(() =>
- {
- editorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 1;
- editorBeatmap.ControlPointInfo.Clear();
- editorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = beat_length });
});
[TestCase(1)]
@@ -102,6 +102,27 @@ namespace osu.Game.Rulesets.Osu.Tests
assertSnappedDistance((float)beat_length * 2);
}
+ [Test]
+ public void TestLimitedDistance()
+ {
+ AddStep("create limited grid", () =>
+ {
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.SlateGray
+ },
+ grid = new TestOsuDistanceSnapGrid(new HitCircle { Position = grid_position }, new HitCircle { StartTime = 200 }),
+ new SnappingCursorContainer { GetSnapPosition = v => grid.GetSnappedPosition(grid.ToLocalSpace(v)).position }
+ };
+ });
+
+ AddStep("move mouse outside grid", () => InputManager.MoveMouseTo(grid.ToScreenSpace(grid_position + new Vector2((float)beat_length, 0) * 3f)));
+ assertSnappedDistance((float)beat_length * 2);
+ }
+
private void assertSnappedDistance(float expectedDistance) => AddAssert($"snap distance = {expectedDistance}", () =>
{
Vector2 snappedPosition = grid.GetSnappedPosition(grid.ToLocalSpace(InputManager.CurrentState.Mouse.Position)).position;
@@ -152,8 +173,8 @@ namespace osu.Game.Rulesets.Osu.Tests
{
public new float DistanceSpacing => base.DistanceSpacing;
- public TestOsuDistanceSnapGrid(OsuHitObject hitObject)
- : base(hitObject)
+ public TestOsuDistanceSnapGrid(OsuHitObject hitObject, OsuHitObject nextHitObject = null)
+ : base(hitObject, nextHitObject)
{
}
}
@@ -164,9 +185,9 @@ namespace osu.Game.Rulesets.Osu.Tests
public float GetBeatSnapDistanceAt(double referenceTime) => (float)beat_length;
- public float DurationToDistance(double referenceTime, double duration) => 0;
+ public float DurationToDistance(double referenceTime, double duration) => (float)duration;
- public double DistanceToDuration(double referenceTime, float distance) => 0;
+ public double DistanceToDuration(double referenceTime, float distance) => distance;
public double GetSnappedDurationFromDistance(double referenceTime, float distance) => 0;
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 3aea9e0387..fddf176fd0 100644
--- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
+++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
@@ -2,7 +2,7 @@
-
+
diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs
index e2ea6a12d7..155e814596 100644
--- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs
@@ -10,6 +10,7 @@ using osu.Framework.Graphics.Lines;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
+using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Osu.Objects;
using osuTK;
using osuTK.Graphics;
@@ -29,7 +30,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
private readonly Container marker;
private readonly Drawable markerRing;
- private bool isClicked;
+ [Resolved(CanBeNull = true)]
+ private IDistanceSnapProvider snapProvider { get; set; }
[Resolved]
private OsuColour colours { get; set; }
@@ -101,7 +103,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
markerRing.Alpha = IsSelected.Value ? 1 : 0;
Color4 colour = isSegmentSeparator ? colours.Red : colours.Yellow;
- if (IsHovered || isClicked || IsSelected.Value)
+ if (IsHovered || IsSelected.Value)
colour = Color4.White;
marker.Colour = colour;
}
@@ -127,21 +129,18 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
protected override bool OnMouseDown(MouseDownEvent e)
{
- isClicked = true;
- return true;
+ if (RequestSelection != null)
+ {
+ RequestSelection.Invoke(Index);
+ return true;
+ }
+
+ return false;
}
- protected override bool OnMouseUp(MouseUpEvent e)
- {
- isClicked = false;
- return true;
- }
+ protected override bool OnMouseUp(MouseUpEvent e) => RequestSelection != null;
- protected override bool OnClick(ClickEvent e)
- {
- RequestSelection?.Invoke(Index);
- return true;
- }
+ protected override bool OnClick(ClickEvent e) => RequestSelection != null;
protected override bool OnDragStart(DragStartEvent e) => true;
@@ -151,12 +150,16 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
if (Index == 0)
{
- // Special handling for the head - only the position of the slider changes
- slider.Position += e.Delta;
+ // Special handling for the head control point - the position of the slider changes which means the snapped position and time have to be taken into account
+ (Vector2 snappedPosition, double snappedTime) = snapProvider?.GetSnappedPosition(e.MousePosition, slider.StartTime) ?? (e.MousePosition, slider.StartTime);
+ Vector2 movementDelta = snappedPosition - slider.Position;
+
+ slider.Position += movementDelta;
+ slider.StartTime = snappedTime;
// Since control points are relative to the position of the slider, they all need to be offset backwards by the delta
for (int i = 1; i < newControlPoints.Length; i++)
- newControlPoints[i] -= e.Delta;
+ newControlPoints[i] -= movementDelta;
}
else
newControlPoints[Index] += e.Delta;
diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs
index b70c11427a..6962736157 100644
--- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs
@@ -2,27 +2,36 @@
// 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.Input;
+using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Osu.Objects;
+using osu.Game.Screens.Edit.Compose;
using osuTK;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
{
- public class PathControlPointVisualiser : CompositeDrawable
+ public class PathControlPointVisualiser : CompositeDrawable, IKeyBindingHandler
{
public Action ControlPointsChanged;
internal readonly Container Pieces;
private readonly Slider slider;
+ private readonly bool allowSelection;
private InputManager inputManager;
- public PathControlPointVisualiser(Slider slider)
+ [Resolved(CanBeNull = true)]
+ private IPlacementHandler placementHandler { get; set; }
+
+ public PathControlPointVisualiser(Slider slider, bool allowSelection)
{
this.slider = slider;
+ this.allowSelection = allowSelection;
RelativeSizeAxes = Axes.Both;
@@ -42,11 +51,15 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
while (slider.Path.ControlPoints.Length > Pieces.Count)
{
- Pieces.Add(new PathControlPointPiece(slider, Pieces.Count)
+ var piece = new PathControlPointPiece(slider, Pieces.Count)
{
ControlPointsChanged = c => ControlPointsChanged?.Invoke(c),
- RequestSelection = selectPiece
- });
+ };
+
+ if (allowSelection)
+ piece.RequestSelection = selectPiece;
+
+ Pieces.Add(piece);
}
while (slider.Path.ControlPoints.Length < Pieces.Count)
@@ -70,5 +83,51 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
piece.IsSelected.Value = piece.Index == index;
}
}
+
+ public bool OnPressed(PlatformAction action)
+ {
+ switch (action.ActionMethod)
+ {
+ case PlatformActionMethod.Delete:
+ var newControlPoints = new List();
+
+ foreach (var piece in Pieces)
+ {
+ if (!piece.IsSelected.Value)
+ newControlPoints.Add(slider.Path.ControlPoints[piece.Index]);
+ }
+
+ // Ensure that there are any points to be deleted
+ if (newControlPoints.Count == slider.Path.ControlPoints.Length)
+ return false;
+
+ // If there are 0 remaining control points, treat the slider as being deleted
+ if (newControlPoints.Count == 0)
+ {
+ placementHandler?.Delete(slider);
+ return true;
+ }
+
+ // Make control points relative
+ Vector2 first = newControlPoints[0];
+ for (int i = 0; i < newControlPoints.Count; i++)
+ newControlPoints[i] = newControlPoints[i] - first;
+
+ // The slider's position defines the position of the first control point, and all further control points are relative to that point
+ slider.Position = slider.Position + first;
+
+ // Since pieces are re-used, they will not point to the deleted control points while remaining selected
+ foreach (var piece in Pieces)
+ piece.IsSelected.Value = false;
+
+ ControlPointsChanged?.Invoke(newControlPoints.ToArray());
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool OnReleased(PlatformAction action) => action.ActionMethod == PlatformActionMethod.Delete;
}
}
diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs
index d28cf7b492..78f4c4d992 100644
--- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs
@@ -43,5 +43,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
Size = body.Size;
OriginPosition = body.PathOffset;
}
+
+ public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => body.ReceivePositionalInputAt(screenSpacePos);
}
}
diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs
index 6f5309c2c2..9c0afada29 100644
--- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs
@@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
bodyPiece = new SliderBodyPiece(),
headCirclePiece = new HitCirclePiece(),
tailCirclePiece = new HitCirclePiece(),
- new PathControlPointVisualiser(HitObject) { ControlPointsChanged = _ => updateSlider() },
+ new PathControlPointVisualiser(HitObject, false) { ControlPointsChanged = _ => updateSlider() },
};
setState(PlacementState.Initial);
diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs
index f612ba9dfc..25362820a3 100644
--- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs
@@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
BodyPiece = new SliderBodyPiece(),
HeadBlueprint = CreateCircleSelectionBlueprint(slider, SliderPosition.Start),
TailBlueprint = CreateCircleSelectionBlueprint(slider, SliderPosition.End),
- ControlPointVisualiser = new PathControlPointVisualiser(sliderObject) { ControlPointsChanged = onNewControlPoints },
+ ControlPointVisualiser = new PathControlPointVisualiser(sliderObject, true) { ControlPointsChanged = onNewControlPoints },
};
}
diff --git a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs
index cc08d356f9..3437af8c1e 100644
--- a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs
+++ b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs
@@ -2,8 +2,12 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
+using System.Linq;
+using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.UI;
using osuTK;
@@ -12,11 +16,36 @@ namespace osu.Game.Rulesets.Osu.Edit
{
public class DrawableOsuEditRuleset : DrawableOsuRuleset
{
+ ///
+ /// Hit objects are intentionally made to fade out at a constant slower rate than in gameplay.
+ /// This allows a mapper to gain better historical context and use recent hitobjects as reference / snap points.
+ ///
+ private const double editor_hit_object_fade_out_extension = 500;
+
public DrawableOsuEditRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList mods)
: base(ruleset, beatmap, mods)
{
}
+ public override DrawableHitObject CreateDrawableRepresentation(OsuHitObject h)
+ => base.CreateDrawableRepresentation(h)?.With(d => d.ApplyCustomUpdateState += updateState);
+
+ private void updateState(DrawableHitObject hitObject, ArmedState state)
+ {
+ switch (state)
+ {
+ case ArmedState.Miss:
+ // Get the existing fade out transform
+ var existing = hitObject.Transforms.LastOrDefault(t => t.TargetMember == nameof(Alpha));
+ if (existing == null)
+ return;
+
+ using (hitObject.BeginAbsoluteSequence(existing.StartTime))
+ hitObject.FadeOut(editor_hit_object_fade_out_extension).Expire();
+ break;
+ }
+ }
+
protected override Playfield CreatePlayfield() => new OsuPlayfieldNoCursor();
public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new OsuPlayfieldAdjustmentContainer { Size = Vector2.One };
diff --git a/osu.Game.Rulesets.Osu/Edit/OsuDistanceSnapGrid.cs b/osu.Game.Rulesets.Osu/Edit/OsuDistanceSnapGrid.cs
index 79cd51a7f4..9b00204d51 100644
--- a/osu.Game.Rulesets.Osu/Edit/OsuDistanceSnapGrid.cs
+++ b/osu.Game.Rulesets.Osu/Edit/OsuDistanceSnapGrid.cs
@@ -8,8 +8,8 @@ namespace osu.Game.Rulesets.Osu.Edit
{
public class OsuDistanceSnapGrid : CircularDistanceSnapGrid
{
- public OsuDistanceSnapGrid(OsuHitObject hitObject)
- : base(hitObject, hitObject.StackedEndPosition)
+ public OsuDistanceSnapGrid(OsuHitObject hitObject, OsuHitObject nextHitObject)
+ : base(hitObject, nextHitObject, hitObject.StackedEndPosition)
{
Masking = true;
}
diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs
index fcf2772219..812afaaa24 100644
--- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs
+++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps;
@@ -60,25 +61,40 @@ namespace osu.Game.Rulesets.Osu.Edit
var objects = selectedHitObjects.ToList();
if (objects.Count == 0)
+ return createGrid(h => h.StartTime <= EditorClock.CurrentTime);
+
+ double minTime = objects.Min(h => h.StartTime);
+ return createGrid(h => h.StartTime < minTime, objects.Count + 1);
+ }
+
+ ///
+ /// Creates a grid from the last matching a predicate to a target .
+ ///
+ /// A predicate that matches s where the grid can start from.
+ /// Only the last matching the predicate is used.
+ /// An offset from the selected via at which the grid should stop.
+ /// The from a selected to a target .
+ private OsuDistanceSnapGrid createGrid(Func sourceSelector, int targetOffset = 1)
+ {
+ if (targetOffset < 1) throw new ArgumentOutOfRangeException(nameof(targetOffset));
+
+ int sourceIndex = -1;
+
+ for (int i = 0; i < EditorBeatmap.HitObjects.Count; i++)
{
- var lastObject = EditorBeatmap.HitObjects.LastOrDefault(h => h.StartTime <= EditorClock.CurrentTime);
+ if (!sourceSelector(EditorBeatmap.HitObjects[i]))
+ break;
- if (lastObject == null)
- return null;
-
- return new OsuDistanceSnapGrid(lastObject);
+ sourceIndex = i;
}
- else
- {
- double minTime = objects.Min(h => h.StartTime);
- var lastObject = EditorBeatmap.HitObjects.LastOrDefault(h => h.StartTime < minTime);
+ if (sourceIndex == -1)
+ return null;
- if (lastObject == null)
- return null;
+ OsuHitObject sourceObject = EditorBeatmap.HitObjects[sourceIndex];
+ OsuHitObject targetObject = sourceIndex + targetOffset < EditorBeatmap.HitObjects.Count ? EditorBeatmap.HitObjects[sourceIndex + targetOffset] : null;
- return new OsuDistanceSnapGrid(lastObject);
- }
+ return new OsuDistanceSnapGrid(sourceObject, targetObject);
}
}
}
diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs
index 472267eb66..9418565907 100644
--- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs
+++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs
@@ -4,13 +4,34 @@
using System.Linq;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Screens.Edit.Compose.Components;
+using osuTK;
namespace osu.Game.Rulesets.Osu.Edit
{
public class OsuSelectionHandler : SelectionHandler
{
- public override void HandleMovement(MoveSelectionEvent moveEvent)
+ public override bool HandleMovement(MoveSelectionEvent moveEvent)
{
+ Vector2 minPosition = new Vector2(float.MaxValue, float.MaxValue);
+ Vector2 maxPosition = new Vector2(float.MinValue, float.MinValue);
+
+ // Go through all hitobjects to make sure they would remain in the bounds of the editor after movement, before any movement is attempted
+ foreach (var h in SelectedHitObjects.OfType())
+ {
+ if (h is Spinner)
+ {
+ // Spinners don't support position adjustments
+ continue;
+ }
+
+ // Stacking is not considered
+ minPosition = Vector2.ComponentMin(minPosition, Vector2.ComponentMin(h.EndPosition + moveEvent.InstantDelta, h.Position + moveEvent.InstantDelta));
+ maxPosition = Vector2.ComponentMax(maxPosition, Vector2.ComponentMax(h.EndPosition + moveEvent.InstantDelta, h.Position + moveEvent.InstantDelta));
+ }
+
+ if (minPosition.X < 0 || minPosition.Y < 0 || maxPosition.X > DrawWidth || maxPosition.Y > DrawHeight)
+ return false;
+
foreach (var h in SelectedHitObjects.OfType())
{
if (h is Spinner)
@@ -22,7 +43,7 @@ namespace osu.Game.Rulesets.Osu.Edit
h.Position += moveEvent.InstantDelta;
}
- base.HandleMovement(moveEvent);
+ return true;
}
}
}
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs
index 17fcd03dd5..1664a37a66 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs
@@ -55,8 +55,10 @@ namespace osu.Game.Rulesets.Osu.Mods
}
for (int i = 0; i < amountWiggles; i++)
+ {
using (drawable.BeginAbsoluteSequence(osuObject.StartTime - osuObject.TimePreempt + i * wiggle_duration, true))
wiggle();
+ }
// Keep wiggling sliders and spinners for their duration
if (!(osuObject is IHasEndTime endTime))
@@ -65,8 +67,10 @@ namespace osu.Game.Rulesets.Osu.Mods
amountWiggles = (int)(endTime.Duration / wiggle_duration);
for (int i = 0; i < amountWiggles; i++)
+ {
using (drawable.BeginAbsoluteSequence(osuObject.StartTime + i * wiggle_duration, true))
wiggle();
+ }
}
}
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/ConnectionRenderer.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/ConnectionRenderer.cs
deleted file mode 100644
index 9106f4c7bd..0000000000
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/ConnectionRenderer.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using osu.Framework.Graphics.Containers;
-using osu.Game.Rulesets.Objects;
-using System.Collections.Generic;
-
-namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
-{
- ///
- /// Connects hit objects visually, for example with follow points.
- ///
- public abstract class ConnectionRenderer : LifetimeManagementContainer
- where T : HitObject
- {
- ///
- /// Hit objects to create connections for
- ///
- public abstract IEnumerable HitObjects { get; set; }
- }
-}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs
index 89ffddf4cb..db34ae1d87 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs
@@ -12,6 +12,9 @@ using osu.Game.Skinning;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
{
+ ///
+ /// A single follow point positioned between two adjacent s.
+ ///
public class FollowPoint : Container
{
private const float width = 8;
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs
new file mode 100644
index 0000000000..1e032eb977
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs
@@ -0,0 +1,140 @@
+// 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 JetBrains.Annotations;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Rulesets.Objects.Types;
+using osuTK;
+
+namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
+{
+ ///
+ /// Visualises the s between two s.
+ ///
+ public class FollowPointConnection : CompositeDrawable
+ {
+ // Todo: These shouldn't be constants
+ private const int spacing = 32;
+ private const double preempt = 800;
+
+ ///
+ /// The start time of .
+ ///
+ public readonly Bindable StartTime = new Bindable();
+
+ ///
+ /// The which s will exit from.
+ ///
+ [NotNull]
+ public readonly DrawableOsuHitObject Start;
+
+ ///
+ /// Creates a new .
+ ///
+ /// The which s will exit from.
+ public FollowPointConnection([NotNull] DrawableOsuHitObject start)
+ {
+ Start = start;
+
+ RelativeSizeAxes = Axes.Both;
+
+ StartTime.BindTo(Start.HitObject.StartTimeBindable);
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+ bindEvents(Start);
+ }
+
+ private DrawableOsuHitObject end;
+
+ ///
+ /// The which s will enter.
+ ///
+ [CanBeNull]
+ public DrawableOsuHitObject End
+ {
+ get => end;
+ set
+ {
+ end = value;
+
+ if (end != null)
+ bindEvents(end);
+
+ if (IsLoaded)
+ scheduleRefresh();
+ else
+ refresh();
+ }
+ }
+
+ private void bindEvents(DrawableOsuHitObject drawableObject)
+ {
+ drawableObject.HitObject.PositionBindable.BindValueChanged(_ => scheduleRefresh());
+ drawableObject.HitObject.DefaultsApplied += scheduleRefresh;
+ }
+
+ private void scheduleRefresh() => Scheduler.AddOnce(refresh);
+
+ private void refresh()
+ {
+ ClearInternal();
+
+ if (End == null)
+ return;
+
+ OsuHitObject osuStart = Start.HitObject;
+ OsuHitObject osuEnd = End.HitObject;
+
+ if (osuEnd.NewCombo)
+ return;
+
+ if (osuStart is Spinner || osuEnd is Spinner)
+ return;
+
+ Vector2 startPosition = osuStart.EndPosition;
+ Vector2 endPosition = osuEnd.Position;
+ double startTime = (osuStart as IHasEndTime)?.EndTime ?? osuStart.StartTime;
+ double endTime = osuEnd.StartTime;
+
+ Vector2 distanceVector = endPosition - startPosition;
+ int distance = (int)distanceVector.Length;
+ float rotation = (float)(Math.Atan2(distanceVector.Y, distanceVector.X) * (180 / Math.PI));
+ double duration = endTime - startTime;
+
+ for (int d = (int)(spacing * 1.5); d < distance - spacing; d += spacing)
+ {
+ float fraction = (float)d / distance;
+ Vector2 pointStartPosition = startPosition + (fraction - 0.1f) * distanceVector;
+ Vector2 pointEndPosition = startPosition + fraction * distanceVector;
+ double fadeOutTime = startTime + fraction * duration;
+ double fadeInTime = fadeOutTime - preempt;
+
+ FollowPoint fp;
+
+ AddInternal(fp = new FollowPoint
+ {
+ Position = pointStartPosition,
+ Rotation = rotation,
+ Alpha = 0,
+ Scale = new Vector2(1.5f * osuEnd.Scale),
+ });
+
+ using (fp.BeginAbsoluteSequence(fadeInTime))
+ {
+ fp.FadeIn(osuEnd.TimeFadeIn);
+ fp.ScaleTo(osuEnd.Scale, osuEnd.TimeFadeIn, Easing.Out);
+ fp.MoveTo(pointEndPosition, osuEnd.TimeFadeIn, Easing.Out);
+ fp.Delay(fadeOutTime - fadeInTime).FadeOut(osuEnd.TimeFadeIn);
+ }
+
+ fp.Expire(true);
+ }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs
index a269b87c75..be192080f9 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs
@@ -1,121 +1,110 @@
// 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 osuTK;
+using System.Linq;
+using osu.Framework.Extensions;
using osu.Framework.Graphics;
-using osu.Game.Rulesets.Objects.Types;
+using osu.Framework.Graphics.Containers;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
{
- public class FollowPointRenderer : ConnectionRenderer
+ ///
+ /// Visualises connections between s.
+ ///
+ public class FollowPointRenderer : CompositeDrawable
{
- private int pointDistance = 32;
-
///
- /// Determines how much space there is between points.
+ /// All the s contained by this .
///
- public int PointDistance
- {
- get => pointDistance;
- set
- {
- if (pointDistance == value) return;
+ internal IReadOnlyList Connections => connections;
- pointDistance = value;
- update();
- }
- }
-
- private int preEmpt = 800;
-
- ///
- /// Follow points to the next hitobject start appearing for this many milliseconds before an hitobject's end time.
- ///
- public int PreEmpt
- {
- get => preEmpt;
- set
- {
- if (preEmpt == value) return;
-
- preEmpt = value;
- update();
- }
- }
-
- private IEnumerable hitObjects;
-
- public override IEnumerable HitObjects
- {
- get => hitObjects;
- set
- {
- hitObjects = value;
- update();
- }
- }
+ private readonly List connections = new List();
public override bool RemoveCompletedTransforms => false;
- private void update()
+ ///
+ /// Adds the s around a .
+ /// This includes s leading into , and s exiting .
+ ///
+ /// The to add s for.
+ public void AddFollowPoints(DrawableOsuHitObject hitObject)
+ => addConnection(new FollowPointConnection(hitObject).With(g => g.StartTime.BindValueChanged(_ => onStartTimeChanged(g))));
+
+ ///
+ /// Removes the s around a .
+ /// This includes s leading into , and s exiting .
+ ///
+ /// The to remove s for.
+ public void RemoveFollowPoints(DrawableOsuHitObject hitObject) => removeGroup(connections.Single(g => g.Start == hitObject));
+
+ ///
+ /// Adds a to this .
+ ///
+ /// The to add.
+ /// The index of in .
+ private void addConnection(FollowPointConnection connection)
{
- ClearInternal();
+ AddInternal(connection);
- if (hitObjects == null)
- return;
+ // Groups are sorted by their start time when added such that the index can be used to post-process other surrounding connections
+ int index = connections.AddInPlace(connection, Comparer.Create((g1, g2) => g1.StartTime.Value.CompareTo(g2.StartTime.Value)));
- OsuHitObject prevHitObject = null;
-
- foreach (var currHitObject in hitObjects)
+ if (index < connections.Count - 1)
{
- if (prevHitObject != null && !currHitObject.NewCombo && !(prevHitObject is Spinner) && !(currHitObject is Spinner))
- {
- Vector2 startPosition = prevHitObject.EndPosition;
- Vector2 endPosition = currHitObject.Position;
- double startTime = (prevHitObject as IHasEndTime)?.EndTime ?? prevHitObject.StartTime;
- double endTime = currHitObject.StartTime;
+ // Update the connection's end point to the next connection's start point
+ // h1 -> -> -> h2
+ // connection nextGroup
- Vector2 distanceVector = endPosition - startPosition;
- int distance = (int)distanceVector.Length;
- float rotation = (float)(Math.Atan2(distanceVector.Y, distanceVector.X) * (180 / Math.PI));
- double duration = endTime - startTime;
-
- for (int d = (int)(PointDistance * 1.5); d < distance - PointDistance; d += PointDistance)
- {
- float fraction = (float)d / distance;
- Vector2 pointStartPosition = startPosition + (fraction - 0.1f) * distanceVector;
- Vector2 pointEndPosition = startPosition + fraction * distanceVector;
- double fadeOutTime = startTime + fraction * duration;
- double fadeInTime = fadeOutTime - PreEmpt;
-
- FollowPoint fp;
-
- AddInternal(fp = new FollowPoint
- {
- Position = pointStartPosition,
- Rotation = rotation,
- Alpha = 0,
- Scale = new Vector2(1.5f * currHitObject.Scale),
- });
-
- using (fp.BeginAbsoluteSequence(fadeInTime))
- {
- fp.FadeIn(currHitObject.TimeFadeIn);
- fp.ScaleTo(currHitObject.Scale, currHitObject.TimeFadeIn, Easing.Out);
-
- fp.MoveTo(pointEndPosition, currHitObject.TimeFadeIn, Easing.Out);
-
- fp.Delay(fadeOutTime - fadeInTime).FadeOut(currHitObject.TimeFadeIn);
- }
-
- fp.Expire(true);
- }
- }
-
- prevHitObject = currHitObject;
+ FollowPointConnection nextConnection = connections[index + 1];
+ connection.End = nextConnection.Start;
}
+ else
+ {
+ // The end point may be non-null during re-ordering
+ connection.End = null;
+ }
+
+ if (index > 0)
+ {
+ // Update the previous connection's end point to the current connection's start point
+ // h1 -> -> -> h2
+ // prevGroup connection
+
+ FollowPointConnection previousConnection = connections[index - 1];
+ previousConnection.End = connection.Start;
+ }
+ }
+
+ ///
+ /// Removes a from this .
+ ///
+ /// The to remove.
+ /// Whether was removed.
+ private void removeGroup(FollowPointConnection connection)
+ {
+ RemoveInternal(connection);
+
+ int index = connections.IndexOf(connection);
+
+ if (index > 0)
+ {
+ // Update the previous connection's end point to the next connection's start point
+ // h1 -> -> -> h2 -> -> -> h3
+ // prevGroup connection nextGroup
+ // The current connection's end point is used since there may not be a next connection
+ FollowPointConnection previousConnection = connections[index - 1];
+ previousConnection.End = connection.End;
+ }
+
+ connections.Remove(connection);
+ }
+
+ private void onStartTimeChanged(FollowPointConnection connection)
+ {
+ // Naive but can be improved if performance becomes an issue
+ removeGroup(connection);
+ addConnection(connection);
}
}
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs
index f60b7e67b2..3e23d09741 100644
--- a/osu.Game.Rulesets.Osu/Objects/Slider.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs
@@ -133,12 +133,14 @@ namespace osu.Game.Rulesets.Osu.Objects
var sampleList = new List();
if (firstSample != null)
+ {
sampleList.Add(new HitSampleInfo
{
Bank = firstSample.Bank,
Volume = firstSample.Volume,
Name = @"slidertick",
});
+ }
switch (e.Type)
{
diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
index 69e53d6eea..6d1ea4bbfc 100644
--- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
+++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
@@ -9,7 +9,6 @@ using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables.Connections;
using osu.Game.Rulesets.UI;
-using System.Linq;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Osu.UI.Cursor;
using osu.Game.Skinning;
@@ -20,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.UI
{
private readonly ApproachCircleProxyContainer approachCircles;
private readonly JudgementContainer judgementLayer;
- private readonly ConnectionRenderer connectionLayer;
+ private readonly FollowPointRenderer followPoints;
public static readonly Vector2 BASE_SIZE = new Vector2(512, 384);
@@ -30,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.UI
{
InternalChildren = new Drawable[]
{
- connectionLayer = new FollowPointRenderer
+ followPoints = new FollowPointRenderer
{
RelativeSizeAxes = Axes.Both,
Depth = 2,
@@ -64,11 +63,18 @@ namespace osu.Game.Rulesets.Osu.UI
};
base.Add(h);
+
+ followPoints.AddFollowPoints((DrawableOsuHitObject)h);
}
- public override void PostProcess()
+ public override bool Remove(DrawableHitObject h)
{
- connectionLayer.HitObjects = HitObjectContainer.Objects.Select(d => d.HitObject).OfType();
+ bool result = base.Remove(h);
+
+ if (result)
+ followPoints.RemoveFollowPoints((DrawableOsuHitObject)h);
+
+ return result;
}
private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj
index b0ca314551..fb3fe8808d 100644
--- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj
+++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj
@@ -1,9 +1,7 @@
-
netstandard2.0
Library
- AnyCPU
true
click the circles. to the beat.
diff --git a/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj b/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj
index 3e46bb89af..8ee640cd99 100644
--- a/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj
+++ b/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj
@@ -1,6 +1,5 @@
-
+
-
Debug
iPhoneSimulator
@@ -33,5 +32,4 @@
-
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
index 717e795112..b5bd384e05 100644
--- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
+++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
@@ -2,7 +2,7 @@
-
+
diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj
index 656ebcc7c2..0a2b189c3a 100644
--- a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj
+++ b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj
@@ -1,9 +1,7 @@
-
netstandard2.0
Library
- AnyCPU
true
bash the drum. to the beat.
diff --git a/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj b/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj
index 5c0713b895..ca68369ebb 100644
--- a/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj
+++ b/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj
@@ -1,6 +1,5 @@
-
+
-
Debug
iPhoneSimulator
@@ -48,5 +47,4 @@
-
\ No newline at end of file
diff --git a/osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs b/osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs
index 18cbd4e7c5..7df7df22ea 100644
--- a/osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs
+++ b/osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs
@@ -225,8 +225,10 @@ namespace osu.Game.Tests.NonVisual
private void fastForwardToPoint(double destination)
{
for (int i = 0; i < 1000; i++)
+ {
if (handler.SetFrameFromTime(destination) == null)
return;
+ }
throw new TimeoutException("Seek was never fulfilled");
}
diff --git a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs
index 0d96dd08da..085f502517 100644
--- a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs
+++ b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs
@@ -25,7 +25,9 @@ namespace osu.Game.Tests.Skins
var comboColors = decoder.Decode(stream).ComboColours;
List expectedColors;
+
if (hasColours)
+ {
expectedColors = new List
{
new Color4(142, 199, 255, 255),
@@ -33,6 +35,7 @@ namespace osu.Game.Tests.Skins
new Color4(128, 255, 255, 255),
new Color4(100, 100, 100, 100),
};
+ }
else
expectedColors = new DefaultSkin().Configuration.ComboColours;
diff --git a/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs b/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs
index df6740421b..f3f6444149 100644
--- a/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs
+++ b/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs
@@ -34,6 +34,7 @@ namespace osu.Game.Tests.Visual.Components
PreviewTrack track = null;
AddStep("get track", () => track = getOwnedTrack());
+ AddUntilStep("wait loaded", () => track.IsLoaded);
AddStep("start", () => track.Start());
AddAssert("started", () => track.IsRunning);
AddStep("stop", () => track.Stop());
@@ -52,6 +53,8 @@ namespace osu.Game.Tests.Visual.Components
track2 = getOwnedTrack();
});
+ AddUntilStep("wait loaded", () => track1.IsLoaded && track2.IsLoaded);
+
AddStep("start track 1", () => track1.Start());
AddStep("start track 2", () => track2.Start());
AddAssert("track 1 stopped", () => !track1.IsRunning);
@@ -64,6 +67,7 @@ namespace osu.Game.Tests.Visual.Components
PreviewTrack track = null;
AddStep("get track", () => track = getOwnedTrack());
+ AddUntilStep("wait loaded", () => track.IsLoaded);
AddStep("start", () => track.Start());
AddStep("stop by owner", () => trackManager.StopAnyPlaying(this));
AddAssert("stopped", () => !track.IsRunning);
@@ -76,6 +80,7 @@ namespace osu.Game.Tests.Visual.Components
PreviewTrack track = null;
AddStep("get track", () => Add(owner = new TestTrackOwner(track = getTrack())));
+ AddUntilStep("wait loaded", () => track.IsLoaded);
AddStep("start", () => track.Start());
AddStep("attempt stop", () => trackManager.StopAnyPlaying(this));
AddAssert("not stopped", () => track.IsRunning);
@@ -89,16 +94,24 @@ namespace osu.Game.Tests.Visual.Components
{
var track = getTrack();
- Add(track);
+ LoadComponentAsync(track, Add);
return track;
}
private class TestTrackOwner : CompositeDrawable, IPreviewTrackOwner
{
+ private readonly PreviewTrack track;
+
public TestTrackOwner(PreviewTrack track)
{
- AddInternal(track);
+ this.track = track;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ LoadComponentAsync(track, AddInternal);
}
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
diff --git a/osu.Game.Tests/Visual/Editor/TestSceneDistanceSnapGrid.cs b/osu.Game.Tests/Visual/Editor/TestSceneDistanceSnapGrid.cs
index b8c31d5dbb..e4c987923c 100644
--- a/osu.Game.Tests/Visual/Editor/TestSceneDistanceSnapGrid.cs
+++ b/osu.Game.Tests/Visual/Editor/TestSceneDistanceSnapGrid.cs
@@ -32,7 +32,11 @@ namespace osu.Game.Tests.Visual.Editor
{
editorBeatmap = new EditorBeatmap(new OsuBeatmap());
editorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = beat_length });
+ }
+ [SetUp]
+ public void Setup() => Schedule(() =>
+ {
Children = new Drawable[]
{
new Box
@@ -42,7 +46,7 @@ namespace osu.Game.Tests.Visual.Editor
},
new TestDistanceSnapGrid(new HitObject(), grid_position)
};
- }
+ });
[TestCase(1)]
[TestCase(2)]
@@ -57,12 +61,29 @@ namespace osu.Game.Tests.Visual.Editor
AddStep($"set beat divisor = {divisor}", () => BeatDivisor.Value = divisor);
}
+ [Test]
+ public void TestLimitedDistance()
+ {
+ AddStep("create limited grid", () =>
+ {
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.SlateGray
+ },
+ new TestDistanceSnapGrid(new HitObject(), grid_position, new HitObject { StartTime = 100 })
+ };
+ });
+ }
+
private class TestDistanceSnapGrid : DistanceSnapGrid
{
public new float DistanceSpacing => base.DistanceSpacing;
- public TestDistanceSnapGrid(HitObject hitObject, Vector2 centrePosition)
- : base(hitObject, centrePosition)
+ public TestDistanceSnapGrid(HitObject hitObject, Vector2 centrePosition, HitObject nextHitObject = null)
+ : base(hitObject, nextHitObject, centrePosition)
{
}
@@ -77,7 +98,7 @@ namespace osu.Game.Tests.Visual.Editor
int beatIndex = 0;
- for (float s = centrePosition.X + DistanceSpacing; s <= DrawWidth; s += DistanceSpacing, beatIndex++)
+ for (float s = centrePosition.X + DistanceSpacing; s <= DrawWidth && beatIndex < MaxIntervals; s += DistanceSpacing, beatIndex++)
{
AddInternal(new Circle
{
@@ -90,7 +111,7 @@ namespace osu.Game.Tests.Visual.Editor
beatIndex = 0;
- for (float s = centrePosition.X - DistanceSpacing; s >= 0; s -= DistanceSpacing, beatIndex++)
+ for (float s = centrePosition.X - DistanceSpacing; s >= 0 && beatIndex < MaxIntervals; s -= DistanceSpacing, beatIndex++)
{
AddInternal(new Circle
{
@@ -103,7 +124,7 @@ namespace osu.Game.Tests.Visual.Editor
beatIndex = 0;
- for (float s = centrePosition.Y + DistanceSpacing; s <= DrawHeight; s += DistanceSpacing, beatIndex++)
+ for (float s = centrePosition.Y + DistanceSpacing; s <= DrawHeight && beatIndex < MaxIntervals; s += DistanceSpacing, beatIndex++)
{
AddInternal(new Circle
{
@@ -116,7 +137,7 @@ namespace osu.Game.Tests.Visual.Editor
beatIndex = 0;
- for (float s = centrePosition.Y - DistanceSpacing; s >= 0; s -= DistanceSpacing, beatIndex++)
+ for (float s = centrePosition.Y - DistanceSpacing; s >= 0 && beatIndex < MaxIntervals; s -= DistanceSpacing, beatIndex++)
{
AddInternal(new Circle
{
@@ -138,9 +159,9 @@ namespace osu.Game.Tests.Visual.Editor
public float GetBeatSnapDistanceAt(double referenceTime) => 10;
- public float DurationToDistance(double referenceTime, double duration) => 0;
+ public float DurationToDistance(double referenceTime, double duration) => (float)duration;
- public double DistanceToDuration(double referenceTime, float distance) => 0;
+ public double DistanceToDuration(double referenceTime, float distance) => distance;
public double GetSnappedDurationFromDistance(double referenceTime, float distance) => 0;
diff --git a/osu.Game.Tests/Visual/Editor/TestSceneEditorComposeTimeline.cs b/osu.Game.Tests/Visual/Editor/TestSceneEditorComposeTimeline.cs
index a8c2362910..6e5b3b93e9 100644
--- a/osu.Game.Tests/Visual/Editor/TestSceneEditorComposeTimeline.cs
+++ b/osu.Game.Tests/Visual/Editor/TestSceneEditorComposeTimeline.cs
@@ -10,9 +10,9 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
-using osu.Framework.Graphics.UserInterface;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
+using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Edit.Compose.Components.Timeline;
using osuTK;
using osuTK.Graphics;
@@ -101,7 +101,7 @@ namespace osu.Game.Tests.Visual.Editor
}
}
- private class StartStopButton : Button
+ private class StartStopButton : OsuButton
{
private IAdjustableClock adjustableClock;
private bool started;
diff --git a/osu.Game.Tests/Visual/Editor/TestSceneTimingScreen.cs b/osu.Game.Tests/Visual/Editor/TestSceneTimingScreen.cs
new file mode 100644
index 0000000000..121853d8d0
--- /dev/null
+++ b/osu.Game.Tests/Visual/Editor/TestSceneTimingScreen.cs
@@ -0,0 +1,35 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Game.Rulesets.Osu;
+using osu.Game.Screens.Edit.Timing;
+
+namespace osu.Game.Tests.Visual.Editor
+{
+ [TestFixture]
+ public class TestSceneTimingScreen : EditorClockTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(ControlPointTable),
+ typeof(ControlPointSettings),
+ typeof(Section<>),
+ typeof(TimingSection),
+ typeof(EffectSection),
+ typeof(SampleSection),
+ typeof(DifficultySection),
+ typeof(RowAttribute)
+ };
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
+ Child = new TimingScreen();
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs
index 64022b2410..6e8975f11b 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs
@@ -237,6 +237,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddUntilStep("player not exited", () => Player.IsCurrentScreen());
AddStep("exit", () => Player.Exit());
confirmExited();
+ confirmNoTrackAdjustments();
}
private void confirmPaused()
@@ -258,6 +259,11 @@ namespace osu.Game.Tests.Visual.Gameplay
AddUntilStep("player exited", () => !Player.IsCurrentScreen());
}
+ private void confirmNoTrackAdjustments()
+ {
+ AddAssert("track has no adjustments", () => Beatmap.Value.Track.AggregateFrequency.Value == 1);
+ }
+
private void restart() => AddStep("restart", () => Player.Restart());
private void pause() => AddStep("pause", () => Player.Pause());
private void resume() => AddStep("resume", () => Player.Resume());
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs
index bf26892539..7790126db5 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs
@@ -3,11 +3,16 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Screens;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
+using osu.Game.Screens;
using osu.Game.Screens.Play;
using osu.Game.Screens.Ranking;
using osu.Game.Screens.Ranking.Pages;
@@ -27,7 +32,8 @@ namespace osu.Game.Tests.Visual.Gameplay
typeof(ScoreResultsPage),
typeof(RetryButton),
typeof(ReplayDownloadButton),
- typeof(LocalLeaderboardPage)
+ typeof(LocalLeaderboardPage),
+ typeof(TestPlayer)
};
[BackgroundDependencyLoader]
@@ -43,26 +49,82 @@ namespace osu.Game.Tests.Visual.Gameplay
var beatmapInfo = beatmaps.QueryBeatmap(b => b.RulesetID == 0);
if (beatmapInfo != null)
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmapInfo);
+ }
- LoadScreen(new SoloResults(new ScoreInfo
+ private TestSoloResults createResultsScreen() => new TestSoloResults(new ScoreInfo
+ {
+ TotalScore = 2845370,
+ Accuracy = 0.98,
+ MaxCombo = 123,
+ Rank = ScoreRank.A,
+ Date = DateTimeOffset.Now,
+ Statistics = new Dictionary
{
- TotalScore = 2845370,
- Accuracy = 0.98,
- MaxCombo = 123,
- Rank = ScoreRank.A,
- Date = DateTimeOffset.Now,
- Statistics = new Dictionary
+ { HitResult.Great, 50 },
+ { HitResult.Good, 20 },
+ { HitResult.Meh, 50 },
+ { HitResult.Miss, 1 }
+ },
+ User = new User
+ {
+ Username = "peppy",
+ }
+ });
+
+ [Test]
+ public void ResultsWithoutPlayer()
+ {
+ TestSoloResults screen = null;
+
+ AddStep("load results", () => Child = new OsuScreenStack(screen = createResultsScreen())
+ {
+ RelativeSizeAxes = Axes.Both
+ });
+ AddUntilStep("wait for loaded", () => screen.IsLoaded);
+ AddAssert("retry overlay not present", () => screen.RetryOverlay == null);
+ }
+
+ [Test]
+ public void ResultsWithPlayer()
+ {
+ TestSoloResults screen = null;
+
+ AddStep("load results", () => Child = new TestResultsContainer(screen = createResultsScreen()));
+ AddUntilStep("wait for loaded", () => screen.IsLoaded);
+ AddAssert("retry overlay present", () => screen.RetryOverlay != null);
+ }
+
+ private class TestResultsContainer : Container
+ {
+ [Cached(typeof(Player))]
+ private readonly Player player = new TestPlayer();
+
+ public TestResultsContainer(IScreen screen)
+ {
+ RelativeSizeAxes = Axes.Both;
+
+ InternalChild = new OsuScreenStack(screen)
{
- { HitResult.Great, 50 },
- { HitResult.Good, 20 },
- { HitResult.Meh, 50 },
- { HitResult.Miss, 1 }
- },
- User = new User
- {
- Username = "peppy",
- }
- }));
+ RelativeSizeAxes = Axes.Both,
+ };
+ }
+ }
+
+ private class TestSoloResults : SoloResults
+ {
+ public HotkeyRetryOverlay RetryOverlay;
+
+ public TestSoloResults(ScoreInfo score)
+ : base(score)
+ {
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ RetryOverlay = InternalChildren.OfType().SingleOrDefault();
+ }
}
}
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs
index b3d4820737..8beb107269 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs
@@ -326,7 +326,11 @@ namespace osu.Game.Tests.Visual.Gameplay
public IBindable GetConfig(TLookup lookup) => throw new NotImplementedException();
- public event Action SourceChanged;
+ public event Action SourceChanged
+ {
+ add { }
+ remove { }
+ }
}
private class TestSkinComponent : ISkinComponent
diff --git a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs
index 01400bf1d9..28b5693ef4 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs
@@ -130,12 +130,14 @@ namespace osu.Game.Tests.Visual.Online
AddRepeatStep("add many messages", () =>
{
for (int i = 0; i < messages_per_call; i++)
+ {
testChannel.AddNewMessages(new Message(sequence++)
{
Sender = longUsernameUser,
Content = "Many messages! " + Guid.NewGuid(),
Timestamp = DateTimeOffset.Now
});
+ }
}, Channel.MAX_HISTORY / messages_per_call + 5);
AddAssert("Ensure no adjacent day separators", () =>
@@ -143,8 +145,10 @@ namespace osu.Game.Tests.Visual.Online
var indices = chatDisplay.FillFlow.OfType().Select(ds => chatDisplay.FillFlow.IndexOf(ds));
foreach (var i in indices)
+ {
if (i < chatDisplay.FillFlow.Count && chatDisplay.FillFlow[i + 1] is DrawableChannel.DaySeparator)
return false;
+ }
return true;
});
diff --git a/osu.Game.Tests/Visual/Online/TestSceneVotePill.cs b/osu.Game.Tests/Visual/Online/TestSceneVotePill.cs
new file mode 100644
index 0000000000..8197cf72de
--- /dev/null
+++ b/osu.Game.Tests/Visual/Online/TestSceneVotePill.cs
@@ -0,0 +1,76 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+using osu.Framework.Graphics;
+using osu.Game.Overlays.Comments;
+using osu.Game.Online.API.Requests.Responses;
+
+namespace osu.Game.Tests.Visual.Online
+{
+ [TestFixture]
+ public class TestSceneVotePill : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(VotePill)
+ };
+
+ private VotePill votePill;
+
+ [Test]
+ public void TestUserCommentPill()
+ {
+ AddStep("Log in", logIn);
+ AddStep("User comment", () => addVotePill(getUserComment()));
+ AddStep("Click", () => votePill.Click());
+ AddAssert("Not loading", () => !votePill.IsLoading);
+ }
+
+ [Test]
+ public void TestRandomCommentPill()
+ {
+ AddStep("Log in", logIn);
+ AddStep("Random comment", () => addVotePill(getRandomComment()));
+ AddStep("Click", () => votePill.Click());
+ AddAssert("Loading", () => votePill.IsLoading);
+ }
+
+ [Test]
+ public void TestOfflineRandomCommentPill()
+ {
+ AddStep("Log out", API.Logout);
+ AddStep("Random comment", () => addVotePill(getRandomComment()));
+ AddStep("Click", () => votePill.Click());
+ AddAssert("Not loading", () => !votePill.IsLoading);
+ }
+
+ private void logIn() => API.Login("localUser", "password");
+
+ private Comment getUserComment() => new Comment
+ {
+ IsVoted = false,
+ UserId = API.LocalUser.Value.Id,
+ VotesCount = 10,
+ };
+
+ private Comment getRandomComment() => new Comment
+ {
+ IsVoted = false,
+ UserId = 4444,
+ VotesCount = 2,
+ };
+
+ private void addVotePill(Comment comment)
+ {
+ Clear();
+ Add(votePill = new VotePill(comment)
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ });
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
index 8b82567a8d..aa63bc1cf6 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
@@ -467,8 +467,10 @@ namespace osu.Game.Tests.Visual.SongSelect
private void advanceSelection(bool diff, int direction = 1, int count = 1)
{
if (count == 1)
+ {
AddStep($"select {(direction > 0 ? "next" : "prev")} {(diff ? "diff" : "set")}", () =>
carousel.SelectNext(direction, !diff));
+ }
else
{
AddRepeatStep($"select {(direction > 0 ? "next" : "prev")} {(diff ? "diff" : "set")}", () =>
diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
index efe7fee5e4..794d135b06 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
@@ -132,11 +132,13 @@ namespace osu.Game.Tests.Visual.SongSelect
changeRuleset(1);
if (rulesetsInSameBeatmap)
+ {
AddStep("import multi-ruleset map", () =>
{
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray();
manager.Import(createTestBeatmapSet(0, usableRulesets)).Wait();
});
+ }
else
{
addRulesetImportStep(1);
diff --git a/osu.Game.Tests/Visual/TestSceneOsuGame.cs b/osu.Game.Tests/Visual/TestSceneOsuGame.cs
index fcc3a3596f..36cd49d839 100644
--- a/osu.Game.Tests/Visual/TestSceneOsuGame.cs
+++ b/osu.Game.Tests/Visual/TestSceneOsuGame.cs
@@ -109,16 +109,20 @@ namespace osu.Game.Tests.Visual
AddAssert("check OsuGame DI members", () =>
{
foreach (var type in requiredGameDependencies)
+ {
if (game.Dependencies.Get(type) == null)
throw new Exception($"{type} has not been cached");
+ }
return true;
});
AddAssert("check OsuGameBase DI members", () =>
{
foreach (var type in requiredGameBaseDependencies)
+ {
if (gameBase.Dependencies.Get(type) == null)
throw new Exception($"{type} has not been cached");
+ }
return true;
});
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs
new file mode 100644
index 0000000000..2ada5b927b
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs
@@ -0,0 +1,145 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Sprites;
+using osu.Game.Graphics.UserInterface;
+using osuTK.Input;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ public class TestSceneStatefulMenuItem : ManualInputManagerTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(OsuMenu),
+ typeof(StatefulMenuItem),
+ typeof(TernaryStateMenuItem),
+ typeof(DrawableStatefulMenuItem),
+ };
+
+ [Test]
+ public void TestTernaryMenuItem()
+ {
+ OsuMenu menu = null;
+
+ Bindable state = new Bindable(TernaryState.Indeterminate);
+
+ AddStep("create menu", () =>
+ {
+ state.Value = TernaryState.Indeterminate;
+
+ Child = menu = new OsuMenu(Direction.Vertical, true)
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Items = new[]
+ {
+ new TernaryStateMenuItem("First"),
+ new TernaryStateMenuItem("Second") { State = { BindTarget = state } },
+ new TernaryStateMenuItem("Third") { State = { Value = TernaryState.True } },
+ }
+ };
+ });
+
+ checkState(TernaryState.Indeterminate);
+
+ click();
+ checkState(TernaryState.True);
+
+ click();
+ checkState(TernaryState.False);
+
+ click();
+ checkState(TernaryState.True);
+
+ click();
+ checkState(TernaryState.False);
+
+ AddStep("change state via bindable", () => state.Value = TernaryState.True);
+
+ void click() =>
+ AddStep("click", () =>
+ {
+ InputManager.MoveMouseTo(menu.ScreenSpaceDrawQuad.Centre);
+ InputManager.Click(MouseButton.Left);
+ });
+
+ void checkState(TernaryState expected)
+ => AddAssert($"state is {expected}", () => state.Value == expected);
+ }
+
+ [Test]
+ public void TestCustomState()
+ {
+ AddStep("create menu", () =>
+ {
+ Child = new OsuMenu(Direction.Vertical, true)
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Items = new[]
+ {
+ new TestMenuItem("First", MenuItemType.Standard, getNextState),
+ new TestMenuItem("Second", MenuItemType.Standard, getNextState) { State = { Value = TestStates.State2 } },
+ new TestMenuItem("Third", MenuItemType.Standard, getNextState) { State = { Value = TestStates.State3 } },
+ }
+ };
+ });
+ }
+
+ private TestStates getNextState(TestStates state)
+ {
+ switch (state)
+ {
+ case TestStates.State1:
+ return TestStates.State2;
+
+ case TestStates.State2:
+ return TestStates.State3;
+
+ case TestStates.State3:
+ return TestStates.State1;
+ }
+
+ return TestStates.State1;
+ }
+
+ private class TestMenuItem : StatefulMenuItem
+ {
+ public TestMenuItem(string text, MenuItemType type, Func changeStateFunc)
+ : base(text, changeStateFunc, type)
+ {
+ }
+
+ public override IconUsage? GetIconForState(TestStates state)
+ {
+ switch (state)
+ {
+ case TestStates.State1:
+ return FontAwesome.Solid.DiceOne;
+
+ case TestStates.State2:
+ return FontAwesome.Solid.DiceTwo;
+
+ case TestStates.State3:
+ return FontAwesome.Solid.DiceThree;
+
+ default:
+ throw new ArgumentOutOfRangeException(nameof(state), state, null);
+ }
+ }
+ }
+
+ private enum TestStates
+ {
+ State1,
+ State2,
+ State3
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs
new file mode 100644
index 0000000000..2abda56a28
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs
@@ -0,0 +1,34 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using osu.Framework.Graphics;
+using osu.Game.Graphics.UserInterface;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ public class TestSceneToggleMenuItem : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(OsuMenu),
+ typeof(ToggleMenuItem),
+ typeof(DrawableStatefulMenuItem)
+ };
+
+ public TestSceneToggleMenuItem()
+ {
+ Add(new OsuMenu(Direction.Vertical, true)
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Items = new[]
+ {
+ new ToggleMenuItem("First"),
+ new ToggleMenuItem("Second") { State = { Value = true } }
+ }
+ });
+ }
+ }
+}
diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj
index aa29fc802c..c5998c9cfc 100644
--- a/osu.Game.Tests/osu.Game.Tests.csproj
+++ b/osu.Game.Tests/osu.Game.Tests.csproj
@@ -3,7 +3,7 @@
-
+
diff --git a/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs b/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs
index 41d32d9448..9905e17824 100644
--- a/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs
+++ b/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs
@@ -102,7 +102,8 @@ namespace osu.Game.Tournament.Tests.Components
Content = "Okay okay, calm down guys. Let's do this!"
}));
- AddStep("multiple messages", () => testChannel.AddNewMessages(new Message(nextMessageId())
+ AddStep("multiple messages", () => testChannel.AddNewMessages(
+ new Message(nextMessageId())
{
Sender = admin,
Content = "I spam you!"
diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneTeamIntroScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneTeamIntroScreen.cs
index 3d340e393c..e36b594ff2 100644
--- a/osu.Game.Tournament.Tests/Screens/TestSceneTeamIntroScreen.cs
+++ b/osu.Game.Tournament.Tests/Screens/TestSceneTeamIntroScreen.cs
@@ -3,7 +3,6 @@
using System.Linq;
using osu.Framework.Allocation;
-using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Game.Tournament.Models;
using osu.Game.Tournament.Screens.TeamIntro;
@@ -13,7 +12,7 @@ namespace osu.Game.Tournament.Tests.Screens
public class TestSceneTeamIntroScreen : LadderTestScene
{
[Cached]
- private readonly Bindable currentMatch = new Bindable();
+ private readonly LadderInfo ladder = new LadderInfo();
[BackgroundDependencyLoader]
private void load()
@@ -22,7 +21,7 @@ namespace osu.Game.Tournament.Tests.Screens
match.Team1.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym.Value == "USA");
match.Team2.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym.Value == "JPN");
match.Round.Value = Ladder.Rounds.FirstOrDefault(g => g.Name.Value == "Finals");
- currentMatch.Value = match;
+ ladder.CurrentMatch.Value = match;
Add(new TeamIntroScreen
{
diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs
index 6f5e17a36e..5cb35a506f 100644
--- a/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs
+++ b/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs
@@ -3,7 +3,6 @@
using System.Linq;
using osu.Framework.Allocation;
-using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Game.Tournament.Models;
using osu.Game.Tournament.Screens.TeamWin;
@@ -13,7 +12,7 @@ namespace osu.Game.Tournament.Tests.Screens
public class TestSceneTeamWinScreen : LadderTestScene
{
[Cached]
- private readonly Bindable currentMatch = new Bindable();
+ private readonly LadderInfo ladder = new LadderInfo();
[BackgroundDependencyLoader]
private void load()
@@ -22,7 +21,7 @@ namespace osu.Game.Tournament.Tests.Screens
match.Team1.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym.Value == "USA");
match.Team2.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym.Value == "JPN");
match.Round.Value = Ladder.Rounds.FirstOrDefault(g => g.Name.Value == "Finals");
- currentMatch.Value = match;
+ ladder.CurrentMatch.Value = match;
Add(new TeamWinScreen
{
diff --git a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj
index 371ffcdf9e..d58a724c27 100644
--- a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj
+++ b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj
@@ -5,7 +5,7 @@
-
+
diff --git a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs
index f6c1be0e36..0908814537 100644
--- a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs
+++ b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs
@@ -131,6 +131,7 @@ namespace osu.Game.Tournament.Components
});
if (!string.IsNullOrEmpty(mods))
+ {
AddInternal(new Sprite
{
Texture = textures.Get($"mods/{mods}"),
@@ -139,6 +140,7 @@ namespace osu.Game.Tournament.Components
Margin = new MarginPadding(20),
Scale = new Vector2(0.5f)
});
+ }
}
private void matchChanged(ValueChangedEvent match)
diff --git a/osu.Game.Tournament/Components/TourneyVideo.cs b/osu.Game.Tournament/Components/TourneyVideo.cs
index 4f4660f645..206689ca1a 100644
--- a/osu.Game.Tournament/Components/TourneyVideo.cs
+++ b/osu.Game.Tournament/Components/TourneyVideo.cs
@@ -7,6 +7,7 @@ using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Video;
+using osu.Framework.Timing;
using osu.Game.Graphics;
namespace osu.Game.Tournament.Components
@@ -15,6 +16,8 @@ namespace osu.Game.Tournament.Components
{
private readonly VideoSprite video;
+ private readonly ManualClock manualClock;
+
public TourneyVideo(Stream stream)
{
if (stream == null)
@@ -26,11 +29,14 @@ namespace osu.Game.Tournament.Components
};
}
else
+ {
InternalChild = video = new VideoSprite(stream)
{
RelativeSizeAxes = Axes.Both,
FillMode = FillMode.Fit,
+ Clock = new FramedClock(manualClock = new ManualClock())
};
+ }
}
public bool Loop
@@ -41,5 +47,17 @@ namespace osu.Game.Tournament.Components
video.Loop = value;
}
}
+
+ protected override void Update()
+ {
+ base.Update();
+
+ if (manualClock != null && Clock.ElapsedFrameTime < 100)
+ {
+ // we want to avoid seeking as much as possible, because we care about performance, not sync.
+ // to avoid seeking completely, we only increment out local clock when in an updating state.
+ manualClock.CurrentTime += Clock.ElapsedFrameTime;
+ }
+ }
}
}
diff --git a/osu.Game.Tournament/IPC/FileBasedIPC.cs b/osu.Game.Tournament/IPC/FileBasedIPC.cs
index e05d96e098..47f2bed77a 100644
--- a/osu.Game.Tournament/IPC/FileBasedIPC.cs
+++ b/osu.Game.Tournament/IPC/FileBasedIPC.cs
@@ -60,6 +60,7 @@ namespace osu.Game.Tournament.IPC
const string file_ipc_channel_filename = "ipc-channel.txt";
if (Storage.Exists(file_ipc_filename))
+ {
scheduled = Scheduler.AddDelayed(delegate
{
try
@@ -134,6 +135,7 @@ namespace osu.Game.Tournament.IPC
// file might be in use.
}
}, 250, true);
+ }
}
catch (Exception e)
{
diff --git a/osu.Game.Tournament/Screens/Drawings/DrawingsScreen.cs b/osu.Game.Tournament/Screens/Drawings/DrawingsScreen.cs
index 3a14b6d9c2..5efa0a1e69 100644
--- a/osu.Game.Tournament/Screens/Drawings/DrawingsScreen.cs
+++ b/osu.Game.Tournament/Screens/Drawings/DrawingsScreen.cs
@@ -15,7 +15,6 @@ using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
-using osu.Game.Graphics.UserInterface;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.Models;
using osu.Game.Tournament.Screens.Drawings.Components;
@@ -24,7 +23,7 @@ using osuTK.Graphics;
namespace osu.Game.Tournament.Screens.Drawings
{
- public class DrawingsScreen : CompositeDrawable
+ public class DrawingsScreen : TournamentScreen
{
private const string results_filename = "drawings_results.txt";
@@ -128,21 +127,21 @@ namespace osu.Game.Tournament.Screens.Drawings
// Control panel container
new ControlPanel
{
- new OsuButton
+ new TourneyButton
{
RelativeSizeAxes = Axes.X,
Text = "Begin random",
Action = teamsContainer.StartScrolling,
},
- new OsuButton
+ new TourneyButton
{
RelativeSizeAxes = Axes.X,
Text = "Stop random",
Action = teamsContainer.StopScrolling,
},
- new OsuButton
+ new TourneyButton
{
RelativeSizeAxes = Axes.X,
@@ -150,7 +149,7 @@ namespace osu.Game.Tournament.Screens.Drawings
Action = reloadTeams
},
new ControlPanel.Spacer(),
- new OsuButton
+ new TourneyButton
{
RelativeSizeAxes = Axes.X,
@@ -195,7 +194,7 @@ namespace osu.Game.Tournament.Screens.Drawings
}
}
- writeOp = writeOp?.ContinueWith(t => { writeAction(); }) ?? Task.Run((Action)writeAction);
+ writeOp = writeOp?.ContinueWith(t => { writeAction(); }) ?? Task.Run(writeAction);
}
private void reloadTeams()
diff --git a/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs
index b036350879..2c515edda7 100644
--- a/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs
+++ b/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs
@@ -266,12 +266,14 @@ namespace osu.Game.Tournament.Screens.Editors
drawableContainer.Clear();
if (Model.BeatmapInfo != null)
+ {
drawableContainer.Child = new TournamentBeatmapPanel(Model.BeatmapInfo, Model.Mods)
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Width = 300
};
+ }
}
}
}
diff --git a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs
index a4479f3cfd..e1f6d16623 100644
--- a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs
+++ b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs
@@ -11,7 +11,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
-using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.Settings;
@@ -32,7 +31,7 @@ namespace osu.Game.Tournament.Screens.Editors
[BackgroundDependencyLoader]
private void load()
{
- ControlPanel.Add(new OsuButton
+ ControlPanel.Add(new TourneyButton
{
RelativeSizeAxes = Axes.X,
Text = "Add all countries",
diff --git a/osu.Game.Tournament/Screens/Editors/TournamentEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/TournamentEditorScreen.cs
index 50d3207345..32cf6bbcc8 100644
--- a/osu.Game.Tournament/Screens/Editors/TournamentEditorScreen.cs
+++ b/osu.Game.Tournament/Screens/Editors/TournamentEditorScreen.cs
@@ -9,7 +9,6 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
-using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Settings;
using osu.Game.Tournament.Components;
using osuTK;
@@ -56,7 +55,7 @@ namespace osu.Game.Tournament.Screens.Editors
{
Children = new Drawable[]
{
- new OsuButton
+ new TourneyButton
{
RelativeSizeAxes = Axes.X,
Text = "Add new",
diff --git a/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs b/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs
index b9a74bfe16..6a3095d42d 100644
--- a/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs
+++ b/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs
@@ -103,13 +103,13 @@ namespace osu.Game.Tournament.Screens.Gameplay
{
Children = new Drawable[]
{
- warmupButton = new OsuButton
+ warmupButton = new TourneyButton
{
RelativeSizeAxes = Axes.X,
Text = "Toggle warmup",
Action = () => warmup.Toggle()
},
- new OsuButton
+ new TourneyButton
{
RelativeSizeAxes = Axes.X,
Text = "Toggle chat",
diff --git a/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs b/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs
index 83a41a662f..66e68a0f37 100644
--- a/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs
+++ b/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs
@@ -81,8 +81,10 @@ namespace osu.Game.Tournament.Screens.Ladder
LadderInfo.Matches.ItemsRemoved += matches =>
{
foreach (var p in matches)
- foreach (var d in MatchesContainer.Where(d => d.Match == p))
- d.Expire();
+ {
+ foreach (var d in MatchesContainer.Where(d => d.Match == p))
+ d.Expire();
+ }
layout.Invalidate();
};
diff --git a/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs b/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs
index ec55bb5b54..7a5fc2cd06 100644
--- a/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs
+++ b/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs
@@ -60,32 +60,32 @@ namespace osu.Game.Tournament.Screens.MapPool
{
Text = "Current Mode"
},
- buttonRedBan = new OsuButton
+ buttonRedBan = new TourneyButton
{
RelativeSizeAxes = Axes.X,
Text = "Red Ban",
Action = () => setMode(TeamColour.Red, ChoiceType.Ban)
},
- buttonBlueBan = new OsuButton
+ buttonBlueBan = new TourneyButton
{
RelativeSizeAxes = Axes.X,
Text = "Blue Ban",
Action = () => setMode(TeamColour.Blue, ChoiceType.Ban)
},
- buttonRedPick = new OsuButton
+ buttonRedPick = new TourneyButton
{
RelativeSizeAxes = Axes.X,
Text = "Red Pick",
Action = () => setMode(TeamColour.Red, ChoiceType.Pick)
},
- buttonBluePick = new OsuButton
+ buttonBluePick = new TourneyButton
{
RelativeSizeAxes = Axes.X,
Text = "Blue Pick",
Action = () => setMode(TeamColour.Blue, ChoiceType.Pick)
},
new ControlPanel.Spacer(),
- new OsuButton
+ new TourneyButton
{
RelativeSizeAxes = Axes.X,
Text = "Reset",
diff --git a/osu.Game.Tournament/Screens/TeamIntro/TeamIntroScreen.cs b/osu.Game.Tournament/Screens/TeamIntro/TeamIntroScreen.cs
index c901a5c7ef..47c923ff30 100644
--- a/osu.Game.Tournament/Screens/TeamIntro/TeamIntroScreen.cs
+++ b/osu.Game.Tournament/Screens/TeamIntro/TeamIntroScreen.cs
@@ -164,6 +164,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro
if (team != null)
{
foreach (var p in team.Players)
+ {
players.Add(new OsuSpriteText
{
Text = p.Username,
@@ -172,6 +173,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro
Anchor = left ? Anchor.CentreRight : Anchor.CentreLeft,
Origin = left ? Anchor.CentreRight : Anchor.CentreLeft,
});
+ }
}
}
diff --git a/osu.Game.Tournament/Screens/TournamentScreen.cs b/osu.Game.Tournament/Screens/TournamentScreen.cs
index 9d58ca2240..0b5b3e728b 100644
--- a/osu.Game.Tournament/Screens/TournamentScreen.cs
+++ b/osu.Game.Tournament/Screens/TournamentScreen.cs
@@ -10,6 +10,8 @@ namespace osu.Game.Tournament.Screens
{
public abstract class TournamentScreen : CompositeDrawable
{
+ public const double FADE_DELAY = 200;
+
[Resolved]
protected LadderInfo LadderInfo { get; private set; }
@@ -18,14 +20,8 @@ namespace osu.Game.Tournament.Screens
RelativeSizeAxes = Axes.Both;
}
- public override void Hide()
- {
- this.FadeOut(200);
- }
+ public override void Hide() => this.FadeOut(FADE_DELAY);
- public override void Show()
- {
- this.FadeIn(200);
- }
+ public override void Show() => this.FadeIn(FADE_DELAY);
}
}
diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs
index dbfa70704b..d34ea9648d 100644
--- a/osu.Game.Tournament/TournamentGameBase.cs
+++ b/osu.Game.Tournament/TournamentGameBase.cs
@@ -18,7 +18,6 @@ using osu.Framework.IO.Stores;
using osu.Framework.Platform;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
-using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API.Requests;
using osu.Game.Tournament.IPC;
using osu.Game.Tournament.Models;
@@ -76,7 +75,7 @@ namespace osu.Game.Tournament
AddRange(new[]
{
- new OsuButton
+ new TourneyButton
{
Text = "Save Changes",
Width = 140,
@@ -165,15 +164,17 @@ namespace osu.Game.Tournament
// link matches to rounds
foreach (var round in ladder.Rounds)
- foreach (var id in round.Matches)
{
- var found = ladder.Matches.FirstOrDefault(p => p.ID == id);
-
- if (found != null)
+ foreach (var id in round.Matches)
{
- found.Round.Value = round;
- if (round.StartDate.Value > found.Date.Value)
- found.Date.Value = round.StartDate.Value;
+ var found = ladder.Matches.FirstOrDefault(p => p.ID == id);
+
+ if (found != null)
+ {
+ found.Round.Value = round;
+ if (round.StartDate.Value > found.Date.Value)
+ found.Date.Value = round.StartDate.Value;
+ }
}
}
@@ -193,15 +194,19 @@ namespace osu.Game.Tournament
bool addedInfo = false;
foreach (var t in ladder.Teams)
- foreach (var p in t.Players)
- if (string.IsNullOrEmpty(p.Username))
+ {
+ foreach (var p in t.Players)
{
- var req = new GetUserRequest(p.Id);
- req.Perform(API);
- p.Username = req.Result.Username;
+ if (string.IsNullOrEmpty(p.Username))
+ {
+ var req = new GetUserRequest(p.Id);
+ req.Perform(API);
+ p.Username = req.Result.Username;
- addedInfo = true;
+ addedInfo = true;
+ }
}
+ }
return addedInfo;
}
@@ -214,15 +219,19 @@ namespace osu.Game.Tournament
bool addedInfo = false;
foreach (var r in ladder.Rounds)
- foreach (var b in r.Beatmaps)
- if (b.BeatmapInfo == null)
+ {
+ foreach (var b in r.Beatmaps)
{
- var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = b.ID });
- req.Perform(API);
- b.BeatmapInfo = req.Result?.ToBeatmap(RulesetStore);
+ if (b.BeatmapInfo == null && b.ID > 0)
+ {
+ var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = b.ID });
+ req.Perform(API);
+ b.BeatmapInfo = req.Result?.ToBeatmap(RulesetStore);
- addedInfo = true;
+ addedInfo = true;
+ }
}
+ }
return addedInfo;
}
diff --git a/osu.Game.Tournament/TournamentSceneManager.cs b/osu.Game.Tournament/TournamentSceneManager.cs
index 02ee1c8603..de3d685c31 100644
--- a/osu.Game.Tournament/TournamentSceneManager.cs
+++ b/osu.Game.Tournament/TournamentSceneManager.cs
@@ -8,7 +8,8 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Platform;
-using osu.Game.Graphics.UserInterface;
+using osu.Framework.Threading;
+using osu.Game.Graphics;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.Models;
using osu.Game.Tournament.Screens;
@@ -36,6 +37,7 @@ namespace osu.Game.Tournament
private TournamentMatchChatDisplay chat = new TournamentMatchChatDisplay();
private Container chatContainer;
+ private FillFlowContainer buttons;
public TournamentSceneManager()
{
@@ -101,68 +103,136 @@ namespace osu.Game.Tournament
Colour = Color4.Black,
RelativeSizeAxes = Axes.Both,
},
- new FillFlowContainer
+ buttons = new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
+ Spacing = new Vector2(2),
+ Padding = new MarginPadding(2),
Children = new Drawable[]
{
- new OsuButton { RelativeSizeAxes = Axes.X, Text = "Setup", Action = () => SetScreen(typeof(SetupScreen)) },
- new Container { RelativeSizeAxes = Axes.X, Height = 50 },
- new OsuButton { RelativeSizeAxes = Axes.X, Text = "Team Editor", Action = () => SetScreen(typeof(TeamEditorScreen)) },
- new OsuButton { RelativeSizeAxes = Axes.X, Text = "Rounds Editor", Action = () => SetScreen(typeof(RoundEditorScreen)) },
- new OsuButton { RelativeSizeAxes = Axes.X, Text = "Bracket Editor", Action = () => SetScreen(typeof(LadderEditorScreen)) },
- new Container { RelativeSizeAxes = Axes.X, Height = 50 },
- new OsuButton { RelativeSizeAxes = Axes.X, Text = "Drawings", Action = () => SetScreen(typeof(DrawingsScreen)) },
- new OsuButton { RelativeSizeAxes = Axes.X, Text = "Showcase", Action = () => SetScreen(typeof(ShowcaseScreen)) },
- new Container { RelativeSizeAxes = Axes.X, Height = 50 },
- new OsuButton { RelativeSizeAxes = Axes.X, Text = "Schedule", Action = () => SetScreen(typeof(ScheduleScreen)) },
- new OsuButton { RelativeSizeAxes = Axes.X, Text = "Bracket", Action = () => SetScreen(typeof(LadderScreen)) },
- new Container { RelativeSizeAxes = Axes.X, Height = 50 },
- new OsuButton { RelativeSizeAxes = Axes.X, Text = "TeamIntro", Action = () => SetScreen(typeof(TeamIntroScreen)) },
- new OsuButton { RelativeSizeAxes = Axes.X, Text = "MapPool", Action = () => SetScreen(typeof(MapPoolScreen)) },
- new OsuButton { RelativeSizeAxes = Axes.X, Text = "Gameplay", Action = () => SetScreen(typeof(GameplayScreen)) },
- new Container { RelativeSizeAxes = Axes.X, Height = 50 },
- new OsuButton { RelativeSizeAxes = Axes.X, Text = "Win", Action = () => SetScreen(typeof(TeamWinScreen)) },
+ new ScreenButton(typeof(SetupScreen)) { Text = "Setup", RequestSelection = SetScreen },
+ new Separator(),
+ new ScreenButton(typeof(TeamEditorScreen)) { Text = "Team Editor", RequestSelection = SetScreen },
+ new ScreenButton(typeof(RoundEditorScreen)) { Text = "Rounds Editor", RequestSelection = SetScreen },
+ new ScreenButton(typeof(LadderEditorScreen)) { Text = "Bracket Editor", RequestSelection = SetScreen },
+ new Separator(),
+ new ScreenButton(typeof(ScheduleScreen)) { Text = "Schedule", RequestSelection = SetScreen },
+ new ScreenButton(typeof(LadderScreen)) { Text = "Bracket", RequestSelection = SetScreen },
+ new Separator(),
+ new ScreenButton(typeof(TeamIntroScreen)) { Text = "TeamIntro", RequestSelection = SetScreen },
+ new Separator(),
+ new ScreenButton(typeof(MapPoolScreen)) { Text = "MapPool", RequestSelection = SetScreen },
+ new ScreenButton(typeof(GameplayScreen)) { Text = "Gameplay", RequestSelection = SetScreen },
+ new Separator(),
+ new ScreenButton(typeof(TeamWinScreen)) { Text = "Win", RequestSelection = SetScreen },
+ new Separator(),
+ new ScreenButton(typeof(DrawingsScreen)) { Text = "Drawings", RequestSelection = SetScreen },
+ new ScreenButton(typeof(ShowcaseScreen)) { Text = "Showcase", RequestSelection = SetScreen },
}
},
},
},
};
+ foreach (var drawable in screens)
+ drawable.Hide();
+
SetScreen(typeof(SetupScreen));
}
+ private float depth;
+
+ private Drawable currentScreen;
+ private ScheduledDelegate scheduledHide;
+
public void SetScreen(Type screenType)
{
- var screen = screens.FirstOrDefault(s => s.GetType() == screenType);
- if (screen == null) return;
+ var target = screens.FirstOrDefault(s => s.GetType() == screenType);
- foreach (var s in screens.Children)
+ if (target == null || currentScreen == target) return;
+
+ if (scheduledHide?.Completed == false)
{
- if (s == screen)
- {
- s.Show();
- if (s is IProvideVideo)
- video.FadeOut(200);
- else
- video.Show();
- }
- else
- s.Hide();
+ scheduledHide.RunTask();
+ scheduledHide.Cancel(); // see https://github.com/ppy/osu-framework/issues/2967
+ scheduledHide = null;
}
- switch (screen)
+ var lastScreen = currentScreen;
+ currentScreen = target;
+
+ if (currentScreen is IProvideVideo)
+ {
+ video.FadeOut(200);
+
+ // delay the hide to avoid a double-fade transition.
+ scheduledHide = Scheduler.AddDelayed(() => lastScreen?.Hide(), TournamentScreen.FADE_DELAY);
+ }
+ else
+ {
+ lastScreen?.Hide();
+ video.Show();
+ }
+
+ screens.ChangeChildDepth(currentScreen, depth--);
+ currentScreen.Show();
+
+ switch (currentScreen)
{
case GameplayScreen _:
case MapPoolScreen _:
- chatContainer.FadeIn(100);
+ chatContainer.FadeIn(TournamentScreen.FADE_DELAY);
break;
default:
- chatContainer.FadeOut(100);
+ chatContainer.FadeOut(TournamentScreen.FADE_DELAY);
break;
}
+
+ foreach (var s in buttons.OfType())
+ s.IsSelected = screenType == s.Type;
+ }
+
+ private class Separator : CompositeDrawable
+ {
+ public Separator()
+ {
+ RelativeSizeAxes = Axes.X;
+ Height = 20;
+ }
+ }
+
+ private class ScreenButton : TourneyButton
+ {
+ public readonly Type Type;
+
+ public ScreenButton(Type type)
+ {
+ Type = type;
+ BackgroundColour = OsuColour.Gray(0.2f);
+ Action = () => RequestSelection(type);
+
+ RelativeSizeAxes = Axes.X;
+ }
+
+ private bool isSelected;
+
+ public Action RequestSelection;
+
+ public bool IsSelected
+ {
+ get => isSelected;
+ set
+ {
+ if (value == isSelected)
+ return;
+
+ isSelected = value;
+ BackgroundColour = isSelected ? Color4.SkyBlue : OsuColour.Gray(0.2f);
+ SpriteText.Colour = isSelected ? Color4.Black : Color4.White;
+ }
+ }
}
}
}
diff --git a/osu.Game.Tournament/TourneyButton.cs b/osu.Game.Tournament/TourneyButton.cs
new file mode 100644
index 0000000000..12872d3197
--- /dev/null
+++ b/osu.Game.Tournament/TourneyButton.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.Graphics.UserInterface;
+
+namespace osu.Game.Tournament
+{
+ public class TourneyButton : OsuButton
+ {
+ public TourneyButton()
+ : base(null)
+ {
+ }
+ }
+}
diff --git a/osu.Game.Tournament/osu.Game.Tournament.csproj b/osu.Game.Tournament/osu.Game.Tournament.csproj
index bddaff0a80..f5306facaf 100644
--- a/osu.Game.Tournament/osu.Game.Tournament.csproj
+++ b/osu.Game.Tournament/osu.Game.Tournament.csproj
@@ -1,9 +1,7 @@
-
netstandard2.0
Library
- AnyCPU
true
tools for tournaments.
diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs
index 22ce7d4711..1234554e79 100644
--- a/osu.Game/Audio/PreviewTrack.cs
+++ b/osu.Game/Audio/PreviewTrack.cs
@@ -9,15 +9,18 @@ using osu.Framework.Threading;
namespace osu.Game.Audio
{
+ [LongRunningLoad]
public abstract class PreviewTrack : Component
{
///
/// Invoked when this has stopped playing.
+ /// Not invoked in a thread-safe context.
///
public event Action Stopped;
///
/// Invoked when this has started playing.
+ /// Not invoked in a thread-safe context.
///
public event Action Started;
@@ -29,7 +32,7 @@ namespace osu.Game.Audio
{
track = GetTrack();
if (track != null)
- track.Completed += () => Schedule(Stop);
+ track.Completed += Stop;
}
///
@@ -93,6 +96,7 @@ namespace osu.Game.Audio
hasStarted = false;
track.Stop();
+
Stopped?.Invoke();
}
diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs
index e12c46ef16..fad2b5a5e8 100644
--- a/osu.Game/Audio/PreviewTrackManager.cs
+++ b/osu.Game/Audio/PreviewTrackManager.cs
@@ -46,18 +46,18 @@ namespace osu.Game.Audio
{
var track = CreatePreviewTrack(beatmapSetInfo, trackStore);
- track.Started += () =>
+ track.Started += () => Schedule(() =>
{
current?.Stop();
current = track;
audio.Tracks.AddAdjustment(AdjustableProperty.Volume, muteBindable);
- };
+ });
- track.Stopped += () =>
+ track.Stopped += () => Schedule(() =>
{
current = null;
audio.Tracks.RemoveAdjustment(AdjustableProperty.Volume, muteBindable);
- };
+ });
return track;
}
diff --git a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs
index c00b04b660..51b3377394 100644
--- a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs
+++ b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs
@@ -43,6 +43,11 @@ namespace osu.Game.Beatmaps.ControlPoints
set => BeatLengthBindable.Value = value;
}
+ ///
+ /// The BPM at this control point.
+ ///
+ public double BPM => 60000 / BeatLength;
+
public override bool EquivalentTo(ControlPoint other) =>
other is TimingControlPoint otherTyped
&& TimeSignature == otherTyped.TimeSignature && BeatLength.Equals(otherTyped.BeatLength);
diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetCover.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetCover.cs
index d0db7765c2..5245bc319d 100644
--- a/osu.Game/Beatmaps/Drawables/BeatmapSetCover.cs
+++ b/osu.Game/Beatmaps/Drawables/BeatmapSetCover.cs
@@ -8,6 +8,7 @@ using osu.Framework.Graphics.Textures;
namespace osu.Game.Beatmaps.Drawables
{
+ [LongRunningLoad]
public class BeatmapSetCover : Sprite
{
private readonly BeatmapSetInfo set;
diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs
index 5dbd67d304..e3320f62ac 100644
--- a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs
@@ -144,16 +144,16 @@ namespace osu.Game.Beatmaps.Formats
var endTime = split.Length > 3 ? double.Parse(split[3], CultureInfo.InvariantCulture) : double.MaxValue;
var groupNumber = split.Length > 4 ? int.Parse(split[4]) : 0;
timelineGroup = storyboardSprite?.AddTrigger(triggerName, startTime, endTime, groupNumber);
- }
break;
+ }
case "L":
{
var startTime = double.Parse(split[1], CultureInfo.InvariantCulture);
var loopCount = int.Parse(split[2]);
timelineGroup = storyboardSprite?.AddLoop(startTime, loopCount);
- }
break;
+ }
default:
{
@@ -171,16 +171,16 @@ namespace osu.Game.Beatmaps.Formats
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue;
timelineGroup?.Alpha.Add(easing, startTime, endTime, startValue, endValue);
- }
break;
+ }
case "S":
{
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue;
timelineGroup?.Scale.Add(easing, startTime, endTime, new Vector2(startValue), new Vector2(endValue));
- }
break;
+ }
case "V":
{
@@ -189,16 +189,16 @@ namespace osu.Game.Beatmaps.Formats
var endX = split.Length > 6 ? float.Parse(split[6], CultureInfo.InvariantCulture) : startX;
var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY;
timelineGroup?.Scale.Add(easing, startTime, endTime, new Vector2(startX, startY), new Vector2(endX, endY));
- }
break;
+ }
case "R":
{
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue;
timelineGroup?.Rotation.Add(easing, startTime, endTime, MathHelper.RadiansToDegrees(startValue), MathHelper.RadiansToDegrees(endValue));
- }
break;
+ }
case "M":
{
@@ -208,24 +208,24 @@ namespace osu.Game.Beatmaps.Formats
var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY;
timelineGroup?.X.Add(easing, startTime, endTime, startX, endX);
timelineGroup?.Y.Add(easing, startTime, endTime, startY, endY);
- }
break;
+ }
case "MX":
{
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue;
timelineGroup?.X.Add(easing, startTime, endTime, startValue, endValue);
- }
break;
+ }
case "MY":
{
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue;
timelineGroup?.Y.Add(easing, startTime, endTime, startValue, endValue);
- }
break;
+ }
case "C":
{
@@ -238,8 +238,8 @@ namespace osu.Game.Beatmaps.Formats
timelineGroup?.Colour.Add(easing, startTime, endTime,
new Color4(startRed / 255f, startGreen / 255f, startBlue / 255f, 1),
new Color4(endRed / 255f, endGreen / 255f, endBlue / 255f, 1));
- }
break;
+ }
case "P":
{
@@ -259,14 +259,16 @@ namespace osu.Game.Beatmaps.Formats
timelineGroup?.FlipV.Add(easing, startTime, endTime, true, startTime == endTime);
break;
}
- }
+
break;
+ }
default:
throw new InvalidDataException($@"Unknown command type: {commandType}");
}
- }
+
break;
+ }
}
}
}
diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs
index 3fc33e9f52..7c69a992dd 100644
--- a/osu.Game/Beatmaps/WorkingBeatmap.cs
+++ b/osu.Game/Beatmaps/WorkingBeatmap.cs
@@ -133,8 +133,10 @@ namespace osu.Game.Beatmaps
obj.ApplyDefaults(converted.ControlPointInfo, converted.BeatmapInfo.BaseDifficulty);
foreach (var mod in mods.OfType())
- foreach (var obj in converted.HitObjects)
- mod.ApplyToHitObject(obj);
+ {
+ foreach (var obj in converted.HitObjects)
+ mod.ApplyToHitObject(obj);
+ }
processor?.PostProcess();
diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs
index 9fed8e03ac..8fa4eaf267 100644
--- a/osu.Game/Database/ArchiveModelManager.cs
+++ b/osu.Game/Database/ArchiveModelManager.cs
@@ -264,9 +264,12 @@ namespace osu.Game.Database
{
// for now, concatenate all .osu files in the set to create a unique hash.
MemoryStream hashable = new MemoryStream();
+
foreach (string file in reader.Filenames.Where(f => HashableFileTypes.Any(f.EndsWith)))
+ {
using (Stream s = reader.GetStream(file))
s.CopyTo(hashable);
+ }
return hashable.Length > 0 ? hashable.ComputeSHA2Hash() : null;
}
@@ -485,12 +488,16 @@ namespace osu.Game.Database
// import files to manager
foreach (string file in reader.Filenames)
+ {
using (Stream s = reader.GetStream(file))
+ {
fileInfos.Add(new TFileModel
{
Filename = FileSafety.PathStandardise(file.Substring(prefix.Length)),
FileInfo = files.Add(s)
});
+ }
+ }
return fileInfos;
}
@@ -651,8 +658,10 @@ namespace osu.Game.Database
private void handleEvent(Action a)
{
if (delayingEvents)
+ {
lock (queuedEvents)
queuedEvents.Add(a);
+ }
else
a.Invoke();
}
diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs
index 15068d81c0..61391b7102 100644
--- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs
+++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs
@@ -8,9 +8,6 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics.Sprites;
using System.Collections.Generic;
using osu.Framework.Graphics;
-using osu.Framework.Logging;
-using osu.Game.Overlays;
-using osu.Game.Overlays.Notifications;
using osu.Game.Users;
namespace osu.Game.Graphics.Containers
@@ -23,21 +20,12 @@ namespace osu.Game.Graphics.Containers
}
private OsuGame game;
- private ChannelManager channelManager;
- private Action showNotImplementedError;
[BackgroundDependencyLoader(true)]
- private void load(OsuGame game, NotificationOverlay notifications, ChannelManager channelManager)
+ private void load(OsuGame game)
{
// will be null in tests
this.game = game;
- this.channelManager = channelManager;
-
- showNotImplementedError = () => notifications?.Post(new SimpleNotification
- {
- Text = @"This link type is not yet supported!",
- Icon = FontAwesome.Solid.LifeRing,
- });
}
public void AddLinks(string text, List links)
@@ -56,85 +44,47 @@ namespace osu.Game.Graphics.Containers
foreach (var link in links)
{
AddText(text.Substring(previousLinkEnd, link.Index - previousLinkEnd));
- AddLink(text.Substring(link.Index, link.Length), link.Url, link.Action, link.Argument);
+ AddLink(text.Substring(link.Index, link.Length), link.Action, link.Argument ?? link.Url);
previousLinkEnd = link.Index + link.Length;
}
AddText(text.Substring(previousLinkEnd));
}
- public IEnumerable AddLink(string text, string url, LinkAction linkType = LinkAction.External, string linkArgument = null, string tooltipText = null, Action creationParameters = null)
- => createLink(AddText(text, creationParameters), text, url, linkType, linkArgument, tooltipText);
+ public void AddLink(string text, string url, Action creationParameters = null) =>
+ createLink(AddText(text, creationParameters), new LinkDetails(LinkAction.External, url), url);
- public IEnumerable AddLink(string text, Action action, string tooltipText = null, Action creationParameters = null)
- => createLink(AddText(text, creationParameters), text, tooltipText: tooltipText, action: action);
+ public void AddLink(string text, Action action, string tooltipText = null, Action creationParameters = null)
+ => createLink(AddText(text, creationParameters), new LinkDetails(LinkAction.Custom, null), tooltipText, action);
- public IEnumerable AddLink(IEnumerable text, string url, LinkAction linkType = LinkAction.External, string linkArgument = null, string tooltipText = null)
+ public void AddLink(string text, LinkAction action, string argument, string tooltipText = null, Action creationParameters = null)
+ => createLink(AddText(text, creationParameters), new LinkDetails(action, argument), null);
+
+ public void AddLink(IEnumerable text, LinkAction action = LinkAction.External, string linkArgument = null, string tooltipText = null)
{
foreach (var t in text)
AddArbitraryDrawable(t);
- return createLink(text, null, url, linkType, linkArgument, tooltipText);
+ createLink(text, new LinkDetails(action, linkArgument), tooltipText);
}
- public IEnumerable AddUserLink(User user, Action creationParameters = null)
- => createLink(AddText(user.Username, creationParameters), user.Username, null, LinkAction.OpenUserProfile, user.Id.ToString(), "View profile");
+ public void AddUserLink(User user, Action creationParameters = null)
+ => createLink(AddText(user.Username, creationParameters), new LinkDetails(LinkAction.OpenUserProfile, user.Id.ToString()), "View Profile");
- private IEnumerable createLink(IEnumerable drawables, string text, string url = null, LinkAction linkType = LinkAction.External, string linkArgument = null, string tooltipText = null, Action action = null)
+ private void createLink(IEnumerable drawables, LinkDetails link, string tooltipText, Action action = null)
{
AddInternal(new DrawableLinkCompiler(drawables.OfType().ToList())
{
RelativeSizeAxes = Axes.Both,
- TooltipText = tooltipText ?? (url != text ? url : string.Empty),
- Action = action ?? (() =>
+ TooltipText = tooltipText,
+ Action = () =>
{
- switch (linkType)
- {
- case LinkAction.OpenBeatmap:
- // TODO: proper query params handling
- if (linkArgument != null && int.TryParse(linkArgument.Contains('?') ? linkArgument.Split('?')[0] : linkArgument, out int beatmapId))
- game?.ShowBeatmap(beatmapId);
- break;
-
- case LinkAction.OpenBeatmapSet:
- if (int.TryParse(linkArgument, out int setId))
- game?.ShowBeatmapSet(setId);
- break;
-
- case LinkAction.OpenChannel:
- try
- {
- channelManager?.OpenChannel(linkArgument);
- }
- catch (ChannelNotFoundException)
- {
- Logger.Log($"The requested channel \"{linkArgument}\" does not exist");
- }
-
- break;
-
- case LinkAction.OpenEditorTimestamp:
- case LinkAction.JoinMultiplayerMatch:
- case LinkAction.Spectate:
- showNotImplementedError?.Invoke();
- break;
-
- case LinkAction.External:
- game?.OpenUrlExternally(url);
- break;
-
- case LinkAction.OpenUserProfile:
- if (long.TryParse(linkArgument, out long userId))
- game?.ShowUser(userId);
- break;
-
- default:
- throw new NotImplementedException($"This {nameof(LinkAction)} ({linkType.ToString()}) is missing an associated action.");
- }
- }),
+ if (action != null)
+ action();
+ else
+ game.HandleLink(link);
+ },
});
-
- return drawables;
}
// We want the compilers to always be visible no matter where they are, so RelativeSizeAxes is used.
diff --git a/osu.Game/Graphics/Containers/ParallaxContainer.cs b/osu.Game/Graphics/Containers/ParallaxContainer.cs
index f65a0a469a..86f922e4b8 100644
--- a/osu.Game/Graphics/Containers/ParallaxContainer.cs
+++ b/osu.Game/Graphics/Containers/ParallaxContainer.cs
@@ -69,9 +69,11 @@ namespace osu.Game.Graphics.Containers
{
Vector2 offset = (input.CurrentState.Mouse == null ? Vector2.Zero : ToLocalSpace(input.CurrentState.Mouse.Position) - DrawSize / 2) * ParallaxAmount;
- double elapsed = MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 1000);
+ const float parallax_duration = 100;
- content.Position = Interpolation.ValueAt(elapsed, content.Position, offset, 0, 1000, Easing.OutQuint);
+ double elapsed = MathHelper.Clamp(Clock.ElapsedFrameTime, 0, parallax_duration);
+
+ content.Position = Interpolation.ValueAt(elapsed, content.Position, offset, 0, parallax_duration, Easing.OutQuint);
content.Scale = Interpolation.ValueAt(elapsed, content.Scale, new Vector2(1 + System.Math.Abs(ParallaxAmount)), 0, 1000, Easing.OutQuint);
}
diff --git a/osu.Game/Graphics/Containers/ShakeContainer.cs b/osu.Game/Graphics/Containers/ShakeContainer.cs
index e5a6bcc28e..dca9df1e98 100644
--- a/osu.Game/Graphics/Containers/ShakeContainer.cs
+++ b/osu.Game/Graphics/Containers/ShakeContainer.cs
@@ -43,9 +43,11 @@ namespace osu.Game.Graphics.Containers
// if we don't have enough time for the second shake, skip it.
if (!maximumLength.HasValue || maximumLength >= ShakeDuration * 4)
+ {
sequence = sequence
.MoveToX(shake_amount, ShakeDuration, Easing.InOutSine).Then()
.MoveToX(-shake_amount, ShakeDuration, Easing.InOutSine).Then();
+ }
sequence.MoveToX(0, ShakeDuration / 2, Easing.InSine);
}
diff --git a/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs b/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs
new file mode 100644
index 0000000000..591ed3df83
--- /dev/null
+++ b/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs
@@ -0,0 +1,133 @@
+// 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.Audio;
+using osu.Framework.Audio.Sample;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.UserInterface;
+using osu.Framework.Input.Events;
+using osu.Game.Graphics.Sprites;
+using osuTK.Graphics;
+
+namespace osu.Game.Graphics.UserInterface
+{
+ public class DrawableOsuMenuItem : Menu.DrawableMenuItem
+ {
+ public const int MARGIN_HORIZONTAL = 17;
+ public const int MARGIN_VERTICAL = 4;
+ private const int text_size = 17;
+ private const int transition_length = 80;
+
+ private SampleChannel sampleClick;
+ private SampleChannel sampleHover;
+
+ private TextContainer text;
+
+ public DrawableOsuMenuItem(MenuItem item)
+ : base(item)
+ {
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(AudioManager audio)
+ {
+ sampleHover = audio.Samples.Get(@"UI/generic-hover");
+ sampleClick = audio.Samples.Get(@"UI/generic-select");
+
+ BackgroundColour = Color4.Transparent;
+ BackgroundColourHover = OsuColour.FromHex(@"172023");
+
+ updateTextColour();
+ }
+
+ private void updateTextColour()
+ {
+ switch ((Item as OsuMenuItem)?.Type)
+ {
+ default:
+ case MenuItemType.Standard:
+ text.Colour = Color4.White;
+ break;
+
+ case MenuItemType.Destructive:
+ text.Colour = Color4.Red;
+ break;
+
+ case MenuItemType.Highlighted:
+ text.Colour = OsuColour.FromHex(@"ffcc22");
+ break;
+ }
+ }
+
+ protected override bool OnHover(HoverEvent e)
+ {
+ sampleHover.Play();
+ text.BoldText.FadeIn(transition_length, Easing.OutQuint);
+ text.NormalText.FadeOut(transition_length, Easing.OutQuint);
+ return base.OnHover(e);
+ }
+
+ protected override void OnHoverLost(HoverLostEvent e)
+ {
+ text.BoldText.FadeOut(transition_length, Easing.OutQuint);
+ text.NormalText.FadeIn(transition_length, Easing.OutQuint);
+ base.OnHoverLost(e);
+ }
+
+ protected override bool OnClick(ClickEvent e)
+ {
+ sampleClick.Play();
+ return base.OnClick(e);
+ }
+
+ protected sealed override Drawable CreateContent() => text = CreateTextContainer();
+ protected virtual TextContainer CreateTextContainer() => new TextContainer();
+
+ protected class TextContainer : Container, IHasText
+ {
+ public string Text
+ {
+ get => NormalText.Text;
+ set
+ {
+ NormalText.Text = value;
+ BoldText.Text = value;
+ }
+ }
+
+ public readonly SpriteText NormalText;
+ public readonly SpriteText BoldText;
+
+ public TextContainer()
+ {
+ Anchor = Anchor.CentreLeft;
+ Origin = Anchor.CentreLeft;
+
+ AutoSizeAxes = Axes.Both;
+
+ Children = new Drawable[]
+ {
+ NormalText = new OsuSpriteText
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ Font = OsuFont.GetFont(size: text_size),
+ Margin = new MarginPadding { Horizontal = MARGIN_HORIZONTAL, Vertical = MARGIN_VERTICAL },
+ },
+ BoldText = new OsuSpriteText
+ {
+ AlwaysPresent = true,
+ Alpha = 0,
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold),
+ Margin = new MarginPadding { Horizontal = MARGIN_HORIZONTAL, Vertical = MARGIN_VERTICAL },
+ }
+ };
+ }
+ }
+ }
+}
diff --git a/osu.Game/Graphics/UserInterface/DrawableStatefulMenuItem.cs b/osu.Game/Graphics/UserInterface/DrawableStatefulMenuItem.cs
new file mode 100644
index 0000000000..3dc99f2dbe
--- /dev/null
+++ b/osu.Game/Graphics/UserInterface/DrawableStatefulMenuItem.cs
@@ -0,0 +1,72 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Sprites;
+using osuTK;
+
+namespace osu.Game.Graphics.UserInterface
+{
+ public class DrawableStatefulMenuItem : DrawableOsuMenuItem
+ {
+ protected new StatefulMenuItem Item => (StatefulMenuItem)base.Item;
+
+ public DrawableStatefulMenuItem(StatefulMenuItem item)
+ : base(item)
+ {
+ }
+
+ protected override TextContainer CreateTextContainer() => new ToggleTextContainer(Item);
+
+ private class ToggleTextContainer : TextContainer
+ {
+ private readonly StatefulMenuItem menuItem;
+ private readonly Bindable
public class OsuButton : Button
{
- private Box hover;
+ public string Text
+ {
+ get => SpriteText?.Text;
+ set
+ {
+ if (SpriteText != null)
+ SpriteText.Text = value;
+ }
+ }
- public OsuButton()
+ private Color4? backgroundColour;
+
+ public Color4 BackgroundColour
+ {
+ set
+ {
+ backgroundColour = value;
+ Background.FadeColour(value);
+ }
+ }
+
+ protected override Container Content { get; }
+
+ protected Box Hover;
+ protected Box Background;
+ protected SpriteText SpriteText;
+
+ public OsuButton(HoverSampleSet? hoverSounds = HoverSampleSet.Loud)
{
Height = 40;
- Content.Masking = true;
- Content.CornerRadius = 5;
+ AddInternal(Content = new Container
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Masking = true,
+ CornerRadius = 5,
+ RelativeSizeAxes = Axes.Both,
+ Children = new Drawable[]
+ {
+ Background = new Box
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ },
+ Hover = new Box
+ {
+ Alpha = 0,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.White.Opacity(.1f),
+ Blending = BlendingParameters.Additive,
+ Depth = float.MinValue
+ },
+ SpriteText = CreateText(),
+ }
+ });
+
+ if (hoverSounds.HasValue)
+ AddInternal(new HoverClickSounds(hoverSounds.Value));
+
+ Enabled.BindValueChanged(enabledChanged, true);
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
- BackgroundColour = colours.BlueDark;
-
- AddRange(new Drawable[]
- {
- hover = new Box
- {
- RelativeSizeAxes = Axes.Both,
- Blending = BlendingParameters.Additive,
- Colour = Color4.White.Opacity(0.1f),
- Alpha = 0,
- Depth = -1
- },
- new HoverClickSounds(HoverSampleSet.Loud),
- });
+ if (backgroundColour == null)
+ BackgroundColour = colours.BlueDark;
Enabled.ValueChanged += enabledChanged;
Enabled.TriggerChange();
}
- private void enabledChanged(ValueChangedEvent e)
+ protected override bool OnClick(ClickEvent e)
{
- this.FadeColour(e.NewValue ? Color4.White : Color4.Gray, 200, Easing.OutQuint);
+ if (Enabled.Value)
+ {
+ Debug.Assert(backgroundColour != null);
+ Background.FlashColour(backgroundColour.Value, 200);
+ }
+
+ return base.OnClick(e);
}
protected override bool OnHover(HoverEvent e)
{
- hover.FadeIn(200);
- return true;
+ if (Enabled.Value)
+ Hover.FadeIn(200, Easing.OutQuint);
+
+ return base.OnHover(e);
}
protected override void OnHoverLost(HoverLostEvent e)
{
- hover.FadeOut(200);
base.OnHoverLost(e);
+
+ Hover.FadeOut(300);
}
protected override bool OnMouseDown(MouseDownEvent e)
@@ -80,12 +135,17 @@ namespace osu.Game.Graphics.UserInterface
return base.OnMouseUp(e);
}
- protected override SpriteText CreateText() => new OsuSpriteText
+ protected virtual SpriteText CreateText() => new OsuSpriteText
{
Depth = -1,
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Font = OsuFont.GetFont(weight: FontWeight.Bold)
};
+
+ private void enabledChanged(ValueChangedEvent e)
+ {
+ this.FadeColour(e.NewValue ? Color4.White : Color4.Gray, 200, Easing.OutQuint);
+ }
}
}
diff --git a/osu.Game/Graphics/UserInterface/OsuContextMenu.cs b/osu.Game/Graphics/UserInterface/OsuContextMenu.cs
index cea8427296..4b629080e1 100644
--- a/osu.Game/Graphics/UserInterface/OsuContextMenu.cs
+++ b/osu.Game/Graphics/UserInterface/OsuContextMenu.cs
@@ -6,6 +6,7 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Effects;
+using osu.Framework.Graphics.UserInterface;
namespace osu.Game.Graphics.UserInterface
{
@@ -35,5 +36,7 @@ namespace osu.Game.Graphics.UserInterface
protected override void AnimateOpen() => this.FadeIn(fade_duration, Easing.OutQuint);
protected override void AnimateClose() => this.FadeOut(fade_duration, Easing.OutQuint);
+
+ protected override Menu CreateSubMenu() => new OsuContextMenu();
}
}
diff --git a/osu.Game/Graphics/UserInterface/OsuMenu.cs b/osu.Game/Graphics/UserInterface/OsuMenu.cs
index c4c6950eb1..e7bf4f66ee 100644
--- a/osu.Game/Graphics/UserInterface/OsuMenu.cs
+++ b/osu.Game/Graphics/UserInterface/OsuMenu.cs
@@ -1,18 +1,12 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using osu.Framework.Allocation;
-using osu.Framework.Audio;
-using osu.Framework.Audio.Sample;
using osuTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
-using osu.Framework.Input.Events;
using osu.Game.Graphics.Containers;
-using osu.Game.Graphics.Sprites;
using osuTK;
namespace osu.Game.Graphics.UserInterface
@@ -45,7 +39,16 @@ namespace osu.Game.Graphics.UserInterface
}
}
- protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableOsuMenuItem(item);
+ protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item)
+ {
+ switch (item)
+ {
+ case StatefulMenuItem stateful:
+ return new DrawableStatefulMenuItem(stateful);
+ }
+
+ return new DrawableOsuMenuItem(item);
+ }
protected override ScrollContainer CreateScrollContainer(Direction direction) => new OsuScrollContainer(direction);
@@ -53,122 +56,5 @@ namespace osu.Game.Graphics.UserInterface
{
Anchor = Direction == Direction.Horizontal ? Anchor.BottomLeft : Anchor.TopRight
};
-
- protected class DrawableOsuMenuItem : DrawableMenuItem
- {
- private const int margin_horizontal = 17;
- private const int text_size = 17;
- private const int transition_length = 80;
- public const int MARGIN_VERTICAL = 4;
-
- private SampleChannel sampleClick;
- private SampleChannel sampleHover;
-
- private TextContainer text;
-
- public DrawableOsuMenuItem(MenuItem item)
- : base(item)
- {
- }
-
- [BackgroundDependencyLoader]
- private void load(AudioManager audio)
- {
- sampleHover = audio.Samples.Get(@"UI/generic-hover");
- sampleClick = audio.Samples.Get(@"UI/generic-select");
-
- BackgroundColour = Color4.Transparent;
- BackgroundColourHover = OsuColour.FromHex(@"172023");
-
- updateTextColour();
- }
-
- private void updateTextColour()
- {
- switch ((Item as OsuMenuItem)?.Type)
- {
- default:
- case MenuItemType.Standard:
- text.Colour = Color4.White;
- break;
-
- case MenuItemType.Destructive:
- text.Colour = Color4.Red;
- break;
-
- case MenuItemType.Highlighted:
- text.Colour = OsuColour.FromHex(@"ffcc22");
- break;
- }
- }
-
- protected override bool OnHover(HoverEvent e)
- {
- sampleHover.Play();
- text.BoldText.FadeIn(transition_length, Easing.OutQuint);
- text.NormalText.FadeOut(transition_length, Easing.OutQuint);
- return base.OnHover(e);
- }
-
- protected override void OnHoverLost(HoverLostEvent e)
- {
- text.BoldText.FadeOut(transition_length, Easing.OutQuint);
- text.NormalText.FadeIn(transition_length, Easing.OutQuint);
- base.OnHoverLost(e);
- }
-
- protected override bool OnClick(ClickEvent e)
- {
- sampleClick.Play();
- return base.OnClick(e);
- }
-
- protected sealed override Drawable CreateContent() => text = CreateTextContainer();
- protected virtual TextContainer CreateTextContainer() => new TextContainer();
-
- protected class TextContainer : Container, IHasText
- {
- public string Text
- {
- get => NormalText.Text;
- set
- {
- NormalText.Text = value;
- BoldText.Text = value;
- }
- }
-
- public readonly SpriteText NormalText;
- public readonly SpriteText BoldText;
-
- public TextContainer()
- {
- Anchor = Anchor.CentreLeft;
- Origin = Anchor.CentreLeft;
-
- AutoSizeAxes = Axes.Both;
-
- Children = new Drawable[]
- {
- NormalText = new OsuSpriteText
- {
- Anchor = Anchor.CentreLeft,
- Origin = Anchor.CentreLeft,
- Font = OsuFont.GetFont(size: text_size),
- Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL },
- },
- BoldText = new OsuSpriteText
- {
- AlwaysPresent = true,
- Alpha = 0,
- Anchor = Anchor.CentreLeft,
- Origin = Anchor.CentreLeft,
- Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold),
- Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL },
- }
- };
- }
- }
- }
}
}
diff --git a/osu.Game/Graphics/UserInterface/OsuMenuItem.cs b/osu.Game/Graphics/UserInterface/OsuMenuItem.cs
index b7aa666302..0fe41937ce 100644
--- a/osu.Game/Graphics/UserInterface/OsuMenuItem.cs
+++ b/osu.Game/Graphics/UserInterface/OsuMenuItem.cs
@@ -11,9 +11,8 @@ namespace osu.Game.Graphics.UserInterface
public readonly MenuItemType Type;
public OsuMenuItem(string text, MenuItemType type = MenuItemType.Standard)
- : base(text)
+ : this(text, type, null)
{
- Type = type;
}
public OsuMenuItem(string text, MenuItemType type, Action action)
diff --git a/osu.Game/Graphics/UserInterface/OsuTabControl.cs b/osu.Game/Graphics/UserInterface/OsuTabControl.cs
index c55d14456b..5d1bdc62e9 100644
--- a/osu.Game/Graphics/UserInterface/OsuTabControl.cs
+++ b/osu.Game/Graphics/UserInterface/OsuTabControl.cs
@@ -51,8 +51,10 @@ namespace osu.Game.Graphics.UserInterface
});
if (isEnumType && AddEnumEntriesAutomatically)
+ {
foreach (var val in (T[])Enum.GetValues(typeof(T)))
AddItem(val);
+ }
}
[BackgroundDependencyLoader]
diff --git a/osu.Game/Graphics/UserInterface/ScoreCounter.cs b/osu.Game/Graphics/UserInterface/ScoreCounter.cs
index 63062cdc9d..e291401670 100644
--- a/osu.Game/Graphics/UserInterface/ScoreCounter.cs
+++ b/osu.Game/Graphics/UserInterface/ScoreCounter.cs
@@ -43,9 +43,12 @@ namespace osu.Game.Graphics.UserInterface
protected override string FormatCount(double count)
{
string format = new string('0', (int)LeadingZeroes);
+
if (UseCommaSeparator)
+ {
for (int i = format.Length - 3; i > 0; i -= 3)
format = format.Insert(i, @",");
+ }
return ((long)count).ToString(format);
}
diff --git a/osu.Game/Graphics/UserInterface/StatefulMenuItem.cs b/osu.Game/Graphics/UserInterface/StatefulMenuItem.cs
new file mode 100644
index 0000000000..0d7b36e51b
--- /dev/null
+++ b/osu.Game/Graphics/UserInterface/StatefulMenuItem.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 System;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics.Sprites;
+
+namespace osu.Game.Graphics.UserInterface
+{
+ ///
+ /// An which contains and displays a state.
+ ///
+ public abstract class StatefulMenuItem : OsuMenuItem
+ {
+ ///
+ /// The current state that should be displayed.
+ ///
+ public readonly Bindable State = new Bindable();
+
+ ///
+ /// Creates a new .
+ ///
+ /// The text to display.
+ /// A function that mutates a state to another state after this is pressed.
+ /// The type of action which this performs.
+ protected StatefulMenuItem(string text, Func changeStateFunc, MenuItemType type = MenuItemType.Standard)
+ : this(text, changeStateFunc, type, null)
+ {
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ /// The text to display.
+ /// A function that mutates a state to another state after this is pressed.
+ /// The type of action which this performs.
+ /// A delegate to be invoked when this is pressed.
+ protected StatefulMenuItem(string text, Func changeStateFunc, MenuItemType type, Action action)
+ : base(text, type)
+ {
+ Action.Value = () =>
+ {
+ State.Value = changeStateFunc?.Invoke(State.Value) ?? State.Value;
+ action?.Invoke(State.Value);
+ };
+ }
+
+ ///
+ /// Retrieves the icon to be displayed for a state.
+ ///
+ /// The state to retrieve the relevant icon for.
+ /// The icon to be displayed for .
+ public abstract IconUsage? GetIconForState(object state);
+ }
+
+ public abstract class StatefulMenuItem : StatefulMenuItem
+ where T : struct
+ {
+ ///
+ /// The current state that should be displayed.
+ ///
+ public new readonly Bindable State = new Bindable();
+
+ ///
+ /// Creates a new .
+ ///
+ /// The text to display.
+ /// A function that mutates a state to another state after this is pressed.
+ /// The type of action which this performs.
+ protected StatefulMenuItem(string text, Func changeStateFunc, MenuItemType type = MenuItemType.Standard)
+ : this(text, changeStateFunc, type, null)
+ {
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ /// The text to display.
+ /// A function that mutates a state to another state after this is pressed.
+ /// The type of action which this performs.
+ /// A delegate to be invoked when this is pressed.
+ protected StatefulMenuItem(string text, Func changeStateFunc, MenuItemType type, Action action)
+ : base(text, o => changeStateFunc?.Invoke((T)o) ?? o, type, o => action?.Invoke((T)o))
+ {
+ base.State.BindValueChanged(state =>
+ {
+ if (state.NewValue == null)
+ base.State.Value = default(T);
+
+ State.Value = (T)base.State.Value;
+ }, true);
+
+ State.BindValueChanged(state => base.State.Value = state.NewValue);
+ }
+
+ public sealed override IconUsage? GetIconForState(object state) => GetIconForState((T)state);
+
+ ///
+ /// Retrieves the icon to be displayed for a state.
+ ///
+ /// The state to retrieve the relevant icon for.
+ /// The icon to be displayed for .
+ public abstract IconUsage? GetIconForState(T state);
+ }
+}
diff --git a/osu.Game/Graphics/UserInterface/TernaryState.cs b/osu.Game/Graphics/UserInterface/TernaryState.cs
new file mode 100644
index 0000000000..d4de28044f
--- /dev/null
+++ b/osu.Game/Graphics/UserInterface/TernaryState.cs
@@ -0,0 +1,27 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+namespace osu.Game.Graphics.UserInterface
+{
+ ///
+ /// An on/off state with an extra indeterminate state.
+ ///
+ public enum TernaryState
+ {
+ ///
+ /// The current state is false.
+ ///
+ False,
+
+ ///
+ /// The current state is a combination of and .
+ /// The state becomes if the is pressed.
+ ///
+ Indeterminate,
+
+ ///
+ /// The current state is true.
+ ///
+ True
+ }
+}
diff --git a/osu.Game/Graphics/UserInterface/TernaryStateMenuItem.cs b/osu.Game/Graphics/UserInterface/TernaryStateMenuItem.cs
new file mode 100644
index 0000000000..2d9e2106d4
--- /dev/null
+++ b/osu.Game/Graphics/UserInterface/TernaryStateMenuItem.cs
@@ -0,0 +1,79 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using osu.Framework.Graphics.Sprites;
+
+namespace osu.Game.Graphics.UserInterface
+{
+ ///
+ /// An with three possible states.
+ ///
+ public class TernaryStateMenuItem : StatefulMenuItem
+ {
+ ///
+ /// Creates a new .
+ ///
+ /// The text to display.
+ /// The type of action which this performs.
+ public TernaryStateMenuItem(string text, MenuItemType type = MenuItemType.Standard)
+ : this(text, type, null)
+ {
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ /// The text to display.
+ /// The type of action which this performs.
+ /// A delegate to be invoked when this is pressed.
+ public TernaryStateMenuItem(string text, MenuItemType type, Action action)
+ : this(text, getNextState, type, action)
+ {
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ /// The text to display.
+ /// A function that mutates a state to another state after this is pressed.
+ /// The type of action which this performs.
+ /// A delegate to be invoked when this is pressed.
+ protected TernaryStateMenuItem(string text, Func changeStateFunc, MenuItemType type, Action action)
+ : base(text, changeStateFunc, type, action)
+ {
+ }
+
+ public override IconUsage? GetIconForState(TernaryState state)
+ {
+ switch (state)
+ {
+ case TernaryState.Indeterminate:
+ return FontAwesome.Solid.DotCircle;
+
+ case TernaryState.True:
+ return FontAwesome.Solid.Check;
+ }
+
+ return null;
+ }
+
+ private static TernaryState getNextState(TernaryState state)
+ {
+ switch (state)
+ {
+ case TernaryState.False:
+ return TernaryState.True;
+
+ case TernaryState.Indeterminate:
+ return TernaryState.True;
+
+ case TernaryState.True:
+ return TernaryState.False;
+
+ default:
+ throw new ArgumentOutOfRangeException(nameof(state), state, null);
+ }
+ }
+ }
+}
diff --git a/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs b/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs
new file mode 100644
index 0000000000..f9ff9859dd
--- /dev/null
+++ b/osu.Game/Graphics/UserInterface/ToggleMenuItem.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 System;
+using osu.Framework.Graphics.Sprites;
+
+namespace osu.Game.Graphics.UserInterface
+{
+ ///
+ /// An which displays an enabled or disabled state.
+ ///
+ public class ToggleMenuItem : StatefulMenuItem
+ {
+ ///
+ /// Creates a new .
+ ///
+ /// The text to display.
+ /// The type of action which this performs.
+ public ToggleMenuItem(string text, MenuItemType type = MenuItemType.Standard)
+ : this(text, type, null)
+ {
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ /// The text to display.
+ /// The type of action which this performs.
+ /// A delegate to be invoked when this is pressed.
+ public ToggleMenuItem(string text, MenuItemType type, Action action)
+ : base(text, value => !value, type, action)
+ {
+ }
+
+ public override IconUsage? GetIconForState(bool state) => state ? (IconUsage?)FontAwesome.Solid.Check : null;
+ }
+}
diff --git a/osu.Game/IO/Archives/ZipArchiveReader.cs b/osu.Game/IO/Archives/ZipArchiveReader.cs
index 9033e7529d..35f38ea7e8 100644
--- a/osu.Game/IO/Archives/ZipArchiveReader.cs
+++ b/osu.Game/IO/Archives/ZipArchiveReader.cs
@@ -1,30 +1,16 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using osu.Framework.IO.Stores;
using SharpCompress.Archives.Zip;
-using SharpCompress.Common;
namespace osu.Game.IO.Archives
{
public sealed class ZipArchiveReader : ArchiveReader
{
- ///
- /// List of substrings that indicate a file should be ignored during the import process
- /// (usually due to representing no useful data and being autogenerated by the OS).
- ///
- private static readonly string[] filename_ignore_list =
- {
- // Mac-specific
- "__MACOSX",
- ".DS_Store",
- // Windows-specific
- "Thumbs.db"
- };
-
private readonly Stream archiveStream;
private readonly ZipArchive archive;
@@ -58,9 +44,7 @@ namespace osu.Game.IO.Archives
archiveStream.Dispose();
}
- private static bool canBeIgnored(IEntry entry) => filename_ignore_list.Any(ignoredName => entry.Key.IndexOf(ignoredName, StringComparison.OrdinalIgnoreCase) >= 0);
-
- public override IEnumerable Filenames => archive.Entries.Where(e => !canBeIgnored(e)).Select(e => e.Key).ToArray();
+ public override IEnumerable Filenames => archive.Entries.Select(e => e.Key).ExcludeSystemFileNames();
public override Stream GetUnderlyingStream() => archiveStream;
}
diff --git a/osu.Game/Input/KeyBindingStore.cs b/osu.Game/Input/KeyBindingStore.cs
index caddb1ae0d..74b3134964 100644
--- a/osu.Game/Input/KeyBindingStore.cs
+++ b/osu.Game/Input/KeyBindingStore.cs
@@ -46,6 +46,7 @@ namespace osu.Game.Input
continue;
foreach (var insertable in group.Skip(count).Take(aimCount - count))
+ {
// insert any defaults which are missing.
usage.Context.DatabasedKeyBinding.Add(new DatabasedKeyBinding
{
@@ -54,6 +55,7 @@ namespace osu.Game.Input
RulesetID = rulesetId,
Variant = variant
});
+ }
}
}
}
diff --git a/osu.Game/Online/API/DummyAPIAccess.cs b/osu.Game/Online/API/DummyAPIAccess.cs
index 6c04c77dc0..28132765d3 100644
--- a/osu.Game/Online/API/DummyAPIAccess.cs
+++ b/osu.Game/Online/API/DummyAPIAccess.cs
@@ -19,7 +19,7 @@ namespace osu.Game.Online.API
public Bindable Activity { get; } = new Bindable();
- public bool IsLoggedIn => true;
+ public bool IsLoggedIn => State == APIState.Online;
public string ProvidedUsername => LocalUser.Value.Username;
diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs
index 4f6066cab1..1d8c5609d9 100644
--- a/osu.Game/Online/Chat/ChannelManager.cs
+++ b/osu.Game/Online/Chat/ChannelManager.cs
@@ -220,7 +220,7 @@ namespace osu.Game.Online.Chat
break;
}
- var channel = availableChannels.Where(c => c.Name == content || c.Name == $"#{content}").FirstOrDefault();
+ var channel = availableChannels.FirstOrDefault(c => c.Name == content || c.Name == $"#{content}");
if (channel == null)
{
diff --git a/osu.Game/Online/Chat/MessageFormatter.cs b/osu.Game/Online/Chat/MessageFormatter.cs
index 3ffff281f8..717de18c14 100644
--- a/osu.Game/Online/Chat/MessageFormatter.cs
+++ b/osu.Game/Online/Chat/MessageFormatter.cs
@@ -81,7 +81,7 @@ namespace osu.Game.Online.Chat
//since we just changed the line display text, offset any already processed links.
result.Links.ForEach(l => l.Index -= l.Index > index ? m.Length - displayText.Length : 0);
- var details = getLinkDetails(linkText);
+ var details = GetLinkDetails(linkText);
result.Links.Add(new Link(linkText, index, displayText.Length, linkActionOverride ?? details.Action, details.Argument));
//adjust the offset for processing the current matches group.
@@ -98,7 +98,7 @@ namespace osu.Game.Online.Chat
var linkText = m.Groups["link"].Value;
var indexLength = linkText.Length;
- var details = getLinkDetails(linkText);
+ var details = GetLinkDetails(linkText);
var link = new Link(linkText, index, indexLength, details.Action, details.Argument);
// sometimes an already-processed formatted link can reduce to a simple URL, too
@@ -109,7 +109,7 @@ namespace osu.Game.Online.Chat
}
}
- private static LinkDetails getLinkDetails(string url)
+ public static LinkDetails GetLinkDetails(string url)
{
var args = url.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
args[0] = args[0].TrimEnd(':');
@@ -255,17 +255,17 @@ namespace osu.Game.Online.Chat
OriginalText = Text = text;
}
}
+ }
- public class LinkDetails
+ public class LinkDetails
+ {
+ public LinkAction Action;
+ public string Argument;
+
+ public LinkDetails(LinkAction action, string argument)
{
- public LinkAction Action;
- public string Argument;
-
- public LinkDetails(LinkAction action, string argument)
- {
- Action = action;
- Argument = argument;
- }
+ Action = action;
+ Argument = argument;
}
}
@@ -279,6 +279,7 @@ namespace osu.Game.Online.Chat
JoinMultiplayerMatch,
Spectate,
OpenUserProfile,
+ Custom
}
public class Link : IComparable
diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs
index 83de0635fb..d214743b30 100644
--- a/osu.Game/Online/Leaderboards/Leaderboard.cs
+++ b/osu.Game/Online/Leaderboards/Leaderboard.cs
@@ -75,8 +75,10 @@ namespace osu.Game.Online.Leaderboards
int i = 0;
foreach (var s in scrollFlow.Children)
+ {
using (s.BeginDelayedSequence(i++ * 50, true))
s.Show();
+ }
scrollContainer.ScrollTo(0f, false);
}, (showScoresCancellationSource = new CancellationTokenSource()).Token));
@@ -342,13 +344,17 @@ namespace osu.Game.Online.Leaderboards
else
{
if (bottomY - fadeBottom > 0 && FadeBottom)
+ {
c.Colour = ColourInfo.GradientVertical(
Color4.White.Opacity(Math.Min(1 - (topY - fadeBottom) / LeaderboardScore.HEIGHT, 1)),
Color4.White.Opacity(Math.Min(1 - (bottomY - fadeBottom) / LeaderboardScore.HEIGHT, 1)));
+ }
else if (FadeTop)
+ {
c.Colour = ColourInfo.GradientVertical(
Color4.White.Opacity(Math.Min(1 - (fadeTop - topY) / LeaderboardScore.HEIGHT, 1)),
Color4.White.Opacity(Math.Min(1 - (fadeTop - bottomY) / LeaderboardScore.HEIGHT, 1)));
+ }
}
}
}
diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
index 9387482f14..623db07938 100644
--- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs
+++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
@@ -21,6 +21,7 @@ using osu.Game.Users.Drawables;
using osuTK;
using osuTK.Graphics;
using Humanizer;
+using osu.Game.Online.API;
namespace osu.Game.Online.Leaderboards
{
@@ -37,6 +38,7 @@ namespace osu.Game.Online.Leaderboards
private readonly ScoreInfo score;
private readonly int rank;
+ private readonly bool allowHighlight;
private Box background;
private Container content;
@@ -49,17 +51,18 @@ namespace osu.Game.Online.Leaderboards
private List statisticsLabels;
- public LeaderboardScore(ScoreInfo score, int rank)
+ public LeaderboardScore(ScoreInfo score, int rank, bool allowHighlight = true)
{
this.score = score;
this.rank = rank;
+ this.allowHighlight = allowHighlight;
RelativeSizeAxes = Axes.X;
Height = HEIGHT;
}
[BackgroundDependencyLoader]
- private void load()
+ private void load(IAPIProvider api, OsuColour colour)
{
var user = score.User;
@@ -100,7 +103,7 @@ namespace osu.Game.Online.Leaderboards
background = new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = Color4.Black,
+ Colour = user.Id == api.LocalUser.Value.Id && allowHighlight ? colour.Green : Color4.Black,
Alpha = background_alpha,
},
},
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index 4dcc181bea..7735030bbb 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -215,31 +215,102 @@ namespace osu.Game
private ExternalLinkOpener externalLinkOpener;
- public void OpenUrlExternally(string url)
+ ///
+ /// Handle an arbitrary URL. Displays via in-game overlays where possible.
+ /// This can be called from a non-thread-safe non-game-loaded state.
+ ///
+ /// The URL to load.
+ public void HandleLink(string url) => HandleLink(MessageFormatter.GetLinkDetails(url));
+
+ ///
+ /// Handle a specific .
+ /// This can be called from a non-thread-safe non-game-loaded state.
+ ///
+ /// The link to load.
+ public void HandleLink(LinkDetails link) => Schedule(() =>
+ {
+ switch (link.Action)
+ {
+ case LinkAction.OpenBeatmap:
+ // TODO: proper query params handling
+ if (link.Argument != null && int.TryParse(link.Argument.Contains('?') ? link.Argument.Split('?')[0] : link.Argument, out int beatmapId))
+ ShowBeatmap(beatmapId);
+ break;
+
+ case LinkAction.OpenBeatmapSet:
+ if (int.TryParse(link.Argument, out int setId))
+ ShowBeatmapSet(setId);
+ break;
+
+ case LinkAction.OpenChannel:
+ ShowChannel(link.Argument);
+ break;
+
+ case LinkAction.OpenEditorTimestamp:
+ case LinkAction.JoinMultiplayerMatch:
+ case LinkAction.Spectate:
+ waitForReady(() => notifications, _ => notifications?.Post(new SimpleNotification
+ {
+ Text = @"This link type is not yet supported!",
+ Icon = FontAwesome.Solid.LifeRing,
+ }));
+ break;
+
+ case LinkAction.External:
+ OpenUrlExternally(link.Argument);
+ break;
+
+ case LinkAction.OpenUserProfile:
+ if (long.TryParse(link.Argument, out long userId))
+ ShowUser(userId);
+ break;
+
+ default:
+ throw new NotImplementedException($"This {nameof(LinkAction)} ({link.Action.ToString()}) is missing an associated action.");
+ }
+ });
+
+ public void OpenUrlExternally(string url) => waitForReady(() => externalLinkOpener, _ =>
{
if (url.StartsWith("/"))
url = $"{API.Endpoint}{url}";
externalLinkOpener.OpenUrlExternally(url);
- }
+ });
+
+ ///
+ /// Open a specific channel in chat.
+ ///
+ /// The channel to display.
+ public void ShowChannel(string channel) => waitForReady(() => channelManager, _ =>
+ {
+ try
+ {
+ channelManager.OpenChannel(channel);
+ }
+ catch (ChannelNotFoundException)
+ {
+ Logger.Log($"The requested channel \"{channel}\" does not exist");
+ }
+ });
///
/// Show a beatmap set as an overlay.
///
/// The set to display.
- public void ShowBeatmapSet(int setId) => beatmapSetOverlay.FetchAndShowBeatmapSet(setId);
+ public void ShowBeatmapSet(int setId) => waitForReady(() => beatmapSetOverlay, _ => beatmapSetOverlay.FetchAndShowBeatmapSet(setId));
///
/// Show a user's profile as an overlay.
///
/// The user to display.
- public void ShowUser(long userId) => userProfile.ShowUser(userId);
+ public void ShowUser(long userId) => waitForReady(() => userProfile, _ => userProfile.ShowUser(userId));
///
/// Show a beatmap's set as an overlay, displaying the given beatmap.
///
/// The beatmap to show.
- public void ShowBeatmap(int beatmapId) => beatmapSetOverlay.FetchAndShowBeatmap(beatmapId);
+ public void ShowBeatmap(int beatmapId) => waitForReady(() => beatmapSetOverlay, _ => beatmapSetOverlay.FetchAndShowBeatmap(beatmapId));
///
/// Present a beatmap at song select immediately.
@@ -331,8 +402,10 @@ namespace osu.Game
nextBeatmap.Track.Completed += currentTrackCompleted;
using (var oldBeatmap = beatmap.OldValue)
+ {
if (oldBeatmap?.Track != null)
oldBeatmap.Track.Completed -= currentTrackCompleted;
+ }
nextBeatmap?.LoadBeatmapAsync();
}
@@ -397,6 +470,23 @@ namespace osu.Game
performFromMainMenuTask = Schedule(() => performFromMainMenu(action, taskName));
}
+ ///
+ /// Wait for the game (and target component) to become loaded and then run an action.
+ ///
+ /// A function to retrieve a (potentially not-yet-constructed) target instance.
+ /// The action to perform on the instance when load is confirmed.
+ /// The type of the target instance.
+ private void waitForReady(Func retrieveInstance, Action action)
+ where T : Drawable
+ {
+ var instance = retrieveInstance();
+
+ if (ScreenStack == null || ScreenStack.CurrentScreen is StartupScreen || instance?.IsLoaded != true)
+ Schedule(() => waitForReady(retrieveInstance, action));
+ else
+ action(instance);
+ }
+
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs
index 194a439b06..87321030a9 100644
--- a/osu.Game/OsuGameBase.cs
+++ b/osu.Game/OsuGameBase.cs
@@ -292,8 +292,10 @@ namespace osu.Game
var extension = Path.GetExtension(paths.First())?.ToLowerInvariant();
foreach (var importer in fileImporters)
+ {
if (importer.HandledExtensions.Contains(extension))
await importer.Import(paths);
+ }
}
public string[] HandledExtensions => fileImporters.SelectMany(i => i.HandledExtensions).ToArray();
diff --git a/osu.Game/Overlays/Changelog/ChangelogBuild.cs b/osu.Game/Overlays/Changelog/ChangelogBuild.cs
index bce1be5941..5a3ce6291e 100644
--- a/osu.Game/Overlays/Changelog/ChangelogBuild.cs
+++ b/osu.Game/Overlays/Changelog/ChangelogBuild.cs
@@ -110,7 +110,7 @@ namespace osu.Game.Overlays.Changelog
t.Font = fontLarge;
t.Colour = entryColour;
});
- title.AddLink($"{entry.Repository.Replace("ppy/", "")}#{entry.GithubPullRequestId}", entry.GithubUrl, Online.Chat.LinkAction.External,
+ title.AddLink($"{entry.Repository.Replace("ppy/", "")}#{entry.GithubPullRequestId}", entry.GithubUrl,
creationParameters: t =>
{
t.Font = fontLarge;
@@ -130,6 +130,7 @@ namespace osu.Game.Overlays.Changelog
});
if (entry.GithubUser.UserId != null)
+ {
title.AddUserLink(new User
{
Username = entry.GithubUser.OsuUsername,
@@ -139,18 +140,23 @@ namespace osu.Game.Overlays.Changelog
t.Font = fontMedium;
t.Colour = entryColour;
});
+ }
else if (entry.GithubUser.GithubUrl != null)
- title.AddLink(entry.GithubUser.DisplayName, entry.GithubUser.GithubUrl, Online.Chat.LinkAction.External, null, null, t =>
+ {
+ title.AddLink(entry.GithubUser.DisplayName, entry.GithubUser.GithubUrl, t =>
{
t.Font = fontMedium;
t.Colour = entryColour;
});
+ }
else
+ {
title.AddText(entry.GithubUser.DisplayName, t =>
{
t.Font = fontSmall;
t.Colour = entryColour;
});
+ }
ChangelogEntries.Add(titleContainer);
diff --git a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs
index adcd33fb48..3297b00322 100644
--- a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs
+++ b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs
@@ -68,11 +68,13 @@ namespace osu.Game.Overlays.Changelog
}
if (build != null)
+ {
Children = new Drawable[]
{
new ChangelogBuildWithNavigation(build) { SelectBuild = SelectBuild },
new Comments(build)
};
+ }
}
public class ChangelogBuildWithNavigation : ChangelogBuild
diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs
index abc1b7233d..560123eb55 100644
--- a/osu.Game/Overlays/Comments/CommentsContainer.cs
+++ b/osu.Game/Overlays/Comments/CommentsContainer.cs
@@ -162,10 +162,12 @@ namespace osu.Game.Overlays.Comments
foreach (var c in response.Comments)
{
if (c.IsTopLevel)
+ {
page.Add(new DrawableComment(c)
{
ShowDeleted = { BindTarget = ShowDeleted }
});
+ }
}
LoadComponentAsync(page, loaded =>
diff --git a/osu.Game/Overlays/Comments/VotePill.cs b/osu.Game/Overlays/Comments/VotePill.cs
index e8d9013fd9..ab35a477aa 100644
--- a/osu.Game/Overlays/Comments/VotePill.cs
+++ b/osu.Game/Overlays/Comments/VotePill.cs
@@ -48,8 +48,6 @@ namespace osu.Game.Overlays.Comments
{
this.comment = comment;
- Action = onAction;
-
AutoSizeAxes = Axes.X;
Height = 20;
LoadingAnimationSize = new Vector2(10);
@@ -60,6 +58,9 @@ namespace osu.Game.Overlays.Comments
{
AccentColour = borderContainer.BorderColour = sideNumber.Colour = colours.GreenLight;
hoverLayer.Colour = Color4.Black.Opacity(0.5f);
+
+ if (api.IsLoggedIn && api.LocalUser.Value.Id != comment.UserId)
+ Action = onAction;
}
protected override void LoadComplete()
@@ -157,6 +158,9 @@ namespace osu.Game.Overlays.Comments
private void updateDisplay()
{
+ if (Action == null)
+ return;
+
if (isVoted.Value)
{
hoverLayer.FadeTo(IsHovered ? 1 : 0);
diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs
index 3ffc3f332b..c1c5113c5e 100644
--- a/osu.Game/Overlays/Direct/DirectPanel.cs
+++ b/osu.Game/Overlays/Direct/DirectPanel.cs
@@ -149,8 +149,10 @@ namespace osu.Game.Overlays.Direct
icons.Add(new GroupedDifficultyIcon(SetInfo.Beatmaps.FindAll(b => b.Ruleset.Equals(ruleset)), ruleset, this is DirectListPanel ? Color4.White : colours.Gray5));
}
else
+ {
foreach (var b in SetInfo.Beatmaps.OrderBy(beatmap => beatmap.StarDifficulty))
icons.Add(new DifficultyIcon(b));
+ }
return icons;
}
diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs
index 58892cd0dd..8252020e9b 100644
--- a/osu.Game/Overlays/Mods/ModButton.cs
+++ b/osu.Game/Overlays/Mods/ModButton.cs
@@ -194,8 +194,10 @@ namespace osu.Game.Overlays.Mods
start = Mods.Length - 1;
for (int i = start; i < Mods.Length && i >= 0; i += direction)
+ {
if (SelectAt(i))
return;
+ }
Deselect();
}
diff --git a/osu.Game/Overlays/Mods/ModSection.cs b/osu.Game/Overlays/Mods/ModSection.cs
index 35a94eb43f..3b16189e73 100644
--- a/osu.Game/Overlays/Mods/ModSection.cs
+++ b/osu.Game/Overlays/Mods/ModSection.cs
@@ -112,6 +112,7 @@ namespace osu.Game.Overlays.Mods
if (selected == null) continue;
foreach (var type in modTypes)
+ {
if (type.IsInstanceOfType(selected))
{
if (immediate)
@@ -119,6 +120,7 @@ namespace osu.Game.Overlays.Mods
else
Scheduler.AddDelayed(button.Deselect, delay += 50);
}
+ }
}
}
diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs
index 6b79f2af07..4f73cbfacd 100644
--- a/osu.Game/Overlays/NowPlayingOverlay.cs
+++ b/osu.Game/Overlays/NowPlayingOverlay.cs
@@ -168,12 +168,13 @@ namespace osu.Game.Overlays
},
}
},
- progressBar = new ProgressBar
+ progressBar = new HoverableProgressBar
{
Origin = Anchor.BottomCentre,
Anchor = Anchor.BottomCentre,
- Height = progress_height,
+ Height = progress_height / 2,
FillColour = colours.Yellow,
+ BackgroundColour = colours.YellowDarker.Opacity(0.5f),
OnSeek = musicController.SeekTo
}
},
@@ -401,5 +402,20 @@ namespace osu.Game.Overlays
return base.OnDragEnd(e);
}
}
+
+ private class HoverableProgressBar : ProgressBar
+ {
+ protected override bool OnHover(HoverEvent e)
+ {
+ this.ResizeHeightTo(progress_height, 500, Easing.OutQuint);
+ return base.OnHover(e);
+ }
+
+ protected override void OnHoverLost(HoverLostEvent e)
+ {
+ this.ResizeHeightTo(progress_height / 2, 500, Easing.OutQuint);
+ base.OnHoverLost(e);
+ }
+ }
}
}
diff --git a/osu.Game/Overlays/Settings/SidebarButton.cs b/osu.Game/Overlays/Settings/SidebarButton.cs
index a94f76e7af..68836bc6b3 100644
--- a/osu.Game/Overlays/Settings/SidebarButton.cs
+++ b/osu.Game/Overlays/Settings/SidebarButton.cs
@@ -1,7 +1,6 @@
// 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;
using osuTK.Graphics;
using osu.Framework.Allocation;
@@ -9,21 +8,18 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
-using osu.Framework.Graphics.UserInterface;
-using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Overlays.Settings
{
- public class SidebarButton : Button
+ public class SidebarButton : OsuButton
{
private readonly SpriteIcon drawableIcon;
private readonly SpriteText headerText;
private readonly Box selectionIndicator;
private readonly Container text;
- public new Action Action;
private SettingsSection section;
@@ -62,12 +58,11 @@ namespace osu.Game.Overlays.Settings
public SidebarButton()
{
- BackgroundColour = OsuColour.Gray(60);
- Background.Alpha = 0;
-
Height = Sidebar.DEFAULT_WIDTH;
RelativeSizeAxes = Axes.X;
+ BackgroundColour = Color4.Black;
+
AddRange(new Drawable[]
{
text = new Container
@@ -99,7 +94,6 @@ namespace osu.Game.Overlays.Settings
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
},
- new HoverClickSounds(HoverSampleSet.Loud),
});
}
@@ -108,23 +102,5 @@ namespace osu.Game.Overlays.Settings
{
selectionIndicator.Colour = colours.Yellow;
}
-
- protected override bool OnClick(ClickEvent e)
- {
- Action?.Invoke(section);
- return base.OnClick(e);
- }
-
- protected override bool OnHover(HoverEvent e)
- {
- Background.FadeTo(0.4f, 200);
- return base.OnHover(e);
- }
-
- protected override void OnHoverLost(HoverLostEvent e)
- {
- Background.FadeTo(0, 200);
- base.OnHoverLost(e);
- }
}
}
diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs
index d028664fe0..2948231c4b 100644
--- a/osu.Game/Overlays/SettingsPanel.cs
+++ b/osu.Game/Overlays/SettingsPanel.cs
@@ -123,9 +123,9 @@ namespace osu.Game.Overlays
var button = new SidebarButton
{
Section = section,
- Action = s =>
+ Action = () =>
{
- SectionsContainer.ScrollTo(s);
+ SectionsContainer.ScrollTo(section);
Sidebar.State = ExpandedState.Contracted;
},
};
diff --git a/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs b/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs
index 2c79f5bc0e..8f2dbce6f7 100644
--- a/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs
+++ b/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs
@@ -18,8 +18,6 @@ namespace osu.Game.Overlays.Toolbar
{
public class ToolbarRulesetSelector : RulesetSelector
{
- private const float padding = 10;
-
protected Drawable ModeButtonLine { get; private set; }
public ToolbarRulesetSelector()
@@ -39,7 +37,7 @@ namespace osu.Game.Overlays.Toolbar
},
ModeButtonLine = new Container
{
- Size = new Vector2(padding * 2 + ToolbarButton.WIDTH, 3),
+ Size = new Vector2(ToolbarButton.WIDTH, 3),
Anchor = Anchor.BottomLeft,
Origin = Anchor.TopLeft,
Masking = true,
@@ -91,7 +89,6 @@ namespace osu.Game.Overlays.Toolbar
RelativeSizeAxes = Axes.Y,
AutoSizeAxes = Axes.X,
Direction = FillDirection.Horizontal,
- Padding = new MarginPadding { Left = padding, Right = padding },
};
protected override bool OnKeyDown(KeyDownEvent e)
diff --git a/osu.Game/Rulesets/Difficulty/Utils/LimitedCapacityStack.cs b/osu.Game/Rulesets/Difficulty/Utils/LimitedCapacityStack.cs
index 95b7d9b19d..d47caf409b 100644
--- a/osu.Game/Rulesets/Difficulty/Utils/LimitedCapacityStack.cs
+++ b/osu.Game/Rulesets/Difficulty/Utils/LimitedCapacityStack.cs
@@ -81,8 +81,10 @@ namespace osu.Game.Rulesets.Difficulty.Utils
yield return array[i];
if (Count == capacity)
+ {
for (int i = 0; i < marker; ++i)
yield return array[i];
+ }
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
diff --git a/osu.Game/Rulesets/Edit/DrawableEditRulesetWrapper.cs b/osu.Game/Rulesets/Edit/DrawableEditRulesetWrapper.cs
index af565f8896..4710465536 100644
--- a/osu.Game/Rulesets/Edit/DrawableEditRulesetWrapper.cs
+++ b/osu.Game/Rulesets/Edit/DrawableEditRulesetWrapper.cs
@@ -64,6 +64,10 @@ namespace osu.Game.Rulesets.Edit
drawableRuleset.Playfield.PostProcess();
}
+ public override bool PropagatePositionalInputSubTree => false;
+
+ public override bool PropagateNonPositionalInputSubTree => false;
+
public PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => drawableRuleset.CreatePlayfieldAdjustmentContainer();
protected override void Dispose(bool isDisposing)
diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs
index 1c942e52ce..805fc2b46f 100644
--- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs
+++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs
@@ -40,6 +40,9 @@ namespace osu.Game.Rulesets.Edit
[Resolved]
protected IFrameBasedClock EditorClock { get; private set; }
+ [Resolved]
+ private IAdjustableClock adjustableClock { get; set; }
+
[Resolved]
private BindableBeatDivisor beatDivisor { get; set; }
@@ -256,6 +259,9 @@ namespace osu.Game.Rulesets.Edit
public void EndPlacement(HitObject hitObject)
{
EditorBeatmap.Add(hitObject);
+
+ adjustableClock.Seek(hitObject.StartTime);
+
showGridFor(Enumerable.Empty());
}
diff --git a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs
index 0701513933..2923411ce1 100644
--- a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs
+++ b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs
@@ -82,6 +82,9 @@ namespace osu.Game.Rulesets.Edit
}
}
+ // When not selected, input is only required for the blueprint itself to receive IsHovering
+ protected override bool ShouldBeConsideredForInput(Drawable child) => State == SelectionState.Selected;
+
///
/// Selects this , causing it to become visible.
///
diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
index 1d9b66f88d..af1a2fb63a 100644
--- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
+++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
@@ -113,8 +113,10 @@ namespace osu.Game.Rulesets.Objects.Drawables
if (samples.Length > 0)
{
if (HitObject.SampleControlPoint == null)
+ {
throw new ArgumentNullException(nameof(HitObject.SampleControlPoint), $"{nameof(HitObject)}s must always have an attached {nameof(HitObject.SampleControlPoint)}."
+ $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}.");
+ }
samples = samples.Select(s => HitObject.SampleControlPoint.ApplyTo(s)).ToArray();
foreach (var s in samples)
diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs
index e990938291..4049e40013 100644
--- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs
@@ -74,9 +74,12 @@ namespace osu.Game.Rulesets.Objects.Legacy
string[] pointSplit = split[5].Split('|');
int pointCount = 1;
+
foreach (var t in pointSplit)
+ {
if (t.Length > 1)
pointCount++;
+ }
var points = new Vector2[pointCount];
diff --git a/osu.Game/Rulesets/Objects/SliderPath.cs b/osu.Game/Rulesets/Objects/SliderPath.cs
index bc9571c85d..7763b0eaaf 100644
--- a/osu.Game/Rulesets/Objects/SliderPath.cs
+++ b/osu.Game/Rulesets/Objects/SliderPath.cs
@@ -185,8 +185,10 @@ namespace osu.Game.Rulesets.Objects
ReadOnlySpan cpSpan = ControlPoints.Slice(start, end - start);
foreach (Vector2 t in calculateSubpath(cpSpan))
+ {
if (calculatedPath.Count == 0 || calculatedPath.Last() != t)
calculatedPath.Add(t);
+ }
start = end;
}
diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs
index 23988ff0ff..7d13afe9e5 100644
--- a/osu.Game/Rulesets/RulesetStore.cs
+++ b/osu.Game/Rulesets/RulesetStore.cs
@@ -69,8 +69,10 @@ namespace osu.Game.Rulesets
//add any other modes
foreach (var r in instances.Where(r => r.LegacyID == null))
+ {
if (context.RulesetInfo.FirstOrDefault(ri => ri.InstantiationInfo == r.RulesetInfo.InstantiationInfo) == null)
context.RulesetInfo.Add(r.RulesetInfo);
+ }
context.SaveChanges();
diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs
index e005eea831..d1749d33c0 100644
--- a/osu.Game/Rulesets/UI/DrawableRuleset.cs
+++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs
@@ -436,8 +436,10 @@ namespace osu.Game.Rulesets.UI
return h.HitWindows;
foreach (var n in h.NestedHitObjects)
+ {
if (h.HitWindows.WindowFor(HitResult.Miss) > 0)
return n.HitWindows;
+ }
}
return null;
diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs
index f2e7f51b52..ca4983e3d7 100644
--- a/osu.Game/Rulesets/UI/Playfield.cs
+++ b/osu.Game/Rulesets/UI/Playfield.cs
@@ -130,9 +130,13 @@ namespace osu.Game.Rulesets.UI
base.Update();
if (beatmap != null)
+ {
foreach (var mod in mods)
+ {
if (mod is IUpdatableByPlayfield updatable)
updatable.Update(this);
+ }
+ }
}
///
diff --git a/osu.Game/Screens/Edit/BindableBeatDivisor.cs b/osu.Game/Screens/Edit/BindableBeatDivisor.cs
index a724f354e7..ce95d81f54 100644
--- a/osu.Game/Screens/Edit/BindableBeatDivisor.cs
+++ b/osu.Game/Screens/Edit/BindableBeatDivisor.cs
@@ -29,7 +29,10 @@ namespace osu.Game.Screens.Edit
set
{
if (!VALID_DIVISORS.Contains(value))
- throw new ArgumentOutOfRangeException($"Provided divisor is not in {nameof(VALID_DIVISORS)}");
+ {
+ // If it doesn't match, value will be 0, but will be clamped to the valid range via DefaultMinValue
+ value = Array.FindLast(VALID_DIVISORS, d => d < value);
+ }
base.Value = value;
}
diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs
index 4d89e43ee5..9e4691e4dd 100644
--- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs
@@ -218,12 +218,17 @@ namespace osu.Game.Screens.Edit.Compose.Components
}
AddInternal(marker = new Marker());
+ }
- CurrentNumber.ValueChanged += div =>
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ CurrentNumber.BindValueChanged(div =>
{
marker.MoveToX(getMappedPosition(div.NewValue), 100, Easing.OutQuint);
marker.Flash();
- };
+ }, true);
}
protected override void UpdateValue(float value)
diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs
index a145dea6af..8fa022f129 100644
--- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs
@@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Input;
using osu.Framework.Input.Events;
+using osu.Framework.Timing;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools;
using osu.Game.Rulesets.Objects;
@@ -30,6 +31,9 @@ namespace osu.Game.Screens.Edit.Compose.Components
private SelectionHandler selectionHandler;
private InputManager inputManager;
+ [Resolved]
+ private IAdjustableClock adjustableClock { get; set; }
+
[Resolved]
private HitObjectComposer composer { get; set; }
@@ -106,6 +110,17 @@ namespace osu.Game.Screens.Edit.Compose.Components
return true;
}
+ protected override bool OnDoubleClick(DoubleClickEvent e)
+ {
+ SelectionBlueprint clickedBlueprint = selectionHandler.SelectedBlueprints.FirstOrDefault(b => b.IsHovered);
+
+ if (clickedBlueprint == null)
+ return false;
+
+ adjustableClock?.Seek(clickedBlueprint.DrawableObject.HitObject.StartTime);
+ return true;
+ }
+
protected override bool OnMouseUp(MouseUpEvent e)
{
// Special case for when a drag happened instead of a click
@@ -254,6 +269,12 @@ namespace osu.Game.Screens.Edit.Compose.Components
{
Debug.Assert(!clickSelectionBegan);
+ // If a select blueprint is already hovered, disallow changes in selection.
+ // Exception is made when holding control, as deselection should still be allowed.
+ if (!e.CurrentState.Keyboard.ControlPressed &&
+ selectionHandler.SelectedBlueprints.Any(s => s.IsHovered))
+ return;
+
foreach (SelectionBlueprint blueprint in selectionBlueprints.AliveBlueprints)
{
if (blueprint.IsHovered)
@@ -361,7 +382,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
(Vector2 snappedPosition, double snappedTime) = composer.GetSnappedPosition(ToLocalSpace(movePosition), draggedObject.StartTime);
// Move the hitobjects
- selectionHandler.HandleMovement(new MoveSelectionEvent(movementBlueprint, startPosition, ToScreenSpace(snappedPosition)));
+ if (!selectionHandler.HandleMovement(new MoveSelectionEvent(movementBlueprint, startPosition, ToScreenSpace(snappedPosition))))
+ return true;
// Apply the start time at the newly snapped-to position
double offset = snappedTime - draggedObject.StartTime;
diff --git a/osu.Game/Screens/Edit/Compose/Components/CircularDistanceSnapGrid.cs b/osu.Game/Screens/Edit/Compose/Components/CircularDistanceSnapGrid.cs
index f45115e1e4..0f2bae6305 100644
--- a/osu.Game/Screens/Edit/Compose/Components/CircularDistanceSnapGrid.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/CircularDistanceSnapGrid.cs
@@ -12,8 +12,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
{
public abstract class CircularDistanceSnapGrid : DistanceSnapGrid
{
- protected CircularDistanceSnapGrid(HitObject hitObject, Vector2 centrePosition)
- : base(hitObject, centrePosition)
+ protected CircularDistanceSnapGrid(HitObject hitObject, HitObject nextHitObject, Vector2 centrePosition)
+ : base(hitObject, nextHitObject, centrePosition)
{
}
@@ -45,7 +45,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
float dx = Math.Max(centrePosition.X, DrawWidth - centrePosition.X);
float dy = Math.Max(centrePosition.Y, DrawHeight - centrePosition.Y);
float maxDistance = new Vector2(dx, dy).Length;
- int requiredCircles = (int)(maxDistance / DistanceSpacing);
+ int requiredCircles = Math.Min(MaxIntervals, (int)(maxDistance / DistanceSpacing));
for (int i = 0; i < requiredCircles; i++)
{
@@ -65,15 +65,17 @@ namespace osu.Game.Screens.Edit.Compose.Components
public override (Vector2 position, double time) GetSnappedPosition(Vector2 position)
{
- Vector2 direction = position - CentrePosition;
+ if (MaxIntervals == 0)
+ return (CentrePosition, StartTime);
+ Vector2 direction = position - CentrePosition;
if (direction == Vector2.Zero)
direction = new Vector2(0.001f, 0.001f);
float distance = direction.Length;
float radius = DistanceSpacing;
- int radialCount = Math.Max(1, (int)Math.Round(distance / radius));
+ int radialCount = MathHelper.Clamp((int)Math.Round(distance / radius), 1, MaxIntervals);
Vector2 normalisedDirection = direction * new Vector2(1f / distance);
Vector2 snappedPosition = CentrePosition + normalisedDirection * radialCount * radius;
diff --git a/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs b/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs
index 193474093f..475b6e7274 100644
--- a/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Caching;
using osu.Framework.Graphics;
@@ -29,6 +30,11 @@ namespace osu.Game.Screens.Edit.Compose.Components
///
protected double StartTime { get; private set; }
+ ///
+ /// The maximum number of distance snapping intervals allowed.
+ ///
+ protected int MaxIntervals { get; private set; }
+
///
/// The position which the grid is centred on.
/// The first beat snapping tick is located at + in the desired direction.
@@ -49,12 +55,15 @@ namespace osu.Game.Screens.Edit.Compose.Components
private readonly Cached gridCache = new Cached();
private readonly HitObject hitObject;
+ private readonly HitObject nextHitObject;
- protected DistanceSnapGrid(HitObject hitObject, Vector2 centrePosition)
+ protected DistanceSnapGrid(HitObject hitObject, [CanBeNull] HitObject nextHitObject, Vector2 centrePosition)
{
this.hitObject = hitObject;
+ this.nextHitObject = nextHitObject;
CentrePosition = centrePosition;
+
RelativeSizeAxes = Axes.Both;
}
@@ -74,6 +83,16 @@ namespace osu.Game.Screens.Edit.Compose.Components
private void updateSpacing()
{
DistanceSpacing = SnapProvider.GetBeatSnapDistanceAt(StartTime);
+
+ if (nextHitObject == null)
+ MaxIntervals = int.MaxValue;
+ else
+ {
+ // +1 is added since a snapped hitobject may have its start time slightly less than the snapped time due to floating point errors
+ double maxDuration = nextHitObject.StartTime - StartTime + 1;
+ MaxIntervals = (int)(maxDuration / SnapProvider.DistanceToDuration(StartTime, DistanceSpacing));
+ }
+
gridCache.Invalidate();
}
diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs
index d7821eff07..44bf22cfe1 100644
--- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs
@@ -8,21 +8,21 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
-using osu.Framework.Input.Events;
+using osu.Framework.Input;
+using osu.Framework.Input.Bindings;
using osu.Framework.Input.States;
using osu.Game.Graphics;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
using osuTK;
-using osuTK.Input;
namespace osu.Game.Screens.Edit.Compose.Components
{
///
/// A component which outlines s and handles movement of selections.
///
- public class SelectionHandler : CompositeDrawable
+ public class SelectionHandler : CompositeDrawable, IKeyBindingHandler
{
public const float BORDER_RADIUS = 2;
@@ -68,26 +68,24 @@ namespace osu.Game.Screens.Edit.Compose.Components
/// Handles the selected s being moved.
///
/// The move event.
- public virtual void HandleMovement(MoveSelectionEvent moveEvent)
- {
- }
+ /// Whether any s were moved.
+ public virtual bool HandleMovement(MoveSelectionEvent moveEvent) => false;
- protected override bool OnKeyDown(KeyDownEvent e)
+ public bool OnPressed(PlatformAction action)
{
- if (e.Repeat)
- return base.OnKeyDown(e);
-
- switch (e.Key)
+ switch (action.ActionMethod)
{
- case Key.Delete:
+ case PlatformActionMethod.Delete:
foreach (var h in selectedBlueprints.ToList())
placementHandler.Delete(h.DrawableObject.HitObject);
return true;
}
- return base.OnKeyDown(e);
+ return false;
}
+ public bool OnReleased(PlatformAction action) => action.ActionMethod == PlatformActionMethod.Delete;
+
#endregion
#region Selection Handling
diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs
index 35408e4003..2d088cd3f7 100644
--- a/osu.Game/Screens/Edit/Editor.cs
+++ b/osu.Game/Screens/Edit/Editor.cs
@@ -36,6 +36,8 @@ namespace osu.Game.Screens.Edit
{
protected override BackgroundScreen CreateBackground() => new BackgroundScreenCustom(@"Backgrounds/bg4");
+ public override float BackgroundParallaxAmount => 0.1f;
+
public override bool AllowBackButton => false;
public override bool HideOverlaysOnEnter => true;
@@ -64,7 +66,10 @@ namespace osu.Game.Screens.Edit
{
this.host = host;
- // TODO: should probably be done at a DrawableRuleset level to share logic with Player.
+ beatDivisor.Value = Beatmap.Value.BeatmapInfo.BeatDivisor;
+ beatDivisor.BindValueChanged(divisor => Beatmap.Value.BeatmapInfo.BeatDivisor = divisor.NewValue);
+
+ // Todo: should probably be done at a DrawableRuleset level to share logic with Player.
var sourceClock = (IAdjustableClock)Beatmap.Value.Track ?? new StopwatchClock();
clock = new EditorClock(Beatmap.Value, beatDivisor) { IsCoupled = false };
clock.ChangeSource(sourceClock);
@@ -241,7 +246,8 @@ namespace osu.Game.Screens.Edit
base.OnEntering(last);
Background.FadeColour(Color4.DarkGray, 500);
- resetTrack();
+
+ resetTrack(true);
}
public override bool OnExiting(IScreen next)
@@ -252,10 +258,24 @@ namespace osu.Game.Screens.Edit
return base.OnExiting(next);
}
- private void resetTrack()
+ private void resetTrack(bool seekToStart = false)
{
Beatmap.Value.Track?.ResetSpeedAdjustments();
Beatmap.Value.Track?.Stop();
+
+ if (seekToStart)
+ {
+ double targetTime = 0;
+
+ if (Beatmap.Value.Beatmap.HitObjects.Count > 0)
+ {
+ // seek to one beat length before the first hitobject
+ targetTime = Beatmap.Value.Beatmap.HitObjects[0].StartTime;
+ targetTime -= Beatmap.Value.Beatmap.ControlPointInfo.TimingPointAt(targetTime).BeatLength;
+ }
+
+ clock.Seek(Math.Max(0, targetTime));
+ }
}
private void exportBeatmap() => host.OpenFileExternally(Beatmap.Value.Save());
diff --git a/osu.Game/Screens/Edit/Timing/ControlPointSettings.cs b/osu.Game/Screens/Edit/Timing/ControlPointSettings.cs
new file mode 100644
index 0000000000..e1182d9fa4
--- /dev/null
+++ b/osu.Game/Screens/Edit/Timing/ControlPointSettings.cs
@@ -0,0 +1,50 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Collections.Generic;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Containers;
+
+namespace osu.Game.Screens.Edit.Timing
+{
+ public class ControlPointSettings : CompositeDrawable
+ {
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ RelativeSizeAxes = Axes.Both;
+
+ InternalChildren = new Drawable[]
+ {
+ new Box
+ {
+ Colour = colours.Gray3,
+ RelativeSizeAxes = Axes.Both,
+ },
+ new OsuScrollContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Child = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ Children = createSections()
+ },
+ }
+ };
+ }
+
+ private IReadOnlyList createSections() => new Drawable[]
+ {
+ new TimingSection(),
+ new DifficultySection(),
+ new SampleSection(),
+ new EffectSection(),
+ };
+ }
+}
diff --git a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs
new file mode 100644
index 0000000000..96e3ab48f2
--- /dev/null
+++ b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs
@@ -0,0 +1,247 @@
+// 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.Bindables;
+using osu.Framework.Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Input.Events;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Containers;
+using osu.Game.Graphics.Sprites;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Screens.Edit.Timing
+{
+ public class ControlPointTable : TableContainer
+ {
+ private const float horizontal_inset = 20;
+ private const float row_height = 25;
+ private const int text_size = 14;
+
+ private readonly FillFlowContainer backgroundFlow;
+
+ [Resolved]
+ private Bindable selectedGroup { get; set; }
+
+ public ControlPointTable()
+ {
+ RelativeSizeAxes = Axes.X;
+ AutoSizeAxes = Axes.Y;
+
+ Padding = new MarginPadding { Horizontal = horizontal_inset };
+ RowSize = new Dimension(GridSizeMode.Absolute, row_height);
+
+ AddInternal(backgroundFlow = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Depth = 1f,
+ Padding = new MarginPadding { Horizontal = -horizontal_inset },
+ Margin = new MarginPadding { Top = row_height }
+ });
+ }
+
+ public IEnumerable ControlGroups
+ {
+ set
+ {
+ Content = null;
+ backgroundFlow.Clear();
+
+ if (value?.Any() != true)
+ return;
+
+ foreach (var group in value)
+ {
+ backgroundFlow.Add(new RowBackground(group));
+ }
+
+ Columns = createHeaders();
+ Content = value.Select((g, i) => createContent(i, g)).ToArray().ToRectangular();
+ }
+ }
+
+ private TableColumn[] createHeaders()
+ {
+ var columns = new List
+ {
+ new TableColumn(string.Empty, Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
+ new TableColumn("Time", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
+ new TableColumn("Attributes", Anchor.Centre),
+ };
+
+ return columns.ToArray();
+ }
+
+ private Drawable[] createContent(int index, ControlPointGroup group) => new Drawable[]
+ {
+ new OsuSpriteText
+ {
+ Text = $"#{index + 1}",
+ Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold),
+ Margin = new MarginPadding(10)
+ },
+ new OsuSpriteText
+ {
+ Text = $"{group.Time:n0}ms",
+ Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold)
+ },
+ new ControlGroupAttributes(group),
+ };
+
+ private class ControlGroupAttributes : CompositeDrawable
+ {
+ private readonly IBindableList controlPoints;
+
+ private readonly FillFlowContainer fill;
+
+ public ControlGroupAttributes(ControlPointGroup group)
+ {
+ InternalChild = fill = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Direction = FillDirection.Horizontal,
+ Padding = new MarginPadding(10),
+ Spacing = new Vector2(2)
+ };
+
+ controlPoints = group.ControlPoints.GetBoundCopy();
+ controlPoints.ItemsAdded += _ => createChildren();
+ controlPoints.ItemsRemoved += _ => createChildren();
+
+ createChildren();
+ }
+
+ private void createChildren()
+ {
+ fill.ChildrenEnumerable = controlPoints.Select(createAttribute).Where(c => c != null);
+ }
+
+ private Drawable createAttribute(ControlPoint controlPoint)
+ {
+ switch (controlPoint)
+ {
+ case TimingControlPoint timing:
+ return new RowAttribute("timing", () => $"{60000 / timing.BeatLength:n1}bpm {timing.TimeSignature}");
+
+ case DifficultyControlPoint difficulty:
+
+ return new RowAttribute("difficulty", () => $"{difficulty.SpeedMultiplier:n2}x");
+
+ case EffectControlPoint effect:
+ return new RowAttribute("effect", () => $"{(effect.KiaiMode ? "Kiai " : "")}{(effect.OmitFirstBarLine ? "NoBarLine " : "")}");
+
+ case SampleControlPoint sample:
+ return new RowAttribute("sample", () => $"{sample.SampleBank} {sample.SampleVolume}%");
+ }
+
+ return null;
+ }
+ }
+
+ protected override Drawable CreateHeader(int index, TableColumn column) => new HeaderText(column?.Header ?? string.Empty);
+
+ private class HeaderText : OsuSpriteText
+ {
+ public HeaderText(string text)
+ {
+ Text = text.ToUpper();
+ Font = OsuFont.GetFont(size: 12, weight: FontWeight.Black);
+ }
+ }
+
+ public class RowBackground : OsuClickableContainer
+ {
+ private readonly ControlPointGroup controlGroup;
+ private const int fade_duration = 100;
+
+ private readonly Box hoveredBackground;
+
+ [Resolved]
+ private Bindable selectedGroup { get; set; }
+
+ public RowBackground(ControlPointGroup controlGroup)
+ {
+ this.controlGroup = controlGroup;
+ RelativeSizeAxes = Axes.X;
+ Height = 25;
+
+ AlwaysPresent = true;
+
+ CornerRadius = 3;
+ Masking = true;
+
+ Children = new Drawable[]
+ {
+ hoveredBackground = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Alpha = 0,
+ },
+ };
+
+ Action = () => selectedGroup.Value = controlGroup;
+ }
+
+ private Color4 colourHover;
+ private Color4 colourSelected;
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ hoveredBackground.Colour = colourHover = colours.BlueDarker;
+ colourSelected = colours.YellowDarker;
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ selectedGroup.BindValueChanged(group => { Selected = controlGroup == group.NewValue; }, true);
+ }
+
+ private bool selected;
+
+ protected bool Selected
+ {
+ get => selected;
+ set
+ {
+ if (value == selected)
+ return;
+
+ selected = value;
+ updateState();
+ }
+ }
+
+ protected override bool OnHover(HoverEvent e)
+ {
+ updateState();
+ return base.OnHover(e);
+ }
+
+ protected override void OnHoverLost(HoverLostEvent e)
+ {
+ updateState();
+ base.OnHoverLost(e);
+ }
+
+ private void updateState()
+ {
+ hoveredBackground.FadeColour(selected ? colourSelected : colourHover, 450, Easing.OutQuint);
+
+ if (selected || IsHovered)
+ hoveredBackground.FadeIn(fade_duration, Easing.OutQuint);
+ else
+ hoveredBackground.FadeOut(fade_duration, Easing.OutQuint);
+ }
+ }
+ }
+}
diff --git a/osu.Game/Screens/Edit/Timing/DifficultySection.cs b/osu.Game/Screens/Edit/Timing/DifficultySection.cs
new file mode 100644
index 0000000000..58a7f97e5f
--- /dev/null
+++ b/osu.Game/Screens/Edit/Timing/DifficultySection.cs
@@ -0,0 +1,48 @@
+// 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.Bindables;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Overlays.Settings;
+
+namespace osu.Game.Screens.Edit.Timing
+{
+ internal class DifficultySection : Section
+ {
+ private SettingsSlider multiplier;
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Flow.AddRange(new[]
+ {
+ multiplier = new SettingsSlider
+ {
+ LabelText = "Speed Multiplier",
+ Bindable = new DifficultyControlPoint().SpeedMultiplierBindable,
+ RelativeSizeAxes = Axes.X,
+ }
+ });
+ }
+
+ protected override void OnControlPointChanged(ValueChangedEvent point)
+ {
+ if (point.NewValue != null)
+ {
+ multiplier.Bindable = point.NewValue.SpeedMultiplierBindable;
+ }
+ }
+
+ protected override DifficultyControlPoint CreatePoint()
+ {
+ var reference = Beatmap.Value.Beatmap.ControlPointInfo.DifficultyPointAt(SelectedGroup.Value.Time);
+
+ return new DifficultyControlPoint
+ {
+ SpeedMultiplier = reference.SpeedMultiplier,
+ };
+ }
+ }
+}
diff --git a/osu.Game/Screens/Edit/Timing/EffectSection.cs b/osu.Game/Screens/Edit/Timing/EffectSection.cs
new file mode 100644
index 0000000000..71e7f42713
--- /dev/null
+++ b/osu.Game/Screens/Edit/Timing/EffectSection.cs
@@ -0,0 +1,46 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Graphics.UserInterfaceV2;
+
+namespace osu.Game.Screens.Edit.Timing
+{
+ internal class EffectSection : Section
+ {
+ private LabelledSwitchButton kiai;
+ private LabelledSwitchButton omitBarLine;
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Flow.AddRange(new[]
+ {
+ kiai = new LabelledSwitchButton { Label = "Kiai Time" },
+ omitBarLine = new LabelledSwitchButton { Label = "Skip Bar Line" },
+ });
+ }
+
+ protected override void OnControlPointChanged(ValueChangedEvent point)
+ {
+ if (point.NewValue != null)
+ {
+ kiai.Current = point.NewValue.KiaiModeBindable;
+ omitBarLine.Current = point.NewValue.OmitFirstBarLineBindable;
+ }
+ }
+
+ protected override EffectControlPoint CreatePoint()
+ {
+ var reference = Beatmap.Value.Beatmap.ControlPointInfo.EffectPointAt(SelectedGroup.Value.Time);
+
+ return new EffectControlPoint
+ {
+ KiaiMode = reference.KiaiMode,
+ OmitFirstBarLine = reference.OmitFirstBarLine
+ };
+ }
+ }
+}
diff --git a/osu.Game/Screens/Edit/Timing/RowAttribute.cs b/osu.Game/Screens/Edit/Timing/RowAttribute.cs
new file mode 100644
index 0000000000..be8f693683
--- /dev/null
+++ b/osu.Game/Screens/Edit/Timing/RowAttribute.cs
@@ -0,0 +1,60 @@
+// 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.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Cursor;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+
+namespace osu.Game.Screens.Edit.Timing
+{
+ public class RowAttribute : CompositeDrawable, IHasTooltip
+ {
+ private readonly string header;
+ private readonly Func content;
+
+ public RowAttribute(string header, Func content)
+ {
+ this.header = header;
+ this.content = content;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ AutoSizeAxes = Axes.X;
+
+ Height = 20;
+
+ Anchor = Anchor.CentreLeft;
+ Origin = Anchor.CentreLeft;
+
+ Masking = true;
+ CornerRadius = 5;
+
+ InternalChildren = new Drawable[]
+ {
+ new Box
+ {
+ Colour = colours.Yellow,
+ RelativeSizeAxes = Axes.Both,
+ },
+ new OsuSpriteText
+ {
+ Padding = new MarginPadding(2),
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Font = OsuFont.Default.With(weight: FontWeight.SemiBold, size: 12),
+ Text = header,
+ Colour = colours.Gray3
+ },
+ };
+ }
+
+ public string TooltipText => content();
+ }
+}
diff --git a/osu.Game/Screens/Edit/Timing/SampleSection.cs b/osu.Game/Screens/Edit/Timing/SampleSection.cs
new file mode 100644
index 0000000000..4665c77991
--- /dev/null
+++ b/osu.Game/Screens/Edit/Timing/SampleSection.cs
@@ -0,0 +1,55 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Bindables;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Graphics.UserInterfaceV2;
+using osu.Game.Overlays.Settings;
+
+namespace osu.Game.Screens.Edit.Timing
+{
+ internal class SampleSection : Section
+ {
+ private LabelledTextBox bank;
+ private SettingsSlider volume;
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Flow.AddRange(new Drawable[]
+ {
+ bank = new LabelledTextBox
+ {
+ Label = "Bank Name",
+ },
+ volume = new SettingsSlider
+ {
+ Bindable = new SampleControlPoint().SampleVolumeBindable,
+ LabelText = "Volume",
+ }
+ });
+ }
+
+ protected override void OnControlPointChanged(ValueChangedEvent point)
+ {
+ if (point.NewValue != null)
+ {
+ bank.Current = point.NewValue.SampleBankBindable;
+ volume.Bindable = point.NewValue.SampleVolumeBindable;
+ }
+ }
+
+ protected override SampleControlPoint CreatePoint()
+ {
+ var reference = Beatmap.Value.Beatmap.ControlPointInfo.SamplePointAt(SelectedGroup.Value.Time);
+
+ return new SampleControlPoint
+ {
+ SampleBank = reference.SampleBank,
+ SampleVolume = reference.SampleVolume,
+ };
+ }
+ }
+}
diff --git a/osu.Game/Screens/Edit/Timing/Section.cs b/osu.Game/Screens/Edit/Timing/Section.cs
new file mode 100644
index 0000000000..ccf1582486
--- /dev/null
+++ b/osu.Game/Screens/Edit/Timing/Section.cs
@@ -0,0 +1,130 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Linq;
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Graphics;
+using osu.Game.Graphics.UserInterface;
+
+namespace osu.Game.Screens.Edit.Timing
+{
+ internal abstract class Section : CompositeDrawable
+ where T : ControlPoint
+ {
+ private OsuCheckbox checkbox;
+ private Container content;
+
+ protected FillFlowContainer Flow { get; private set; }
+
+ protected Bindable ControlPoint { get; } = new Bindable();
+
+ private const float header_height = 20;
+
+ [Resolved]
+ protected IBindable Beatmap { get; private set; }
+
+ [Resolved]
+ protected Bindable SelectedGroup { get; private set; }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ RelativeSizeAxes = Axes.X;
+ AutoSizeDuration = 200;
+ AutoSizeEasing = Easing.OutQuint;
+ AutoSizeAxes = Axes.Y;
+
+ Masking = true;
+
+ InternalChildren = new Drawable[]
+ {
+ new Box
+ {
+ Colour = colours.Gray1,
+ RelativeSizeAxes = Axes.Both,
+ },
+ new Container
+ {
+ RelativeSizeAxes = Axes.X,
+ Height = header_height,
+ Children = new Drawable[]
+ {
+ checkbox = new OsuCheckbox
+ {
+ LabelText = typeof(T).Name.Replace(typeof(ControlPoint).Name, string.Empty)
+ }
+ }
+ },
+ content = new Container
+ {
+ Y = header_height,
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ Colour = colours.Gray2,
+ RelativeSizeAxes = Axes.Both,
+ },
+ Flow = new FillFlowContainer
+ {
+ Padding = new MarginPadding(10),
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ },
+ }
+ }
+ };
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ checkbox.Current.BindValueChanged(selected =>
+ {
+ if (selected.NewValue)
+ {
+ if (SelectedGroup.Value == null)
+ {
+ checkbox.Current.Value = false;
+ return;
+ }
+
+ if (ControlPoint.Value == null)
+ SelectedGroup.Value.Add(ControlPoint.Value = CreatePoint());
+ }
+ else
+ {
+ if (ControlPoint.Value != null)
+ {
+ SelectedGroup.Value.Remove(ControlPoint.Value);
+ ControlPoint.Value = null;
+ }
+ }
+
+ content.BypassAutoSizeAxes = selected.NewValue ? Axes.None : Axes.Y;
+ }, true);
+
+ SelectedGroup.BindValueChanged(points =>
+ {
+ ControlPoint.Value = points.NewValue?.ControlPoints.OfType().FirstOrDefault();
+ checkbox.Current.Value = ControlPoint.Value != null;
+ }, true);
+
+ ControlPoint.BindValueChanged(OnControlPointChanged, true);
+ }
+
+ protected abstract void OnControlPointChanged(ValueChangedEvent point);
+
+ protected abstract T CreatePoint();
+ }
+}
diff --git a/osu.Game/Screens/Edit/Timing/TimingScreen.cs b/osu.Game/Screens/Edit/Timing/TimingScreen.cs
index 9ded4207e5..d9da3ff92d 100644
--- a/osu.Game/Screens/Edit/Timing/TimingScreen.cs
+++ b/osu.Game/Screens/Edit/Timing/TimingScreen.cs
@@ -1,13 +1,151 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System.Linq;
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Timing;
+using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Containers;
+using osu.Game.Graphics.UserInterface;
+using osuTK;
+
namespace osu.Game.Screens.Edit.Timing
{
- public class TimingScreen : EditorScreen
+ public class TimingScreen : EditorScreenWithTimeline
{
- public TimingScreen()
+ [Cached]
+ private Bindable selectedGroup = new Bindable();
+
+ [Resolved]
+ private IAdjustableClock clock { get; set; }
+
+ protected override Drawable CreateMainContent() => new GridContainer
{
- Child = new ScreenWhiteBox.UnderConstructionMessage("Timing mode");
+ RelativeSizeAxes = Axes.Both,
+ ColumnDimensions = new[]
+ {
+ new Dimension(),
+ new Dimension(GridSizeMode.Absolute, 200),
+ },
+ Content = new[]
+ {
+ new Drawable[]
+ {
+ new ControlPointList(),
+ new ControlPointSettings(),
+ },
+ }
+ };
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ selectedGroup.BindValueChanged(selected =>
+ {
+ if (selected.NewValue != null)
+ clock.Seek(selected.NewValue.Time);
+ });
+ }
+
+ public class ControlPointList : CompositeDrawable
+ {
+ private OsuButton deleteButton;
+ private ControlPointTable table;
+
+ private IBindableList controlGroups;
+
+ [Resolved]
+ private IFrameBasedClock clock { get; set; }
+
+ [Resolved]
+ protected IBindable Beatmap { get; private set; }
+
+ [Resolved]
+ private Bindable selectedGroup { get; set; }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ RelativeSizeAxes = Axes.Both;
+
+ InternalChildren = new Drawable[]
+ {
+ new Box
+ {
+ Colour = colours.Gray0,
+ RelativeSizeAxes = Axes.Both,
+ },
+ new OsuScrollContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Child = table = new ControlPointTable(),
+ },
+ new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Both,
+ Anchor = Anchor.BottomRight,
+ Origin = Anchor.BottomRight,
+ Direction = FillDirection.Horizontal,
+ Margin = new MarginPadding(10),
+ Spacing = new Vector2(5),
+ Children = new Drawable[]
+ {
+ deleteButton = new OsuButton
+ {
+ Text = "-",
+ Size = new Vector2(30, 30),
+ Action = delete,
+ Anchor = Anchor.BottomRight,
+ Origin = Anchor.BottomRight,
+ },
+ new OsuButton
+ {
+ Text = "+",
+ Action = addNew,
+ Size = new Vector2(30, 30),
+ Anchor = Anchor.BottomRight,
+ Origin = Anchor.BottomRight,
+ },
+ }
+ },
+ };
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ selectedGroup.BindValueChanged(selected => { deleteButton.Enabled.Value = selected.NewValue != null; }, true);
+
+ controlGroups = Beatmap.Value.Beatmap.ControlPointInfo.Groups.GetBoundCopy();
+ controlGroups.ItemsAdded += _ => createContent();
+ controlGroups.ItemsRemoved += _ => createContent();
+ createContent();
+ }
+
+ private void createContent() => table.ControlGroups = controlGroups;
+
+ private void delete()
+ {
+ if (selectedGroup.Value == null)
+ return;
+
+ Beatmap.Value.Beatmap.ControlPointInfo.RemoveGroup(selectedGroup.Value);
+
+ selectedGroup.Value = Beatmap.Value.Beatmap.ControlPointInfo.Groups.FirstOrDefault(g => g.Time >= clock.CurrentTime);
+ }
+
+ private void addNew()
+ {
+ selectedGroup.Value = Beatmap.Value.Beatmap.ControlPointInfo.GroupAt(clock.CurrentTime, true);
+ }
}
}
}
diff --git a/osu.Game/Screens/Edit/Timing/TimingSection.cs b/osu.Game/Screens/Edit/Timing/TimingSection.cs
new file mode 100644
index 0000000000..906644ce14
--- /dev/null
+++ b/osu.Game/Screens/Edit/Timing/TimingSection.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 osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Beatmaps.Timing;
+using osu.Game.Overlays.Settings;
+
+namespace osu.Game.Screens.Edit.Timing
+{
+ internal class TimingSection : Section
+ {
+ private SettingsSlider bpm;
+ private SettingsEnumDropdown timeSignature;
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Flow.AddRange(new Drawable[]
+ {
+ bpm = new BPMSlider
+ {
+ Bindable = new TimingControlPoint().BeatLengthBindable,
+ LabelText = "BPM",
+ },
+ timeSignature = new SettingsEnumDropdown
+ {
+ LabelText = "Time Signature"
+ },
+ });
+ }
+
+ protected override void OnControlPointChanged(ValueChangedEvent point)
+ {
+ if (point.NewValue != null)
+ {
+ bpm.Bindable = point.NewValue.BeatLengthBindable;
+ timeSignature.Bindable = point.NewValue.TimeSignatureBindable;
+ }
+ }
+
+ protected override TimingControlPoint CreatePoint()
+ {
+ var reference = Beatmap.Value.Beatmap.ControlPointInfo.TimingPointAt(SelectedGroup.Value.Time);
+
+ return new TimingControlPoint
+ {
+ BeatLength = reference.BeatLength,
+ TimeSignature = reference.TimeSignature
+ };
+ }
+
+ private class BPMSlider : SettingsSlider
+ {
+ private readonly BindableDouble beatLengthBindable = new BindableDouble();
+
+ private BindableDouble bpmBindable;
+
+ public override Bindable Bindable
+ {
+ get => base.Bindable;
+ set
+ {
+ // incoming will be beatlength
+
+ beatLengthBindable.UnbindBindings();
+ beatLengthBindable.BindTo(value);
+
+ base.Bindable = bpmBindable = new BindableDouble(beatLengthToBpm(beatLengthBindable.Value))
+ {
+ MinValue = beatLengthToBpm(beatLengthBindable.MaxValue),
+ MaxValue = beatLengthToBpm(beatLengthBindable.MinValue),
+ Default = beatLengthToBpm(beatLengthBindable.Default),
+ };
+
+ bpmBindable.BindValueChanged(bpm => beatLengthBindable.Value = beatLengthToBpm(bpm.NewValue));
+ }
+ }
+
+ private double beatLengthToBpm(double beatLength) => 60000 / beatLength;
+ }
+ }
+}
diff --git a/osu.Game/Screens/Multi/Components/BeatmapTitle.cs b/osu.Game/Screens/Multi/Components/BeatmapTitle.cs
index e096fb33da..b41b2d073e 100644
--- a/osu.Game/Screens/Multi/Components/BeatmapTitle.cs
+++ b/osu.Game/Screens/Multi/Components/BeatmapTitle.cs
@@ -57,11 +57,13 @@ namespace osu.Game.Screens.Multi.Components
var beatmap = CurrentItem.Value?.Beatmap;
if (beatmap == null)
+ {
textFlow.AddText("No beatmap selected", s =>
{
s.Font = s.Font.With(size: TextSize);
s.Colour = colours.PinkLight;
});
+ }
else
{
textFlow.AddLink(new[]
@@ -81,7 +83,7 @@ namespace osu.Game.Screens.Multi.Components
Text = new LocalisedString((beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title)),
Font = OsuFont.GetFont(size: TextSize),
}
- }, null, LinkAction.OpenBeatmap, beatmap.OnlineBeatmapID.ToString(), "Open beatmap");
+ }, LinkAction.OpenBeatmap, beatmap.OnlineBeatmapID.ToString(), "Open beatmap");
}
}
}
diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs
index f2efbe6073..2f2028ff53 100644
--- a/osu.Game/Screens/Play/GameplayClockContainer.cs
+++ b/osu.Game/Screens/Play/GameplayClockContainer.cs
@@ -162,16 +162,12 @@ namespace osu.Game.Screens.Play
if (sourceClock != beatmap.Track)
return;
+ removeSourceClockAdjustments();
+
sourceClock = new TrackVirtual(beatmap.Track.Length);
adjustableClock.ChangeSource(sourceClock);
}
- public void ResetLocalAdjustments()
- {
- // In the case of replays, we may have changed the playback rate.
- UserPlaybackRate.Value = 1;
- }
-
protected override void Update()
{
if (!IsPaused.Value)
@@ -198,6 +194,14 @@ namespace osu.Game.Screens.Play
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
+
+ removeSourceClockAdjustments();
+ sourceClock = null;
+ }
+
+ private void removeSourceClockAdjustments()
+ {
+ sourceClock.ResetSpeedAdjustments();
(sourceClock as IAdjustableAudioComponent)?.RemoveAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust);
}
}
diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs
index a05937801c..968b83e68c 100644
--- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs
+++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs
@@ -100,9 +100,11 @@ namespace osu.Game.Screens.Play.HUD
if (text.Alpha > 0 || button.Progress.Value > 0 || button.IsHovered)
Alpha = 1;
else
+ {
Alpha = Interpolation.ValueAt(
MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 200),
Alpha, MathHelper.Clamp(1 - positionalAdjust, 0.04f, 1), 0, 200, Easing.OutQuint);
+ }
}
private class Button : HoldToConfirmContainer, IKeyBindingHandler
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index a3c39d9cc1..a9b0649fab 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -536,8 +536,6 @@ namespace osu.Game.Screens.Play
return true;
}
- GameplayClockContainer.ResetLocalAdjustments();
-
// GameplayClockContainer performs seeks / start / stop operations on the beatmap's track.
// as we are no longer the current screen, we cannot guarantee the track is still usable.
GameplayClockContainer.StopUsingBeatmapClock();
diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs
index 31cdff5fb9..835867fe62 100644
--- a/osu.Game/Screens/Play/SkipOverlay.cs
+++ b/osu.Game/Screens/Play/SkipOverlay.cs
@@ -181,8 +181,11 @@ namespace osu.Game.Screens.Play
this.FadeIn(500, Easing.OutExpo);
if (!IsHovered && !IsDragged)
+ {
using (BeginDelayedSequence(1000))
scheduledHide = Schedule(Hide);
+ }
+
break;
case Visibility.Hidden:
diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs
index 3640197dad..d063988b3f 100644
--- a/osu.Game/Screens/Ranking/Results.cs
+++ b/osu.Game/Screens/Ranking/Results.cs
@@ -116,146 +116,147 @@ namespace osu.Game.Screens.Ranking
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
- InternalChildren = new Drawable[]
+ InternalChild = new AspectContainer
{
- new AspectContainer
+ RelativeSizeAxes = Axes.Y,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Height = overscan,
+ Children = new Drawable[]
{
- RelativeSizeAxes = Axes.Y,
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Height = overscan,
- Children = new Drawable[]
+ circleOuterBackground = new CircularContainer
{
- circleOuterBackground = new CircularContainer
+ RelativeSizeAxes = Axes.Both,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Masking = true,
+ Children = new Drawable[]
{
- RelativeSizeAxes = Axes.Both,
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Masking = true,
- Children = new Drawable[]
+ new Box
{
- new Box
- {
- Alpha = 0.2f,
- RelativeSizeAxes = Axes.Both,
- Colour = Color4.Black,
- }
- }
- },
- circleOuter = new CircularContainer
- {
- Size = new Vector2(circle_outer_scale),
- EdgeEffect = new EdgeEffectParameters
- {
- Colour = Color4.Black.Opacity(0.4f),
- Type = EdgeEffectType.Shadow,
- Radius = 15,
- },
- RelativeSizeAxes = Axes.Both,
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Masking = true,
- Children = new Drawable[]
- {
- new Box
- {
- RelativeSizeAxes = Axes.Both,
- Colour = Color4.White,
- },
- backgroundParallax = new ParallaxContainer
- {
- RelativeSizeAxes = Axes.Both,
- ParallaxAmount = 0.01f,
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Children = new Drawable[]
- {
- new Sprite
- {
- RelativeSizeAxes = Axes.Both,
- Alpha = 0.2f,
- Texture = Beatmap.Value.Background,
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- FillMode = FillMode.Fill
- }
- }
- },
- modeChangeButtons = new ResultModeTabControl
- {
- Anchor = Anchor.BottomCentre,
- Origin = Anchor.BottomCentre,
- RelativeSizeAxes = Axes.X,
- Height = 50,
- Margin = new MarginPadding { Bottom = 110 },
- },
- new OsuSpriteText
- {
- Anchor = Anchor.CentreLeft,
- Origin = Anchor.BottomCentre,
- Text = $"{Score.MaxCombo}x",
- RelativePositionAxes = Axes.X,
- Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 40),
- X = 0.1f,
- Colour = colours.BlueDarker,
- },
- new OsuSpriteText
- {
- Anchor = Anchor.CentreLeft,
- Origin = Anchor.TopCentre,
- Text = "max combo",
- Font = OsuFont.GetFont(size: 20),
- RelativePositionAxes = Axes.X,
- X = 0.1f,
- Colour = colours.Gray6,
- },
- new OsuSpriteText
- {
- Anchor = Anchor.CentreLeft,
- Origin = Anchor.BottomCentre,
- Text = $"{Score.Accuracy:P2}",
- Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 40),
- RelativePositionAxes = Axes.X,
- X = 0.9f,
- Colour = colours.BlueDarker,
- },
- new OsuSpriteText
- {
- Anchor = Anchor.CentreLeft,
- Origin = Anchor.TopCentre,
- Text = "accuracy",
- Font = OsuFont.GetFont(size: 20),
- RelativePositionAxes = Axes.X,
- X = 0.9f,
- Colour = colours.Gray6,
- },
- }
- },
- circleInner = new CircularContainer
- {
- Size = new Vector2(0.6f),
- EdgeEffect = new EdgeEffectParameters
- {
- Colour = Color4.Black.Opacity(0.4f),
- Type = EdgeEffectType.Shadow,
- Radius = 15,
- },
- RelativeSizeAxes = Axes.Both,
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Masking = true,
- Children = new Drawable[]
- {
- new Box
- {
- RelativeSizeAxes = Axes.Both,
- Colour = Color4.White,
- },
+ Alpha = 0.2f,
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.Black,
}
}
+ },
+ circleOuter = new CircularContainer
+ {
+ Size = new Vector2(circle_outer_scale),
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Colour = Color4.Black.Opacity(0.4f),
+ Type = EdgeEffectType.Shadow,
+ Radius = 15,
+ },
+ RelativeSizeAxes = Axes.Both,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Masking = true,
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.White,
+ },
+ backgroundParallax = new ParallaxContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ ParallaxAmount = 0.01f,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Children = new Drawable[]
+ {
+ new Sprite
+ {
+ RelativeSizeAxes = Axes.Both,
+ Alpha = 0.2f,
+ Texture = Beatmap.Value.Background,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ FillMode = FillMode.Fill
+ }
+ }
+ },
+ modeChangeButtons = new ResultModeTabControl
+ {
+ Anchor = Anchor.BottomCentre,
+ Origin = Anchor.BottomCentre,
+ RelativeSizeAxes = Axes.X,
+ Height = 50,
+ Margin = new MarginPadding { Bottom = 110 },
+ },
+ new OsuSpriteText
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.BottomCentre,
+ Text = $"{Score.MaxCombo}x",
+ RelativePositionAxes = Axes.X,
+ Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 40),
+ X = 0.1f,
+ Colour = colours.BlueDarker,
+ },
+ new OsuSpriteText
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.TopCentre,
+ Text = "max combo",
+ Font = OsuFont.GetFont(size: 20),
+ RelativePositionAxes = Axes.X,
+ X = 0.1f,
+ Colour = colours.Gray6,
+ },
+ new OsuSpriteText
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.BottomCentre,
+ Text = $"{Score.Accuracy:P2}",
+ Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 40),
+ RelativePositionAxes = Axes.X,
+ X = 0.9f,
+ Colour = colours.BlueDarker,
+ },
+ new OsuSpriteText
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.TopCentre,
+ Text = "accuracy",
+ Font = OsuFont.GetFont(size: 20),
+ RelativePositionAxes = Axes.X,
+ X = 0.9f,
+ Colour = colours.Gray6,
+ },
+ }
+ },
+ circleInner = new CircularContainer
+ {
+ Size = new Vector2(0.6f),
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Colour = Color4.Black.Opacity(0.4f),
+ Type = EdgeEffectType.Shadow,
+ Radius = 15,
+ },
+ RelativeSizeAxes = Axes.Both,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Masking = true,
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.White,
+ },
+ }
}
- },
- new HotkeyRetryOverlay
+ }
+ };
+
+ if (player != null)
+ {
+ AddInternal(new HotkeyRetryOverlay
{
Action = () =>
{
@@ -263,8 +264,8 @@ namespace osu.Game.Screens.Ranking
player?.Restart();
},
- },
- };
+ });
+ }
var pages = CreateResultPages();
diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs
index 6c3c9d20f3..afd6211dec 100644
--- a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs
+++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs
@@ -44,10 +44,14 @@ namespace osu.Game.Screens.Select.Carousel
criteria.Artist.Matches(Beatmap.Metadata.ArtistUnicode);
if (match)
+ {
foreach (var criteriaTerm in criteria.SearchTerms)
+ {
match &=
Beatmap.Metadata.SearchableTerms.Any(term => term.IndexOf(criteriaTerm, StringComparison.InvariantCultureIgnoreCase) >= 0) ||
Beatmap.Version.IndexOf(criteriaTerm, StringComparison.InvariantCultureIgnoreCase) >= 0;
+ }
+ }
Filtered.Value = !match;
}
diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
index 337d46ecdd..3ef1fe5bc5 100644
--- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
+++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
@@ -179,7 +179,7 @@ namespace osu.Game.Screens.Select.Leaderboards
return req;
}
- protected override LeaderboardScore CreateDrawableScore(ScoreInfo model, int index) => new LeaderboardScore(model, index)
+ protected override LeaderboardScore CreateDrawableScore(ScoreInfo model, int index) => new LeaderboardScore(model, index, IsOnlineScope)
{
Action = () => ScoreSelected?.Invoke(model)
};
diff --git a/osu.Game/Screens/Select/Leaderboards/UserTopScoreContainer.cs b/osu.Game/Screens/Select/Leaderboards/UserTopScoreContainer.cs
index da8f676cd0..a787eb5629 100644
--- a/osu.Game/Screens/Select/Leaderboards/UserTopScoreContainer.cs
+++ b/osu.Game/Screens/Select/Leaderboards/UserTopScoreContainer.cs
@@ -77,7 +77,7 @@ namespace osu.Game.Screens.Select.Leaderboards
if (newScore == null)
return;
- LoadComponentAsync(new LeaderboardScore(newScore.Score, newScore.Position)
+ LoadComponentAsync(new LeaderboardScore(newScore.Score, newScore.Position, false)
{
Action = () => ScoreSelected?.Invoke(newScore.Score)
}, drawableScore =>
diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs
index 409ea4bbbe..375b994169 100644
--- a/osu.Game/Screens/Select/SongSelect.cs
+++ b/osu.Game/Screens/Select/SongSelect.cs
@@ -251,11 +251,13 @@ namespace osu.Game.Screens.Select
{
// if we have no beatmaps but osu-stable is found, let's prompt the user to import.
if (!beatmaps.GetAllUsableBeatmapSetsEnumerable().Any() && beatmaps.StableInstallationAvailable)
+ {
dialogOverlay.Push(new ImportFromStablePopup(() =>
{
Task.Run(beatmaps.ImportFromStableAsync).ContinueWith(_ => scores.ImportFromStableAsync(), TaskContinuationOptions.OnlyOnRanToCompletion);
Task.Run(skins.ImportFromStableAsync);
}));
+ }
});
}
}
@@ -332,12 +334,14 @@ namespace osu.Game.Screens.Select
if (e.NewValue is DummyWorkingBeatmap) return;
if (this.IsCurrentScreen() && !Carousel.SelectBeatmap(e.NewValue?.BeatmapInfo, false))
+ {
// If selecting new beatmap without bypassing filters failed, there's possibly a ruleset mismatch
if (e.NewValue?.BeatmapInfo?.Ruleset != null && !e.NewValue.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value))
{
Ruleset.Value = e.NewValue.BeatmapInfo.Ruleset;
Carousel.SelectBeatmap(e.NewValue.BeatmapInfo);
}
+ }
}
// We need to keep track of the last selected beatmap ignoring debounce to play the correct selection sounds.
diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs
index fea15458e4..67a83f19e2 100644
--- a/osu.Game/Skinning/LegacySkin.cs
+++ b/osu.Game/Skinning/LegacySkin.cs
@@ -35,9 +35,12 @@ namespace osu.Game.Skinning
: base(skin)
{
Stream stream = storage?.GetStream(filename);
+
if (stream != null)
+ {
using (LineBufferedReader reader = new LineBufferedReader(stream))
Configuration = new LegacySkinDecoder().Decode(reader);
+ }
else
Configuration = new DefaultSkinConfiguration();
diff --git a/osu.Game/Skinning/LegacySkinExtensions.cs b/osu.Game/Skinning/LegacySkinExtensions.cs
index c5582af836..c758b699ed 100644
--- a/osu.Game/Skinning/LegacySkinExtensions.cs
+++ b/osu.Game/Skinning/LegacySkinExtensions.cs
@@ -22,17 +22,19 @@ namespace osu.Game.Skinning
if (animatable)
{
- for (int i = 0;; i++)
+ for (int i = 0; true; i++)
{
if ((texture = getFrameTexture(i)) == null)
break;
if (animation == null)
+ {
animation = new TextureAnimation
{
DefaultFrameLength = default_frame_time,
Repeat = looping
};
+ }
animation.AddFrame(texture);
}
@@ -42,10 +44,12 @@ namespace osu.Game.Skinning
return animation;
if ((texture = source.GetTexture(componentName)) != null)
+ {
return new Sprite
{
Texture = texture
};
+ }
return null;
}
diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs
index bdf8be773b..6d23f22515 100644
--- a/osu.Game/Skinning/SkinnableSound.cs
+++ b/osu.Game/Skinning/SkinnableSound.cs
@@ -81,9 +81,13 @@ namespace osu.Game.Skinning
var ch = skin.GetSample(s);
if (ch == null && allowFallback)
+ {
foreach (var lookup in s.LookupNames)
+ {
if ((ch = samples.Get($"Gameplay/{lookup}")) != null)
break;
+ }
+ }
if (ch != null)
{
@@ -91,8 +95,10 @@ namespace osu.Game.Skinning
ch.Volume.Value = s.Volume / 100.0;
if (adjustments != null)
+ {
foreach (var adjustment in adjustments)
ch.AddAdjustment(adjustment.property, adjustment.bindable);
+ }
}
return ch;
@@ -104,8 +110,10 @@ namespace osu.Game.Skinning
base.Dispose(isDisposing);
if (channels != null)
+ {
foreach (var c in channels)
c.Dispose();
+ }
}
}
}
diff --git a/osu.Game/Storyboards/CommandTimelineGroup.cs b/osu.Game/Storyboards/CommandTimelineGroup.cs
index 461ee762e9..364c971874 100644
--- a/osu.Game/Storyboards/CommandTimelineGroup.cs
+++ b/osu.Game/Storyboards/CommandTimelineGroup.cs
@@ -65,6 +65,7 @@ namespace osu.Game.Storyboards
public virtual IEnumerable.TypedCommand> GetCommands(CommandTimelineSelector timelineSelector, double offset = 0)
{
if (offset != 0)
+ {
return timelineSelector(this).Commands.Select(command =>
new CommandTimeline.TypedCommand
{
@@ -74,6 +75,7 @@ namespace osu.Game.Storyboards
StartValue = command.StartValue,
EndValue = command.EndValue,
});
+ }
return timelineSelector(this).Commands;
}
diff --git a/osu.Game/Storyboards/StoryboardSprite.cs b/osu.Game/Storyboards/StoryboardSprite.cs
index 37c3ff495f..d5e69fd103 100644
--- a/osu.Game/Storyboards/StoryboardSprite.cs
+++ b/osu.Game/Storyboards/StoryboardSprite.cs
@@ -105,9 +105,13 @@ namespace osu.Game.Storyboards
var commands = TimelineGroup.GetCommands(timelineSelector);
foreach (var loop in loops)
commands = commands.Concat(loop.GetCommands(timelineSelector));
+
if (triggeredGroups != null)
+ {
foreach (var pair in triggeredGroups)
commands = commands.Concat(pair.Item1.GetCommands(timelineSelector, pair.Item2));
+ }
+
return commands;
}
diff --git a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs
index e99b5fc5fb..b144de35c5 100644
--- a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs
+++ b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs
@@ -72,11 +72,15 @@ namespace osu.Game.Tests.Beatmaps
break;
if (objectCounter >= ourMapping.Objects.Count)
+ {
Assert.Fail($"The conversion did not generate a hitobject, but should have, for hitobject at time: {expectedMapping.StartTime}:\n"
+ $"Expected: {JsonConvert.SerializeObject(expectedMapping.Objects[objectCounter])}\n");
+ }
else if (objectCounter >= expectedMapping.Objects.Count)
+ {
Assert.Fail($"The conversion generated a hitobject, but should not have, for hitobject at time: {ourMapping.StartTime}:\n"
+ $"Received: {JsonConvert.SerializeObject(ourMapping.Objects[objectCounter])}\n");
+ }
else if (!expectedMapping.Objects[objectCounter].Equals(ourMapping.Objects[objectCounter]))
{
Assert.Fail($"The conversion generated differing hitobjects for object at time: {expectedMapping.StartTime}:\n"
diff --git a/osu.Game/Tests/Visual/OsuGridTestScene.cs b/osu.Game/Tests/Visual/OsuGridTestScene.cs
index c09f4d6218..48f85be6ba 100644
--- a/osu.Game/Tests/Visual/OsuGridTestScene.cs
+++ b/osu.Game/Tests/Visual/OsuGridTestScene.cs
@@ -37,9 +37,12 @@ namespace osu.Game.Tests.Visual
Add(testContainer = new GridContainer { RelativeSizeAxes = Axes.Both });
cells = new Drawable[rows, cols];
+
for (int r = 0; r < rows; r++)
- for (int c = 0; c < cols; c++)
- cells[r, c] = new Container { RelativeSizeAxes = Axes.Both };
+ {
+ for (int c = 0; c < cols; c++)
+ cells[r, c] = new Container { RelativeSizeAxes = Axes.Both };
+ }
testContainer.Content = cells.ToJagged();
}
diff --git a/osu.Game/Updater/SimpleUpdateManager.cs b/osu.Game/Updater/SimpleUpdateManager.cs
index 4789ac94d2..f76cba7f41 100644
--- a/osu.Game/Updater/SimpleUpdateManager.cs
+++ b/osu.Game/Updater/SimpleUpdateManager.cs
@@ -29,7 +29,7 @@ namespace osu.Game.Updater
version = game.Version;
if (game.IsDeployedBuild)
- Schedule(() => Task.Run(() => checkForUpdateAsync()));
+ Schedule(() => Task.Run(checkForUpdateAsync));
}
private async void checkForUpdateAsync()
diff --git a/osu.Game/Users/Drawables/DrawableAvatar.cs b/osu.Game/Users/Drawables/DrawableAvatar.cs
index ee3cf6331b..ee9af15863 100644
--- a/osu.Game/Users/Drawables/DrawableAvatar.cs
+++ b/osu.Game/Users/Drawables/DrawableAvatar.cs
@@ -13,6 +13,7 @@ using osu.Game.Graphics.Containers;
namespace osu.Game.Users.Drawables
{
+ [LongRunningLoad]
public class DrawableAvatar : Container
{
///
diff --git a/osu.Game/Users/UserCoverBackground.cs b/osu.Game/Users/UserCoverBackground.cs
index e583acac9f..a45fd85901 100644
--- a/osu.Game/Users/UserCoverBackground.cs
+++ b/osu.Game/Users/UserCoverBackground.cs
@@ -46,6 +46,7 @@ namespace osu.Game.Users
};
}
else
+ {
InternalChild = new Sprite
{
RelativeSizeAxes = Axes.Both,
@@ -54,6 +55,7 @@ namespace osu.Game.Users
Anchor = Anchor.Centre,
Origin = Anchor.Centre
};
+ }
}
protected override void LoadComplete()
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 0cb09d9b14..baa1c14071 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -1,32 +1,27 @@
-
netstandard2.0
Library
- AnyCPU
true
osu!
ppy.osu.Game
- ppy Pty Ltd
- https://github.com/ppy/osu/blob/master/LICENCE.md
- https://github.com/ppy/osu
- https://github.com/ppy/osu
- Automated release.
- Copyright (c) 2019 ppy Pty Ltd
- osu game
+ icon.png
-
-
+
+
+ True
+ icon.png
+
-
+
-
+
diff --git a/osu.TestProject.props b/osu.TestProject.props
index a5c70f4edc..7e87bc5414 100644
--- a/osu.TestProject.props
+++ b/osu.TestProject.props
@@ -1,16 +1,12 @@
-
osu.Game.Tests.VisualTestRunner
-
-
-
-
+
-
+
VisualTestRunner.cs
diff --git a/osu.iOS.props b/osu.iOS.props
index 719aced705..0184e45c15 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -5,91 +5,51 @@
PackageReference
--nolinkaway
-lstdc++ -lbz2 -framework AudioToolbox -framework AVFoundation -framework CoreMedia -framework VideoToolbox -framework SystemConfiguration -framework CFNetwork -framework Accelerate
+ bin\$(Platform)\$(Configuration)
+ cjk,mideast,other,rare,west
+ false
+ $(DefaultMtouchExtraArgs) -gcc_flags "$(DefaultMtouchGccFlags)"
+ NSUrlSessionHandler
+
+ iPhone Developer
+ true
+
+
+ true
+ full
+ false
+ DEBUG;ENABLE_TEST_CLOUD;
+ true
+ true
+
+
+ pdbonly
+ true
+
+
+ x86_64
+ None
+
+
+ true
+ SdkOnly
+ ARM64
+ Entitlements.plist
- true
- full
- false
- bin\iPhoneSimulator\Debug
- DEBUG;ENABLE_TEST_CLOUD;
- prompt
- 4
- iPhone Developer
- true
- true
true
25823
- None
- x86_64
- NSUrlSessionHandler
false
-
- Default
- $(DefaultMtouchExtraArgs) -gcc_flags "$(DefaultMtouchGccFlags)"
- false
- cjk,mideast,other,rare,west
-
-
- pdbonly
- true
- bin\iPhone\Release
-
- prompt
- 4
- iPhone Distribution
- true
- true
- Entitlements.plist
- SdkOnly
- ARM64
- NSUrlSessionHandler
-
- Default
- $(DefaultMtouchExtraArgs) -gcc_flags "$(DefaultMtouchGccFlags)"
- false
- cjk,mideast,other,rare,west
- pdbonly
- true
- bin\iPhoneSimulator\Release
-
- prompt
- 4
- iPhone Developer
true
- None
- x86_64
- NSUrlSessionHandler
-
- Default
- $(DefaultMtouchExtraArgs) -gcc_flags "$(DefaultMtouchGccFlags)"
- false
- cjk,mideast,other,rare,west
- true
- full
- false
- bin\iPhone\Debug
- DEBUG;ENABLE_TEST_CLOUD;
- prompt
- 4
- iPhone Developer
true
- true
- true
- true
- Entitlements.plist
28126
- SdkOnly
- ARM64
- NSUrlSessionHandler
-
- Default
- $(DefaultMtouchExtraArgs) -gcc_flags "$(DefaultMtouchGccFlags)"
- false
- cjk,mideast,other,rare,west
+
+
+ true
@@ -109,21 +69,10 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/osu.iOS.sln b/osu.iOS.sln
deleted file mode 100644
index 21d02d33ab..0000000000
--- a/osu.iOS.sln
+++ /dev/null
@@ -1,187 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27004.2006
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game", "osu.Game\osu.Game.csproj", "{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Osu", "osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj", "{C92A607B-1FDD-4954-9F92-03FF547D9080}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Catch", "osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj", "{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Taiko", "osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj", "{F167E17A-7DE6-4AF5-B920-A5112296C695}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Mania", "osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj", "{48F4582B-7687-4621-9CBE-5C24197CB536}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.iOS", "osu.iOS\osu.iOS.csproj", "{3F082D0B-A964-43D7-BDF7-C256D76A50D0}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Tests.iOS", "osu.Game.Tests.iOS\osu.Game.Tests.iOS.csproj", "{65FF8E19-6934-469B-B690-23C6D6E56A17}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Taiko.Tests.iOS", "osu.Game.Rulesets.Taiko.Tests.iOS\osu.Game.Rulesets.Taiko.Tests.iOS.csproj", "{7E408809-66AC-49D1-AF4D-98834F9B979A}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Osu.Tests.iOS", "osu.Game.Rulesets.Osu.Tests.iOS\osu.Game.Rulesets.Osu.Tests.iOS.csproj", "{6653CA6F-DB06-4604-A3FD-762E25C2AF96}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Mania.Tests.iOS", "osu.Game.Rulesets.Mania.Tests.iOS\osu.Game.Rulesets.Mania.Tests.iOS.csproj", "{39FD990E-B6CE-4B2A-999F-BC008CF2C64C}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Catch.Tests.iOS", "osu.Game.Rulesets.Catch.Tests.iOS\osu.Game.Rulesets.Catch.Tests.iOS.csproj", "{4004C7B7-1A62-43F1-9DF2-52450FA67E70}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- Debug|iPhoneSimulator = Debug|iPhoneSimulator
- Release|iPhone = Release|iPhone
- Release|iPhoneSimulator = Release|iPhoneSimulator
- Debug|iPhone = Debug|iPhone
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.Build.0 = Release|Any CPU
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|iPhone.ActiveCfg = Release|Any CPU
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|iPhone.Build.0 = Release|Any CPU
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|iPhone.Build.0 = Debug|Any CPU
- {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Release|Any CPU.Build.0 = Release|Any CPU
- {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Release|iPhone.ActiveCfg = Release|Any CPU
- {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Release|iPhone.Build.0 = Release|Any CPU
- {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Debug|iPhone.Build.0 = Debug|Any CPU
- {C92A607B-1FDD-4954-9F92-03FF547D9080}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C92A607B-1FDD-4954-9F92-03FF547D9080}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C92A607B-1FDD-4954-9F92-03FF547D9080}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C92A607B-1FDD-4954-9F92-03FF547D9080}.Release|Any CPU.Build.0 = Release|Any CPU
- {C92A607B-1FDD-4954-9F92-03FF547D9080}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {C92A607B-1FDD-4954-9F92-03FF547D9080}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {C92A607B-1FDD-4954-9F92-03FF547D9080}.Release|iPhone.ActiveCfg = Release|Any CPU
- {C92A607B-1FDD-4954-9F92-03FF547D9080}.Release|iPhone.Build.0 = Release|Any CPU
- {C92A607B-1FDD-4954-9F92-03FF547D9080}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {C92A607B-1FDD-4954-9F92-03FF547D9080}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {C92A607B-1FDD-4954-9F92-03FF547D9080}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {C92A607B-1FDD-4954-9F92-03FF547D9080}.Debug|iPhone.Build.0 = Debug|Any CPU
- {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Release|Any CPU.Build.0 = Release|Any CPU
- {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Release|iPhone.ActiveCfg = Release|Any CPU
- {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Release|iPhone.Build.0 = Release|Any CPU
- {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Debug|iPhone.Build.0 = Debug|Any CPU
- {F167E17A-7DE6-4AF5-B920-A5112296C695}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F167E17A-7DE6-4AF5-B920-A5112296C695}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F167E17A-7DE6-4AF5-B920-A5112296C695}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F167E17A-7DE6-4AF5-B920-A5112296C695}.Release|Any CPU.Build.0 = Release|Any CPU
- {F167E17A-7DE6-4AF5-B920-A5112296C695}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {F167E17A-7DE6-4AF5-B920-A5112296C695}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {F167E17A-7DE6-4AF5-B920-A5112296C695}.Release|iPhone.ActiveCfg = Release|Any CPU
- {F167E17A-7DE6-4AF5-B920-A5112296C695}.Release|iPhone.Build.0 = Release|Any CPU
- {F167E17A-7DE6-4AF5-B920-A5112296C695}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {F167E17A-7DE6-4AF5-B920-A5112296C695}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {F167E17A-7DE6-4AF5-B920-A5112296C695}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {F167E17A-7DE6-4AF5-B920-A5112296C695}.Debug|iPhone.Build.0 = Debug|Any CPU
- {48F4582B-7687-4621-9CBE-5C24197CB536}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {48F4582B-7687-4621-9CBE-5C24197CB536}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {48F4582B-7687-4621-9CBE-5C24197CB536}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {48F4582B-7687-4621-9CBE-5C24197CB536}.Release|Any CPU.Build.0 = Release|Any CPU
- {48F4582B-7687-4621-9CBE-5C24197CB536}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {48F4582B-7687-4621-9CBE-5C24197CB536}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {48F4582B-7687-4621-9CBE-5C24197CB536}.Release|iPhone.ActiveCfg = Release|Any CPU
- {48F4582B-7687-4621-9CBE-5C24197CB536}.Release|iPhone.Build.0 = Release|Any CPU
- {48F4582B-7687-4621-9CBE-5C24197CB536}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {48F4582B-7687-4621-9CBE-5C24197CB536}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {48F4582B-7687-4621-9CBE-5C24197CB536}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {48F4582B-7687-4621-9CBE-5C24197CB536}.Debug|iPhone.Build.0 = Debug|Any CPU
- {3F082D0B-A964-43D7-BDF7-C256D76A50D0}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
- {3F082D0B-A964-43D7-BDF7-C256D76A50D0}.Release|Any CPU.ActiveCfg = Release|iPhone
- {3F082D0B-A964-43D7-BDF7-C256D76A50D0}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
- {3F082D0B-A964-43D7-BDF7-C256D76A50D0}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
- {3F082D0B-A964-43D7-BDF7-C256D76A50D0}.Release|iPhone.ActiveCfg = Release|iPhone
- {3F082D0B-A964-43D7-BDF7-C256D76A50D0}.Release|iPhone.Build.0 = Release|iPhone
- {3F082D0B-A964-43D7-BDF7-C256D76A50D0}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
- {3F082D0B-A964-43D7-BDF7-C256D76A50D0}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
- {3F082D0B-A964-43D7-BDF7-C256D76A50D0}.Debug|iPhone.ActiveCfg = Debug|iPhone
- {3F082D0B-A964-43D7-BDF7-C256D76A50D0}.Debug|iPhone.Build.0 = Debug|iPhone
- {65FF8E19-6934-469B-B690-23C6D6E56A17}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
- {65FF8E19-6934-469B-B690-23C6D6E56A17}.Release|Any CPU.ActiveCfg = Release|iPhone
- {65FF8E19-6934-469B-B690-23C6D6E56A17}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
- {65FF8E19-6934-469B-B690-23C6D6E56A17}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
- {65FF8E19-6934-469B-B690-23C6D6E56A17}.Release|iPhone.ActiveCfg = Release|iPhone
- {65FF8E19-6934-469B-B690-23C6D6E56A17}.Release|iPhone.Build.0 = Release|iPhone
- {65FF8E19-6934-469B-B690-23C6D6E56A17}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
- {65FF8E19-6934-469B-B690-23C6D6E56A17}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
- {65FF8E19-6934-469B-B690-23C6D6E56A17}.Debug|iPhone.ActiveCfg = Debug|iPhone
- {65FF8E19-6934-469B-B690-23C6D6E56A17}.Debug|iPhone.Build.0 = Debug|iPhone
- {7E408809-66AC-49D1-AF4D-98834F9B979A}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
- {7E408809-66AC-49D1-AF4D-98834F9B979A}.Release|Any CPU.ActiveCfg = Release|iPhone
- {7E408809-66AC-49D1-AF4D-98834F9B979A}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
- {7E408809-66AC-49D1-AF4D-98834F9B979A}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
- {7E408809-66AC-49D1-AF4D-98834F9B979A}.Release|iPhone.ActiveCfg = Release|iPhone
- {7E408809-66AC-49D1-AF4D-98834F9B979A}.Release|iPhone.Build.0 = Release|iPhone
- {7E408809-66AC-49D1-AF4D-98834F9B979A}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
- {7E408809-66AC-49D1-AF4D-98834F9B979A}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
- {7E408809-66AC-49D1-AF4D-98834F9B979A}.Debug|iPhone.ActiveCfg = Debug|iPhone
- {7E408809-66AC-49D1-AF4D-98834F9B979A}.Debug|iPhone.Build.0 = Debug|iPhone
- {6653CA6F-DB06-4604-A3FD-762E25C2AF96}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
- {6653CA6F-DB06-4604-A3FD-762E25C2AF96}.Release|Any CPU.ActiveCfg = Release|iPhone
- {6653CA6F-DB06-4604-A3FD-762E25C2AF96}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
- {6653CA6F-DB06-4604-A3FD-762E25C2AF96}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
- {6653CA6F-DB06-4604-A3FD-762E25C2AF96}.Release|iPhone.ActiveCfg = Release|iPhone
- {6653CA6F-DB06-4604-A3FD-762E25C2AF96}.Release|iPhone.Build.0 = Release|iPhone
- {6653CA6F-DB06-4604-A3FD-762E25C2AF96}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
- {6653CA6F-DB06-4604-A3FD-762E25C2AF96}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
- {6653CA6F-DB06-4604-A3FD-762E25C2AF96}.Debug|iPhone.ActiveCfg = Debug|iPhone
- {6653CA6F-DB06-4604-A3FD-762E25C2AF96}.Debug|iPhone.Build.0 = Debug|iPhone
- {39FD990E-B6CE-4B2A-999F-BC008CF2C64C}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
- {39FD990E-B6CE-4B2A-999F-BC008CF2C64C}.Release|Any CPU.ActiveCfg = Release|iPhone
- {39FD990E-B6CE-4B2A-999F-BC008CF2C64C}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
- {39FD990E-B6CE-4B2A-999F-BC008CF2C64C}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
- {39FD990E-B6CE-4B2A-999F-BC008CF2C64C}.Release|iPhone.ActiveCfg = Release|iPhone
- {39FD990E-B6CE-4B2A-999F-BC008CF2C64C}.Release|iPhone.Build.0 = Release|iPhone
- {39FD990E-B6CE-4B2A-999F-BC008CF2C64C}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
- {39FD990E-B6CE-4B2A-999F-BC008CF2C64C}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
- {39FD990E-B6CE-4B2A-999F-BC008CF2C64C}.Debug|iPhone.ActiveCfg = Debug|iPhone
- {39FD990E-B6CE-4B2A-999F-BC008CF2C64C}.Debug|iPhone.Build.0 = Debug|iPhone
- {4004C7B7-1A62-43F1-9DF2-52450FA67E70}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
- {4004C7B7-1A62-43F1-9DF2-52450FA67E70}.Release|Any CPU.ActiveCfg = Release|iPhone
- {4004C7B7-1A62-43F1-9DF2-52450FA67E70}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
- {4004C7B7-1A62-43F1-9DF2-52450FA67E70}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
- {4004C7B7-1A62-43F1-9DF2-52450FA67E70}.Release|iPhone.ActiveCfg = Release|iPhone
- {4004C7B7-1A62-43F1-9DF2-52450FA67E70}.Release|iPhone.Build.0 = Release|iPhone
- {4004C7B7-1A62-43F1-9DF2-52450FA67E70}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
- {4004C7B7-1A62-43F1-9DF2-52450FA67E70}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
- {4004C7B7-1A62-43F1-9DF2-52450FA67E70}.Debug|iPhone.ActiveCfg = Debug|iPhone
- {4004C7B7-1A62-43F1-9DF2-52450FA67E70}.Debug|iPhone.Build.0 = Debug|iPhone
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {671B0BEC-2403-45B0-9357-2C97CC517668}
- EndGlobalSection
- GlobalSection(MonoDevelopProperties) = preSolution
- Policies = $0
- $0.TextStylePolicy = $1
- $1.EolMarker = Windows
- $1.scope = text/x-csharp
- $1.FileWidth = 80
- $1.TabsToSpaces = True
- $0.CSharpFormattingPolicy = $2
- $2.scope = text/x-csharp
- EndGlobalSection
-EndGlobal
diff --git a/osu.iOS.sln.DotSettings b/osu.iOS.sln.DotSettings
deleted file mode 100644
index 752b817910..0000000000
--- a/osu.iOS.sln.DotSettings
+++ /dev/null
@@ -1,836 +0,0 @@
-
- True
- True
- True
- True
- ExplicitlyExcluded
- ExplicitlyExcluded
- SOLUTION
- HINT
- WARNING
-
- True
- WARNING
- WARNING
- HINT
- HINT
- HINT
- HINT
- WARNING
- WARNING
- WARNING
- HINT
- WARNING
- HINT
- SUGGESTION
- HINT
- HINT
- HINT
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- HINT
- WARNING
- WARNING
- HINT
- WARNING
- WARNING
- DO_NOT_SHOW
- HINT
- WARNING
- DO_NOT_SHOW
- WARNING
- HINT
- HINT
- HINT
- ERROR
- HINT
- HINT
- HINT
- WARNING
- WARNING
- HINT
- DO_NOT_SHOW
- HINT
- HINT
- HINT
- HINT
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- HINT
- HINT
- HINT
- HINT
- HINT
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- HINT
- DO_NOT_SHOW
- DO_NOT_SHOW
- DO_NOT_SHOW
- WARNING
-
- WARNING
- WARNING
- WARNING
- ERROR
- WARNING
- WARNING
- HINT
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- HINT
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- HINT
- DO_NOT_SHOW
- DO_NOT_SHOW
- DO_NOT_SHOW
- WARNING
- WARNING
- HINT
- WARNING
- HINT
- HINT
- HINT
- HINT
- HINT
- HINT
- HINT
-
- HINT
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- WARNING
- HINT
- WARNING
- WARNING
- HINT
- HINT
- WARNING
- WARNING
- <?xml version="1.0" encoding="utf-16"?><Profile name="Code Cleanup (peppy)"><CSArrangeThisQualifier>True</CSArrangeThisQualifier><CSUseVar><BehavourStyle>CAN_CHANGE_TO_EXPLICIT</BehavourStyle><LocalVariableStyle>ALWAYS_EXPLICIT</LocalVariableStyle><ForeachVariableStyle>ALWAYS_EXPLICIT</ForeachVariableStyle></CSUseVar><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName></RegionName></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><CSUpdateFileHeader>True</CSUpdateFileHeader><CSCodeStyleAttributes ArrangeTypeAccessModifier="False" ArrangeTypeMemberAccessModifier="False" SortModifiers="True" RemoveRedundantParentheses="True" AddMissingParentheses="False" ArrangeBraces="False" ArrangeAttributes="False" ArrangeArgumentsStyle="False" /><XAMLCollapseEmptyTags>False</XAMLCollapseEmptyTags><CSFixBuiltinTypeReferences>True</CSFixBuiltinTypeReferences><CSArrangeQualifiers>True</CSArrangeQualifiers></Profile>
- Code Cleanup (peppy)
- Required
- Required
- Required
- Explicit
- ExpressionBody
- ExpressionBody
- True
- NEXT_LINE
- True
- True
- True
- True
- True
- True
- True
- True
- NEXT_LINE
- 1
- 1
- NEXT_LINE
- MULTILINE
- NEXT_LINE
- 1
- 1
- True
- NEXT_LINE
- NEVER
- NEVER
- True
- False
- True
- NEVER
- False
- False
- True
- False
- False
- True
- True
- False
- False
- CHOP_IF_LONG
- True
- 200
- CHOP_IF_LONG
- False
- False
- AABB
- API
- BPM
- GC
- GL
- GLSL
- HID
- HUD
- ID
- IP
- IPC
- LTRB
- MD5
- NS
- OS
- RGB
- RNG
- SHA
- SRGB
- TK
- SS
- PP
- GMT
- QAT
- BNG
- UI
- False
- HINT
- <?xml version="1.0" encoding="utf-16"?>
-<Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns">
- <TypePattern DisplayName="COM interfaces or structs">
- <TypePattern.Match>
- <Or>
- <And>
- <Kind Is="Interface" />
- <Or>
- <HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" />
- <HasAttribute Name="System.Runtime.InteropServices.ComImport" />
- </Or>
- </And>
- <Kind Is="Struct" />
- </Or>
- </TypePattern.Match>
- </TypePattern>
- <TypePattern DisplayName="NUnit Test Fixtures" RemoveRegions="All">
- <TypePattern.Match>
- <And>
- <Kind Is="Class" />
- <HasAttribute Name="NUnit.Framework.TestFixtureAttribute" Inherited="True" />
- </And>
- </TypePattern.Match>
- <Entry DisplayName="Setup/Teardown Methods">
- <Entry.Match>
- <And>
- <Kind Is="Method" />
- <Or>
- <HasAttribute Name="NUnit.Framework.SetUpAttribute" Inherited="True" />
- <HasAttribute Name="NUnit.Framework.TearDownAttribute" Inherited="True" />
- <HasAttribute Name="NUnit.Framework.FixtureSetUpAttribute" Inherited="True" />
- <HasAttribute Name="NUnit.Framework.FixtureTearDownAttribute" Inherited="True" />
- </Or>
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="All other members" />
- <Entry Priority="100" DisplayName="Test Methods">
- <Entry.Match>
- <And>
- <Kind Is="Method" />
- <HasAttribute Name="NUnit.Framework.TestAttribute" />
- </And>
- </Entry.Match>
- <Entry.SortBy>
- <Name />
- </Entry.SortBy>
- </Entry>
- </TypePattern>
- <TypePattern DisplayName="Default Pattern">
- <Group DisplayName="Fields/Properties">
- <Group DisplayName="Public Fields">
- <Entry DisplayName="Constant Fields">
- <Entry.Match>
- <And>
- <Access Is="Public" />
- <Or>
- <Kind Is="Constant" />
- <Readonly />
- <And>
- <Static />
- <Readonly />
- </And>
- </Or>
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Static Fields">
- <Entry.Match>
- <And>
- <Access Is="Public" />
- <Static />
- <Not>
- <Readonly />
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Normal Fields">
- <Entry.Match>
- <And>
- <Access Is="Public" />
- <Not>
- <Or>
- <Static />
- <Readonly />
- </Or>
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Entry DisplayName="Public Properties">
- <Entry.Match>
- <And>
- <Access Is="Public" />
- <Kind Is="Property" />
- </And>
- </Entry.Match>
- </Entry>
- <Group DisplayName="Internal Fields">
- <Entry DisplayName="Constant Fields">
- <Entry.Match>
- <And>
- <Access Is="Internal" />
- <Or>
- <Kind Is="Constant" />
- <Readonly />
- <And>
- <Static />
- <Readonly />
- </And>
- </Or>
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Static Fields">
- <Entry.Match>
- <And>
- <Access Is="Internal" />
- <Static />
- <Not>
- <Readonly />
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Normal Fields">
- <Entry.Match>
- <And>
- <Access Is="Internal" />
- <Not>
- <Or>
- <Static />
- <Readonly />
- </Or>
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Entry DisplayName="Internal Properties">
- <Entry.Match>
- <And>
- <Access Is="Internal" />
- <Kind Is="Property" />
- </And>
- </Entry.Match>
- </Entry>
- <Group DisplayName="Protected Fields">
- <Entry DisplayName="Constant Fields">
- <Entry.Match>
- <And>
- <Access Is="Protected" />
- <Or>
- <Kind Is="Constant" />
- <Readonly />
- <And>
- <Static />
- <Readonly />
- </And>
- </Or>
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Static Fields">
- <Entry.Match>
- <And>
- <Access Is="Protected" />
- <Static />
- <Not>
- <Readonly />
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Normal Fields">
- <Entry.Match>
- <And>
- <Access Is="Protected" />
- <Not>
- <Or>
- <Static />
- <Readonly />
- </Or>
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Entry DisplayName="Protected Properties">
- <Entry.Match>
- <And>
- <Access Is="Protected" />
- <Kind Is="Property" />
- </And>
- </Entry.Match>
- </Entry>
- <Group DisplayName="Private Fields">
- <Entry DisplayName="Constant Fields">
- <Entry.Match>
- <And>
- <Access Is="Private" />
- <Or>
- <Kind Is="Constant" />
- <Readonly />
- <And>
- <Static />
- <Readonly />
- </And>
- </Or>
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Static Fields">
- <Entry.Match>
- <And>
- <Access Is="Private" />
- <Static />
- <Not>
- <Readonly />
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Normal Fields">
- <Entry.Match>
- <And>
- <Access Is="Private" />
- <Not>
- <Or>
- <Static />
- <Readonly />
- </Or>
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Entry DisplayName="Private Properties">
- <Entry.Match>
- <And>
- <Access Is="Private" />
- <Kind Is="Property" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Group DisplayName="Constructor/Destructor">
- <Entry DisplayName="Ctor">
- <Entry.Match>
- <Kind Is="Constructor" />
- </Entry.Match>
- </Entry>
- <Region Name="Disposal">
- <Entry DisplayName="Dtor">
- <Entry.Match>
- <Kind Is="Destructor" />
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Dispose()">
- <Entry.Match>
- <And>
- <Access Is="Public" />
- <Kind Is="Method" />
- <Name Is="Dispose" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Dispose(true)">
- <Entry.Match>
- <And>
- <Access Is="Protected" />
- <Or>
- <Virtual />
- <Override />
- </Or>
- <Kind Is="Method" />
- <Name Is="Dispose" />
- </And>
- </Entry.Match>
- </Entry>
- </Region>
- </Group>
- <Group DisplayName="Methods">
- <Group DisplayName="Public">
- <Entry DisplayName="Static Methods">
- <Entry.Match>
- <And>
- <Access Is="Public" />
- <Static />
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Methods">
- <Entry.Match>
- <And>
- <Access Is="Public" />
- <Not>
- <Static />
- </Not>
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Group DisplayName="Internal">
- <Entry DisplayName="Static Methods">
- <Entry.Match>
- <And>
- <Access Is="Internal" />
- <Static />
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Methods">
- <Entry.Match>
- <And>
- <Access Is="Internal" />
- <Not>
- <Static />
- </Not>
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Group DisplayName="Protected">
- <Entry DisplayName="Static Methods">
- <Entry.Match>
- <And>
- <Access Is="Protected" />
- <Static />
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Methods">
- <Entry.Match>
- <And>
- <Access Is="Protected" />
- <Not>
- <Static />
- </Not>
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Group DisplayName="Private">
- <Entry DisplayName="Static Methods">
- <Entry.Match>
- <And>
- <Access Is="Private" />
- <Static />
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Methods">
- <Entry.Match>
- <And>
- <Access Is="Private" />
- <Not>
- <Static />
- </Not>
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- </Group>
- </TypePattern>
-</Patterns>
- Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
-See the LICENCE file in the repository root for full licence text.
-
- <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" />
- <Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb"><ExtraRule Prefix="_" Suffix="" Style="aaBb" /></Policy>
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Private" Description="private methods"><ElementKinds><Kind Name="ASYNC_METHOD" /><Kind Name="METHOD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></Policy>
- <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Protected, ProtectedInternal, Internal, Public" Description="internal/protected/public methods"><ElementKinds><Kind Name="ASYNC_METHOD" /><Kind Name="METHOD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></Policy>
- <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Private" Description="private properties"><ElementKinds><Kind Name="PROPERTY" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></Policy>
- <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Protected, ProtectedInternal, Internal, Public" Description="internal/protected/public properties"><ElementKinds><Kind Name="PROPERTY" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></Policy>
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
- o!f – Object Initializer: Anchor&Origin
- True
- constant("Centre")
- 0
- True
- True
- 2.0
- InCSharpFile
- ofao
- True
- Anchor = Anchor.$anchor$,
-Origin = Anchor.$anchor$,
- True
- True
- o!f – InternalChildren = []
- True
- True
- 2.0
- InCSharpFile
- ofic
- True
- InternalChildren = new Drawable[]
-{
- $END$
-};
- True
- True
- o!f – new GridContainer { .. }
- True
- True
- 2.0
- InCSharpFile
- ofgc
- True
- new GridContainer
-{
- RelativeSizeAxes = Axes.Both,
- Content = new[]
- {
- new Drawable[] { $END$ },
- new Drawable[] { }
- }
-};
- True
- True
- o!f – new FillFlowContainer { .. }
- True
- True
- 2.0
- InCSharpFile
- offf
- True
- new FillFlowContainer
-{
- RelativeSizeAxes = Axes.Both,
- Direction = FillDirection.Vertical,
- Children = new Drawable[]
- {
- $END$
- }
-},
- True
- True
- o!f – new Container { .. }
- True
- True
- 2.0
- InCSharpFile
- ofcont
- True
- new Container
-{
- RelativeSizeAxes = Axes.Both,
- Children = new Drawable[]
- {
- $END$
- }
-},
- True
- True
- o!f – BackgroundDependencyLoader load()
- True
- True
- 2.0
- InCSharpFile
- ofbdl
- True
- [BackgroundDependencyLoader]
-private void load()
-{
- $END$
-}
- True
- True
- o!f – new Box { .. }
- True
- True
- 2.0
- InCSharpFile
- ofbox
- True
- new Box
-{
- Colour = Color4.Black,
- RelativeSizeAxes = Axes.Both,
-},
- True
- True
- o!f – Children = []
- True
- True
- 2.0
- InCSharpFile
- ofc
- True
- Children = new Drawable[]
-{
- $END$
-};
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
- True
diff --git a/osu.iOS.slnf b/osu.iOS.slnf
new file mode 100644
index 0000000000..48b1a095a1
--- /dev/null
+++ b/osu.iOS.slnf
@@ -0,0 +1,19 @@
+{
+ "solution": {
+ "path": "osu.sln",
+ "projects": [
+ "osu.Game.Rulesets.Catch.Tests.iOS\\osu.Game.Rulesets.Catch.Tests.iOS.csproj",
+ "osu.Game.Rulesets.Catch\\osu.Game.Rulesets.Catch.csproj",
+ "osu.Game.Rulesets.Mania.Tests.iOS\\osu.Game.Rulesets.Mania.Tests.iOS.csproj",
+ "osu.Game.Rulesets.Mania\\osu.Game.Rulesets.Mania.csproj",
+ "osu.Game.Rulesets.Osu.Tests.iOS\\osu.Game.Rulesets.Osu.Tests.iOS.csproj",
+ "osu.Game.Rulesets.Osu\\osu.Game.Rulesets.Osu.csproj",
+ "osu.Game.Rulesets.Taiko.Tests.iOS\\osu.Game.Rulesets.Taiko.Tests.iOS.csproj",
+ "osu.Game.Rulesets.Taiko\\osu.Game.Rulesets.Taiko.csproj",
+ "osu.Game.Tests.iOS\\osu.Game.Tests.iOS.csproj",
+ "osu.Game.Tests\\osu.Game.Tests.csproj",
+ "osu.Game\\osu.Game.csproj",
+ "osu.iOS\\osu.iOS.csproj"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/osu.iOS/AppDelegate.cs b/osu.iOS/AppDelegate.cs
index 9ef21e014c..14e3627752 100644
--- a/osu.iOS/AppDelegate.cs
+++ b/osu.iOS/AppDelegate.cs
@@ -4,7 +4,6 @@
using System.Threading.Tasks;
using Foundation;
using osu.Framework.iOS;
-using osu.Game;
using UIKit;
namespace osu.iOS
@@ -16,9 +15,12 @@ namespace osu.iOS
protected override Framework.Game CreateGame() => game = new OsuGameIOS();
- public override bool OpenUrl(UIApplication application, NSUrl url, string sourceApplication, NSObject annotation)
+ public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
{
- Task.Run(() => game.Import(url.Path));
+ if (url.IsFileUrl)
+ Task.Run(() => game.Import(url.Path));
+ else
+ Task.Run(() => game.HandleLink(url.AbsoluteString));
return true;
}
}
diff --git a/osu.iOS/Info.plist b/osu.iOS/Info.plist
index a118b329aa..5ceccdf99f 100644
--- a/osu.iOS/Info.plist
+++ b/osu.iOS/Info.plist
@@ -14,6 +14,8 @@
0.1.0
LSRequiresIPhoneOS
+ LSSupportsOpeningDocumentsInPlace
+
MinimumOSVersion
10.0
UIDeviceFamily
@@ -32,9 +34,9 @@
UIStatusBarHidden
NSCameraUsageDescription
- We don't really use the camera.
- NSMicrophoneUsageDescription
- We don't really use the microphone.
+ We don't really use the camera.
+ NSMicrophoneUsageDescription
+ We don't really use the microphone.
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
@@ -109,5 +111,17 @@
+ CFBundleURLTypes
+
+
+ CFBundleURLSchemes
+
+ osu
+ osump
+
+ CFBundleTypeRole
+ Editor
+
+
diff --git a/osu.iOS/osu.iOS.csproj b/osu.iOS/osu.iOS.csproj
index 19d1acf014..d60a3475e7 100644
--- a/osu.iOS/osu.iOS.csproj
+++ b/osu.iOS/osu.iOS.csproj
@@ -1,6 +1,5 @@
-
+
-
Debug
iPhoneSimulator
@@ -55,27 +54,66 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
-
\ No newline at end of file
diff --git a/osu.sln b/osu.sln
index 688339fab5..1f4faae6b9 100644
--- a/osu.sln
+++ b/osu.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27004.2006
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29424.173
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game", "osu.Game\osu.Game.csproj", "{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}"
EndProject
@@ -25,68 +25,379 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Rulesets.Taiko.Tes
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Rulesets.Osu.Tests", "osu.Game.Rulesets.Osu.Tests\osu.Game.Rulesets.Osu.Tests.csproj", "{6A2D5D58-0261-4A75-BE84-2BE8B076B7C2}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Tournament", "osu.Game.Tournament\osu.Game.Tournament.csproj", "{5672CA4D-1B37-425B-A118-A8DA26E78938}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Tournament", "osu.Game.Tournament\osu.Game.Tournament.csproj", "{5672CA4D-1B37-425B-A118-A8DA26E78938}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Tournament.Tests", "osu.Game.Tournament.Tests\osu.Game.Tournament.Tests.csproj", "{5789E78D-38F9-4072-AB7B-978F34B2C17F}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Tournament.Tests", "osu.Game.Tournament.Tests\osu.Game.Tournament.Tests.csproj", "{5789E78D-38F9-4072-AB7B-978F34B2C17F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.iOS", "osu.iOS\osu.iOS.csproj", "{3F082D0B-A964-43D7-BDF7-C256D76A50D0}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Tests.iOS", "osu.Game.Tests.iOS\osu.Game.Tests.iOS.csproj", "{65FF8E19-6934-469B-B690-23C6D6E56A17}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Taiko.Tests.iOS", "osu.Game.Rulesets.Taiko.Tests.iOS\osu.Game.Rulesets.Taiko.Tests.iOS.csproj", "{7E408809-66AC-49D1-AF4D-98834F9B979A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Osu.Tests.iOS", "osu.Game.Rulesets.Osu.Tests.iOS\osu.Game.Rulesets.Osu.Tests.iOS.csproj", "{6653CA6F-DB06-4604-A3FD-762E25C2AF96}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Mania.Tests.iOS", "osu.Game.Rulesets.Mania.Tests.iOS\osu.Game.Rulesets.Mania.Tests.iOS.csproj", "{39FD990E-B6CE-4B2A-999F-BC008CF2C64C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Catch.Tests.iOS", "osu.Game.Rulesets.Catch.Tests.iOS\osu.Game.Rulesets.Catch.Tests.iOS.csproj", "{4004C7B7-1A62-43F1-9DF2-52450FA67E70}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Android", "osu.Android\osu.Android.csproj", "{D1D5F9A8-B40B-40E6-B02F-482D03346D3D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Catch.Tests.Android", "osu.Game.Rulesets.Catch.Tests.Android\osu.Game.Rulesets.Catch.Tests.Android.csproj", "{C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Mania.Tests.Android", "osu.Game.Rulesets.Mania.Tests.Android\osu.Game.Rulesets.Mania.Tests.Android.csproj", "{531F1092-DB27-445D-AA33-2A77C7187C99}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Osu.Tests.Android", "osu.Game.Rulesets.Osu.Tests.Android\osu.Game.Rulesets.Osu.Tests.Android.csproj", "{90CAB706-39CB-4B93-9629-3218A6FF8E9B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Taiko.Tests.Android", "osu.Game.Rulesets.Taiko.Tests.Android\osu.Game.Rulesets.Taiko.Tests.Android.csproj", "{3701A0A1-8476-42C6-B5C4-D24129B4A484}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Tests.Android", "osu.Game.Tests.Android\osu.Game.Tests.Android.csproj", "{5CC222DC-5716-4499-B897-DCBDDA4A5CF9}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{10DF8F12-50FD-45D8-8A38-17BA764BF54D}"
+ ProjectSection(SolutionItems) = preProject
+ .editorconfig = .editorconfig
+ Directory.Build.props = Directory.Build.props
+ global.json = global.json
+ osu.Android.props = osu.Android.props
+ osu.iOS.props = osu.iOS.props
+ osu.sln.DotSettings = osu.sln.DotSettings
+ osu.TestProject.props = osu.TestProject.props
+ EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|iPhone = Debug|iPhone
+ Debug|iPhoneSimulator = Debug|iPhoneSimulator
Release|Any CPU = Release|Any CPU
+ Release|iPhone = Release|iPhone
+ Release|iPhoneSimulator = Release|iPhoneSimulator
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|iPhone.Build.0 = Release|Any CPU
+ {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{C92A607B-1FDD-4954-9F92-03FF547D9080}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C92A607B-1FDD-4954-9F92-03FF547D9080}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C92A607B-1FDD-4954-9F92-03FF547D9080}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {C92A607B-1FDD-4954-9F92-03FF547D9080}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {C92A607B-1FDD-4954-9F92-03FF547D9080}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {C92A607B-1FDD-4954-9F92-03FF547D9080}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{C92A607B-1FDD-4954-9F92-03FF547D9080}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C92A607B-1FDD-4954-9F92-03FF547D9080}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C92A607B-1FDD-4954-9F92-03FF547D9080}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {C92A607B-1FDD-4954-9F92-03FF547D9080}.Release|iPhone.Build.0 = Release|Any CPU
+ {C92A607B-1FDD-4954-9F92-03FF547D9080}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {C92A607B-1FDD-4954-9F92-03FF547D9080}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Release|iPhone.Build.0 = Release|Any CPU
+ {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{F167E17A-7DE6-4AF5-B920-A5112296C695}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F167E17A-7DE6-4AF5-B920-A5112296C695}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F167E17A-7DE6-4AF5-B920-A5112296C695}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {F167E17A-7DE6-4AF5-B920-A5112296C695}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {F167E17A-7DE6-4AF5-B920-A5112296C695}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {F167E17A-7DE6-4AF5-B920-A5112296C695}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{F167E17A-7DE6-4AF5-B920-A5112296C695}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F167E17A-7DE6-4AF5-B920-A5112296C695}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F167E17A-7DE6-4AF5-B920-A5112296C695}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {F167E17A-7DE6-4AF5-B920-A5112296C695}.Release|iPhone.Build.0 = Release|Any CPU
+ {F167E17A-7DE6-4AF5-B920-A5112296C695}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {F167E17A-7DE6-4AF5-B920-A5112296C695}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{48F4582B-7687-4621-9CBE-5C24197CB536}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{48F4582B-7687-4621-9CBE-5C24197CB536}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {48F4582B-7687-4621-9CBE-5C24197CB536}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {48F4582B-7687-4621-9CBE-5C24197CB536}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {48F4582B-7687-4621-9CBE-5C24197CB536}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {48F4582B-7687-4621-9CBE-5C24197CB536}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{48F4582B-7687-4621-9CBE-5C24197CB536}.Release|Any CPU.ActiveCfg = Release|Any CPU
{48F4582B-7687-4621-9CBE-5C24197CB536}.Release|Any CPU.Build.0 = Release|Any CPU
+ {48F4582B-7687-4621-9CBE-5C24197CB536}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {48F4582B-7687-4621-9CBE-5C24197CB536}.Release|iPhone.Build.0 = Release|Any CPU
+ {48F4582B-7687-4621-9CBE-5C24197CB536}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {48F4582B-7687-4621-9CBE-5C24197CB536}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{54377672-20B1-40AF-8087-5CF73BF3953A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{54377672-20B1-40AF-8087-5CF73BF3953A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {54377672-20B1-40AF-8087-5CF73BF3953A}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {54377672-20B1-40AF-8087-5CF73BF3953A}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {54377672-20B1-40AF-8087-5CF73BF3953A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {54377672-20B1-40AF-8087-5CF73BF3953A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{54377672-20B1-40AF-8087-5CF73BF3953A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{54377672-20B1-40AF-8087-5CF73BF3953A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {54377672-20B1-40AF-8087-5CF73BF3953A}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {54377672-20B1-40AF-8087-5CF73BF3953A}.Release|iPhone.Build.0 = Release|Any CPU
+ {54377672-20B1-40AF-8087-5CF73BF3953A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {54377672-20B1-40AF-8087-5CF73BF3953A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{419659FD-72EA-4678-9EB8-B22A746CED70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{419659FD-72EA-4678-9EB8-B22A746CED70}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {419659FD-72EA-4678-9EB8-B22A746CED70}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {419659FD-72EA-4678-9EB8-B22A746CED70}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {419659FD-72EA-4678-9EB8-B22A746CED70}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {419659FD-72EA-4678-9EB8-B22A746CED70}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{419659FD-72EA-4678-9EB8-B22A746CED70}.Release|Any CPU.ActiveCfg = Release|Any CPU
{419659FD-72EA-4678-9EB8-B22A746CED70}.Release|Any CPU.Build.0 = Release|Any CPU
+ {419659FD-72EA-4678-9EB8-B22A746CED70}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {419659FD-72EA-4678-9EB8-B22A746CED70}.Release|iPhone.Build.0 = Release|Any CPU
+ {419659FD-72EA-4678-9EB8-B22A746CED70}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {419659FD-72EA-4678-9EB8-B22A746CED70}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{3AD63355-D6B1-4365-8D31-5652C989BEF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3AD63355-D6B1-4365-8D31-5652C989BEF1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3AD63355-D6B1-4365-8D31-5652C989BEF1}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {3AD63355-D6B1-4365-8D31-5652C989BEF1}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {3AD63355-D6B1-4365-8D31-5652C989BEF1}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {3AD63355-D6B1-4365-8D31-5652C989BEF1}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{3AD63355-D6B1-4365-8D31-5652C989BEF1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3AD63355-D6B1-4365-8D31-5652C989BEF1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3AD63355-D6B1-4365-8D31-5652C989BEF1}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {3AD63355-D6B1-4365-8D31-5652C989BEF1}.Release|iPhone.Build.0 = Release|Any CPU
+ {3AD63355-D6B1-4365-8D31-5652C989BEF1}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {3AD63355-D6B1-4365-8D31-5652C989BEF1}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{7E9E9C34-B204-406B-82E2-E01E900699CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7E9E9C34-B204-406B-82E2-E01E900699CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7E9E9C34-B204-406B-82E2-E01E900699CD}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {7E9E9C34-B204-406B-82E2-E01E900699CD}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {7E9E9C34-B204-406B-82E2-E01E900699CD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {7E9E9C34-B204-406B-82E2-E01E900699CD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{7E9E9C34-B204-406B-82E2-E01E900699CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7E9E9C34-B204-406B-82E2-E01E900699CD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7E9E9C34-B204-406B-82E2-E01E900699CD}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {7E9E9C34-B204-406B-82E2-E01E900699CD}.Release|iPhone.Build.0 = Release|Any CPU
+ {7E9E9C34-B204-406B-82E2-E01E900699CD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {7E9E9C34-B204-406B-82E2-E01E900699CD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{B698561F-FB28-46B1-857E-3CA7B92F9D70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B698561F-FB28-46B1-857E-3CA7B92F9D70}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B698561F-FB28-46B1-857E-3CA7B92F9D70}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {B698561F-FB28-46B1-857E-3CA7B92F9D70}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {B698561F-FB28-46B1-857E-3CA7B92F9D70}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {B698561F-FB28-46B1-857E-3CA7B92F9D70}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{B698561F-FB28-46B1-857E-3CA7B92F9D70}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B698561F-FB28-46B1-857E-3CA7B92F9D70}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B698561F-FB28-46B1-857E-3CA7B92F9D70}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {B698561F-FB28-46B1-857E-3CA7B92F9D70}.Release|iPhone.Build.0 = Release|Any CPU
+ {B698561F-FB28-46B1-857E-3CA7B92F9D70}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {B698561F-FB28-46B1-857E-3CA7B92F9D70}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{6A2D5D58-0261-4A75-BE84-2BE8B076B7C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6A2D5D58-0261-4A75-BE84-2BE8B076B7C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6A2D5D58-0261-4A75-BE84-2BE8B076B7C2}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {6A2D5D58-0261-4A75-BE84-2BE8B076B7C2}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {6A2D5D58-0261-4A75-BE84-2BE8B076B7C2}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {6A2D5D58-0261-4A75-BE84-2BE8B076B7C2}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{6A2D5D58-0261-4A75-BE84-2BE8B076B7C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6A2D5D58-0261-4A75-BE84-2BE8B076B7C2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6A2D5D58-0261-4A75-BE84-2BE8B076B7C2}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {6A2D5D58-0261-4A75-BE84-2BE8B076B7C2}.Release|iPhone.Build.0 = Release|Any CPU
+ {6A2D5D58-0261-4A75-BE84-2BE8B076B7C2}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {6A2D5D58-0261-4A75-BE84-2BE8B076B7C2}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{5672CA4D-1B37-425B-A118-A8DA26E78938}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5672CA4D-1B37-425B-A118-A8DA26E78938}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5672CA4D-1B37-425B-A118-A8DA26E78938}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {5672CA4D-1B37-425B-A118-A8DA26E78938}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {5672CA4D-1B37-425B-A118-A8DA26E78938}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {5672CA4D-1B37-425B-A118-A8DA26E78938}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{5672CA4D-1B37-425B-A118-A8DA26E78938}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5672CA4D-1B37-425B-A118-A8DA26E78938}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5672CA4D-1B37-425B-A118-A8DA26E78938}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {5672CA4D-1B37-425B-A118-A8DA26E78938}.Release|iPhone.Build.0 = Release|Any CPU
+ {5672CA4D-1B37-425B-A118-A8DA26E78938}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {5672CA4D-1B37-425B-A118-A8DA26E78938}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{5789E78D-38F9-4072-AB7B-978F34B2C17F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5789E78D-38F9-4072-AB7B-978F34B2C17F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5789E78D-38F9-4072-AB7B-978F34B2C17F}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {5789E78D-38F9-4072-AB7B-978F34B2C17F}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {5789E78D-38F9-4072-AB7B-978F34B2C17F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {5789E78D-38F9-4072-AB7B-978F34B2C17F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{5789E78D-38F9-4072-AB7B-978F34B2C17F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5789E78D-38F9-4072-AB7B-978F34B2C17F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5789E78D-38F9-4072-AB7B-978F34B2C17F}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {5789E78D-38F9-4072-AB7B-978F34B2C17F}.Release|iPhone.Build.0 = Release|Any CPU
+ {5789E78D-38F9-4072-AB7B-978F34B2C17F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {5789E78D-38F9-4072-AB7B-978F34B2C17F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {3F082D0B-A964-43D7-BDF7-C256D76A50D0}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
+ {3F082D0B-A964-43D7-BDF7-C256D76A50D0}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {3F082D0B-A964-43D7-BDF7-C256D76A50D0}.Debug|iPhone.Build.0 = Debug|iPhone
+ {3F082D0B-A964-43D7-BDF7-C256D76A50D0}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {3F082D0B-A964-43D7-BDF7-C256D76A50D0}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {3F082D0B-A964-43D7-BDF7-C256D76A50D0}.Release|Any CPU.ActiveCfg = Release|iPhone
+ {3F082D0B-A964-43D7-BDF7-C256D76A50D0}.Release|iPhone.ActiveCfg = Release|iPhone
+ {3F082D0B-A964-43D7-BDF7-C256D76A50D0}.Release|iPhone.Build.0 = Release|iPhone
+ {3F082D0B-A964-43D7-BDF7-C256D76A50D0}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {3F082D0B-A964-43D7-BDF7-C256D76A50D0}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ {65FF8E19-6934-469B-B690-23C6D6E56A17}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
+ {65FF8E19-6934-469B-B690-23C6D6E56A17}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {65FF8E19-6934-469B-B690-23C6D6E56A17}.Debug|iPhone.Build.0 = Debug|iPhone
+ {65FF8E19-6934-469B-B690-23C6D6E56A17}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {65FF8E19-6934-469B-B690-23C6D6E56A17}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {65FF8E19-6934-469B-B690-23C6D6E56A17}.Release|Any CPU.ActiveCfg = Release|iPhone
+ {65FF8E19-6934-469B-B690-23C6D6E56A17}.Release|iPhone.ActiveCfg = Release|iPhone
+ {65FF8E19-6934-469B-B690-23C6D6E56A17}.Release|iPhone.Build.0 = Release|iPhone
+ {65FF8E19-6934-469B-B690-23C6D6E56A17}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {65FF8E19-6934-469B-B690-23C6D6E56A17}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ {7E408809-66AC-49D1-AF4D-98834F9B979A}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
+ {7E408809-66AC-49D1-AF4D-98834F9B979A}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {7E408809-66AC-49D1-AF4D-98834F9B979A}.Debug|iPhone.Build.0 = Debug|iPhone
+ {7E408809-66AC-49D1-AF4D-98834F9B979A}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {7E408809-66AC-49D1-AF4D-98834F9B979A}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {7E408809-66AC-49D1-AF4D-98834F9B979A}.Release|Any CPU.ActiveCfg = Release|iPhone
+ {7E408809-66AC-49D1-AF4D-98834F9B979A}.Release|iPhone.ActiveCfg = Release|iPhone
+ {7E408809-66AC-49D1-AF4D-98834F9B979A}.Release|iPhone.Build.0 = Release|iPhone
+ {7E408809-66AC-49D1-AF4D-98834F9B979A}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {7E408809-66AC-49D1-AF4D-98834F9B979A}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ {6653CA6F-DB06-4604-A3FD-762E25C2AF96}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
+ {6653CA6F-DB06-4604-A3FD-762E25C2AF96}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {6653CA6F-DB06-4604-A3FD-762E25C2AF96}.Debug|iPhone.Build.0 = Debug|iPhone
+ {6653CA6F-DB06-4604-A3FD-762E25C2AF96}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {6653CA6F-DB06-4604-A3FD-762E25C2AF96}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {6653CA6F-DB06-4604-A3FD-762E25C2AF96}.Release|Any CPU.ActiveCfg = Release|iPhone
+ {6653CA6F-DB06-4604-A3FD-762E25C2AF96}.Release|iPhone.ActiveCfg = Release|iPhone
+ {6653CA6F-DB06-4604-A3FD-762E25C2AF96}.Release|iPhone.Build.0 = Release|iPhone
+ {6653CA6F-DB06-4604-A3FD-762E25C2AF96}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {6653CA6F-DB06-4604-A3FD-762E25C2AF96}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ {39FD990E-B6CE-4B2A-999F-BC008CF2C64C}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
+ {39FD990E-B6CE-4B2A-999F-BC008CF2C64C}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {39FD990E-B6CE-4B2A-999F-BC008CF2C64C}.Debug|iPhone.Build.0 = Debug|iPhone
+ {39FD990E-B6CE-4B2A-999F-BC008CF2C64C}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {39FD990E-B6CE-4B2A-999F-BC008CF2C64C}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {39FD990E-B6CE-4B2A-999F-BC008CF2C64C}.Release|Any CPU.ActiveCfg = Release|iPhone
+ {39FD990E-B6CE-4B2A-999F-BC008CF2C64C}.Release|iPhone.ActiveCfg = Release|iPhone
+ {39FD990E-B6CE-4B2A-999F-BC008CF2C64C}.Release|iPhone.Build.0 = Release|iPhone
+ {39FD990E-B6CE-4B2A-999F-BC008CF2C64C}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {39FD990E-B6CE-4B2A-999F-BC008CF2C64C}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ {4004C7B7-1A62-43F1-9DF2-52450FA67E70}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
+ {4004C7B7-1A62-43F1-9DF2-52450FA67E70}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {4004C7B7-1A62-43F1-9DF2-52450FA67E70}.Debug|iPhone.Build.0 = Debug|iPhone
+ {4004C7B7-1A62-43F1-9DF2-52450FA67E70}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {4004C7B7-1A62-43F1-9DF2-52450FA67E70}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {4004C7B7-1A62-43F1-9DF2-52450FA67E70}.Release|Any CPU.ActiveCfg = Release|iPhone
+ {4004C7B7-1A62-43F1-9DF2-52450FA67E70}.Release|iPhone.ActiveCfg = Release|iPhone
+ {4004C7B7-1A62-43F1-9DF2-52450FA67E70}.Release|iPhone.Build.0 = Release|iPhone
+ {4004C7B7-1A62-43F1-9DF2-52450FA67E70}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {4004C7B7-1A62-43F1-9DF2-52450FA67E70}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Debug|iPhone.Deploy.0 = Debug|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Release|iPhone.Build.0 = Release|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Release|iPhone.Deploy.0 = Release|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Debug|iPhone.Deploy.0 = Debug|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Release|iPhone.Build.0 = Release|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Release|iPhone.Deploy.0 = Release|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Debug|iPhone.Deploy.0 = Debug|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Release|Any CPU.Build.0 = Release|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Release|iPhone.Build.0 = Release|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Release|iPhone.Deploy.0 = Release|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Debug|iPhone.Deploy.0 = Debug|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Release|iPhone.Build.0 = Release|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Release|iPhone.Deploy.0 = Release|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Debug|iPhone.Deploy.0 = Debug|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Release|iPhone.Build.0 = Release|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Release|iPhone.Deploy.0 = Release|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Debug|iPhone.Deploy.0 = Debug|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Release|iPhone.Build.0 = Release|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Release|iPhone.Deploy.0 = Release|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings
index ed162eed6e..44c5c05bc0 100644
--- a/osu.sln.DotSettings
+++ b/osu.sln.DotSettings
@@ -12,7 +12,7 @@
HINT
HINT
WARNING
-
+ WARNING
True
WARNING
WARNING
@@ -70,11 +70,20 @@
WARNING
WARNING
DO_NOT_SHOW
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
HINT
WARNING
DO_NOT_SHOW
WARNING
HINT
+ DO_NOT_SHOW
HINT
HINT
ERROR
@@ -125,6 +134,7 @@
WARNING
WARNING
WARNING
+ WARNING
WARNING
WARNING
ERROR
@@ -171,7 +181,7 @@
WARNING
WARNING
WARNING
- HINT
+ WARNING
WARNING
WARNING
WARNING
@@ -201,6 +211,7 @@
HINT
HINT
+ HINT
WARNING
WARNING
WARNING
@@ -218,9 +229,14 @@
WARNING
<?xml version="1.0" encoding="utf-16"?><Profile name="Code Cleanup (peppy)"><CSArrangeThisQualifier>True</CSArrangeThisQualifier><CSUseVar><BehavourStyle>CAN_CHANGE_TO_EXPLICIT</BehavourStyle><LocalVariableStyle>ALWAYS_EXPLICIT</LocalVariableStyle><ForeachVariableStyle>ALWAYS_EXPLICIT</ForeachVariableStyle></CSUseVar><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName></RegionName></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><CSUpdateFileHeader>True</CSUpdateFileHeader><CSCodeStyleAttributes ArrangeTypeAccessModifier="False" ArrangeTypeMemberAccessModifier="False" SortModifiers="True" RemoveRedundantParentheses="True" AddMissingParentheses="False" ArrangeBraces="False" ArrangeAttributes="False" ArrangeArgumentsStyle="False" /><XAMLCollapseEmptyTags>False</XAMLCollapseEmptyTags><CSFixBuiltinTypeReferences>True</CSFixBuiltinTypeReferences><CSArrangeQualifiers>True</CSArrangeQualifiers></Profile>
Code Cleanup (peppy)
- Required
- Required
- Required
+ RequiredForMultiline
+ RequiredForMultiline
+ RequiredForMultiline
+ RequiredForMultiline
+ RequiredForMultiline
+ RequiredForMultiline
+ RequiredForMultiline
+ RequiredForMultiline
Explicit
ExpressionBody
ExpressionBody
@@ -239,6 +255,10 @@
1
NEXT_LINE
MULTILINE
+ True
+ True
+ True
+ True
NEXT_LINE
1
1
@@ -275,6 +295,7 @@
HUD
ID
IL
+ IOS
IP
IPC
JIT
@@ -288,397 +309,397 @@
SHA
SRGB
TK
- SS
- PP
- GMT
- QAT
- BNG
+ SS
+ PP
+ GMT
+ QAT
+ BNG
UI
False
HINT
<?xml version="1.0" encoding="utf-16"?>
<Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns">
- <TypePattern DisplayName="COM interfaces or structs">
- <TypePattern.Match>
- <Or>
- <And>
- <Kind Is="Interface" />
- <Or>
- <HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" />
- <HasAttribute Name="System.Runtime.InteropServices.ComImport" />
- </Or>
- </And>
- <Kind Is="Struct" />
- </Or>
- </TypePattern.Match>
- </TypePattern>
- <TypePattern DisplayName="NUnit Test Fixtures" RemoveRegions="All">
- <TypePattern.Match>
- <And>
- <Kind Is="Class" />
- <HasAttribute Name="NUnit.Framework.TestFixtureAttribute" Inherited="True" />
- </And>
- </TypePattern.Match>
- <Entry DisplayName="Setup/Teardown Methods">
- <Entry.Match>
- <And>
- <Kind Is="Method" />
- <Or>
- <HasAttribute Name="NUnit.Framework.SetUpAttribute" Inherited="True" />
- <HasAttribute Name="NUnit.Framework.TearDownAttribute" Inherited="True" />
- <HasAttribute Name="NUnit.Framework.FixtureSetUpAttribute" Inherited="True" />
- <HasAttribute Name="NUnit.Framework.FixtureTearDownAttribute" Inherited="True" />
- </Or>
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="All other members" />
- <Entry Priority="100" DisplayName="Test Methods">
- <Entry.Match>
- <And>
- <Kind Is="Method" />
- <HasAttribute Name="NUnit.Framework.TestAttribute" />
- </And>
- </Entry.Match>
- <Entry.SortBy>
- <Name />
- </Entry.SortBy>
- </Entry>
- </TypePattern>
- <TypePattern DisplayName="Default Pattern">
- <Group DisplayName="Fields/Properties">
- <Group DisplayName="Public Fields">
- <Entry DisplayName="Constant Fields">
- <Entry.Match>
- <And>
- <Access Is="Public" />
- <Or>
- <Kind Is="Constant" />
- <Readonly />
- <And>
- <Static />
- <Readonly />
- </And>
- </Or>
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Static Fields">
- <Entry.Match>
- <And>
- <Access Is="Public" />
- <Static />
- <Not>
- <Readonly />
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Normal Fields">
- <Entry.Match>
- <And>
- <Access Is="Public" />
- <Not>
- <Or>
- <Static />
- <Readonly />
- </Or>
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Entry DisplayName="Public Properties">
- <Entry.Match>
- <And>
- <Access Is="Public" />
- <Kind Is="Property" />
- </And>
- </Entry.Match>
- </Entry>
- <Group DisplayName="Internal Fields">
- <Entry DisplayName="Constant Fields">
- <Entry.Match>
- <And>
- <Access Is="Internal" />
- <Or>
- <Kind Is="Constant" />
- <Readonly />
- <And>
- <Static />
- <Readonly />
- </And>
- </Or>
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Static Fields">
- <Entry.Match>
- <And>
- <Access Is="Internal" />
- <Static />
- <Not>
- <Readonly />
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Normal Fields">
- <Entry.Match>
- <And>
- <Access Is="Internal" />
- <Not>
- <Or>
- <Static />
- <Readonly />
- </Or>
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Entry DisplayName="Internal Properties">
- <Entry.Match>
- <And>
- <Access Is="Internal" />
- <Kind Is="Property" />
- </And>
- </Entry.Match>
- </Entry>
- <Group DisplayName="Protected Fields">
- <Entry DisplayName="Constant Fields">
- <Entry.Match>
- <And>
- <Access Is="Protected" />
- <Or>
- <Kind Is="Constant" />
- <Readonly />
- <And>
- <Static />
- <Readonly />
- </And>
- </Or>
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Static Fields">
- <Entry.Match>
- <And>
- <Access Is="Protected" />
- <Static />
- <Not>
- <Readonly />
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Normal Fields">
- <Entry.Match>
- <And>
- <Access Is="Protected" />
- <Not>
- <Or>
- <Static />
- <Readonly />
- </Or>
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Entry DisplayName="Protected Properties">
- <Entry.Match>
- <And>
- <Access Is="Protected" />
- <Kind Is="Property" />
- </And>
- </Entry.Match>
- </Entry>
- <Group DisplayName="Private Fields">
- <Entry DisplayName="Constant Fields">
- <Entry.Match>
- <And>
- <Access Is="Private" />
- <Or>
- <Kind Is="Constant" />
- <Readonly />
- <And>
- <Static />
- <Readonly />
- </And>
- </Or>
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Static Fields">
- <Entry.Match>
- <And>
- <Access Is="Private" />
- <Static />
- <Not>
- <Readonly />
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Normal Fields">
- <Entry.Match>
- <And>
- <Access Is="Private" />
- <Not>
- <Or>
- <Static />
- <Readonly />
- </Or>
- </Not>
- <Kind Is="Field" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Entry DisplayName="Private Properties">
- <Entry.Match>
- <And>
- <Access Is="Private" />
- <Kind Is="Property" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Group DisplayName="Constructor/Destructor">
- <Entry DisplayName="Ctor">
- <Entry.Match>
- <Kind Is="Constructor" />
- </Entry.Match>
- </Entry>
- <Region Name="Disposal">
- <Entry DisplayName="Dtor">
- <Entry.Match>
- <Kind Is="Destructor" />
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Dispose()">
- <Entry.Match>
- <And>
- <Access Is="Public" />
- <Kind Is="Method" />
- <Name Is="Dispose" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Dispose(true)">
- <Entry.Match>
- <And>
- <Access Is="Protected" />
- <Or>
- <Virtual />
- <Override />
- </Or>
- <Kind Is="Method" />
- <Name Is="Dispose" />
- </And>
- </Entry.Match>
- </Entry>
- </Region>
- </Group>
- <Group DisplayName="Methods">
- <Group DisplayName="Public">
- <Entry DisplayName="Static Methods">
- <Entry.Match>
- <And>
- <Access Is="Public" />
- <Static />
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Methods">
- <Entry.Match>
- <And>
- <Access Is="Public" />
- <Not>
- <Static />
- </Not>
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Group DisplayName="Internal">
- <Entry DisplayName="Static Methods">
- <Entry.Match>
- <And>
- <Access Is="Internal" />
- <Static />
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Methods">
- <Entry.Match>
- <And>
- <Access Is="Internal" />
- <Not>
- <Static />
- </Not>
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Group DisplayName="Protected">
- <Entry DisplayName="Static Methods">
- <Entry.Match>
- <And>
- <Access Is="Protected" />
- <Static />
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Methods">
- <Entry.Match>
- <And>
- <Access Is="Protected" />
- <Not>
- <Static />
- </Not>
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- <Group DisplayName="Private">
- <Entry DisplayName="Static Methods">
- <Entry.Match>
- <And>
- <Access Is="Private" />
- <Static />
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- <Entry DisplayName="Methods">
- <Entry.Match>
- <And>
- <Access Is="Private" />
- <Not>
- <Static />
- </Not>
- <Kind Is="Method" />
- </And>
- </Entry.Match>
- </Entry>
- </Group>
- </Group>
- </TypePattern>
+ <TypePattern DisplayName="COM interfaces or structs">
+ <TypePattern.Match>
+ <Or>
+ <And>
+ <Kind Is="Interface" />
+ <Or>
+ <HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" />
+ <HasAttribute Name="System.Runtime.InteropServices.ComImport" />
+ </Or>
+ </And>
+ <Kind Is="Struct" />
+ </Or>
+ </TypePattern.Match>
+ </TypePattern>
+ <TypePattern DisplayName="NUnit Test Fixtures" RemoveRegions="All">
+ <TypePattern.Match>
+ <And>
+ <Kind Is="Class" />
+ <HasAttribute Name="NUnit.Framework.TestFixtureAttribute" Inherited="True" />
+ </And>
+ </TypePattern.Match>
+ <Entry DisplayName="Setup/Teardown Methods">
+ <Entry.Match>
+ <And>
+ <Kind Is="Method" />
+ <Or>
+ <HasAttribute Name="NUnit.Framework.SetUpAttribute" Inherited="True" />
+ <HasAttribute Name="NUnit.Framework.TearDownAttribute" Inherited="True" />
+ <HasAttribute Name="NUnit.Framework.FixtureSetUpAttribute" Inherited="True" />
+ <HasAttribute Name="NUnit.Framework.FixtureTearDownAttribute" Inherited="True" />
+ </Or>
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="All other members" />
+ <Entry Priority="100" DisplayName="Test Methods">
+ <Entry.Match>
+ <And>
+ <Kind Is="Method" />
+ <HasAttribute Name="NUnit.Framework.TestAttribute" />
+ </And>
+ </Entry.Match>
+ <Entry.SortBy>
+ <Name />
+ </Entry.SortBy>
+ </Entry>
+ </TypePattern>
+ <TypePattern DisplayName="Default Pattern">
+ <Group DisplayName="Fields/Properties">
+ <Group DisplayName="Public Fields">
+ <Entry DisplayName="Constant Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Public" />
+ <Or>
+ <Kind Is="Constant" />
+ <Readonly />
+ <And>
+ <Static />
+ <Readonly />
+ </And>
+ </Or>
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Static Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Public" />
+ <Static />
+ <Not>
+ <Readonly />
+ </Not>
+ <Kind Is="Field" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Normal Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Public" />
+ <Not>
+ <Or>
+ <Static />
+ <Readonly />
+ </Or>
+ </Not>
+ <Kind Is="Field" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ </Group>
+ <Entry DisplayName="Public Properties">
+ <Entry.Match>
+ <And>
+ <Access Is="Public" />
+ <Kind Is="Property" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Group DisplayName="Internal Fields">
+ <Entry DisplayName="Constant Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Internal" />
+ <Or>
+ <Kind Is="Constant" />
+ <Readonly />
+ <And>
+ <Static />
+ <Readonly />
+ </And>
+ </Or>
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Static Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Internal" />
+ <Static />
+ <Not>
+ <Readonly />
+ </Not>
+ <Kind Is="Field" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Normal Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Internal" />
+ <Not>
+ <Or>
+ <Static />
+ <Readonly />
+ </Or>
+ </Not>
+ <Kind Is="Field" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ </Group>
+ <Entry DisplayName="Internal Properties">
+ <Entry.Match>
+ <And>
+ <Access Is="Internal" />
+ <Kind Is="Property" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Group DisplayName="Protected Fields">
+ <Entry DisplayName="Constant Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Protected" />
+ <Or>
+ <Kind Is="Constant" />
+ <Readonly />
+ <And>
+ <Static />
+ <Readonly />
+ </And>
+ </Or>
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Static Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Protected" />
+ <Static />
+ <Not>
+ <Readonly />
+ </Not>
+ <Kind Is="Field" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Normal Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Protected" />
+ <Not>
+ <Or>
+ <Static />
+ <Readonly />
+ </Or>
+ </Not>
+ <Kind Is="Field" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ </Group>
+ <Entry DisplayName="Protected Properties">
+ <Entry.Match>
+ <And>
+ <Access Is="Protected" />
+ <Kind Is="Property" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Group DisplayName="Private Fields">
+ <Entry DisplayName="Constant Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Private" />
+ <Or>
+ <Kind Is="Constant" />
+ <Readonly />
+ <And>
+ <Static />
+ <Readonly />
+ </And>
+ </Or>
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Static Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Private" />
+ <Static />
+ <Not>
+ <Readonly />
+ </Not>
+ <Kind Is="Field" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Normal Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Private" />
+ <Not>
+ <Or>
+ <Static />
+ <Readonly />
+ </Or>
+ </Not>
+ <Kind Is="Field" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ </Group>
+ <Entry DisplayName="Private Properties">
+ <Entry.Match>
+ <And>
+ <Access Is="Private" />
+ <Kind Is="Property" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ </Group>
+ <Group DisplayName="Constructor/Destructor">
+ <Entry DisplayName="Ctor">
+ <Entry.Match>
+ <Kind Is="Constructor" />
+ </Entry.Match>
+ </Entry>
+ <Region Name="Disposal">
+ <Entry DisplayName="Dtor">
+ <Entry.Match>
+ <Kind Is="Destructor" />
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Dispose()">
+ <Entry.Match>
+ <And>
+ <Access Is="Public" />
+ <Kind Is="Method" />
+ <Name Is="Dispose" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Dispose(true)">
+ <Entry.Match>
+ <And>
+ <Access Is="Protected" />
+ <Or>
+ <Virtual />
+ <Override />
+ </Or>
+ <Kind Is="Method" />
+ <Name Is="Dispose" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ </Region>
+ </Group>
+ <Group DisplayName="Methods">
+ <Group DisplayName="Public">
+ <Entry DisplayName="Static Methods">
+ <Entry.Match>
+ <And>
+ <Access Is="Public" />
+ <Static />
+ <Kind Is="Method" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Methods">
+ <Entry.Match>
+ <And>
+ <Access Is="Public" />
+ <Not>
+ <Static />
+ </Not>
+ <Kind Is="Method" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ </Group>
+ <Group DisplayName="Internal">
+ <Entry DisplayName="Static Methods">
+ <Entry.Match>
+ <And>
+ <Access Is="Internal" />
+ <Static />
+ <Kind Is="Method" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Methods">
+ <Entry.Match>
+ <And>
+ <Access Is="Internal" />
+ <Not>
+ <Static />
+ </Not>
+ <Kind Is="Method" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ </Group>
+ <Group DisplayName="Protected">
+ <Entry DisplayName="Static Methods">
+ <Entry.Match>
+ <And>
+ <Access Is="Protected" />
+ <Static />
+ <Kind Is="Method" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Methods">
+ <Entry.Match>
+ <And>
+ <Access Is="Protected" />
+ <Not>
+ <Static />
+ </Not>
+ <Kind Is="Method" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ </Group>
+ <Group DisplayName="Private">
+ <Entry DisplayName="Static Methods">
+ <Entry.Match>
+ <And>
+ <Access Is="Private" />
+ <Static />
+ <Kind Is="Method" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Methods">
+ <Entry.Match>
+ <And>
+ <Access Is="Private" />
+ <Not>
+ <Static />
+ </Not>
+ <Kind Is="Method" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ </Group>
+ </Group>
+ </TypePattern>
</Patterns>
Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
See the LICENCE file in the repository root for full licence text.
@@ -773,7 +794,7 @@ Origin = Anchor.$anchor$,
True
InternalChildren = new Drawable[]
{
- $END$
+ $END$
};
True
True
@@ -786,12 +807,12 @@ Origin = Anchor.$anchor$,
True
new GridContainer
{
- RelativeSizeAxes = Axes.Both,
- Content = new[]
- {
- new Drawable[] { $END$ },
- new Drawable[] { }
- }
+ RelativeSizeAxes = Axes.Both,
+ Content = new[]
+ {
+ new Drawable[] { $END$ },
+ new Drawable[] { }
+ }
};
True
True
@@ -804,12 +825,12 @@ Origin = Anchor.$anchor$,
True
new FillFlowContainer
{
- RelativeSizeAxes = Axes.Both,
- Direction = FillDirection.Vertical,
- Children = new Drawable[]
- {
- $END$
- }
+ RelativeSizeAxes = Axes.Both,
+ Direction = FillDirection.Vertical,
+ Children = new Drawable[]
+ {
+ $END$
+ }
},
True
True
@@ -822,11 +843,11 @@ Origin = Anchor.$anchor$,
True
new Container
{
- RelativeSizeAxes = Axes.Both,
- Children = new Drawable[]
- {
- $END$
- }
+ RelativeSizeAxes = Axes.Both,
+ Children = new Drawable[]
+ {
+ $END$
+ }
},
True
True
@@ -840,7 +861,7 @@ Origin = Anchor.$anchor$,
[BackgroundDependencyLoader]
private void load()
{
- $END$
+ $END$
}
True
True
@@ -853,8 +874,8 @@ private void load()
True
new Box
{
- Colour = Color4.Black,
- RelativeSizeAxes = Axes.Both,
+ Colour = Color4.Black,
+ RelativeSizeAxes = Axes.Both,
},
True
True
@@ -867,7 +888,7 @@ private void load()
True
Children = new Drawable[]
{
- $END$
+ $END$
};
True
True