diff --git a/.gitignore b/.gitignore index 6186cb870d..0e2850a01c 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ tools/** build/tools/** +fastlane/report.xml # Build results bin/[Dd]ebug/ diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000000..cdd3a6b349 --- /dev/null +++ b/Gemfile @@ -0,0 +1,6 @@ +source "https://rubygems.org" + +gem "fastlane" + +plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile') +eval_gemfile(plugins_path) if File.exist?(plugins_path) diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000000..17c0db12e7 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,173 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.0) + addressable (2.6.0) + public_suffix (>= 2.0.2, < 4.0) + atomos (0.1.3) + babosa (1.0.2) + claide (1.0.2) + colored (1.2) + colored2 (3.1.2) + commander-fastlane (4.4.6) + highline (~> 1.7.2) + declarative (0.0.10) + declarative-option (0.1.0) + digest-crc (0.4.1) + domain_name (0.5.20180417) + unf (>= 0.0.5, < 1.0.0) + dotenv (2.7.1) + emoji_regex (1.0.1) + excon (0.62.0) + faraday (0.15.4) + multipart-post (>= 1.2, < 3) + faraday-cookie_jar (0.0.6) + faraday (>= 0.7.4) + http-cookie (~> 1.0.0) + faraday_middleware (0.13.1) + faraday (>= 0.7.4, < 1.0) + fastimage (2.1.5) + fastlane (2.117.0) + CFPropertyList (>= 2.3, < 4.0.0) + addressable (>= 2.3, < 3.0.0) + babosa (>= 1.0.2, < 2.0.0) + bundler (>= 1.12.0, < 3.0.0) + colored + commander-fastlane (>= 4.4.6, < 5.0.0) + dotenv (>= 2.1.1, < 3.0.0) + emoji_regex (>= 0.1, < 2.0) + excon (>= 0.45.0, < 1.0.0) + faraday (~> 0.9) + faraday-cookie_jar (~> 0.0.6) + faraday_middleware (~> 0.9) + fastimage (>= 2.1.0, < 3.0.0) + gh_inspector (>= 1.1.2, < 2.0.0) + google-api-client (>= 0.21.2, < 0.24.0) + google-cloud-storage (>= 1.15.0, < 2.0.0) + highline (>= 1.7.2, < 2.0.0) + json (< 3.0.0) + mini_magick (~> 4.5.1) + multi_json + multi_xml (~> 0.5) + multipart-post (~> 2.0.0) + plist (>= 3.1.0, < 4.0.0) + public_suffix (~> 2.0.0) + rubyzip (>= 1.2.2, < 2.0.0) + security (= 0.1.3) + simctl (~> 1.6.3) + slack-notifier (>= 2.0.0, < 3.0.0) + terminal-notifier (>= 1.6.2, < 2.0.0) + terminal-table (>= 1.4.5, < 2.0.0) + tty-screen (>= 0.6.3, < 1.0.0) + tty-spinner (>= 0.8.0, < 1.0.0) + word_wrap (~> 1.0.0) + xcodeproj (>= 1.6.0, < 2.0.0) + xcpretty (~> 0.3.0) + xcpretty-travis-formatter (>= 0.0.3) + fastlane-plugin-clean_testflight_testers (0.2.0) + fastlane-plugin-souyuz (0.8.1) + souyuz (>= 0.8.1) + fastlane-plugin-xamarin (0.6.3) + gh_inspector (1.1.3) + google-api-client (0.23.9) + addressable (~> 2.5, >= 2.5.1) + googleauth (>= 0.5, < 0.7.0) + httpclient (>= 2.8.1, < 3.0) + mime-types (~> 3.0) + representable (~> 3.0) + retriable (>= 2.0, < 4.0) + signet (~> 0.9) + google-cloud-core (1.3.0) + google-cloud-env (~> 1.0) + google-cloud-env (1.0.5) + faraday (~> 0.11) + google-cloud-storage (1.16.0) + digest-crc (~> 0.4) + google-api-client (~> 0.23) + google-cloud-core (~> 1.2) + googleauth (>= 0.6.2, < 0.10.0) + googleauth (0.6.7) + faraday (~> 0.12) + jwt (>= 1.4, < 3.0) + memoist (~> 0.16) + multi_json (~> 1.11) + os (>= 0.9, < 2.0) + signet (~> 0.7) + highline (1.7.10) + http-cookie (1.0.3) + domain_name (~> 0.5) + httpclient (2.8.3) + json (2.2.0) + jwt (2.1.0) + memoist (0.16.0) + mime-types (3.2.2) + mime-types-data (~> 3.2015) + mime-types-data (3.2018.0812) + mini_magick (4.5.1) + mini_portile2 (2.4.0) + multi_json (1.13.1) + multi_xml (0.6.0) + multipart-post (2.0.0) + nanaimo (0.2.6) + naturally (2.2.0) + nokogiri (1.10.1) + mini_portile2 (~> 2.4.0) + os (1.0.0) + plist (3.5.0) + public_suffix (2.0.5) + representable (3.0.4) + declarative (< 0.1.0) + declarative-option (< 0.2.0) + uber (< 0.2.0) + retriable (3.1.2) + rouge (2.0.7) + rubyzip (1.2.2) + security (0.1.3) + signet (0.11.0) + addressable (~> 2.3) + faraday (~> 0.9) + jwt (>= 1.5, < 3.0) + multi_json (~> 1.10) + simctl (1.6.5) + CFPropertyList + naturally + slack-notifier (2.3.2) + souyuz (0.8.1) + fastlane (>= 2.29.0) + highline (~> 1.7) + nokogiri (~> 1.7) + terminal-notifier (1.8.0) + terminal-table (1.8.0) + unicode-display_width (~> 1.1, >= 1.1.1) + tty-cursor (0.6.1) + tty-screen (0.6.5) + tty-spinner (0.9.0) + tty-cursor (~> 0.6.0) + uber (0.1.0) + unf (0.1.4) + unf_ext + unf_ext (0.0.7.5) + unicode-display_width (1.4.1) + word_wrap (1.0.0) + xcodeproj (1.8.1) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.2.6) + xcpretty (0.3.0) + rouge (~> 2.0.7) + xcpretty-travis-formatter (1.0.0) + xcpretty (~> 0.2, >= 0.0.7) + +PLATFORMS + ruby + +DEPENDENCIES + fastlane + fastlane-plugin-clean_testflight_testers + fastlane-plugin-souyuz + fastlane-plugin-xamarin + +BUNDLED WITH + 2.0.1 diff --git a/README.md b/README.md index 8cfc2ffebf..abddb1faa1 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,24 @@ -# osu! [![Build status](https://ci.appveyor.com/api/projects/status/u2p01nx7l6og8buh?svg=true)](https://ci.appveyor.com/project/peppy/osu) [![CodeFactor](https://www.codefactor.io/repository/github/ppy/osu/badge)](https://www.codefactor.io/repository/github/ppy/osu) [![dev chat](https://discordapp.com/api/guilds/188630481301012481/widget.png?style=shield)](https://discord.gg/ppy) +# osu! + +[![Build status](https://ci.appveyor.com/api/projects/status/u2p01nx7l6og8buh?svg=true)](https://ci.appveyor.com/project/peppy/osu) [![CodeFactor](https://www.codefactor.io/repository/github/ppy/osu/badge)](https://www.codefactor.io/repository/github/ppy/osu) [![dev chat](https://discordapp.com/api/guilds/188630481301012481/widget.png?style=shield)](https://discord.gg/ppy) Rhythm is just a *click* away. The future of [osu!](https://osu.ppy.sh) and the beginning of an open era! Commonly known by the codename "osu!lazer". Pew pew. -# Status +## Status This project is still heavily under development, but is in a state where users are encouraged to try it out and keep it installed alongside the stable osu! client. It will continue to evolve over the coming months and hopefully bring some new unique features to the table. We are accepting bug reports (please report with as much detail as possible). Feature requests are welcome as long as you read and understand the contribution guidelines listed below. -# Requirements +## Requirements - A desktop platform with the [.NET Core SDK 2.2](https://www.microsoft.com/net/learn/get-started) or higher installed. - When working with the codebase, we recommend using an IDE with intellisense and syntax highlighting, such as [Visual Studio 2017+](https://visualstudio.microsoft.com/vs/), [Jetbrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/). - Note that there are **[additional requirements for Windows 7 and Windows 8.1](https://docs.microsoft.com/en-us/dotnet/core/windows-prerequisites?tabs=netcore2x)** which you may need to manually install if your operating system is not up-to-date. -# Running osu! +## Running osu! -## Releases +### Releases If you are not interested in developing the game, please head over to the [releases](https://github.com/ppy/osu/releases) to download a precompiled build with automatic updating enabled. @@ -26,7 +28,7 @@ If you are not interested in developing the game, please head over to the [relea If your platform is not listed above, there is still a chance you can manually build it by following the instructions below. -## Downloading the source code +### Downloading the source code Clone the repository **including submodules**: @@ -41,7 +43,7 @@ To update the source code to the latest commit, run the following command inside git pull ``` -## Building +### Building Build configurations for the recommended IDEs (listed above) are included. You should use the provided Build/Run functionality of your IDE to get things going. When testing or building new components, it's highly encouraged you use the `VisualTests` project/configuration. More information on this provided below. @@ -57,7 +59,7 @@ If you are not interested in debugging osu!, you can add `-c Release` to gain pe If the build fails, try to restore nuget packages with `dotnet restore`. -### A note for Linux users +#### 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`. @@ -69,15 +71,15 @@ For example, you can run osu! with the following command: LD_LIBRARY_PATH="$(pwd)/osu.Desktop/bin/Debug/netcoreapp2.2" dotnet run --project osu.Desktop ``` -## Testing with resource/framework modifications +### Testing with resource/framework modifications Sometimes it may be necessary to cross-test changes in [osu-resources](https://github.com/ppy/osu-resources) or [osu-framework](https://github.com/ppy/osu-framework). This can be achieved by running some commands as documented on the [osu-resources](https://github.com/ppy/osu-resources/wiki/Testing-local-resources-checkout-with-other-projects) and [osu-framework](https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects) wiki pages. -## Code analysis +### Code analysis 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 +## 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. @@ -87,7 +89,7 @@ Contributions can be made via pull requests to this repository. We hope to credi Note that while we already have certain standards in place, nothing is set in stone. If you have an issue with the way code is structured; with any libraries we are using; with any processes involved with contributing, *please* bring it up. I welcome all feedback so we can make contributing to this project as pain-free as possible. -# Licence +## Licence The osu! client code and framework are licensed under the [MIT licence](https://opensource.org/licenses/MIT). Please see [the licence file](LICENCE) for more information. [tl;dr](https://tldrlegal.com/license/mit-license) you can do whatever you want as long as you include the original copyright and license notice in any copy of the software/source. diff --git a/fastlane/Appfile b/fastlane/Appfile new file mode 100644 index 0000000000..083de66985 --- /dev/null +++ b/fastlane/Appfile @@ -0,0 +1,2 @@ +app_identifier("sh.ppy.osulazer") # The bundle identifier of your app +apple_id("apple-dev@ppy.sh") # Your Apple email address diff --git a/fastlane/Fastfile b/fastlane/Fastfile new file mode 100644 index 0000000000..3f64bcdf19 --- /dev/null +++ b/fastlane/Fastfile @@ -0,0 +1,65 @@ +update_fastlane + +default_platform(:ios) + +platform :ios do + lane :testflight_prune_dry do + clean_testflight_testers(days_of_inactivity:45, dry_run: true) + end + + # Specify a custom number for what's "inactive" + lane :testflight_prune do + clean_testflight_testers(days_of_inactivity: 45) # 120 days, so about 4 months + end + + lane :update_version do |options| + options[:plist_path] = '../osu.iOS/Info.plist' + app_version(options) + end + + desc 'Deploy to testflight' + lane :beta do |options| + update_version(options) + + provision( + type: 'appstore' + ) + + build( + build_configuration: 'Release', + build_platform: 'iPhone' + ) + + client = HTTPClient.new + changelog = client.get_content 'https://gist.githubusercontent.com/peppy/ab89c29dcc0dce95f39eb218e8fad197/raw' + changelog.gsub!('$BUILD_ID', options[:build]) + + pilot( + wait_processing_interval: 900, + changelog: changelog, + ipa: './osu.iOS/bin/iPhone/Release/osu.iOS.ipa' + ) + end + + desc 'Compile the project' + lane :build do + nuget_restore( + project_path: 'osu.iOS.sln' + ) + + souyuz( + platform: "ios", + build_target: "osu_iOS", + plist_path: "../osu.iOS/Info.plist" + ) + end + + desc 'Install provisioning profiles using match' + lane :provision do |options| + if Helper.is_ci? + options[:readonly] = true + end + + match(options) + end +end diff --git a/fastlane/Matchfile b/fastlane/Matchfile new file mode 100644 index 0000000000..40c974b09e --- /dev/null +++ b/fastlane/Matchfile @@ -0,0 +1 @@ +git_url('https://github.com/peppy/apple-certificates') diff --git a/fastlane/Pluginfile b/fastlane/Pluginfile new file mode 100644 index 0000000000..9f4f47f213 --- /dev/null +++ b/fastlane/Pluginfile @@ -0,0 +1,7 @@ +# Autogenerated by fastlane +# +# Ensure this file is checked in to source control! + +gem 'fastlane-plugin-clean_testflight_testers' +gem 'fastlane-plugin-souyuz' +gem 'fastlane-plugin-xamarin' diff --git a/fastlane/README.md b/fastlane/README.md new file mode 100644 index 0000000000..53bbc62cae --- /dev/null +++ b/fastlane/README.md @@ -0,0 +1,54 @@ +fastlane documentation +================ +# Installation + +Make sure you have the latest version of the Xcode command line tools installed: + +``` +xcode-select --install +``` + +Install _fastlane_ using +``` +[sudo] gem install fastlane -NV +``` +or alternatively using `brew cask install fastlane` + +# Available Actions +## iOS +### ios testflight_prune_dry +``` +fastlane ios testflight_prune_dry +``` + +### ios testflight_prune +``` +fastlane ios testflight_prune +``` + +### ios update_version +``` +fastlane ios update_version +``` + +### ios beta +``` +fastlane ios beta +``` +Deploy to testflight +### ios build +``` +fastlane ios build +``` +Compile the project +### ios provision +``` +fastlane ios provision +``` +Install provisioning profiles using match + +---- + +This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run. +More information about fastlane can be found on [fastlane.tools](https://fastlane.tools). +The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools). diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs index ef8ec0c105..7e5b003f03 100644 --- a/osu.Desktop/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -83,8 +83,7 @@ namespace osu.Desktop public override void SetHost(GameHost host) { base.SetHost(host); - var desktopWindow = host.Window as DesktopGameWindow; - if (desktopWindow != null) + if (host.Window is DesktopGameWindow desktopWindow) { desktopWindow.CursorState |= CursorState.Hidden; diff --git a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs index d40a108c5e..7f85d4ccce 100644 --- a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs @@ -34,13 +34,16 @@ namespace osu.Game.Rulesets.Catch.Tests case JuiceStream stream: foreach (var nested in stream.NestedHitObjects) yield return new ConvertValue((CatchHitObject)nested); + break; case BananaShower shower: foreach (var nested in shower.NestedHitObjects) yield return new ConvertValue((CatchHitObject)nested); + break; default: yield return new ConvertValue((CatchHitObject)hitObject); + break; } } diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseCatchPlayer.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseCatchPlayer.cs index 030c52afea..8f9dd73b80 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestCaseCatchPlayer.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestCaseCatchPlayer.cs @@ -8,7 +8,8 @@ namespace osu.Game.Rulesets.Catch.Tests [TestFixture] public class TestCaseCatchPlayer : Game.Tests.Visual.TestCasePlayer { - public TestCaseCatchPlayer() : base(new CatchRuleset()) + public TestCaseCatchPlayer() + : base(new CatchRuleset()) { } } diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseHyperDash.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseHyperDash.cs index 0851fbed87..7451986a8b 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestCaseHyperDash.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestCaseHyperDash.cs @@ -1,9 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using NUnit.Framework; using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Screens.Play; namespace osu.Game.Rulesets.Catch.Tests { @@ -17,13 +19,30 @@ namespace osu.Game.Rulesets.Catch.Tests protected override IBeatmap CreateBeatmap(Ruleset ruleset) { - var beatmap = new Beatmap { BeatmapInfo = { Ruleset = ruleset.RulesetInfo } }; + var beatmap = new Beatmap + { + BeatmapInfo = + { + Ruleset = ruleset.RulesetInfo, + BaseDifficulty = new BeatmapDifficulty { CircleSize = 3.6f } + } + }; + + // Should produce a hperdash + beatmap.HitObjects.Add(new Fruit { StartTime = 816, X = 308 / 512f, NewCombo = true }); + beatmap.HitObjects.Add(new Fruit { StartTime = 1008, X = 56 / 512f, }); for (int i = 0; i < 512; i++) if (i % 5 < 3) - beatmap.HitObjects.Add(new Fruit { X = i % 10 < 5 ? 0.02f : 0.98f, StartTime = i * 100, NewCombo = i % 8 == 0 }); + beatmap.HitObjects.Add(new Fruit { X = i % 10 < 5 ? 0.02f : 0.98f, StartTime = 2000 + i * 100, NewCombo = i % 8 == 0 }); return beatmap; } + + protected override void AddCheckSteps(Func player) + { + base.AddCheckSteps(player); + AddAssert("First note is hyperdash", () => Beatmap.Value.Beatmap.HitObjects[0] is Fruit f && f.HyperDash); + } } } diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index 2932afa9fe..78b5a510b2 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -56,6 +56,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps rng.Next(); // osu!stable retrieved a random banana rotation rng.Next(); // osu!stable retrieved a random banana colour } + break; case JuiceStream juiceStream: foreach (var nested in juiceStream.NestedHitObjects) @@ -67,6 +68,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps rng.Next(); // osu!stable retrieved a random droplet rotation hitObject.X = MathHelper.Clamp(hitObject.X, 0, 1); } + break; } } @@ -98,7 +100,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps CatchHitObject nextObject = objectWithDroplets[i + 1]; int thisDirection = nextObject.X > currentObject.X ? 1 : -1; - double timeToNext = nextObject.StartTime - currentObject.StartTime; + double timeToNext = nextObject.StartTime - currentObject.StartTime - 1000f / 60f / 4; // 1/4th of a frame of grace time, taken from osu-stable double distanceToNext = Math.Abs(nextObject.X - currentObject.X) - (lastDirection == thisDirection ? lastExcess : halfCatcherWidth); float distanceToHyper = (float)(timeToNext * CatcherArea.Catcher.BASE_SPEED - distanceToNext); if (distanceToHyper < 0) diff --git a/osu.Game.Rulesets.Catch/CatchInputManager.cs b/osu.Game.Rulesets.Catch/CatchInputManager.cs index 285b90b0ce..021d7a7efe 100644 --- a/osu.Game.Rulesets.Catch/CatchInputManager.cs +++ b/osu.Game.Rulesets.Catch/CatchInputManager.cs @@ -19,8 +19,10 @@ namespace osu.Game.Rulesets.Catch { [Description("Move left")] MoveLeft, + [Description("Move right")] MoveRight, + [Description("Engage dash")] Dash, } diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 2d3d94ea3d..8cfda5d532 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -68,14 +68,17 @@ namespace osu.Game.Rulesets.Catch.Difficulty // We want to only consider fruits that contribute to the combo. Droplets are addressed as accuracy and spinners are not relevant for "skill" calculations. case Fruit fruit: yield return new CatchDifficultyHitObject(fruit, lastObject, clockRate, halfCatchWidth); + lastObject = hitObject; break; case JuiceStream _: foreach (var nested in hitObject.NestedHitObjects.OfType().Where(o => !(o is TinyDroplet))) { yield return new CatchDifficultyHitObject(nested, lastObject, clockRate, halfCatchWidth); + lastObject = nested; } + break; } } diff --git a/osu.Game.Rulesets.Catch/MathUtils/FastRandom.cs b/osu.Game.Rulesets.Catch/MathUtils/FastRandom.cs index 2bd2c9766f..b3605b013b 100644 --- a/osu.Game.Rulesets.Catch/MathUtils/FastRandom.cs +++ b/osu.Game.Rulesets.Catch/MathUtils/FastRandom.cs @@ -33,11 +33,11 @@ namespace osu.Game.Rulesets.Catch.MathUtils /// The random value. public uint NextUInt() { - uint t = _x ^ _x << 11; + uint t = _x ^ (_x << 11); _x = _y; _y = _z; _z = _w; - return _w = _w ^ _w >> 19 ^ t ^ t >> 8; + return _w = _w ^ (_w >> 19) ^ t ^ (t >> 8); } /// diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs index c80dacde93..8fed8eb4cd 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable public override Color4 AccentColour { - get { return base.AccentColour; } + get => base.AccentColour; set { base.AccentColour = value; diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs index d5adbee8aa..2e18c5f2ad 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs @@ -23,9 +23,10 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces } private Color4 accentColour; + public Color4 AccentColour { - get { return accentColour; } + get => accentColour; set { accentColour = value; diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 438bfaef55..d0f50c6af2 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Catch.UI public Container ExplodingFruitTarget { - set { MovableCatcher.ExplodingFruitTarget = value; } + set => MovableCatcher.ExplodingFruitTarget = value; } public CatcherArea(BeatmapDifficulty difficulty = null) @@ -158,7 +158,7 @@ namespace osu.Game.Rulesets.Catch.UI protected bool Dashing { - get { return dashing; } + get => dashing; set { if (value == dashing) return; @@ -176,7 +176,7 @@ namespace osu.Game.Rulesets.Catch.UI /// protected bool Trail { - get { return trail; } + get => trail; set { if (value == trail) return; diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs b/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs index 7a2b4e7b39..6b95975059 100644 --- a/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs @@ -40,29 +40,29 @@ namespace osu.Game.Rulesets.Mania.Tests protected override Ruleset CreateRuleset() => new ManiaRuleset(); } - public class ManiaConvertMapping : ConvertMapping, IEquatable - { - public uint RandomW; - public uint RandomX; - public uint RandomY; - public uint RandomZ; + public class ManiaConvertMapping : ConvertMapping, IEquatable + { + public uint RandomW; + public uint RandomX; + public uint RandomY; + public uint RandomZ; - public ManiaConvertMapping() - { - } + public ManiaConvertMapping() + { + } - public ManiaConvertMapping(IBeatmapConverter converter) - { - var maniaConverter = (ManiaBeatmapConverter)converter; - RandomW = maniaConverter.Random.W; - RandomX = maniaConverter.Random.X; - RandomY = maniaConverter.Random.Y; - RandomZ = maniaConverter.Random.Z; - } + public ManiaConvertMapping(IBeatmapConverter converter) + { + var maniaConverter = (ManiaBeatmapConverter)converter; + RandomW = maniaConverter.Random.W; + RandomX = maniaConverter.Random.X; + RandomY = maniaConverter.Random.Y; + RandomZ = maniaConverter.Random.Z; + } - public bool Equals(ManiaConvertMapping other) => other != null && RandomW == other.RandomW && RandomX == other.RandomX && RandomY == other.RandomY && RandomZ == other.RandomZ; - public override bool Equals(ConvertMapping other) => base.Equals(other) && Equals(other as ManiaConvertMapping); - } + public bool Equals(ManiaConvertMapping other) => other != null && RandomW == other.RandomW && RandomX == other.RandomX && RandomY == other.RandomY && RandomZ == other.RandomZ; + public override bool Equals(ConvertMapping other) => base.Equals(other) && Equals(other as ManiaConvertMapping); + } public struct ConvertValue : IEquatable { diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseEditor.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseEditor.cs index 78e7768788..e721eb6fd9 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestCaseEditor.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseEditor.cs @@ -25,8 +25,8 @@ namespace osu.Game.Rulesets.Mania.Tests [BackgroundDependencyLoader] private void load(RulesetConfigCache configCache) { - var config = (ManiaConfigManager)configCache.GetConfigFor(Ruleset.Value.CreateInstance()); - config.BindWith(ManiaSetting.ScrollDirection, direction); + var config = (ManiaRulesetConfigManager)configCache.GetConfigFor(Ruleset.Value.CreateInstance()); + config.BindWith(ManiaRulesetSetting.ScrollDirection, direction); } } } diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index 380ce533bb..71df68c087 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -27,6 +27,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) }; public int TargetColumns; + public bool Dual; public readonly bool IsForCurrentRuleset; // Internal for testing purposes @@ -45,7 +46,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps var roundedOverallDifficulty = Math.Round(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty); if (IsForCurrentRuleset) + { TargetColumns = (int)Math.Max(1, roundedCircleSize); + if (TargetColumns >= 10) + { + TargetColumns = TargetColumns / 2; + Dual = true; + } + } else { float percentSliderOrSpinner = (float)beatmap.HitObjects.Count(h => h is IHasEndTime) / beatmap.HitObjects.Count; @@ -70,14 +78,22 @@ namespace osu.Game.Rulesets.Mania.Beatmaps return base.ConvertBeatmap(original); } - protected override Beatmap CreateBeatmap() => beatmap = new ManiaBeatmap(new StageDefinition { Columns = TargetColumns }); + protected override Beatmap CreateBeatmap() + { + beatmap = new ManiaBeatmap(new StageDefinition { Columns = TargetColumns }); + + if (Dual) + beatmap.Stages.Add(new StageDefinition { Columns = TargetColumns }); + + return beatmap; + } protected override IEnumerable ConvertHitObject(HitObject original, IBeatmap beatmap) { - var maniaOriginal = original as ManiaHitObject; - if (maniaOriginal != null) + if (original is ManiaHitObject maniaOriginal) { yield return maniaOriginal; + yield break; } @@ -92,6 +108,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps private readonly List prevNoteTimes = new List(max_notes_for_density); private double density = int.MaxValue; + private void computeDensity(double newNoteTime) { if (prevNoteTimes.Count == max_notes_for_density) @@ -104,6 +121,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps private double lastTime; private Vector2 lastPosition; private PatternType lastStair = PatternType.Stair; + private void recordNote(double time, Vector2 position) { lastTime = time; diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index 3eff2d62f3..ed52bdd23f 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -65,6 +65,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy if (originalPattern.HitObjects.Count() == 1) { yield return originalPattern; + yield break; } @@ -135,6 +136,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { if (convertType.HasFlag(PatternType.LowProbability)) return generateNRandomNotes(HitObject.StartTime, 0.78, 0.3, 0); + return generateNRandomNotes(HitObject.StartTime, 0.85, 0.36, 0.03); } @@ -142,6 +144,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { if (convertType.HasFlag(PatternType.LowProbability)) return generateNRandomNotes(HitObject.StartTime, 0.43, 0.08, 0); + return generateNRandomNotes(HitObject.StartTime, 0.56, 0.18, 0); } @@ -149,11 +152,13 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { if (convertType.HasFlag(PatternType.LowProbability)) return generateNRandomNotes(HitObject.StartTime, 0.3, 0, 0); + return generateNRandomNotes(HitObject.StartTime, 0.37, 0.08, 0); } if (convertType.HasFlag(PatternType.LowProbability)) return generateNRandomNotes(HitObject.StartTime, 0.17, 0, 0); + return generateNRandomNotes(HitObject.StartTime, 0.27, 0, 0); } diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs index 7004ea4969..34f5f5c415 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs @@ -116,10 +116,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy } if (convertType.HasFlag(PatternType.Cycle) && PreviousPattern.HitObjects.Count() == 1 - // If we convert to 7K + 1, let's not overload the special key - && (TotalColumns != 8 || lastColumn != 0) - // Make sure the last column was not the centre column - && (TotalColumns % 2 == 0 || lastColumn != TotalColumns / 2)) + // If we convert to 7K + 1, let's not overload the special key + && (TotalColumns != 8 || lastColumn != 0) + // Make sure the last column was not the centre column + && (TotalColumns % 2 == 0 || lastColumn != TotalColumns / 2)) { // Generate a new pattern by cycling backwards (similar to Reverse but for only one hit object) int column = RandomStart + TotalColumns - lastColumn - 1; @@ -172,6 +172,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy return pattern = generateRandomPatternWithMirrored(0.12, 0.38, 0.12); if (ConversionDifficulty > 4) return pattern = generateRandomPatternWithMirrored(0.12, 0.17, 0); + return pattern = generateRandomPatternWithMirrored(0.12, 0, 0); } @@ -179,6 +180,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { if (convertType.HasFlag(PatternType.LowProbability)) return pattern = generateRandomPattern(0.78, 0.42, 0, 0); + return pattern = generateRandomPattern(1, 0.62, 0, 0); } @@ -186,6 +188,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { if (convertType.HasFlag(PatternType.LowProbability)) return pattern = generateRandomPattern(0.35, 0.08, 0, 0); + return pattern = generateRandomPattern(0.52, 0.15, 0, 0); } @@ -193,6 +196,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { if (convertType.HasFlag(PatternType.LowProbability)) return pattern = generateRandomPattern(0.18, 0, 0, 0); + return pattern = generateRandomPattern(0.45, 0, 0, 0); } @@ -250,6 +254,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy } else last = GetRandomColumn(); + return last; } } diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs index cf5dc4fe66..b702291c5d 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs @@ -87,6 +87,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy return 4; if (val >= 1 - p3) return 3; + return val >= 1 - p2 ? 2 : 1; } diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternType.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternType.cs index a6fa234960..a3cd455886 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternType.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternType.cs @@ -12,51 +12,63 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy internal enum PatternType { None = 0, + /// /// Keep the same as last row. /// ForceStack = 1 << 0, + /// /// Keep different from last row. /// ForceNotStack = 1 << 1, + /// /// Keep as single note at its original position. /// KeepSingle = 1 << 2, + /// /// Use a lower random value. /// LowProbability = 1 << 3, + /// /// Reserved. /// Alternate = 1 << 4, + /// /// Ignore the repeat count. /// ForceSigSlider = 1 << 5, + /// /// Convert slider to circle. /// ForceNotSlider = 1 << 6, + /// /// Notes gathered together. /// Gathered = 1 << 7, Mirror = 1 << 8, + /// /// Change 0 -> 6. /// Reverse = 1 << 9, + /// /// 1 -> 5 -> 1 -> 5 like reverse. /// Cycle = 1 << 10, + /// /// Next note will be at column + 1. /// Stair = 1 << 11, + /// /// Next note will be at column - 1. /// diff --git a/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs b/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs similarity index 57% rename from osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs rename to osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs index 4e0ad31105..b591f9da22 100644 --- a/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs +++ b/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs @@ -8,9 +8,9 @@ using osu.Game.Rulesets.Mania.UI; namespace osu.Game.Rulesets.Mania.Configuration { - public class ManiaConfigManager : RulesetConfigManager + public class ManiaRulesetConfigManager : RulesetConfigManager { - public ManiaConfigManager(SettingsStore settings, RulesetInfo ruleset, int? variant = null) + public ManiaRulesetConfigManager(SettingsStore settings, RulesetInfo ruleset, int? variant = null) : base(settings, ruleset, variant) { } @@ -19,17 +19,17 @@ namespace osu.Game.Rulesets.Mania.Configuration { base.InitialiseDefaults(); - Set(ManiaSetting.ScrollTime, 2250.0, 50.0, 10000.0, 50.0); - Set(ManiaSetting.ScrollDirection, ManiaScrollingDirection.Down); + Set(ManiaRulesetSetting.ScrollTime, 2250.0, 50.0, 10000.0, 50.0); + Set(ManiaRulesetSetting.ScrollDirection, ManiaScrollingDirection.Down); } public override TrackedSettings CreateTrackedSettings() => new TrackedSettings { - new TrackedSetting(ManiaSetting.ScrollTime, v => new SettingDescription(v, "Scroll Time", $"{v}ms")) + new TrackedSetting(ManiaRulesetSetting.ScrollTime, v => new SettingDescription(v, "Scroll Time", $"{v}ms")) }; } - public enum ManiaSetting + public enum ManiaRulesetSetting { ScrollTime, ScrollDirection diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs index 2f4870f647..b99bddee96 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs @@ -114,8 +114,8 @@ namespace osu.Game.Rulesets.Mania.Difficulty // Lots of arbitrary values from testing. // Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution double accuracyValue = Math.Max(0.0, 0.2 - (Attributes.GreatHitWindow - 34) * 0.006667) - * strainValue - * Math.Pow(Math.Max(0.0, scaledScore - 960000) / 40000, 1.1); + * strainValue + * Math.Pow(Math.Max(0.0, scaledScore - 960000) / 40000, 1.1); // Bonus for many hitcircles - it's harder to keep good accuracy up for longer // accuracyValue *= Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3)); diff --git a/osu.Game.Rulesets.Mania/ManiaInputManager.cs b/osu.Game.Rulesets.Mania/ManiaInputManager.cs index 864084b407..292990fd7e 100644 --- a/osu.Game.Rulesets.Mania/ManiaInputManager.cs +++ b/osu.Game.Rulesets.Mania/ManiaInputManager.cs @@ -19,6 +19,7 @@ namespace osu.Game.Rulesets.Mania { [Description("Special 1")] Special1 = 1, + [Description("Special 2")] Special2, @@ -26,38 +27,55 @@ namespace osu.Game.Rulesets.Mania // above at a later time, without breaking replays/configs. [Description("Key 1")] Key1 = 10, + [Description("Key 2")] Key2, + [Description("Key 3")] Key3, + [Description("Key 4")] Key4, + [Description("Key 5")] Key5, + [Description("Key 6")] Key6, + [Description("Key 7")] Key7, + [Description("Key 8")] Key8, + [Description("Key 9")] Key9, + [Description("Key 10")] Key10, + [Description("Key 11")] Key11, + [Description("Key 12")] Key12, + [Description("Key 13")] Key13, + [Description("Key 14")] Key14, + [Description("Key 15")] Key15, + [Description("Key 16")] Key16, + [Description("Key 17")] Key17, + [Description("Key 18")] Key18, } diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index ba87fe6ed9..b40093844b 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -162,7 +162,7 @@ namespace osu.Game.Rulesets.Mania public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new ManiaReplayFrame(); - public override IRulesetConfigManager CreateConfig(SettingsStore settings) => new ManiaConfigManager(settings, RulesetInfo); + public override IRulesetConfigManager CreateConfig(SettingsStore settings) => new ManiaRulesetConfigManager(settings, RulesetInfo); public override RulesetSettingsSubsection CreateSettings() => new ManiaSettingsSubsection(this); @@ -349,6 +349,7 @@ namespace osu.Game.Rulesets.Mania /// Number of columns in this stage lies at (item - Single). /// Single = 0, + /// /// Columns are grouped into two stages. /// Overall number of columns lies at (item - Dual), further computation is required for diff --git a/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs b/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs index 2ab40b2bc6..2ebfd0cfc1 100644 --- a/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs +++ b/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs @@ -22,19 +22,19 @@ namespace osu.Game.Rulesets.Mania [BackgroundDependencyLoader] private void load() { - var config = (ManiaConfigManager)Config; + var config = (ManiaRulesetConfigManager)Config; Children = new Drawable[] { new SettingsEnumDropdown { LabelText = "Scrolling direction", - Bindable = config.GetBindable(ManiaSetting.ScrollDirection) + Bindable = config.GetBindable(ManiaRulesetSetting.ScrollDirection) }, new SettingsSlider { LabelText = "Scroll speed", - Bindable = config.GetBindable(ManiaSetting.ScrollTime) + Bindable = config.GetBindable(ManiaRulesetSetting.ScrollTime) }, }; } diff --git a/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs b/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs index a88512e12f..a9cd7f2476 100644 --- a/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs +++ b/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs @@ -37,11 +37,11 @@ namespace osu.Game.Rulesets.Mania.MathUtils /// The random value. public uint NextUInt() { - uint t = X ^ X << 11; + uint t = X ^ (X << 11); X = Y; Y = Z; Z = W; - return W = W ^ W >> 19 ^ t ^ t >> 8; + return W = W ^ (W >> 19) ^ t ^ (t >> 8); } /// diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs index 7b2ee9a632..c78bf72979 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs @@ -1,15 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Collections.Generic; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps; -using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Mania.Mods { - public class ManiaModDualStages : Mod, IPlayfieldTypeMod, IApplicableToBeatmapConverter, IApplicableToBeatmap + public class ManiaModDualStages : Mod, IPlayfieldTypeMod, IApplicableToBeatmapConverter { public override string Name => "Dual Stages"; public override string Acronym => "DS"; @@ -29,24 +27,7 @@ namespace osu.Game.Rulesets.Mania.Mods if (isForCurrentRuleset) return; - mbc.TargetColumns *= 2; - } - - public void ApplyToBeatmap(Beatmap beatmap) - { - if (isForCurrentRuleset) - return; - - var maniaBeatmap = (ManiaBeatmap)beatmap; - - var newDefinitions = new List(); - foreach (var existing in maniaBeatmap.Stages) - { - newDefinitions.Add(new StageDefinition { Columns = existing.Columns / 2 }); - newDefinitions.Add(new StageDefinition { Columns = existing.Columns / 2 }); - } - - maniaBeatmap.Stages = newDefinitions; + mbc.Dual = true; } public PlayfieldType PlayfieldType => PlayfieldType.Dual; diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index 777c0ae566..4bfd940aa0 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -85,7 +85,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables public override Color4 AccentColour { - get { return base.AccentColour; } + get => base.AccentColour; set { base.AccentColour = value; diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs index eb7d153a90..43aac7907f 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs @@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables public override Color4 AccentColour { - get { return base.AccentColour; } + get => base.AccentColour; set { base.AccentColour = value; diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs index c80681ea23..7ef90cdb9c 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables public override Color4 AccentColour { - get { return base.AccentColour; } + get => base.AccentColour; set { base.AccentColour = value; diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs index 3decd46888..2baf1ad520 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs @@ -77,11 +77,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces public Color4 AccentColour { - get { return accentColour; } + get => accentColour; set { if (accentColour == value) return; + accentColour = value; updateAccentColour(); @@ -90,7 +91,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces public bool Hitting { - get { return hitting; } + get => hitting; set { hitting = value; diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/GlowPiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/GlowPiece.cs index 4a54ac0aac..b146a33fd3 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/GlowPiece.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/GlowPiece.cs @@ -35,13 +35,15 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces } private Color4 accentColour; + public Color4 AccentColour { - get { return accentColour; } + get => accentColour; set { if (accentColour == value) return; + accentColour = value; updateGlow(); diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/LaneGlowPiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/LaneGlowPiece.cs index 8927e0b068..9e0307c5c2 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/LaneGlowPiece.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/LaneGlowPiece.cs @@ -78,8 +78,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces public Color4 AccentColour { - get { return Colour; } - set { Colour = value; } + get => Colour; + set => Colour = value; } } } diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs index c5db6d7bd9..bb33693783 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs @@ -56,13 +56,15 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces } private Color4 accentColour; + public Color4 AccentColour { - get { return accentColour; } + get => accentColour; set { if (accentColour == value) return; + accentColour = value; colouredBox.Colour = AccentColour.Lighten(0.9f); diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs index 8bb22fb586..5e9f46d9c7 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs @@ -17,9 +17,10 @@ namespace osu.Game.Rulesets.Mania.Objects public double EndTime => StartTime + Duration; private double duration; + public double Duration { - get { return duration; } + get => duration; set { duration = value; @@ -29,7 +30,7 @@ namespace osu.Game.Rulesets.Mania.Objects public override double StartTime { - get { return base.StartTime; } + get => base.StartTime; set { base.StartTime = value; @@ -40,7 +41,7 @@ namespace osu.Game.Rulesets.Mania.Objects public override int Column { - get { return base.Column; } + get => base.Column; set { base.Column = value; diff --git a/osu.Game.Rulesets.Mania/Objects/ManiaHitWindows.cs b/osu.Game.Rulesets.Mania/Objects/ManiaHitWindows.cs index 9ebe638c30..5f2ceab48b 100644 --- a/osu.Game.Rulesets.Mania/Objects/ManiaHitWindows.cs +++ b/osu.Game.Rulesets.Mania/Objects/ManiaHitWindows.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Mania.Objects private static readonly IReadOnlyDictionary base_ranges = new Dictionary { { HitResult.Perfect, (44.8, 38.8, 27.8) }, - { HitResult.Great, (128, 98, 68 ) }, + { HitResult.Great, (128, 98, 68) }, { HitResult.Good, (194, 164, 134) }, { HitResult.Ok, (254, 224, 194) }, { HitResult.Meh, (302, 272, 242) }, diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 856ae8af33..c59bed4ea7 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -97,13 +97,15 @@ namespace osu.Game.Rulesets.Mania.UI public override Axes RelativeSizeAxes => Axes.Y; private bool isSpecial; + public bool IsSpecial { - get { return isSpecial; } + get => isSpecial; set { if (isSpecial == value) return; + isSpecial = value; Width = isSpecial ? special_column_width : column_width; @@ -111,13 +113,15 @@ namespace osu.Game.Rulesets.Mania.UI } private Color4 accentColour; + public Color4 AccentColour { - get { return accentColour; } + get => accentColour; set { if (accentColour == value) return; + accentColour = value; background.AccentColour = value; diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs index b43580e0f3..b4e29ae9f9 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs @@ -70,6 +70,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components { if (accentColour == value) return; + accentColour = value; updateColours(); diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs index cd47bb1183..89e8cd9b5a 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs @@ -73,6 +73,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components { if (accentColour == value) return; + accentColour = value; updateColours(); diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs index b7d8945808..03b55cbead 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs @@ -87,6 +87,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components { if (accentColour == value) return; + accentColour = value; updateColours(); diff --git a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs index b451e28088..d8b7dc0381 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs @@ -15,7 +15,6 @@ using osu.Game.Input.Handlers; using osu.Game.Replays; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Configuration; -using osu.Game.Rulesets.Mania.Mods; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Replays; @@ -35,7 +34,7 @@ namespace osu.Game.Rulesets.Mania.UI public IEnumerable BarLines; - protected new ManiaConfigManager Config => (ManiaConfigManager)base.Config; + protected new ManiaRulesetConfigManager Config => (ManiaRulesetConfigManager)base.Config; private readonly Bindable configDirection = new Bindable(); @@ -75,10 +74,10 @@ namespace osu.Game.Rulesets.Mania.UI { BarLines.ForEach(Playfield.Add); - Config.BindWith(ManiaSetting.ScrollDirection, configDirection); + Config.BindWith(ManiaRulesetSetting.ScrollDirection, configDirection); configDirection.BindValueChanged(direction => Direction.Value = (ScrollingDirection)direction.NewValue, true); - Config.BindWith(ManiaSetting.ScrollTime, TimeRange); + Config.BindWith(ManiaRulesetSetting.ScrollTime, TimeRange); } /// @@ -96,7 +95,7 @@ namespace osu.Game.Rulesets.Mania.UI public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this); - public override int Variant => (int)(Mods.OfType().FirstOrDefault()?.PlayfieldType ?? PlayfieldType.Single) + Beatmap.TotalColumns; + public override int Variant => (int)(Beatmap.Stages.Count == 1 ? PlayfieldType.Single : PlayfieldType.Dual) + Beatmap.TotalColumns; public override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, Variant); diff --git a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs index 0ebcad3637..f7d1ff4db1 100644 --- a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs @@ -33,9 +33,11 @@ namespace osu.Game.Rulesets.Osu.Tests case Slider slider: foreach (var nested in slider.NestedHitObjects) yield return createConvertValue(nested); + break; default: yield return createConvertValue(hitObject); + break; } diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseGameplayCursor.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseGameplayCursor.cs index 6ebfe4fad1..3d553c334f 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseGameplayCursor.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseGameplayCursor.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Tests { private GameplayCursor cursor; - public override IReadOnlyList RequiredTypes => new [] { typeof(CursorTrail) }; + public override IReadOnlyList RequiredTypes => new[] { typeof(CursorTrail) }; public CursorContainer Cursor => cursor; diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircle.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircle.cs index 5484f15581..e1e854e8dc 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircle.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircle.cs @@ -89,7 +89,8 @@ namespace osu.Game.Rulesets.Osu.Tests { private readonly bool auto; - public TestDrawableHitCircle(HitCircle h, bool auto) : base(h) + public TestDrawableHitCircle(HitCircle h, bool auto) + : base(h) { this.auto = auto; } diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs index 1aabf9a904..35e8f3e17e 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs @@ -301,6 +301,7 @@ namespace osu.Game.Rulesets.Osu.Tests } private float judgementOffsetDirection = 1; + private void onNewResult(DrawableHitObject judgedObject, JudgementResult result) { var osuObject = judgedObject as DrawableOsuHitObject; diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinner.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinner.cs index df903efe3d..e8b534bba9 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinner.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinner.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Tests public class TestCaseSpinner : OsuTestCase { public override IReadOnlyList RequiredTypes => new[] -{ + { typeof(SpinnerDisc), typeof(DrawableSpinner), typeof(DrawableOsuHitObject) @@ -67,7 +67,8 @@ namespace osu.Game.Rulesets.Osu.Tests { private bool auto; - public TestDrawableSpinner(Spinner s, bool auto) : base(s) + public TestDrawableSpinner(Spinner s, bool auto) + : base(s) { this.auto = auto; } diff --git a/osu.Game.Rulesets.Osu/Configuration/OsuRulesetConfigManager.cs b/osu.Game.Rulesets.Osu/Configuration/OsuRulesetConfigManager.cs new file mode 100644 index 0000000000..f6edd062e9 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Configuration/OsuRulesetConfigManager.cs @@ -0,0 +1,30 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Configuration; +using osu.Game.Rulesets.Configuration; + +namespace osu.Game.Rulesets.Osu.Configuration +{ + public class OsuRulesetConfigManager : RulesetConfigManager + { + public OsuRulesetConfigManager(SettingsStore settings, RulesetInfo ruleset, int? variant = null) + : base(settings, ruleset, variant) + { + } + + protected override void InitialiseDefaults() + { + base.InitialiseDefaults(); + + Set(OsuRulesetSetting.SnakingInSliders, true); + Set(OsuRulesetSetting.SnakingOutSliders, true); + } + } + + public enum OsuRulesetSetting + { + SnakingInSliders, + SnakingOutSliders + } +} diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 13a21c5c55..0dce5208dd 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -97,7 +97,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty // Longer maps are worth more double lengthBonus = 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) + - (totalHits > 2000 ? Math.Log10(totalHits / 2000.0f) * 0.5f : 0.0f); + (totalHits > 2000 ? Math.Log10(totalHits / 2000.0f) * 0.5f : 0.0f); aimValue *= lengthBonus; @@ -113,7 +113,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty approachRateFactor += 0.3f * (Attributes.ApproachRate - 10.33f); else if (Attributes.ApproachRate < 8.0f) { - approachRateFactor += 0.01f * (8.0f - Attributes.ApproachRate); + approachRateFactor += 0.01f * (8.0f - Attributes.ApproachRate); } aimValue *= approachRateFactor; @@ -126,8 +126,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty { // Apply object-based bonus for flashlight. aimValue *= 1.0f + 0.35f * Math.Min(1.0f, totalHits / 200.0f) + - (totalHits > 200 ? 0.3f * Math.Min(1.0f, (totalHits - 200) / 300.0f) + - (totalHits > 500 ? (totalHits - 500) / 1200.0f : 0.0f) : 0.0f); + (totalHits > 200 + ? 0.3f * Math.Min(1.0f, (totalHits - 200) / 300.0f) + + (totalHits > 500 ? (totalHits - 500) / 1200.0f : 0.0f) + : 0.0f); } // Scale the aim value with accuracy _slightly_ @@ -144,7 +146,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty // Longer maps are worth more speedValue *= 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) + - (totalHits > 2000 ? Math.Log10(totalHits / 2000.0f) * 0.5f : 0.0f); + (totalHits > 2000 ? Math.Log10(totalHits / 2000.0f) * 0.5f : 0.0f); // Penalize misses exponentially. This mainly fixes tag4 maps and the likes until a per-hitobject solution is available speedValue *= Math.Pow(0.97f, countMiss); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 930c711783..37276a3432 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -92,6 +92,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing { if (slider.LazyEndPosition != null) return; + slider.LazyEndPosition = slider.StackedPosition; float approxFollowCircleRadius = (float)(slider.Radius * 3); @@ -127,8 +128,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing { Vector2 pos = hitObject.StackedPosition; - var slider = hitObject as Slider; - if (slider != null) + if (hitObject is Slider slider) { computeSliderCursorPosition(slider); pos = slider.LazyEndPosition ?? pos; diff --git a/osu.Game.Rulesets.Osu/Judgements/ComboResult.cs b/osu.Game.Rulesets.Osu/Judgements/ComboResult.cs index d7c76fccbe..ad292b0439 100644 --- a/osu.Game.Rulesets.Osu/Judgements/ComboResult.cs +++ b/osu.Game.Rulesets.Osu/Judgements/ComboResult.cs @@ -9,8 +9,10 @@ namespace osu.Game.Rulesets.Osu.Judgements { [Description(@"")] None, + [Description(@"Good")] Good, + [Description(@"Amazing")] Perfect } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs index 959bf1dc77..9a769ec39c 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Osu.Mods { foreach (var drawable in drawables) { - var hitObject = (OsuHitObject) drawable.HitObject; + var hitObject = (OsuHitObject)drawable.HitObject; float appearDistance = (float)(hitObject.TimePreempt - hitObject.TimeFadeIn) / 2; @@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.Osu.Mods .MoveTo(originalPosition, moveDuration, Easing.InOutSine); } - theta += (float) hitObject.TimeFadeIn / 1000; + theta += (float)hitObject.TimeFadeIn / 1000; } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/ConnectionRenderer.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/ConnectionRenderer.cs index 0e88e1094e..9106f4c7bd 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/ConnectionRenderer.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/ConnectionRenderer.cs @@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections /// /// Connects hit objects visually, for example with follow points. /// - public abstract class ConnectionRenderer : Container + public abstract class ConnectionRenderer : LifetimeManagementContainer where T : HitObject { /// diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs index 4c0f646ad5..8f9d487d49 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs @@ -12,39 +12,44 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections public class FollowPointRenderer : ConnectionRenderer { private int pointDistance = 32; + /// /// Determines how much space there is between points. /// public int PointDistance { - get { return pointDistance; } + get => pointDistance; set { if (pointDistance == value) return; + 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 { return preEmpt; } + get => preEmpt; set { if (preEmpt == value) return; + preEmpt = value; update(); } } private IEnumerable hitObjects; + public override IEnumerable HitObjects { - get { return hitObjects; } + get => hitObjects; set { hitObjects = value; @@ -56,7 +61,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections private void update() { - Clear(); + ClearInternal(); if (hitObjects == null) return; @@ -86,7 +91,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections FollowPoint fp; - Add(fp = new FollowPoint + AddInternal(fp = new FollowPoint { Position = pointStartPosition, Rotation = rotation, @@ -107,6 +112,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections fp.Expire(true); } } + prevHitObject = currHitObject; } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index e909216508..decd0ce073 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -102,7 +102,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public override Color4 AccentColour { - get { return base.AccentColour; } + get => base.AccentColour; set { base.AccentColour = value; @@ -139,6 +139,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables ApproachCircle.FadeIn(Math.Min(HitObject.TimeFadeIn * 2, HitObject.TimePreempt)); ApproachCircle.ScaleTo(1.1f, HitObject.TimePreempt); + ApproachCircle.Expire(true); } protected override void UpdateCurrentState(ArmedState state) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index b55ec10d1d..ff74954552 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -10,8 +10,8 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; -using osu.Game.Configuration; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu.Configuration; using osu.Game.Rulesets.Scoring; using osuTK.Graphics; using osu.Game.Skinning; @@ -33,6 +33,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private readonly IBindable scaleBindable = new Bindable(); private readonly IBindable pathBindable = new Bindable(); + [Resolved(CanBeNull = true)] + private OsuRulesetConfigManager config { get; set; } + public DrawableSlider(Slider s) : base(s) { @@ -94,10 +97,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables } [BackgroundDependencyLoader] - private void load(OsuConfigManager config) + private void load() { - config.BindWith(OsuSetting.SnakingInSliders, Body.SnakingIn); - config.BindWith(OsuSetting.SnakingOutSliders, Body.SnakingOut); + config?.BindWith(OsuRulesetSetting.SnakingInSliders, Body.SnakingIn); + config?.BindWith(OsuRulesetSetting.SnakingOutSliders, Body.SnakingOut); positionBindable.BindValueChanged(_ => Position = HitObject.StackedPosition); scaleBindable.BindValueChanged(scale => @@ -115,7 +118,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public override Color4 AccentColour { - get { return base.AccentColour; } + get => base.AccentColour; set { base.AccentColour = value; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs index 1105e8525b..b5ce36f889 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs @@ -20,7 +20,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public override bool DisplayResult => false; - public DrawableSliderTick(SliderTick sliderTick) : base(sliderTick) + public DrawableSliderTick(SliderTick sliderTick) + : base(sliderTick) { Size = new Vector2(16) * sliderTick.Scale; Origin = Anchor.Centre; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index 936023d39d..789af4f49b 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -42,7 +42,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private Color4 normalColour; private Color4 completeColour; - public DrawableSpinner(Spinner s) : base(s) + public DrawableSpinner(Spinner s) + : base(s) { Origin = Anchor.Centre; Position = s.Position; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs index 8ed99ca660..8ee065aaea 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs @@ -12,6 +12,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { public class ApproachCircle : Container { + public override bool RemoveWhenNotAlive => false; + public ApproachCircle() { Anchor = Anchor.Centre; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs index 813cd51593..93ac8748dd 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs @@ -18,8 +18,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces public string Text { - get { return number.Text; } - set { number.Text = value; } + get => number.Text; + set => number.Text = value; } public NumberPiece() diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs index afa7f22140..1b2e2c1f47 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces /// public Color4 AccentColour { - get { return accentColour; } + get => accentColour; set { accentColour = value; @@ -136,11 +136,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces public bool Tracking { - get { return tracking; } + get => tracking; private set { if (value == tracking) return; + tracking = value; FollowCircle.ScaleTo(tracking ? 2f : 1, 300, Easing.OutQuint); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs index 6d2dc220da..b088f1914b 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs @@ -40,6 +40,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { if (path.AccentColour == value) return; + path.AccentColour = value; container.ForceRedraw(); @@ -56,6 +57,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { if (path.BorderColour == value) return; + path.BorderColour = value; container.ForceRedraw(); @@ -105,6 +107,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { if (borderColour == value) return; + borderColour = value; InvalidateTexture(); @@ -120,6 +123,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { if (accentColour == value) return; + accentColour = value; InvalidateTexture(); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs index 0d970f4c2c..c982f53c2b 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs @@ -15,10 +15,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces public Color4 AccentColour { - get - { - return Disc.Colour; - } + get => Disc.Colour; set { Disc.Colour = value; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs index 4206852b6c..448a2eada7 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs @@ -17,8 +17,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces public Color4 AccentColour { - get { return background.AccentColour; } - set { background.AccentColour = value; } + get => background.AccentColour; + set => background.AccentColour = value; } private readonly SpinnerBackground background; @@ -43,12 +43,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; private bool tracking; + public bool Tracking { - get { return tracking; } + get => tracking; set { if (value == tracking) return; + tracking = value; background.FadeTo(tracking ? tracking_alpha : idle_alpha, 100); @@ -56,12 +58,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces } private bool complete; + public bool Complete { - get { return complete; } + get => complete; set { if (value == complete) return; + complete = value; updateCompleteTick(); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerSpmCounter.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerSpmCounter.cs index 19f85bf4c3..b1d90c49f6 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerSpmCounter.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerSpmCounter.cs @@ -41,10 +41,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces public double SpinsPerMinute { - get { return spm; } + get => spm; private set { if (value == spm) return; + spm = value; spmText.Text = Math.Truncate(value).ToString(@"#0"); } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index c200b43d91..345f599b9d 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -262,6 +262,7 @@ namespace osu.Game.Rulesets.Osu.Objects { if (nodeIndex < NodeSamples.Count) return NodeSamples[nodeIndex]; + return Samples; } diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs index 2dd34d7d40..b9e083d35b 100644 --- a/osu.Game.Rulesets.Osu/OsuInputManager.cs +++ b/osu.Game.Rulesets.Osu/OsuInputManager.cs @@ -38,6 +38,7 @@ namespace osu.Game.Rulesets.Osu protected override bool Handle(UIEvent e) { if (!AllowUserPresses) return false; + return base.Handle(e); } } diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 200f4af3da..20752517d5 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -16,8 +16,11 @@ using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Replays; using osu.Game.Rulesets.Replays.Types; using osu.Game.Beatmaps.Legacy; +using osu.Game.Configuration; +using osu.Game.Rulesets.Configuration; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Osu.Beatmaps; +using osu.Game.Rulesets.Osu.Configuration; using osu.Game.Rulesets.Osu.Difficulty; using osu.Game.Scoring; @@ -121,7 +124,8 @@ namespace osu.Game.Rulesets.Osu new OsuModAutopilot(), }; case ModType.Fun: - return new Mod[] { + return new Mod[] + { new OsuModTransform(), new OsuModWiggle(), new OsuModGrow() @@ -143,12 +147,14 @@ namespace osu.Game.Rulesets.Osu public override string ShortName => "osu"; - public override RulesetSettingsSubsection CreateSettings() => new OsuSettings(this); + public override RulesetSettingsSubsection CreateSettings() => new OsuSettingsSubsection(this); public override int? LegacyID => 0; public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new OsuReplayFrame(); + public override IRulesetConfigManager CreateConfig(SettingsStore settings) => new OsuRulesetConfigManager(settings, RulesetInfo); + public OsuRuleset(RulesetInfo rulesetInfo = null) : base(rulesetInfo) { diff --git a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs index b024ff4b05..b0fb85d7ed 100644 --- a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs +++ b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs @@ -209,7 +209,7 @@ namespace osu.Game.Rulesets.Osu.Replays // Only "snap" to hitcircles if they are far enough apart. As the time between hitcircles gets shorter the snapping threshold goes up. if (timeDifference > 0 && // Sanity checks ((lastPosition - targetPos).Length > h.Radius * (1.5 + 100.0 / timeDifference) || // Either the distance is big enough - timeDifference >= 266)) // ... or the beats are slow enough to tap anyway. + timeDifference >= 266)) // ... or the beats are slow enough to tap anyway. { // Perform eased movement for (double time = lastFrame.Time + FrameDelay; time < h.StartTime; time += FrameDelay) diff --git a/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs b/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs index 8bcdb5ee41..9a60f0cafc 100644 --- a/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs +++ b/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs @@ -20,6 +20,7 @@ namespace osu.Game.Rulesets.Osu.Replays /// Constants (for spinners). /// protected static readonly Vector2 SPINNER_CENTRE = OsuPlayfield.BASE_SIZE / 2; + protected const float SPIN_RADIUS = 50; /// @@ -46,6 +47,7 @@ namespace osu.Game.Rulesets.Osu.Replays #endregion #region Utilities + protected double ApplyModsToTime(double v) => v; protected double ApplyModsToRate(double v) => v; diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs index 03030121d3..0f8a0ce1ae 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs @@ -255,10 +255,13 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor { [VertexMember(2, VertexAttribPointerType.Float)] public Vector2 Position; + [VertexMember(4, VertexAttribPointerType.Float)] public Color4 Colour; + [VertexMember(2, VertexAttribPointerType.Float)] public Vector2 TexturePosition; + [VertexMember(1, VertexAttribPointerType.Float)] public float Time; diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs index 325a0172b9..ef126cdf7d 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs @@ -213,6 +213,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor public void Expand() { if (!cursorExpand) return; + expandTarget.ScaleTo(released_scale).ScaleTo(pressed_scale, 100, Easing.OutQuad); } diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index 08f9e8785d..2db2b45540 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.UI { public class OsuPlayfield : Playfield { - private readonly Container approachCircles; + private readonly ApproachCircleProxyContainer approachCircles; private readonly JudgementContainer judgementLayer; private readonly ConnectionRenderer connectionLayer; @@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Osu.UI Depth = 1, }, HitObjectContainer, - approachCircles = new Container + approachCircles = new ApproachCircleProxyContainer { RelativeSizeAxes = Axes.Both, Depth = -1, @@ -58,13 +58,26 @@ namespace osu.Game.Rulesets.Osu.UI { h.OnNewResult += onNewResult; - var c = h as IDrawableHitObjectWithProxiedApproach; - if (c != null) - approachCircles.Add(c.ProxiedLayer.CreateProxy()); + if (h is IDrawableHitObjectWithProxiedApproach c) + { + var original = c.ProxiedLayer; + + // Hitobjects only have lifetimes set on LoadComplete. For nested hitobjects (e.g. SliderHeads), this only happens when the parenting slider becomes visible. + // This delegation is required to make sure that the approach circles for those not-yet-loaded objects aren't added prematurely. + original.OnLoadComplete += addApproachCircleProxy; + } base.Add(h); } + private void addApproachCircleProxy(Drawable d) + { + var proxy = d.CreateProxy(); + proxy.LifetimeStart = d.LifetimeStart; + proxy.LifetimeEnd = d.LifetimeEnd; + approachCircles.Add(proxy); + } + public override void PostProcess() { connectionLayer.HitObjects = HitObjectContainer.Objects.Select(d => d.HitObject).OfType(); @@ -86,5 +99,10 @@ namespace osu.Game.Rulesets.Osu.UI } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => HitObjectContainer.ReceivePositionalInputAt(screenSpacePos); + + private class ApproachCircleProxyContainer : LifetimeManagementContainer + { + public void Add(Drawable approachCircleProxy) => AddInternal(approachCircleProxy); + } } } diff --git a/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs b/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs index 935f9c5c0d..85b72cbb5b 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs @@ -8,6 +8,7 @@ using osu.Game.Beatmaps; using osu.Game.Input.Handlers; using osu.Game.Replays; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Configuration; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Replays; @@ -20,6 +21,8 @@ namespace osu.Game.Rulesets.Osu.UI { public class OsuRulesetContainer : RulesetContainer { + protected new OsuRulesetConfigManager Config => (OsuRulesetConfigManager)base.Config; + public OsuRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) : base(ruleset, beatmap) { diff --git a/osu.Game.Rulesets.Osu/UI/OsuSettings.cs b/osu.Game.Rulesets.Osu/UI/OsuSettingsSubsection.cs similarity index 64% rename from osu.Game.Rulesets.Osu/UI/OsuSettings.cs rename to osu.Game.Rulesets.Osu/UI/OsuSettingsSubsection.cs index 3620145ced..ce3432c73d 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuSettings.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuSettingsSubsection.cs @@ -3,34 +3,36 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Game.Configuration; using osu.Game.Overlays.Settings; +using osu.Game.Rulesets.Osu.Configuration; namespace osu.Game.Rulesets.Osu.UI { - public class OsuSettings : RulesetSettingsSubsection + public class OsuSettingsSubsection : RulesetSettingsSubsection { protected override string Header => "osu!"; - public OsuSettings(Ruleset ruleset) + public OsuSettingsSubsection(Ruleset ruleset) : base(ruleset) { } [BackgroundDependencyLoader] - private void load(OsuConfigManager config) + private void load() { + var config = (OsuRulesetConfigManager)Config; + Children = new Drawable[] { new SettingsCheckbox { LabelText = "Snaking in sliders", - Bindable = config.GetBindable(OsuSetting.SnakingInSliders) + Bindable = config.GetBindable(OsuRulesetSetting.SnakingInSliders) }, new SettingsCheckbox { LabelText = "Snaking out sliders", - Bindable = config.GetBindable(OsuSetting.SnakingOutSliders) + Bindable = config.GetBindable(OsuRulesetSetting.SnakingOutSliders) }, }; } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index d6a598fbec..9211eccc40 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -229,6 +229,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables // Ensure alternating centre and rim hits if (lastWasCentre == isCentre) return false; + lastWasCentre = isCentre; UpdateResult(true); diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index 38bf877040..5f755c7cc3 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -49,6 +49,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected void ProxyContent() { if (isProxied) return; + isProxied = true; nonProxiedContent.Remove(Content); @@ -62,6 +63,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected void UnproxyContent() { if (!isProxied) return; + isProxied = false; proxiedContent.Remove(Content); diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs index 5369499dbc..53dbe5d08e 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces /// public override Color4 AccentColour { - get { return base.AccentColour; } + get => base.AccentColour; set { base.AccentColour = value; @@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces /// public override bool KiaiMode { - get { return base.KiaiMode; } + get => base.KiaiMode; set { base.KiaiMode = value; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/TaikoPiece.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/TaikoPiece.cs index dd6a1a5021..773e3ae907 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/TaikoPiece.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/TaikoPiece.cs @@ -11,26 +11,25 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces public class TaikoPiece : BeatSyncedContainer, IHasAccentColour { private Color4 accentColour; + /// /// The colour of the inner circle and outer glows. /// public virtual Color4 AccentColour { - get { return accentColour; } - set { accentColour = value; } + get => accentColour; + set => accentColour = value; } private bool kiaiMode; + /// /// Whether Kiai mode effects are enabled for this circle piece. /// public virtual bool KiaiMode { - get { return kiaiMode; } - set - { - kiaiMode = value; - } + get => kiaiMode; + set => kiaiMode = value; } public TaikoPiece() diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/TickPiece.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/TickPiece.cs index d625047d29..83cf7a64ec 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/TickPiece.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/TickPiece.cs @@ -23,9 +23,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces private const float tick_size = 0.35f; private bool filled; + public bool Filled { - get { return filled; } + get => filled; set { filled = value; diff --git a/osu.Game.Rulesets.Taiko/Objects/Swell.cs b/osu.Game.Rulesets.Taiko/Objects/Swell.cs index 9d511daae4..befa728570 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Swell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Swell.cs @@ -19,7 +19,10 @@ namespace osu.Game.Rulesets.Taiko.Objects /// public int RequiredHits = 10; - public override bool IsStrong { set => throw new NotSupportedException($"{nameof(Swell)} cannot be a strong hitobject."); } + public override bool IsStrong + { + set => throw new NotSupportedException($"{nameof(Swell)} cannot be a strong hitobject."); + } protected override void CreateNestedHitObjects() { diff --git a/osu.Game.Rulesets.Taiko/TaikoInputManager.cs b/osu.Game.Rulesets.Taiko/TaikoInputManager.cs index 2aae0b23b7..058bec5111 100644 --- a/osu.Game.Rulesets.Taiko/TaikoInputManager.cs +++ b/osu.Game.Rulesets.Taiko/TaikoInputManager.cs @@ -19,10 +19,13 @@ namespace osu.Game.Rulesets.Taiko { [Description("Left (rim)")] LeftRim, + [Description("Left (centre)")] LeftCentre, + [Description("Right (centre)")] RightCentre, + [Description("Right (rim)")] RightRim } diff --git a/osu.Game.Tests/Visual/TestCaseBackgroundScreenBeatmap.cs b/osu.Game.Tests/Visual/TestCaseBackgroundScreenBeatmap.cs new file mode 100644 index 0000000000..d850c58f09 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseBackgroundScreenBeatmap.cs @@ -0,0 +1,414 @@ +// 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 System.Threading; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Input.Events; +using osu.Framework.Input.States; +using osu.Framework.Platform; +using osu.Framework.Screens; +using osu.Game.Beatmaps; +using osu.Game.Configuration; +using osu.Game.Database; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Scoring; +using osu.Game.Screens; +using osu.Game.Screens.Backgrounds; +using osu.Game.Screens.Play; +using osu.Game.Screens.Play.PlayerSettings; +using osu.Game.Screens.Select; +using osu.Game.Tests.Resources; +using osu.Game.Users; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Tests.Visual +{ + [TestFixture] + public class TestCaseBackgroundScreenBeatmap : ManualInputManagerTestCase + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(ScreenWithBeatmapBackground), + typeof(PlayerLoader), + typeof(Player), + typeof(UserDimContainer), + typeof(OsuScreen) + }; + + private DummySongSelect songSelect; + private DimAccessiblePlayerLoader playerLoader; + private DimAccessiblePlayer player; + private DatabaseContextFactory factory; + private BeatmapManager manager; + private RulesetStore rulesets; + + private ScreenStackCacheContainer screenStackContainer; + + [BackgroundDependencyLoader] + private void load(GameHost host) + { + factory = new DatabaseContextFactory(LocalStorage); + factory.ResetDatabase(); + + using (var usage = factory.Get()) + usage.Migrate(); + + factory.ResetDatabase(); + + using (var usage = factory.Get()) + usage.Migrate(); + + Dependencies.Cache(rulesets = new RulesetStore(factory)); + Dependencies.Cache(manager = new BeatmapManager(LocalStorage, factory, rulesets, null, null, host, Beatmap.Default)); + Dependencies.Cache(new OsuConfigManager(LocalStorage)); + + Beatmap.SetDefault(); + } + + [SetUp] + public virtual void SetUp() + { + Schedule(() => + { + manager.Delete(manager.GetAllUsableBeatmapSets()); + var temp = TestResources.GetTestBeatmapForImport(); + manager.Import(temp); + Child = screenStackContainer = new ScreenStackCacheContainer { RelativeSizeAxes = Axes.Both }; + screenStackContainer.ScreenStack.Push(songSelect = new DummySongSelect()); + }); + } + + /// + /// Check if properly triggers background dim previews when a user hovers over the visual settings panel. + /// + [Test] + public void PlayerLoaderSettingsHoverTest() + { + setupUserSettings(); + AddStep("Start player loader", () => songSelect.Push(playerLoader = new DimAccessiblePlayerLoader(player = new DimAccessiblePlayer()))); + AddUntilStep(() => playerLoader?.IsLoaded ?? false, "Wait for Player Loader to load"); + AddAssert("Background retained from song select", () => songSelect.IsBackgroundCurrent()); + AddStep("Trigger background preview", () => + { + InputManager.MoveMouseTo(playerLoader.ScreenPos); + InputManager.MoveMouseTo(playerLoader.VisualSettingsPos); + }); + waitForDim(); + AddAssert("Screen is dimmed", () => songSelect.IsBackgroundDimmed()); + AddStep("Stop background preview", () => InputManager.MoveMouseTo(playerLoader.ScreenPos)); + waitForDim(); + AddAssert("Screen is undimmed", () => songSelect.IsBackgroundUndimmed()); + } + + /// + /// In the case of a user triggering the dim preview the instant player gets loaded, then moving the cursor off of the visual settings: + /// The OnHover of PlayerLoader will trigger, which could potentially trigger an undim unless checked for in PlayerLoader. + /// We need to check that in this scenario, the dim is still properly applied after entering player. + /// + [Test] + public void PlayerLoaderTransitionTest() + { + performFullSetup(); + AddStep("Trigger hover event", () => playerLoader.TriggerOnHover()); + AddAssert("Background retained from song select", () => songSelect.IsBackgroundCurrent()); + waitForDim(); + AddAssert("Screen is dimmed and unblurred", () => songSelect.IsBackgroundDimmed() && songSelect.IsBackgroundUnblurred()); + } + + /// + /// Make sure the background is fully invisible (Alpha == 0) when the background should be disabled by the storyboard. + /// + [Test] + public void StoryboardBackgroundVisibilityTest() + { + performFullSetup(); + createFakeStoryboard(); + AddStep("Storyboard Enabled", () => + { + player.ReplacesBackground.Value = true; + player.StoryboardEnabled.Value = true; + }); + waitForDim(); + AddAssert("Background is invisible, storyboard is visible", () => songSelect.IsBackgroundInvisible() && player.IsStoryboardVisible()); + AddStep("Storyboard Disabled", () => + { + player.ReplacesBackground.Value = false; + player.StoryboardEnabled.Value = false; + }); + waitForDim(); + AddAssert("Background is visible, storyboard is invisible", () => songSelect.IsBackgroundVisible() && player.IsStoryboardInvisible()); + } + + /// + /// When exiting player, the screen that it suspends/exits to needs to have a fully visible (Alpha == 1) background. + /// + [Test] + public void StoryboardTransitionTest() + { + performFullSetup(); + createFakeStoryboard(); + AddStep("Exit to song select", () => player.Exit()); + waitForDim(); + AddAssert("Background is visible", () => songSelect.IsBackgroundVisible()); + } + + /// + /// Check if the is properly accepting user dim changes at all. + /// + [Test] + public void DisableUserDimTest() + { + performFullSetup(); + waitForDim(); + AddAssert("Screen is dimmed", () => songSelect.IsBackgroundDimmed()); + AddStep("EnableUserDim disabled", () => songSelect.DimEnabled.Value = false); + waitForDim(); + AddAssert("Screen is undimmed", () => songSelect.IsBackgroundUndimmed()); + AddStep("EnableUserDim enabled", () => songSelect.DimEnabled.Value = true); + waitForDim(); + AddAssert("Screen is dimmed", () => songSelect.IsBackgroundDimmed()); + } + + /// + /// Check if the fade container retains dim when pausing + /// + [Test] + public void PauseTest() + { + performFullSetup(true); + AddStep("Pause", () => player.CurrentPauseContainer.Pause()); + waitForDim(); + AddAssert("Screen is dimmed", () => songSelect.IsBackgroundDimmed()); + AddStep("Unpause", () => player.CurrentPauseContainer.Resume()); + waitForDim(); + AddAssert("Screen is dimmed", () => songSelect.IsBackgroundDimmed()); + } + + /// + /// Check if the fade container removes user dim when suspending for + /// + [Test] + public void TransitionTest() + { + performFullSetup(); + AddStep("Transition to Results", () => player.Push(new FadeAccessibleResults(new ScoreInfo { User = new User { Username = "osu!" } }))); + waitForDim(); + AddAssert("Screen is undimmed and is original background", () => songSelect.IsBackgroundUndimmed() && songSelect.IsBackgroundCurrent()); + } + + /// + /// Check if background gets undimmed when leaving for + /// + [Test] + public void TransitionOutTest() + { + performFullSetup(); + AddStep("Exit to song select", () => player.Exit()); + waitForDim(); + AddAssert("Screen is undimmed", () => songSelect.IsBackgroundUndimmed()); + } + + private void waitForDim() => AddWaitStep(5, "Wait for dim"); + + private void createFakeStoryboard() => AddStep("Create storyboard", () => + { + player.StoryboardEnabled.Value = false; + player.ReplacesBackground.Value = false; + player.CurrentStoryboardContainer.Add(new SpriteText + { + Size = new Vector2(250, 50), + Alpha = 1, + Colour = Color4.Tomato, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = "THIS IS A STORYBOARD", + }); + }); + + private void performFullSetup(bool allowPause = false) + { + setupUserSettings(); + + AddStep("Start player loader", () => + { + songSelect.Push(playerLoader = new DimAccessiblePlayerLoader(player = new DimAccessiblePlayer + { + AllowPause = allowPause, + Ready = true, + })); + }); + AddUntilStep(() => playerLoader.IsLoaded, "Wait for Player Loader to load"); + AddStep("Move mouse to center of screen", () => InputManager.MoveMouseTo(playerLoader.ScreenPos)); + AddUntilStep(() => player.IsLoaded, "Wait for player to load"); + } + + private void setupUserSettings() + { + AddUntilStep(() => songSelect.Carousel.SelectedBeatmap != null, "Song select has selection"); + AddStep("Set default user settings", () => + { + Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Concat(new[] { new OsuModNoFail() }); + songSelect.DimLevel.Value = 0.7f; + songSelect.BlurLevel.Value = 0.0f; + }); + } + + private class DummySongSelect : PlaySongSelect + { + protected override BackgroundScreen CreateBackground() + { + FadeAccessibleBackground background = new FadeAccessibleBackground(Beatmap.Value); + DimEnabled.BindTo(background.EnableUserDim); + return background; + } + + public readonly Bindable DimEnabled = new Bindable(); + public readonly Bindable DimLevel = new Bindable(); + public readonly Bindable BlurLevel = new Bindable(); + + public new BeatmapCarousel Carousel => base.Carousel; + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + config.BindWith(OsuSetting.DimLevel, DimLevel); + config.BindWith(OsuSetting.BlurLevel, BlurLevel); + } + + public bool IsBackgroundDimmed() => ((FadeAccessibleBackground)Background).CurrentColour == OsuColour.Gray(1 - (float)DimLevel.Value); + + public bool IsBackgroundUnblurred() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(0); + + public bool IsBackgroundUndimmed() => ((FadeAccessibleBackground)Background).CurrentColour == Color4.White; + + public bool IsBackgroundInvisible() => ((FadeAccessibleBackground)Background).CurrentAlpha == 0; + + public bool IsBackgroundVisible() => ((FadeAccessibleBackground)Background).CurrentAlpha == 1; + + /// + /// Make sure every time a screen gets pushed, the background doesn't get replaced + /// + /// Whether or not the original background (The one created in DummySongSelect) is still the current background + public bool IsBackgroundCurrent() => ((FadeAccessibleBackground)Background).IsCurrentScreen(); + } + + private class FadeAccessibleResults : SoloResults + { + public FadeAccessibleResults(ScoreInfo score) + : base(score) + { + } + + protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value); + } + + private class DimAccessiblePlayer : Player + { + protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value); + + protected override UserDimContainer CreateStoryboardContainer() + { + return new TestUserDimContainer(true) + { + RelativeSizeAxes = Axes.Both, + Alpha = 1, + EnableUserDim = { Value = true } + }; + } + + public PauseContainer CurrentPauseContainer => PauseContainer; + + public UserDimContainer CurrentStoryboardContainer => StoryboardContainer; + + // Whether or not the player should be allowed to load. + public bool Ready; + + public Bindable StoryboardEnabled; + public readonly Bindable ReplacesBackground = new Bindable(); + public readonly Bindable IsPaused = new Bindable(); + + public bool IsStoryboardVisible() => ((TestUserDimContainer)CurrentStoryboardContainer).CurrentAlpha == 1; + + public bool IsStoryboardInvisible() => ((TestUserDimContainer)CurrentStoryboardContainer).CurrentAlpha <= 1; + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + while (!Ready) + Thread.Sleep(1); + StoryboardEnabled = config.GetBindable(OsuSetting.ShowStoryboard); + ReplacesBackground.BindTo(Background.StoryboardReplacesBackground); + RulesetContainer.IsPaused.BindTo(IsPaused); + } + } + + private class ScreenStackCacheContainer : Container + { + [Cached] + private BackgroundScreenStack backgroundScreenStack; + + public readonly ScreenStack ScreenStack; + + public ScreenStackCacheContainer() + { + Add(backgroundScreenStack = new BackgroundScreenStack { RelativeSizeAxes = Axes.Both }); + Add(ScreenStack = new ScreenStack { RelativeSizeAxes = Axes.Both }); + } + } + + private class DimAccessiblePlayerLoader : PlayerLoader + { + public VisualSettings VisualSettingsPos => VisualSettings; + public BackgroundScreen ScreenPos => Background; + + public DimAccessiblePlayerLoader(Player player) + : base(() => player) + { + } + + public void TriggerOnHover() => OnHover(new HoverEvent(new InputState())); + + protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value); + } + + private class FadeAccessibleBackground : BackgroundScreenBeatmap + { + protected override UserDimContainer CreateFadeContainer() => fadeContainer = new TestUserDimContainer { RelativeSizeAxes = Axes.Both }; + + public Color4 CurrentColour => fadeContainer.CurrentColour; + public float CurrentAlpha => fadeContainer.CurrentAlpha; + + public Vector2 CurrentBlur => Background.BlurSigma; + + private TestUserDimContainer fadeContainer; + + public FadeAccessibleBackground(WorkingBeatmap beatmap) + : base(beatmap) + { + } + } + + private class TestUserDimContainer : UserDimContainer + { + public Color4 CurrentColour => DimContainer.Colour; + public float CurrentAlpha => DimContainer.Alpha; + + public TestUserDimContainer(bool isStoryboard = false) + : base(isStoryboard) + { + } + } + } +} diff --git a/osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs b/osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs index 127ee9e482..2fd8d467f6 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs @@ -141,6 +141,7 @@ namespace osu.Game.Tests.Visual } private SortedList timingPoints => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints; + private TimingControlPoint getNextTimingPoint(TimingControlPoint current) { if (timingPoints[timingPoints.Count - 1] == current) @@ -190,7 +191,7 @@ namespace osu.Game.Tests.Visual public double Value { - set { valueText.Text = $"{value:G}"; } + set => valueText.Text = $"{value:G}"; } public InfoString(string header) diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs index 99bdb05394..618d8376c0 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs @@ -150,6 +150,7 @@ namespace osu.Game.Tests.Visual var currentlySelected = carousel.Items.Find(s => s.Item is CarouselBeatmap && s.Item.State.Value == CarouselItemState.Selected); if (currentlySelected == null) return true; + return currentlySelected.Item.Visible; } @@ -166,8 +167,7 @@ namespace osu.Game.Tests.Visual carousel.Filter(new FilterCriteria { SearchText = "Dingo" }, false); carousel.Filter(new FilterCriteria(), false); eagerSelectedIDs.Add(carousel.SelectedBeatmapSet.ID); - } - ); + }); } /// @@ -522,6 +522,7 @@ namespace osu.Game.Tests.Visual } }); } + return toReturn; } diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs b/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs index 321a38d087..bb55c0b1e8 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs @@ -23,9 +23,6 @@ namespace osu.Game.Tests.Visual [System.ComponentModel.Description("in BeatmapOverlay")] public class TestCaseBeatmapScoresContainer : OsuTestCase { - private readonly IEnumerable scores; - private readonly IEnumerable anotherScores; - private readonly APIScoreInfo topScoreInfo; private readonly Box background; public TestCaseBeatmapScoresContainer() @@ -47,15 +44,7 @@ namespace osu.Game.Tests.Visual } }; - AddStep("scores pack 1", () => scoresContainer.Scores = scores); - AddStep("scores pack 2", () => scoresContainer.Scores = anotherScores); - AddStep("only top score", () => scoresContainer.Scores = new[] { topScoreInfo }); - AddStep("remove scores", () => scoresContainer.Scores = null); - AddStep("resize to big", () => container.ResizeWidthTo(1, 300)); - AddStep("resize to normal", () => container.ResizeWidthTo(0.8f, 300)); - AddStep("online scores", () => scoresContainer.Beatmap = new BeatmapInfo { OnlineBeatmapID = 75, Ruleset = new OsuRuleset().RulesetInfo }); - - scores = new[] + IEnumerable scores = new[] { new APIScoreInfo { @@ -160,14 +149,15 @@ namespace osu.Game.Tests.Visual Accuracy = 0.6543, }, }; - foreach(var s in scores) + + foreach (var s in scores) { s.Statistics.Add(HitResult.Great, RNG.Next(2000)); s.Statistics.Add(HitResult.Good, RNG.Next(2000)); s.Statistics.Add(HitResult.Meh, RNG.Next(2000)); } - anotherScores = new[] + IEnumerable anotherScores = new[] { new APIScoreInfo { @@ -279,7 +269,7 @@ namespace osu.Game.Tests.Visual s.Statistics.Add(HitResult.Meh, RNG.Next(2000)); } - topScoreInfo = new APIScoreInfo + var topScoreInfo = new APIScoreInfo { User = new User { @@ -304,6 +294,14 @@ namespace osu.Game.Tests.Visual topScoreInfo.Statistics.Add(HitResult.Great, RNG.Next(2000)); topScoreInfo.Statistics.Add(HitResult.Good, RNG.Next(2000)); topScoreInfo.Statistics.Add(HitResult.Meh, RNG.Next(2000)); + + AddStep("scores pack 1", () => scoresContainer.Scores = scores); + AddStep("scores pack 2", () => scoresContainer.Scores = anotherScores); + AddStep("only top score", () => scoresContainer.Scores = new[] { topScoreInfo }); + AddStep("remove scores", () => scoresContainer.Scores = null); + AddStep("resize to big", () => container.ResizeWidthTo(1, 300)); + AddStep("resize to normal", () => container.ResizeWidthTo(0.8f, 300)); + AddStep("online scores", () => scoresContainer.Beatmap = new BeatmapInfo { OnlineBeatmapID = 75, Ruleset = new OsuRuleset().RulesetInfo }); } [BackgroundDependencyLoader] diff --git a/osu.Game.Tests/Visual/TestCaseChatLink.cs b/osu.Game.Tests/Visual/TestCaseChatLink.cs index dc537348c9..b2ec2c9b47 100644 --- a/osu.Game.Tests/Visual/TestCaseChatLink.cs +++ b/osu.Game.Tests/Visual/TestCaseChatLink.cs @@ -56,7 +56,7 @@ namespace osu.Game.Tests.Visual var chatManager = new ChannelManager(); BindableList availableChannels = (BindableList)chatManager.AvailableChannels; - availableChannels.Add(new Channel { Name = "#english"}); + availableChannels.Add(new Channel { Name = "#english" }); availableChannels.Add(new Channel { Name = "#japanese" }); Dependencies.Cache(chatManager); diff --git a/osu.Game.Tests/Visual/TestCaseContextMenu.cs b/osu.Game.Tests/Visual/TestCaseContextMenu.cs index f969ec69e2..5cbe97e21d 100644 --- a/osu.Game.Tests/Visual/TestCaseContextMenu.cs +++ b/osu.Game.Tests/Visual/TestCaseContextMenu.cs @@ -61,10 +61,10 @@ namespace osu.Game.Tests.Visual // Move box along a square trajectory container.Loop(c => c - .MoveTo(new Vector2(0, 100), duration).Then() - .MoveTo(new Vector2(100, 100), duration).Then() - .MoveTo(new Vector2(100, 0), duration).Then() - .MoveTo(Vector2.Zero, duration) + .MoveTo(new Vector2(0, 100), duration).Then() + .MoveTo(new Vector2(100, 100), duration).Then() + .MoveTo(new Vector2(100, 0), duration).Then() + .MoveTo(Vector2.Zero, duration) ); } diff --git a/osu.Game.Tests/Visual/TestCaseEditorSeekSnapping.cs b/osu.Game.Tests/Visual/TestCaseEditorSeekSnapping.cs index 244f3b9d3d..0ec87e6f52 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorSeekSnapping.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorSeekSnapping.cs @@ -33,7 +33,7 @@ namespace osu.Game.Tests.Visual { TimingPoints = { - new TimingControlPoint { Time = 0, BeatLength = 200}, + new TimingControlPoint { Time = 0, BeatLength = 200 }, new TimingControlPoint { Time = 100, BeatLength = 400 }, new TimingControlPoint { Time = 175, BeatLength = 800 }, new TimingControlPoint { Time = 350, BeatLength = 200 }, diff --git a/osu.Game.Tests/Visual/TestCaseGameplayMenuOverlay.cs b/osu.Game.Tests/Visual/TestCaseGameplayMenuOverlay.cs index 3f36365a05..a21573236a 100644 --- a/osu.Game.Tests/Visual/TestCaseGameplayMenuOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseGameplayMenuOverlay.cs @@ -265,6 +265,7 @@ namespace osu.Game.Tests.Visual pauseOverlay.OnRetry = lastAction; lastAction = null; } + return triggered; }); AddAssert("Overlay is closed", () => pauseOverlay.State == Visibility.Hidden); diff --git a/osu.Game.Tests/Visual/TestCaseLeaderboard.cs b/osu.Game.Tests/Visual/TestCaseLeaderboard.cs index 822809b96e..eb1a2c0249 100644 --- a/osu.Game.Tests/Visual/TestCaseLeaderboard.cs +++ b/osu.Game.Tests/Visual/TestCaseLeaderboard.cs @@ -20,7 +20,8 @@ namespace osu.Game.Tests.Visual [Description("PlaySongSelect leaderboard")] public class TestCaseLeaderboard : OsuTestCase { - public override IReadOnlyList RequiredTypes => new[] { + public override IReadOnlyList RequiredTypes => new[] + { typeof(Placeholder), typeof(MessagePlaceholder), typeof(RetrievalFailurePlaceholder), diff --git a/osu.Game.Tests/Visual/TestCaseOsuGame.cs b/osu.Game.Tests/Visual/TestCaseOsuGame.cs index c527bce683..9e649b92e4 100644 --- a/osu.Game.Tests/Visual/TestCaseOsuGame.cs +++ b/osu.Game.Tests/Visual/TestCaseOsuGame.cs @@ -4,10 +4,10 @@ using System; using System.Collections.Generic; using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; -using osu.Framework.Screens; -using osu.Game.Screens; +using osu.Framework.Platform; using osu.Game.Screens.Menu; using osuTK.Graphics; @@ -21,8 +21,12 @@ namespace osu.Game.Tests.Visual typeof(OsuLogo), }; - public TestCaseOsuGame() + [BackgroundDependencyLoader] + private void load(GameHost host) { + OsuGame game = new OsuGame(); + game.SetHost(host); + Children = new Drawable[] { new Box @@ -30,10 +34,7 @@ namespace osu.Game.Tests.Visual RelativeSizeAxes = Axes.Both, Colour = Color4.Black, }, - new ScreenStack(new Loader()) - { - RelativeSizeAxes = Axes.Both, - } + game }; } } diff --git a/osu.Game.Tests/Visual/TestCasePlaybackControl.cs b/osu.Game.Tests/Visual/TestCasePlaybackControl.cs index 60fd2fa79b..abcff24c67 100644 --- a/osu.Game.Tests/Visual/TestCasePlaybackControl.cs +++ b/osu.Game.Tests/Visual/TestCasePlaybackControl.cs @@ -26,7 +26,7 @@ namespace osu.Game.Tests.Visual { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(200,100) + Size = new Vector2(200, 100) }; Beatmap.Value = new TestWorkingBeatmap(new Beatmap(), Clock); diff --git a/osu.Game.Tests/Visual/TestCasePlayerLoader.cs b/osu.Game.Tests/Visual/TestCasePlayerLoader.cs index 16cb94c65e..244f553e97 100644 --- a/osu.Game.Tests/Visual/TestCasePlayerLoader.cs +++ b/osu.Game.Tests/Visual/TestCasePlayerLoader.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Screens; using osu.Game.Beatmaps; +using osu.Game.Screens; using osu.Game.Screens.Play; namespace osu.Game.Tests.Visual @@ -13,15 +14,22 @@ namespace osu.Game.Tests.Visual public class TestCasePlayerLoader : ManualInputManagerTestCase { private PlayerLoader loader; - private ScreenStack stack; + private readonly ScreenStack stack; + + [Cached] + private BackgroundScreenStack backgroundStack; + + public TestCasePlayerLoader() + { + InputManager.Add(backgroundStack = new BackgroundScreenStack { RelativeSizeAxes = Axes.Both }); + InputManager.Add(stack = new ScreenStack { RelativeSizeAxes = Axes.Both }); + } [BackgroundDependencyLoader] private void load(OsuGameBase game) { Beatmap.Value = new DummyWorkingBeatmap(game); - InputManager.Add(stack = new ScreenStack { RelativeSizeAxes = Axes.Both }); - AddStep("load dummy beatmap", () => stack.Push(loader = new PlayerLoader(() => new Player { AllowPause = false, diff --git a/osu.Game.Tests/Visual/TestCaseScreenBreadcrumbControl.cs b/osu.Game.Tests/Visual/TestCaseScreenBreadcrumbControl.cs index 531c01158b..204f4a493d 100644 --- a/osu.Game.Tests/Visual/TestCaseScreenBreadcrumbControl.cs +++ b/osu.Game.Tests/Visual/TestCaseScreenBreadcrumbControl.cs @@ -84,7 +84,7 @@ namespace osu.Game.Tests.Visual public TestScreen PushNext() { TestScreen screen = CreateNextScreen(); - this.Push(screen); + this.Push(screen); return screen; } diff --git a/osu.Game.Tests/Visual/TestCaseSkinReloadable.cs b/osu.Game.Tests/Visual/TestCaseSkinReloadable.cs new file mode 100644 index 0000000000..94f01e9d32 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseSkinReloadable.cs @@ -0,0 +1,153 @@ +// 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.Audio.Sample; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Game.Graphics; +using osu.Game.Skinning; +using osuTK.Graphics; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseSkinReloadable : OsuTestCase + { + [Test] + public void TestInitialLoad() + { + var secondarySource = new SecondarySource(); + SkinConsumer consumer = null; + + AddStep("setup layout", () => + { + Child = new SkinSourceContainer + { + RelativeSizeAxes = Axes.Both, + Child = new LocalSkinOverrideContainer(secondarySource) + { + RelativeSizeAxes = Axes.Both, + Child = consumer = new SkinConsumer("test", name => new NamedBox("Default Implementation"), source => true) + } + }; + }); + + AddAssert("consumer using override source", () => consumer.Drawable is SecondarySourceBox); + AddAssert("skinchanged only called once", () => consumer.SkinChangedCount == 1); + } + + [Test] + public void TestOverride() + { + var secondarySource = new SecondarySource(); + + SkinConsumer consumer = null; + Container target = null; + + AddStep("setup layout", () => + { + Child = new SkinSourceContainer + { + RelativeSizeAxes = Axes.Both, + Child = target = new LocalSkinOverrideContainer(secondarySource) + { + RelativeSizeAxes = Axes.Both, + } + }; + }); + + AddStep("add permissive", () => target.Add(consumer = new SkinConsumer("test", name => new NamedBox("Default Implementation"), source => true))); + AddAssert("consumer using override source", () => consumer.Drawable is SecondarySourceBox); + AddAssert("skinchanged only called once", () => consumer.SkinChangedCount == 1); + } + + private class NamedBox : Container + { + public NamedBox(string name) + { + Children = new Drawable[] + { + new Box + { + Colour = Color4.Black, + RelativeSizeAxes = Axes.Both, + }, + new SpriteText + { + Font = OsuFont.Default.With(size: 40), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = name + } + }; + } + } + + private class SkinConsumer : SkinnableDrawable + { + public new Drawable Drawable => base.Drawable; + public int SkinChangedCount { get; private set; } + + public SkinConsumer(string name, Func defaultImplementation, Func allowFallback = null, bool restrictSize = true) + : base(name, defaultImplementation, allowFallback, restrictSize) + { + } + + protected override void SkinChanged(ISkinSource skin, bool allowFallback) + { + base.SkinChanged(skin, allowFallback); + SkinChangedCount++; + } + } + + private class BaseSourceBox : NamedBox + { + public BaseSourceBox() + : base("Base Source") + { + } + } + + private class SecondarySourceBox : NamedBox + { + public SecondarySourceBox() + : base("Secondary Source") + { + } + } + + private class SecondarySource : ISkinSource + { + public event Action SourceChanged; + + public void TriggerSourceChanged() => SourceChanged?.Invoke(); + + public Drawable GetDrawableComponent(string componentName) => new SecondarySourceBox(); + + public Texture GetTexture(string componentName) => throw new NotImplementedException(); + + public SampleChannel GetSample(string sampleName) => throw new NotImplementedException(); + + public TValue GetValue(Func query) where TConfiguration : SkinConfiguration => throw new NotImplementedException(); + } + + private class SkinSourceContainer : Container, ISkinSource + { + public event Action SourceChanged; + + public void TriggerSourceChanged() => SourceChanged?.Invoke(); + + public Drawable GetDrawableComponent(string componentName) => new BaseSourceBox(); + + public Texture GetTexture(string componentName) => throw new NotImplementedException(); + + public SampleChannel GetSample(string sampleName) => throw new NotImplementedException(); + + public TValue GetValue(Func query) where TConfiguration : SkinConfiguration => throw new NotImplementedException(); + } + } +} diff --git a/osu.Game.Tests/Visual/TestCaseSongProgress.cs b/osu.Game.Tests/Visual/TestCaseSongProgress.cs index 9ce33f21d6..9845df7461 100644 --- a/osu.Game.Tests/Visual/TestCaseSongProgress.cs +++ b/osu.Game.Tests/Visual/TestCaseSongProgress.cs @@ -15,7 +15,7 @@ namespace osu.Game.Tests.Visual public class TestCaseSongProgress : OsuTestCase { private readonly SongProgress progress; - private readonly SongProgressGraph graph; + private readonly TestSongProgressGraph graph; private readonly StopwatchClock clock; @@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual Origin = Anchor.BottomLeft, }); - Add(graph = new SongProgressGraph + Add(graph = new TestSongProgressGraph { RelativeSizeAxes = Axes.X, Height = 200, @@ -39,13 +39,24 @@ namespace osu.Game.Tests.Visual Origin = Anchor.TopLeft, }); + AddWaitStep(5); + AddAssert("ensure not created", () => graph.CreationCount == 0); + + AddStep("display values", displayNewValues); + AddWaitStep(5); + AddUntilStep(() => graph.CreationCount == 1, "wait for creation count"); + AddStep("Toggle Bar", () => progress.AllowSeeking = !progress.AllowSeeking); AddWaitStep(5); + AddUntilStep(() => graph.CreationCount == 1, "wait for creation count"); + AddStep("Toggle Bar", () => progress.AllowSeeking = !progress.AllowSeeking); - AddWaitStep(2); + AddWaitStep(5); + AddUntilStep(() => graph.CreationCount == 1, "wait for creation count"); AddRepeatStep("New Values", displayNewValues, 5); - displayNewValues(); + AddWaitStep(5); + AddAssert("ensure debounced", () => graph.CreationCount == 2); } private void displayNewValues() @@ -60,5 +71,16 @@ namespace osu.Game.Tests.Visual progress.AudioClock = clock; progress.OnSeek = pos => clock.Seek(pos); } + + private class TestSongProgressGraph : SongProgressGraph + { + public int CreationCount { get; private set; } + + protected override void RecreateGraph() + { + base.RecreateGraph(); + CreationCount++; + } + } } } diff --git a/osu.Game.Tests/Visual/TestCaseStoryboard.cs b/osu.Game.Tests/Visual/TestCaseStoryboard.cs index fc62b8fe0c..c4b41e40f4 100644 --- a/osu.Game.Tests/Visual/TestCaseStoryboard.cs +++ b/osu.Game.Tests/Visual/TestCaseStoryboard.cs @@ -50,7 +50,10 @@ namespace osu.Game.Tests.Visual }); AddStep("Restart", restart); - AddToggleStep("Passing", passing => { if (storyboard != null) storyboard.Passing = passing; }); + AddToggleStep("Passing", passing => + { + if (storyboard != null) storyboard.Passing = passing; + }); } [BackgroundDependencyLoader] diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs index 5de2f2551d..3b21bdefc4 100644 --- a/osu.Game/Audio/PreviewTrack.cs +++ b/osu.Game/Audio/PreviewTrack.cs @@ -28,7 +28,7 @@ namespace osu.Game.Audio private void load() { track = GetTrack(); - track.Completed += Stop; + track.Completed += () => Schedule(Stop); } /// @@ -63,6 +63,7 @@ namespace osu.Game.Audio if (hasStarted) return; + hasStarted = true; track.Restart(); @@ -81,6 +82,7 @@ namespace osu.Game.Audio if (!hasStarted) return; + hasStarted = false; track.Stop(); diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 736caf69e8..5bc6dce60b 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -50,12 +50,14 @@ namespace osu.Game.Audio { if (!string.IsNullOrEmpty(Suffix)) yield return $"{Namespace}/{Bank}-{Name}{Suffix}"; + yield return $"{Namespace}/{Bank}-{Name}"; } // check non-namespace as a fallback even when we have a namespace if (!string.IsNullOrEmpty(Suffix)) yield return $"{Bank}-{Name}{Suffix}"; + yield return $"{Bank}-{Name}"; } } diff --git a/osu.Game/Beatmaps/BeatmapConverter.cs b/osu.Game/Beatmaps/BeatmapConverter.cs index d6041ad38d..b6fa6674f6 100644 --- a/osu.Game/Beatmaps/BeatmapConverter.cs +++ b/osu.Game/Beatmaps/BeatmapConverter.cs @@ -16,6 +16,7 @@ namespace osu.Game.Beatmaps where T : HitObject { private event Action> ObjectConverted; + event Action> IBeatmapConverter.ObjectConverted { add => ObjectConverted += value; diff --git a/osu.Game/Beatmaps/BeatmapDifficulty.cs b/osu.Game/Beatmaps/BeatmapDifficulty.cs index 21b943e111..8727431e0e 100644 --- a/osu.Game/Beatmaps/BeatmapDifficulty.cs +++ b/osu.Game/Beatmaps/BeatmapDifficulty.cs @@ -48,6 +48,7 @@ namespace osu.Game.Beatmaps return mid + (max - mid) * (difficulty - 5) / 5; if (difficulty < 5) return mid - (mid - min) * (5 - difficulty) / 5; + return mid; } diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs index bac8ad5ed7..001f319307 100644 --- a/osu.Game/Beatmaps/BeatmapMetadata.cs +++ b/osu.Game/Beatmaps/BeatmapMetadata.cs @@ -34,8 +34,8 @@ namespace osu.Game.Beatmaps [Column("Author")] public string AuthorString { - get { return Author?.Username; } - set { Author = new User { Username = value }; } + get => Author?.Username; + set => Author = new User { Username = value }; } /// @@ -48,6 +48,7 @@ namespace osu.Game.Beatmaps [JsonProperty(@"tags")] public string Tags { get; set; } + public int PreviewTime { get; set; } public string AudioFile { get; set; } public string BackgroundFile { get; set; } @@ -72,15 +73,15 @@ namespace osu.Game.Beatmaps return false; return Title == other.Title - && TitleUnicode == other.TitleUnicode - && Artist == other.Artist - && ArtistUnicode == other.ArtistUnicode - && AuthorString == other.AuthorString - && Source == other.Source - && Tags == other.Tags - && PreviewTime == other.PreviewTime - && AudioFile == other.AudioFile - && BackgroundFile == other.BackgroundFile; + && TitleUnicode == other.TitleUnicode + && Artist == other.Artist + && ArtistUnicode == other.ArtistUnicode + && AuthorString == other.AuthorString + && Source == other.Source + && Tags == other.Tags + && PreviewTime == other.PreviewTime + && AudioFile == other.AudioFile + && BackgroundFile == other.BackgroundFile; } } } diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index ad7648e7fd..f4b7b1d74f 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -12,7 +12,7 @@ namespace osu.Game.Beatmaps /// /// Handles the storage and retrieval of Beatmaps/BeatmapSets to the database backing /// - public class BeatmapStore : MutableDatabaseBackedStore + public class BeatmapStore : MutableDatabaseBackedStoreWithFileIncludes { public event Action BeatmapHidden; public event Action BeatmapRestored; @@ -34,6 +34,7 @@ namespace osu.Game.Beatmaps Refresh(ref beatmap, Beatmaps); if (beatmap.Hidden) return false; + beatmap.Hidden = true; } @@ -53,6 +54,7 @@ namespace osu.Game.Beatmaps Refresh(ref beatmap, Beatmaps); if (!beatmap.Hidden) return false; + beatmap.Hidden = false; } @@ -62,18 +64,17 @@ namespace osu.Game.Beatmaps protected override IQueryable AddIncludesForDeletion(IQueryable query) => base.AddIncludesForDeletion(query) - .Include(s => s.Beatmaps).ThenInclude(b => b.Metadata) - .Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty) .Include(s => s.Metadata) - .Include(s => s.Beatmaps).ThenInclude(b => b.Scores); + .Include(s => s.Beatmaps).ThenInclude(b => b.Scores) + .Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty) + .Include(s => s.Beatmaps).ThenInclude(b => b.Metadata); protected override IQueryable AddIncludesForConsumption(IQueryable query) => base.AddIncludesForConsumption(query) .Include(s => s.Metadata) .Include(s => s.Beatmaps).ThenInclude(s => s.Ruleset) .Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty) - .Include(s => s.Beatmaps).ThenInclude(b => b.Metadata) - .Include(s => s.Files).ThenInclude(f => f.FileInfo); + .Include(s => s.Beatmaps).ThenInclude(b => b.Metadata); protected override void Purge(List items, OsuDbContext context) { diff --git a/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs b/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs index c8c735b439..0c59eec1ef 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs @@ -13,8 +13,8 @@ namespace osu.Game.Beatmaps.Drawables public BeatmapBackgroundSprite(WorkingBeatmap working) { - if (working == null) - throw new ArgumentNullException(nameof(working)); + if (working == null) + throw new ArgumentNullException(nameof(working)); this.working = working; } diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs index 72b5f69eee..351e5df17a 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs @@ -23,6 +23,7 @@ namespace osu.Game.Beatmaps.Drawables { if (status == value) return; + status = value; Alpha = value == BeatmapSetOnlineStatus.None ? 0 : 1; diff --git a/osu.Game/Beatmaps/Drawables/DifficultyColouredContainer.cs b/osu.Game/Beatmaps/Drawables/DifficultyColouredContainer.cs index b025b5985c..f1607ad749 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyColouredContainer.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyColouredContainer.cs @@ -48,11 +48,12 @@ namespace osu.Game.Beatmaps.Drawables var rating = beatmap.StarDifficulty; - if (rating < 1.5) return DifficultyRating.Easy; - if (rating < 2.25) return DifficultyRating.Normal; - if (rating < 3.75) return DifficultyRating.Hard; - if (rating < 5.25) return DifficultyRating.Insane; - if (rating < 6.75) return DifficultyRating.Expert; + if (rating < 2.0) return DifficultyRating.Easy; + if (rating < 2.7) return DifficultyRating.Normal; + if (rating < 4.0) return DifficultyRating.Hard; + if (rating < 5.3) return DifficultyRating.Insane; + if (rating < 6.5) return DifficultyRating.Expert; + return DifficultyRating.ExpertPlus; } diff --git a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs index 4d07fd234b..6fa7d47683 100644 --- a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs +++ b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs @@ -25,7 +25,8 @@ namespace osu.Game.Beatmaps.Drawables protected override Drawable CreateDrawable(BeatmapInfo model) { - return new DelayedLoadUnloadWrapper(() => { + return new DelayedLoadUnloadWrapper(() => + { Drawable drawable; var localBeatmap = beatmaps.GetWorkingBeatmap(model); diff --git a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapSetCover.cs b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapSetCover.cs index 45df2b3406..367b63d6d1 100644 --- a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapSetCover.cs +++ b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapSetCover.cs @@ -13,12 +13,14 @@ namespace osu.Game.Beatmaps.Drawables private Drawable displayedCover; private BeatmapSetInfo beatmapSet; + public BeatmapSetInfo BeatmapSet { - get { return beatmapSet; } + get => beatmapSet; set { if (value == beatmapSet) return; + beatmapSet = value; if (IsLoaded) @@ -27,12 +29,14 @@ namespace osu.Game.Beatmaps.Drawables } private BeatmapSetCoverType coverType = BeatmapSetCoverType.Cover; + public BeatmapSetCoverType CoverType { - get { return coverType; } + get => coverType; set { if (value == coverType) return; + coverType = value; if (IsLoaded) diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 34e5afd1cd..040f582e3b 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -72,6 +72,7 @@ namespace osu.Game.Beatmaps.Formats var index = line.AsSpan().IndexOf("//".AsSpan()); if (index > 0) return line.Substring(0, index); + return line; } @@ -115,6 +116,7 @@ namespace osu.Game.Beatmaps.Formats else { if (!(output is IHasCustomColours tHasCustomColours)) return; + tHasCustomColours.CustomColours[pair.Key] = colour; } } diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 1260a524b4..2d8cfa12ee 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -72,9 +72,6 @@ namespace osu.Game.Configuration Set(OsuSetting.MenuParallax, true); - Set(OsuSetting.SnakingInSliders, true); - Set(OsuSetting.SnakingOutSliders, true); - // Gameplay Set(OsuSetting.DimLevel, 0.3, 0, 1, 0.01); Set(OsuSetting.BlurLevel, 0, 0, 1, 0.01); @@ -150,8 +147,6 @@ namespace osu.Game.Configuration DisplayStarsMinimum, DisplayStarsMaximum, RandomSelectAlgorithm, - SnakingInSliders, - SnakingOutSliders, ShowFpsDisplay, ChatDisplayHeight, Version, diff --git a/osu.Game/Configuration/RandomSelectAlgorithm.cs b/osu.Game/Configuration/RandomSelectAlgorithm.cs index 35240db0ee..8d0c87374f 100644 --- a/osu.Game/Configuration/RandomSelectAlgorithm.cs +++ b/osu.Game/Configuration/RandomSelectAlgorithm.cs @@ -5,10 +5,11 @@ using System.ComponentModel; namespace osu.Game.Configuration { - public enum RandomSelectAlgorithm + public enum RandomSelectAlgorithm { [Description("Never repeat")] RandomPermutation, + [Description("Random")] Random } diff --git a/osu.Game/Configuration/RankingType.cs b/osu.Game/Configuration/RankingType.cs index 6514be750d..7701e1dd1d 100644 --- a/osu.Game/Configuration/RankingType.cs +++ b/osu.Game/Configuration/RankingType.cs @@ -8,8 +8,10 @@ namespace osu.Game.Configuration public enum RankingType { Local, + [Description("Global")] Top, + [Description("Selected Mods")] SelectedMod, Friends, diff --git a/osu.Game/Configuration/ScalingMode.cs b/osu.Game/Configuration/ScalingMode.cs index 1dadfcecc9..0bcc908f71 100644 --- a/osu.Game/Configuration/ScalingMode.cs +++ b/osu.Game/Configuration/ScalingMode.cs @@ -9,6 +9,7 @@ namespace osu.Game.Configuration { Off, Everything, + [Description("Excluding overlays")] ExcludeOverlays, Gameplay, diff --git a/osu.Game/Configuration/ScreenshotFormat.cs b/osu.Game/Configuration/ScreenshotFormat.cs index 8015945747..6d4c96bfa9 100644 --- a/osu.Game/Configuration/ScreenshotFormat.cs +++ b/osu.Game/Configuration/ScreenshotFormat.cs @@ -9,6 +9,7 @@ namespace osu.Game.Configuration { [Description("JPG (web-friendly)")] Jpg = 1, + [Description("PNG (lossless)")] Png = 2 } diff --git a/osu.Game/Configuration/ScrollVisualisationMethod.cs b/osu.Game/Configuration/ScrollVisualisationMethod.cs index d2c09f9128..5f48fe8bfd 100644 --- a/osu.Game/Configuration/ScrollVisualisationMethod.cs +++ b/osu.Game/Configuration/ScrollVisualisationMethod.cs @@ -9,8 +9,10 @@ namespace osu.Game.Configuration { [Description("Sequential")] Sequential, + [Description("Overlapping")] Overlapping, + [Description("Constant")] Constant } diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 42dbdfbd8a..9ec184abd7 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading.Tasks; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; +using osu.Framework; using osu.Framework.Extensions; using osu.Framework.IO.File; using osu.Framework.Logging; @@ -53,6 +54,8 @@ namespace osu.Game.Database public virtual string[] HandledExtensions => new[] { ".zip" }; + public virtual bool SupportsImportFromStable => RuntimeInfo.IsDesktop; + protected readonly FileStore Files; protected readonly IDatabaseContextFactory ContextFactory; @@ -105,7 +108,7 @@ namespace osu.Game.Database a.Invoke(); } - protected ArchiveModelManager(Storage storage, IDatabaseContextFactory contextFactory, MutableDatabaseBackedStore modelStore, IIpcHost importHost = null) + protected ArchiveModelManager(Storage storage, IDatabaseContextFactory contextFactory, MutableDatabaseBackedStoreWithFileIncludes modelStore, IIpcHost importHost = null) { ContextFactory = contextFactory; @@ -561,6 +564,7 @@ namespace osu.Game.Database return new LegacyDirectoryArchiveReader(path); if (File.Exists(path)) return new LegacyFileArchiveReader(path); + throw new InvalidFormatException($"{path} is not a valid archive"); } } diff --git a/osu.Game/Database/DatabaseWriteUsage.cs b/osu.Game/Database/DatabaseWriteUsage.cs index 4659c212f3..1fd2f23d50 100644 --- a/osu.Game/Database/DatabaseWriteUsage.cs +++ b/osu.Game/Database/DatabaseWriteUsage.cs @@ -31,6 +31,7 @@ namespace osu.Game.Database protected void Dispose(bool disposing) { if (isDisposed) return; + isDisposed = true; try diff --git a/osu.Game/Database/MutableDatabaseBackedStore.cs b/osu.Game/Database/MutableDatabaseBackedStore.cs index 5bf06d93f1..39a48b5be6 100644 --- a/osu.Game/Database/MutableDatabaseBackedStore.cs +++ b/osu.Game/Database/MutableDatabaseBackedStore.cs @@ -68,6 +68,7 @@ namespace osu.Game.Database Refresh(ref item); if (item.DeletePending) return false; + item.DeletePending = true; } @@ -86,6 +87,7 @@ namespace osu.Game.Database Refresh(ref item, ConsumableItems); if (!item.DeletePending) return false; + item.DeletePending = false; } diff --git a/osu.Game/Database/MutableDatabaseBackedStoreWithFileIncludes.cs b/osu.Game/Database/MutableDatabaseBackedStoreWithFileIncludes.cs new file mode 100644 index 0000000000..5d6ff6b09b --- /dev/null +++ b/osu.Game/Database/MutableDatabaseBackedStoreWithFileIncludes.cs @@ -0,0 +1,27 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using Microsoft.EntityFrameworkCore; +using osu.Framework.Platform; + +namespace osu.Game.Database +{ + public abstract class MutableDatabaseBackedStoreWithFileIncludes : MutableDatabaseBackedStore + where T : class, IHasPrimaryKey, ISoftDelete, IHasFiles + where U : INamedFileInfo + { + protected MutableDatabaseBackedStoreWithFileIncludes(IDatabaseContextFactory contextFactory, Storage storage = null) + : base(contextFactory, storage) + { + } + + protected override IQueryable AddIncludesForConsumption(IQueryable query) => + base.AddIncludesForConsumption(query) + .Include(s => s.Files).ThenInclude(f => f.FileInfo); + + protected override IQueryable AddIncludesForDeletion(IQueryable query) => + base.AddIncludesForDeletion(query) + .Include(s => s.Files); // don't include FileInfo. these are handled by the FileStore itself. + } +} diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index f4abcd6496..ebd9db786f 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -86,7 +86,7 @@ namespace osu.Game.Graphics.Backgrounds public float TriangleScale { - get { return triangleScale; } + get => triangleScale; set { float change = value / triangleScale; @@ -110,10 +110,10 @@ namespace osu.Game.Graphics.Backgrounds if (CreateNewTriangles) addTriangles(false); - float adjustedAlpha = HideAlphaDiscrepancies ? + float adjustedAlpha = HideAlphaDiscrepancies // Cubically scale alpha to make it drop off more sharply. - (float)Math.Pow(DrawColourInfo.Colour.AverageColour.Linear.A, 3) : - 1; + ? (float)Math.Pow(DrawColourInfo.Colour.AverageColour.Linear.A, 3) + : 1; float elapsedSeconds = (float)Time.Elapsed / 1000; // Since position is relative, the velocity needs to scale inversely with DrawHeight. @@ -181,6 +181,7 @@ namespace osu.Game.Graphics.Backgrounds protected override DrawNode CreateDrawNode() => new TrianglesDrawNode(); private readonly TrianglesDrawNodeSharedData sharedData = new TrianglesDrawNodeSharedData(); + protected override void ApplyDrawNode(DrawNode node) { base.ApplyDrawNode(node); diff --git a/osu.Game/Graphics/Containers/ConstrainedIconContainer.cs b/osu.Game/Graphics/Containers/ConstrainedIconContainer.cs index e2e1385f3e..c1811f37d5 100644 --- a/osu.Game/Graphics/Containers/ConstrainedIconContainer.cs +++ b/osu.Game/Graphics/Containers/ConstrainedIconContainer.cs @@ -15,15 +15,9 @@ namespace osu.Game.Graphics.Containers { public Drawable Icon { - get - { - return InternalChild; - } + get => InternalChild; - set - { - InternalChild = value; - } + set => InternalChild = value; } /// @@ -33,8 +27,8 @@ namespace osu.Game.Graphics.Containers /// public new EdgeEffectParameters EdgeEffect { - get { return base.EdgeEffect; } - set { base.EdgeEffect = value; } + get => base.EdgeEffect; + set => base.EdgeEffect = value; } protected override void Update() diff --git a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs index bf48631569..c6ee91f961 100644 --- a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs +++ b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs @@ -24,7 +24,17 @@ namespace osu.Game.Graphics.Containers protected override bool BlockNonPositionalInput => true; - private PreviewTrackManager previewTrackManager; + /// + /// Temporary to allow for overlays in the main screen content to not dim theirselves. + /// Should be eventually replaced by dimming which is aware of the target dim container (traverse parent for certain interface type?). + /// + protected virtual bool DimMainContent => true; + + [Resolved(CanBeNull = true)] + private OsuGame osuGame { get; set; } + + [Resolved] + private PreviewTrackManager previewTrackManager { get; set; } protected readonly Bindable OverlayActivationMode = new Bindable(OverlayActivation.All); @@ -36,10 +46,8 @@ namespace osu.Game.Graphics.Containers } [BackgroundDependencyLoader(true)] - private void load(OsuGame osuGame, AudioManager audio, PreviewTrackManager previewTrackManager) + private void load(AudioManager audio) { - this.previewTrackManager = previewTrackManager; - if (osuGame != null) OverlayActivationMode.BindTo(osuGame.OverlayActivationMode); @@ -93,12 +101,15 @@ namespace osu.Game.Graphics.Containers if (OverlayActivationMode.Value != OverlayActivation.Disabled) { if (PlaySamplesOnStateChange) samplePopIn?.Play(); + if (BlockScreenWideMouse && DimMainContent) osuGame?.AddBlockingOverlay(this); } else State = Visibility.Hidden; + break; case Visibility.Hidden: if (PlaySamplesOnStateChange) samplePopOut?.Play(); + if (BlockScreenWideMouse) osuGame?.RemoveBlockingOverlay(this); break; } } @@ -108,5 +119,11 @@ namespace osu.Game.Graphics.Containers base.PopOut(); previewTrackManager.StopAnyPlaying(this); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + osuGame?.RemoveBlockingOverlay(this); + } } } diff --git a/osu.Game/Graphics/Containers/OsuTextFlowContainer.cs b/osu.Game/Graphics/Containers/OsuTextFlowContainer.cs index e8b8537807..56e5f411b8 100644 --- a/osu.Game/Graphics/Containers/OsuTextFlowContainer.cs +++ b/osu.Game/Graphics/Containers/OsuTextFlowContainer.cs @@ -12,7 +12,8 @@ namespace osu.Game.Graphics.Containers { public class OsuTextFlowContainer : TextFlowContainer { - public OsuTextFlowContainer(Action defaultCreationParameters = null) : base(defaultCreationParameters) + public OsuTextFlowContainer(Action defaultCreationParameters = null) + : base(defaultCreationParameters) { } diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index b8ea4e299c..6bbab4766d 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -24,7 +24,7 @@ namespace osu.Game.Graphics.Containers public Drawable ExpandableHeader { - get { return expandableHeader; } + get => expandableHeader; set { if (value == expandableHeader) return; @@ -40,7 +40,7 @@ namespace osu.Game.Graphics.Containers public Drawable FixedHeader { - get { return fixedHeader; } + get => fixedHeader; set { if (value == fixedHeader) return; @@ -56,7 +56,7 @@ namespace osu.Game.Graphics.Containers public Drawable Footer { - get { return footer; } + get => footer; set { if (value == footer) return; @@ -75,7 +75,7 @@ namespace osu.Game.Graphics.Containers public Drawable HeaderBackground { - get { return headerBackground; } + get => headerBackground; set { if (value == headerBackground) return; @@ -110,6 +110,7 @@ namespace osu.Game.Graphics.Containers private float headerHeight, footerHeight; private readonly MarginPadding originalSectionsMargin; + private void updateSectionsMargin() { if (!Children.Any()) return; @@ -142,6 +143,7 @@ namespace osu.Game.Graphics.Containers public void ScrollToTop() => scrollContainer.ScrollTo(0); private float lastKnownScroll; + protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); diff --git a/osu.Game/Graphics/Containers/UserDimContainer.cs b/osu.Game/Graphics/Containers/UserDimContainer.cs new file mode 100644 index 0000000000..4c8928e122 --- /dev/null +++ b/osu.Game/Graphics/Containers/UserDimContainer.cs @@ -0,0 +1,88 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Configuration; +using osuTK.Graphics; + +namespace osu.Game.Graphics.Containers +{ + /// + /// A container that applies user-configured dim levels to its contents. + /// This container specifies behavior that applies to both Storyboards and Backgrounds. + /// + public class UserDimContainer : Container + { + private const float background_fade_duration = 800; + + private Bindable dimLevel { get; set; } + + private Bindable showStoryboard { get; set; } + + /// + /// Whether or not user-configured dim levels should be applied to the container. + /// + public readonly Bindable EnableUserDim = new Bindable(); + + /// + /// Whether or not the storyboard loaded should completely hide the background behind it. + /// + public readonly Bindable StoryboardReplacesBackground = new Bindable(); + + protected Container DimContainer { get; } + + protected override Container Content => DimContainer; + + private readonly bool isStoryboard; + + /// + /// Creates a new . + /// + /// Whether or not this instance of UserDimContainer contains a storyboard. + /// + /// While both backgrounds and storyboards allow user dim levels to be applied, storyboards can be toggled via + /// and can cause backgrounds to become hidden via . + /// + /// + public UserDimContainer(bool isStoryboard = false) + { + this.isStoryboard = isStoryboard; + AddInternal(DimContainer = new Container { RelativeSizeAxes = Axes.Both }); + } + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + dimLevel = config.GetBindable(OsuSetting.DimLevel); + showStoryboard = config.GetBindable(OsuSetting.ShowStoryboard); + EnableUserDim.ValueChanged += _ => updateBackgroundDim(); + dimLevel.ValueChanged += _ => updateBackgroundDim(); + showStoryboard.ValueChanged += _ => updateBackgroundDim(); + StoryboardReplacesBackground.ValueChanged += _ => updateBackgroundDim(); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + updateBackgroundDim(); + } + + private void updateBackgroundDim() + { + if (isStoryboard) + { + DimContainer.FadeTo(!showStoryboard.Value || dimLevel.Value == 1 ? 0 : 1, background_fade_duration, Easing.OutQuint); + } + else + { + // The background needs to be hidden in the case of it being replaced by the storyboard + DimContainer.FadeTo(showStoryboard.Value && StoryboardReplacesBackground.Value ? 0 : 1, background_fade_duration, Easing.OutQuint); + } + + DimContainer.FadeColour(EnableUserDim.Value ? OsuColour.Gray(1 - (float)dimLevel.Value) : Color4.White, background_fade_duration, Easing.OutQuint); + } + } +} diff --git a/osu.Game/Graphics/Cursor/MenuCursor.cs b/osu.Game/Graphics/Cursor/MenuCursor.cs index 6e6f5f351e..059beeca4d 100644 --- a/osu.Game/Graphics/Cursor/MenuCursor.cs +++ b/osu.Game/Graphics/Cursor/MenuCursor.cs @@ -85,6 +85,7 @@ namespace osu.Game.Graphics.Cursor dragRotationState = DragRotationState.DragStarted; positionMouseDown = e.MousePosition; } + return base.OnMouseDown(e); } @@ -102,6 +103,7 @@ namespace osu.Game.Graphics.Cursor activeCursor.RotateTo(0, 600 * (1 + Math.Abs(activeCursor.Rotation / 720)), Easing.OutElasticHalf); dragRotationState = DragRotationState.NotDragging; } + return base.OnMouseUp(e); } diff --git a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs index 5f9b428dfc..92e5ba6195 100644 --- a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs +++ b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs @@ -43,6 +43,7 @@ namespace osu.Game.Graphics.Cursor } private IProvideCursor currentTarget; + protected override void Update() { base.Update(); diff --git a/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs b/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs index ec4cbb808e..4e0ce4a3e1 100644 --- a/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs +++ b/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs @@ -17,7 +17,8 @@ namespace osu.Game.Graphics.Cursor { protected override ITooltip CreateTooltip() => new OsuTooltip(); - public OsuTooltipContainer(CursorContainer cursor) : base(cursor) + public OsuTooltipContainer(CursorContainer cursor) + : base(cursor) { } diff --git a/osu.Game/Graphics/DrawableDate.cs b/osu.Game/Graphics/DrawableDate.cs index fc5abcdcb8..3ae1033f5d 100644 --- a/osu.Game/Graphics/DrawableDate.cs +++ b/osu.Game/Graphics/DrawableDate.cs @@ -21,6 +21,7 @@ namespace osu.Game.Graphics { if (date == value) return; + date = value.ToLocalTime(); if (LoadState >= LoadState.Ready) diff --git a/osu.Game/Graphics/SpriteIcon.cs b/osu.Game/Graphics/SpriteIcon.cs index dcb29d50ea..f7d7d21435 100644 --- a/osu.Game/Graphics/SpriteIcon.cs +++ b/osu.Game/Graphics/SpriteIcon.cs @@ -65,6 +65,7 @@ namespace osu.Game.Graphics } private FontAwesome loadedIcon; + private void updateTexture() { var loadableIcon = icon; @@ -104,9 +105,10 @@ namespace osu.Game.Graphics } private bool shadow; + public bool Shadow { - get { return shadow; } + get => shadow; set { shadow = value; @@ -119,11 +121,7 @@ namespace osu.Game.Graphics public FontAwesome Icon { - get - { - return icon; - } - + get => icon; set { if (icon == value) return; diff --git a/osu.Game/Graphics/UserInterface/Bar.cs b/osu.Game/Graphics/UserInterface/Bar.cs index 92b71a1cc3..2a858ccbcf 100644 --- a/osu.Game/Graphics/UserInterface/Bar.cs +++ b/osu.Game/Graphics/UserInterface/Bar.cs @@ -26,10 +26,7 @@ namespace osu.Game.Graphics.UserInterface /// public float Length { - get - { - return length; - } + get => length; set { length = MathHelper.Clamp(value, 0, 1); @@ -39,35 +36,21 @@ namespace osu.Game.Graphics.UserInterface public Color4 BackgroundColour { - get - { - return background.Colour; - } - set - { - background.Colour = value; - } + get => background.Colour; + set => background.Colour = value; } public Color4 AccentColour { - get - { - return bar.Colour; - } - set - { - bar.Colour = value; - } + get => bar.Colour; + set => bar.Colour = value; } private BarDirection direction = BarDirection.LeftToRight; + public BarDirection Direction { - get - { - return direction; - } + get => direction; set { direction = value; diff --git a/osu.Game/Graphics/UserInterface/BarGraph.cs b/osu.Game/Graphics/UserInterface/BarGraph.cs index 97335e3c42..58058c9d4c 100644 --- a/osu.Game/Graphics/UserInterface/BarGraph.cs +++ b/osu.Game/Graphics/UserInterface/BarGraph.cs @@ -17,12 +17,10 @@ namespace osu.Game.Graphics.UserInterface public float? MaxValue { get; set; } private BarDirection direction = BarDirection.BottomToTop; + public new BarDirection Direction { - get - { - return direction; - } + get => direction; set { direction = value; @@ -69,6 +67,7 @@ namespace osu.Game.Graphics.UserInterface }); } } + //I'm using ToList() here because Where() returns an Enumerable which can change it's elements afterwards RemoveRange(Children.Where((bar, index) => index >= value.Count()).ToList()); } diff --git a/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs b/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs index e40168d213..40bc98a654 100644 --- a/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs +++ b/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs @@ -57,10 +57,11 @@ namespace osu.Game.Graphics.UserInterface public Visibility State { - get { return state; } + get => state; set { if (value == state) return; + state = value; const float transition_duration = 500; @@ -80,7 +81,8 @@ namespace osu.Game.Graphics.UserInterface } } - public BreadcrumbTabItem(T value) : base(value) + public BreadcrumbTabItem(T value) + : base(value) { Text.Font = Text.Font.With(size: 18); Text.Margin = new MarginPadding { Vertical = 8 }; diff --git a/osu.Game/Graphics/UserInterface/DialogButton.cs b/osu.Game/Graphics/UserInterface/DialogButton.cs index 2796db51a5..dbbe5b4258 100644 --- a/osu.Game/Graphics/UserInterface/DialogButton.cs +++ b/osu.Game/Graphics/UserInterface/DialogButton.cs @@ -154,12 +154,10 @@ namespace osu.Game.Graphics.UserInterface } private Color4 buttonColour; + public Color4 ButtonColour { - get - { - return buttonColour; - } + get => buttonColour; set { buttonColour = value; @@ -169,12 +167,10 @@ namespace osu.Game.Graphics.UserInterface } private Color4 backgroundColour = OsuColour.Gray(34); + public Color4 BackgroundColour { - get - { - return backgroundColour; - } + get => backgroundColour; set { backgroundColour = value; @@ -183,12 +179,10 @@ namespace osu.Game.Graphics.UserInterface } private string text; + public string Text { - get - { - return text; - } + get => text; set { text = value; diff --git a/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs b/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs index 309021b7d6..2ed37799f6 100644 --- a/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs +++ b/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs @@ -51,7 +51,7 @@ namespace osu.Game.Graphics.UserInterface protected override bool OnClick(ClickEvent e) { - if(Link != null) + if (Link != null) host.OpenUrlExternally(Link); return true; } diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index 4f84108d8a..cbbaa6d303 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs @@ -17,7 +17,8 @@ namespace osu.Game.Graphics.UserInterface { private SampleChannel sampleClick; - public HoverClickSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal) : base(sampleSet) + public HoverClickSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal) + : base(sampleSet) { } diff --git a/osu.Game/Graphics/UserInterface/HoverSounds.cs b/osu.Game/Graphics/UserInterface/HoverSounds.cs index b2cd4aab19..b246092a7f 100644 --- a/osu.Game/Graphics/UserInterface/HoverSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverSounds.cs @@ -45,8 +45,10 @@ namespace osu.Game.Graphics.UserInterface { [Description("")] Loud, + [Description("-soft")] Normal, + [Description("-softer")] Soft } diff --git a/osu.Game/Graphics/UserInterface/IconButton.cs b/osu.Game/Graphics/UserInterface/IconButton.cs index b9062b8d39..025aa30986 100644 --- a/osu.Game/Graphics/UserInterface/IconButton.cs +++ b/osu.Game/Graphics/UserInterface/IconButton.cs @@ -19,7 +19,7 @@ namespace osu.Game.Graphics.UserInterface /// public Color4 IconColour { - get { return iconColour ?? Color4.White; } + get => iconColour ?? Color4.White; set { iconColour = value; @@ -34,8 +34,8 @@ namespace osu.Game.Graphics.UserInterface /// public Color4 IconHoverColour { - get { return iconHoverColour ?? IconColour; } - set { iconHoverColour = value; } + get => iconHoverColour ?? IconColour; + set => iconHoverColour = value; } /// @@ -43,8 +43,8 @@ namespace osu.Game.Graphics.UserInterface /// public FontAwesome Icon { - get { return icon.Icon; } - set { icon.Icon = value; } + get => icon.Icon; + set => icon.Icon = value; } /// @@ -52,8 +52,8 @@ namespace osu.Game.Graphics.UserInterface /// public Vector2 IconScale { - get { return icon.Scale; } - set { icon.Scale = value; } + get => icon.Scale; + set => icon.Scale = value; } /// diff --git a/osu.Game/Graphics/UserInterface/LineGraph.cs b/osu.Game/Graphics/UserInterface/LineGraph.cs index 88d64c1bfb..7a20dd3d16 100644 --- a/osu.Game/Graphics/UserInterface/LineGraph.cs +++ b/osu.Game/Graphics/UserInterface/LineGraph.cs @@ -44,7 +44,7 @@ namespace osu.Game.Graphics.UserInterface /// public IEnumerable Values { - get { return values; } + get => values; set { values = value.ToArray(); @@ -112,6 +112,7 @@ namespace osu.Game.Graphics.UserInterface protected float GetYPosition(float value) { if (ActualMaxValue == ActualMinValue) return 0; + return (ActualMaxValue - value) / (ActualMaxValue - ActualMinValue); } } diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/Nub.cs index 470297a83c..1f5195eaf1 100644 --- a/osu.Game/Graphics/UserInterface/Nub.cs +++ b/osu.Game/Graphics/UserInterface/Nub.cs @@ -72,9 +72,10 @@ namespace osu.Game.Graphics.UserInterface } private bool glowing; + public bool Glowing { - get { return glowing; } + get => glowing; set { glowing = value; @@ -94,10 +95,7 @@ namespace osu.Game.Graphics.UserInterface public bool Expanded { - set - { - this.ResizeTo(new Vector2(value ? EXPANDED_SIZE : COLLAPSED_SIZE, 12), 500, Easing.OutQuint); - } + set => this.ResizeTo(new Vector2(value ? EXPANDED_SIZE : COLLAPSED_SIZE, 12), 500, Easing.OutQuint); } private readonly Bindable current = new Bindable(); @@ -116,9 +114,10 @@ namespace osu.Game.Graphics.UserInterface } private Color4 accentColour; + public Color4 AccentColour { - get { return accentColour; } + get => accentColour; set { accentColour = value; @@ -128,9 +127,10 @@ namespace osu.Game.Graphics.UserInterface } private Color4 glowingAccentColour; + public Color4 GlowingAccentColour { - get { return glowingAccentColour; } + get => glowingAccentColour; set { glowingAccentColour = value; @@ -140,9 +140,10 @@ namespace osu.Game.Graphics.UserInterface } private Color4 glowColour; + public Color4 GlowColour { - get { return glowColour; } + get => glowColour; set { glowColour = value; diff --git a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs index 9f5fc503ad..de3d93d845 100644 --- a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs +++ b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs @@ -33,7 +33,7 @@ namespace osu.Game.Graphics.UserInterface public string LabelText { - get { return labelSpriteText?.Text; } + get => labelSpriteText?.Text; set { if (labelSpriteText != null) @@ -43,7 +43,7 @@ namespace osu.Game.Graphics.UserInterface public MarginPadding LabelPadding { - get { return labelSpriteText?.Padding ?? new MarginPadding(); } + get => labelSpriteText?.Padding ?? new MarginPadding(); set { if (labelSpriteText != null) diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs index 0877776d0e..db38067a50 100644 --- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs @@ -17,9 +17,10 @@ namespace osu.Game.Graphics.UserInterface public class OsuDropdown : Dropdown, IHasAccentColour { private Color4 accentColour; + public Color4 AccentColour { - get { return accentColour; } + get => accentColour; set { accentColour = value; @@ -37,11 +38,9 @@ namespace osu.Game.Graphics.UserInterface private void updateAccentColour() { - var header = Header as IHasAccentColour; - if (header != null) header.AccentColour = accentColour; + if (Header is IHasAccentColour header) header.AccentColour = accentColour; - var menu = Menu as IHasAccentColour; - if (menu != null) menu.AccentColour = accentColour; + if (Menu is IHasAccentColour menu) menu.AccentColour = accentColour; } protected override DropdownHeader CreateHeader() => new OsuDropdownHeader(); @@ -49,6 +48,7 @@ namespace osu.Game.Graphics.UserInterface protected override DropdownMenu CreateMenu() => new OsuDropdownMenu(); #region OsuDropdownMenu + protected class OsuDropdownMenu : DropdownMenu, IHasAccentColour { public override bool HandleNonPositionalInput => State == MenuState.Open; @@ -83,9 +83,10 @@ namespace osu.Game.Graphics.UserInterface } private Color4 accentColour; + public Color4 AccentColour { - get { return accentColour; } + get => accentColour; set { accentColour = value; @@ -97,15 +98,17 @@ namespace osu.Game.Graphics.UserInterface protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableOsuDropdownMenuItem(item) { AccentColour = accentColour }; #region DrawableOsuDropdownMenuItem + public class DrawableOsuDropdownMenuItem : DrawableDropdownMenuItem, IHasAccentColour { // IsHovered is used public override bool HandlePositionalInput => true; private Color4? accentColour; + public Color4 AccentColour { - get { return accentColour ?? nonAccentSelectedColour; } + get => accentColour ?? nonAccentSelectedColour; set { accentColour = value; @@ -149,8 +152,7 @@ namespace osu.Game.Graphics.UserInterface { base.UpdateForegroundColour(); - var content = Foreground.Children.FirstOrDefault() as Content; - if (content != null) content.Chevron.Alpha = IsHovered ? 1 : 0; + if (Foreground.Children.FirstOrDefault() is Content content) content.Chevron.Alpha = IsHovered ? 1 : 0; } protected override Drawable CreateContent() => new Content(); @@ -159,8 +161,8 @@ namespace osu.Game.Graphics.UserInterface { public string Text { - get { return Label.Text; } - set { Label.Text = value; } + get => Label.Text; + set => Label.Text = value; } public readonly OsuSpriteText Label; @@ -194,25 +196,29 @@ namespace osu.Game.Graphics.UserInterface } } } + #endregion } + #endregion public class OsuDropdownHeader : DropdownHeader, IHasAccentColour { protected readonly SpriteText Text; + protected override string Label { - get { return Text.Text; } - set { Text.Text = value; } + get => Text.Text; + set => Text.Text = value; } protected readonly SpriteIcon Icon; private Color4 accentColour; + public virtual Color4 AccentColour { - get { return accentColour; } + get => accentColour; set { accentColour = value; diff --git a/osu.Game/Graphics/UserInterface/OsuMenu.cs b/osu.Game/Graphics/UserInterface/OsuMenu.cs index 7fcefee23a..9b5755ea8b 100644 --- a/osu.Game/Graphics/UserInterface/OsuMenu.cs +++ b/osu.Game/Graphics/UserInterface/OsuMenu.cs @@ -125,7 +125,7 @@ namespace osu.Game.Graphics.UserInterface { public string Text { - get { return NormalText.Text; } + get => NormalText.Text; set { NormalText.Text = value; diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index 3fd0ead760..c558fd7c7b 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -35,9 +35,10 @@ namespace osu.Game.Graphics.UserInterface public virtual string TooltipText { get; private set; } private Color4 accentColour; + public Color4 AccentColour { - get { return accentColour; } + get => accentColour; set { accentColour = value; @@ -79,10 +80,7 @@ namespace osu.Game.Graphics.UserInterface new HoverClickSounds() }; - Current.DisabledChanged += disabled => - { - Alpha = disabled ? 0.3f : 1; - }; + Current.DisabledChanged += disabled => { Alpha = disabled ? 0.3f : 1; }; } [BackgroundDependencyLoader] diff --git a/osu.Game/Graphics/UserInterface/OsuTabControl.cs b/osu.Game/Graphics/UserInterface/OsuTabControl.cs index 2db0325813..e2a4955011 100644 --- a/osu.Game/Graphics/UserInterface/OsuTabControl.cs +++ b/osu.Game/Graphics/UserInterface/OsuTabControl.cs @@ -58,14 +58,14 @@ namespace osu.Game.Graphics.UserInterface } private Color4 accentColour; + public Color4 AccentColour { - get { return accentColour; } + get => accentColour; set { accentColour = value; - var dropdown = Dropdown as IHasAccentColour; - if (dropdown != null) + if (Dropdown is IHasAccentColour dropdown) dropdown.AccentColour = value; foreach (var i in TabContainer.Children.OfType()) i.AccentColour = value; @@ -101,9 +101,10 @@ namespace osu.Game.Graphics.UserInterface protected readonly Box Bar; private Color4 accentColour; + public Color4 AccentColour { - get { return accentColour; } + get => accentColour; set { accentColour = value; @@ -146,7 +147,8 @@ namespace osu.Game.Graphics.UserInterface AccentColour = colours.Blue; } - public OsuTabItem(T value) : base(value) + public OsuTabItem(T value) + : base(value) { AutoSizeAxes = Axes.X; RelativeSizeAxes = Axes.Y; @@ -224,11 +226,7 @@ namespace osu.Game.Graphics.UserInterface { public override Color4 AccentColour { - get - { - return base.AccentColour; - } - + get => base.AccentColour; set { base.AccentColour = value; diff --git a/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs b/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs index b56b9ec18f..918473ac53 100644 --- a/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs +++ b/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs @@ -24,9 +24,10 @@ namespace osu.Game.Graphics.UserInterface private readonly SpriteIcon icon; private Color4? accentColour; + public Color4 AccentColour { - get { return accentColour.GetValueOrDefault(); } + get => accentColour.GetValueOrDefault(); set { accentColour = value; @@ -41,8 +42,8 @@ namespace osu.Game.Graphics.UserInterface public string Text { - get { return text.Text; } - set { text.Text = value; } + get => text.Text; + set => text.Text = value; } private const float transition_length = 500; diff --git a/osu.Game/Graphics/UserInterface/PageTabControl.cs b/osu.Game/Graphics/UserInterface/PageTabControl.cs index cc3415e9d2..156a556b5e 100644 --- a/osu.Game/Graphics/UserInterface/PageTabControl.cs +++ b/osu.Game/Graphics/UserInterface/PageTabControl.cs @@ -32,7 +32,8 @@ namespace osu.Game.Graphics.UserInterface protected readonly SpriteText Text; - public PageTabItem(T value) : base(value) + public PageTabItem(T value) + : base(value) { AutoSizeAxes = Axes.X; RelativeSizeAxes = Axes.Y; diff --git a/osu.Game/Graphics/UserInterface/ProgressBar.cs b/osu.Game/Graphics/UserInterface/ProgressBar.cs index 04f85e62b7..d271cd121c 100644 --- a/osu.Game/Graphics/UserInterface/ProgressBar.cs +++ b/osu.Game/Graphics/UserInterface/ProgressBar.cs @@ -18,7 +18,7 @@ namespace osu.Game.Graphics.UserInterface public Color4 FillColour { - set { fill.FadeColour(value, 150, Easing.OutQuint); } + set => fill.FadeColour(value, 150, Easing.OutQuint); } public Color4 BackgroundColour @@ -32,12 +32,12 @@ namespace osu.Game.Graphics.UserInterface public double EndTime { - set { CurrentNumber.MaxValue = value; } + set => CurrentNumber.MaxValue = value; } public double CurrentTime { - set { CurrentNumber.Value = value; } + set => CurrentNumber.Value = value; } public ProgressBar() diff --git a/osu.Game/Graphics/UserInterface/RollingCounter.cs b/osu.Game/Graphics/UserInterface/RollingCounter.cs index 52cd69a76e..cd244ed7e6 100644 --- a/osu.Game/Graphics/UserInterface/RollingCounter.cs +++ b/osu.Game/Graphics/UserInterface/RollingCounter.cs @@ -45,15 +45,13 @@ namespace osu.Game.Graphics.UserInterface /// public virtual T DisplayedCount { - get - { - return displayedCount; - } + get => displayedCount; set { if (EqualityComparer.Default.Equals(displayedCount, value)) return; + displayedCount = value; DisplayedCountSpriteText.Text = FormatCount(value); } @@ -61,7 +59,6 @@ namespace osu.Game.Graphics.UserInterface public abstract void Increment(T amount); - public float TextSize { get => DisplayedCountSpriteText.Font.Size; @@ -70,8 +67,8 @@ namespace osu.Game.Graphics.UserInterface public Color4 AccentColour { - get { return DisplayedCountSpriteText.Colour; } - set { DisplayedCountSpriteText.Colour = value; } + get => DisplayedCountSpriteText.Colour; + set => DisplayedCountSpriteText.Colour = value; } /// diff --git a/osu.Game/Graphics/UserInterface/StarCounter.cs b/osu.Game/Graphics/UserInterface/StarCounter.cs index ad8ff8ec74..7dc05d174f 100644 --- a/osu.Game/Graphics/UserInterface/StarCounter.cs +++ b/osu.Game/Graphics/UserInterface/StarCounter.cs @@ -41,10 +41,7 @@ namespace osu.Game.Graphics.UserInterface /// public float CountStars { - get - { - return countStars; - } + get => countStars; set { @@ -137,6 +134,7 @@ namespace osu.Game.Graphics.UserInterface private class Star : Container { public readonly SpriteIcon Icon; + public Star() { Size = new Vector2(star_size); diff --git a/osu.Game/Graphics/UserInterface/TriangleButton.cs b/osu.Game/Graphics/UserInterface/TriangleButton.cs index 2375017878..685d230a4b 100644 --- a/osu.Game/Graphics/UserInterface/TriangleButton.cs +++ b/osu.Game/Graphics/UserInterface/TriangleButton.cs @@ -31,10 +31,7 @@ namespace osu.Game.Graphics.UserInterface public bool MatchingFilter { - set - { - this.FadeTo(value ? 1 : 0); - } + set => this.FadeTo(value ? 1 : 0); } } } diff --git a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs index eddacf8e2d..1d8298904b 100644 --- a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs +++ b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs @@ -48,11 +48,7 @@ namespace osu.Game.Graphics.UserInterface public override Anchor Origin { - get - { - return base.Origin; - } - + get => base.Origin; set { base.Origin = value; @@ -155,18 +151,12 @@ namespace osu.Game.Graphics.UserInterface public FontAwesome Icon { - set - { - bouncingIcon.Icon = value; - } + set => bouncingIcon.Icon = value; } public string Text { - set - { - text.Text = value; - } + set => text.Text = value; } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => IconLayer.ReceivePositionalInputAt(screenSpacePos) || TextLayer.ReceivePositionalInputAt(screenSpacePos); @@ -217,7 +207,10 @@ namespace osu.Game.Graphics.UserInterface private readonly SpriteIcon icon; - public FontAwesome Icon { set { icon.Icon = value; } } + public FontAwesome Icon + { + set => icon.Icon = value; + } public BouncingIcon() { diff --git a/osu.Game/IO/FileStore.cs b/osu.Game/IO/FileStore.cs index 21639e4f43..458f8964f9 100644 --- a/osu.Game/IO/FileStore.cs +++ b/osu.Game/IO/FileStore.cs @@ -21,7 +21,8 @@ namespace osu.Game.IO public new Storage Storage => base.Storage; - public FileStore(IDatabaseContextFactory contextFactory, Storage storage) : base(contextFactory, storage.GetStorageForDirectory(@"files")) + public FileStore(IDatabaseContextFactory contextFactory, Storage storage) + : base(contextFactory, storage.GetStorageForDirectory(@"files")) { Store = new StorageBackedResourceStore(Storage); } diff --git a/osu.Game/IO/Legacy/SerializationReader.cs b/osu.Game/IO/Legacy/SerializationReader.cs index aba9c289fa..95ee5aea6b 100644 --- a/osu.Game/IO/Legacy/SerializationReader.cs +++ b/osu.Game/IO/Legacy/SerializationReader.cs @@ -39,6 +39,7 @@ namespace osu.Game.IO.Legacy public override string ReadString() { if (ReadByte() == 0) return null; + return base.ReadString(); } @@ -48,6 +49,7 @@ namespace osu.Game.IO.Legacy int len = ReadInt32(); if (len > 0) return ReadBytes(len); if (len < 0) return null; + return Array.Empty(); } @@ -57,6 +59,7 @@ namespace osu.Game.IO.Legacy int len = ReadInt32(); if (len > 0) return ReadChars(len); if (len < 0) return null; + return Array.Empty(); } @@ -65,6 +68,7 @@ namespace osu.Game.IO.Legacy { long ticks = ReadInt64(); if (ticks < 0) throw new IOException("Bad ticks count read!"); + return new DateTime(ticks, DateTimeKind.Utc); } @@ -73,6 +77,7 @@ namespace osu.Game.IO.Legacy { int count = ReadInt32(); if (count < 0) return null; + IList d = new List(count); SerializationReader sr = new SerializationReader(BaseStream); @@ -88,6 +93,7 @@ namespace osu.Game.IO.Legacy { if (skipErrors) continue; + throw; } @@ -102,6 +108,7 @@ namespace osu.Game.IO.Legacy { int count = ReadInt32(); if (count < 0) return null; + IList d = new List(count); for (int i = 0; i < count; i++) d.Add((T)ReadObject()); return d; @@ -112,6 +119,7 @@ namespace osu.Game.IO.Legacy { int count = ReadInt32(); if (count < 0) return null; + IDictionary d = new Dictionary(); for (int i = 0; i < count; i++) d[(T)ReadObject()] = (U)ReadObject(); return d; @@ -174,7 +182,7 @@ namespace osu.Game.IO.Legacy versionBinder = new VersionConfigToNamespaceAssemblyObjectBinder(); formatter = new BinaryFormatter { -// AssemblyFormat = FormatterAssemblyStyle.Simple, + // AssemblyFormat = FormatterAssemblyStyle.Simple, Binder = versionBinder }; } @@ -224,6 +232,7 @@ namespace osu.Game.IO.Legacy genType = BindToType(assemblyName, typ); } } + if (genType != null && tmpTypes.Count > 0) { return genType.MakeGenericType(tmpTypes.ToArray()); diff --git a/osu.Game/IO/Legacy/SerializationWriter.cs b/osu.Game/IO/Legacy/SerializationWriter.cs index be6e9a0afe..695767c822 100644 --- a/osu.Game/IO/Legacy/SerializationWriter.cs +++ b/osu.Game/IO/Legacy/SerializationWriter.cs @@ -8,6 +8,7 @@ using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters; using System.Runtime.Serialization.Formatters.Binary; using System.Text; + // ReSharper disable ConditionIsAlwaysTrueOrFalse (we're allowing nulls to be passed to the writer where the underlying class doesn't). // ReSharper disable HeuristicUnreachableCode @@ -219,7 +220,7 @@ namespace osu.Game.IO.Legacy Write((byte)ObjType.otherType); BinaryFormatter b = new BinaryFormatter { -// AssemblyFormat = FormatterAssemblyStyle.Simple, + // AssemblyFormat = FormatterAssemblyStyle.Simple, TypeFormat = FormatterTypeStyle.TypesWhenNeeded }; b.Serialize(BaseStream, obj); diff --git a/osu.Game/Input/Bindings/DatabasedKeyBinding.cs b/osu.Game/Input/Bindings/DatabasedKeyBinding.cs index 5e15b07b46..8c0072c3da 100644 --- a/osu.Game/Input/Bindings/DatabasedKeyBinding.cs +++ b/osu.Game/Input/Bindings/DatabasedKeyBinding.cs @@ -19,15 +19,15 @@ namespace osu.Game.Input.Bindings [Column("Keys")] public string KeysString { - get { return KeyCombination.ToString(); } - private set { KeyCombination = value; } + get => KeyCombination.ToString(); + private set => KeyCombination = value; } [Column("Action")] public int IntAction { - get { return (int)Action; } - set { Action = value; } + get => (int)Action; + set => Action = value; } } } diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 844b6ea658..97f4a9771f 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -62,31 +62,41 @@ namespace osu.Game.Input.Bindings { [Description("Toggle chat overlay")] ToggleChat, + [Description("Toggle social overlay")] ToggleSocial, + [Description("Reset input settings")] ResetInputSettings, + [Description("Toggle toolbar")] ToggleToolbar, + [Description("Toggle settings")] ToggleSettings, + [Description("Toggle osu!direct")] ToggleDirect, + [Description("Increase volume")] IncreaseVolume, + [Description("Decrease volume")] DecreaseVolume, + [Description("Toggle mute")] ToggleMute, // In-Game Keybindings [Description("Skip cutscene")] SkipCutscene, + [Description("Quick retry (hold)")] QuickRetry, [Description("Take screenshot")] TakeScreenshot, + [Description("Toggle gameplay mouse buttons")] ToggleGameplayMouseButtons, diff --git a/osu.Game/Migrations/20190225062029_AddUserIDColumn.Designer.cs b/osu.Game/Migrations/20190225062029_AddUserIDColumn.Designer.cs new file mode 100644 index 0000000000..8e1e3a59f3 --- /dev/null +++ b/osu.Game/Migrations/20190225062029_AddUserIDColumn.Designer.cs @@ -0,0 +1,487 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using osu.Game.Database; + +namespace osu.Game.Migrations +{ + [DbContext(typeof(OsuDbContext))] + [Migration("20190225062029_AddUserIDColumn")] + partial class AddUserIDColumn + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.1-servicing-10028"); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("ApproachRate"); + + b.Property("CircleSize"); + + b.Property("DrainRate"); + + b.Property("OverallDifficulty"); + + b.Property("SliderMultiplier"); + + b.Property("SliderTickRate"); + + b.HasKey("ID"); + + b.ToTable("BeatmapDifficulty"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("AudioLeadIn"); + + b.Property("BaseDifficultyID"); + + b.Property("BeatDivisor"); + + b.Property("BeatmapSetInfoID"); + + b.Property("Countdown"); + + b.Property("DistanceSpacing"); + + b.Property("GridSize"); + + b.Property("Hash"); + + b.Property("Hidden"); + + b.Property("LetterboxInBreaks"); + + b.Property("MD5Hash"); + + b.Property("MetadataID"); + + b.Property("OnlineBeatmapID"); + + b.Property("Path"); + + b.Property("RulesetID"); + + b.Property("SpecialStyle"); + + b.Property("StackLeniency"); + + b.Property("StarDifficulty"); + + b.Property("Status"); + + b.Property("StoredBookmarks"); + + b.Property("TimelineZoom"); + + b.Property("Version"); + + b.Property("WidescreenStoryboard"); + + b.HasKey("ID"); + + b.HasIndex("BaseDifficultyID"); + + b.HasIndex("BeatmapSetInfoID"); + + b.HasIndex("Hash"); + + b.HasIndex("MD5Hash"); + + b.HasIndex("MetadataID"); + + b.HasIndex("OnlineBeatmapID") + .IsUnique(); + + b.HasIndex("RulesetID"); + + b.ToTable("BeatmapInfo"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Artist"); + + b.Property("ArtistUnicode"); + + b.Property("AudioFile"); + + b.Property("AuthorString") + .HasColumnName("Author"); + + b.Property("BackgroundFile"); + + b.Property("PreviewTime"); + + b.Property("Source"); + + b.Property("Tags"); + + b.Property("Title"); + + b.Property("TitleUnicode"); + + b.HasKey("ID"); + + b.ToTable("BeatmapMetadata"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("BeatmapSetInfoID"); + + b.Property("FileInfoID"); + + b.Property("Filename") + .IsRequired(); + + b.HasKey("ID"); + + b.HasIndex("BeatmapSetInfoID"); + + b.HasIndex("FileInfoID"); + + b.ToTable("BeatmapSetFileInfo"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("DeletePending"); + + b.Property("Hash"); + + b.Property("MetadataID"); + + b.Property("OnlineBeatmapSetID"); + + b.Property("Protected"); + + b.Property("Status"); + + b.HasKey("ID"); + + b.HasIndex("DeletePending"); + + b.HasIndex("Hash") + .IsUnique(); + + b.HasIndex("MetadataID"); + + b.HasIndex("OnlineBeatmapSetID") + .IsUnique(); + + b.ToTable("BeatmapSetInfo"); + }); + + modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("IntKey") + .HasColumnName("Key"); + + b.Property("RulesetID"); + + b.Property("StringValue") + .HasColumnName("Value"); + + b.Property("Variant"); + + b.HasKey("ID"); + + b.HasIndex("RulesetID", "Variant"); + + b.ToTable("Settings"); + }); + + modelBuilder.Entity("osu.Game.IO.FileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Hash"); + + b.Property("ReferenceCount"); + + b.HasKey("ID"); + + b.HasIndex("Hash") + .IsUnique(); + + b.HasIndex("ReferenceCount"); + + b.ToTable("FileInfo"); + }); + + modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("IntAction") + .HasColumnName("Action"); + + b.Property("KeysString") + .HasColumnName("Keys"); + + b.Property("RulesetID"); + + b.Property("Variant"); + + b.HasKey("ID"); + + b.HasIndex("IntAction"); + + b.HasIndex("RulesetID", "Variant"); + + b.ToTable("KeyBinding"); + }); + + modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Available"); + + b.Property("InstantiationInfo"); + + b.Property("Name"); + + b.Property("ShortName"); + + b.HasKey("ID"); + + b.HasIndex("Available"); + + b.HasIndex("ShortName") + .IsUnique(); + + b.ToTable("RulesetInfo"); + }); + + modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("FileInfoID"); + + b.Property("Filename") + .IsRequired(); + + b.Property("ScoreInfoID"); + + b.HasKey("ID"); + + b.HasIndex("FileInfoID"); + + b.HasIndex("ScoreInfoID"); + + b.ToTable("ScoreFileInfo"); + }); + + modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Accuracy") + .HasColumnType("DECIMAL(1,4)"); + + b.Property("BeatmapInfoID"); + + b.Property("Combo"); + + b.Property("Date"); + + b.Property("DeletePending"); + + b.Property("Hash"); + + b.Property("MaxCombo"); + + b.Property("ModsJson") + .HasColumnName("Mods"); + + b.Property("OnlineScoreID"); + + b.Property("PP"); + + b.Property("Rank"); + + b.Property("RulesetID"); + + b.Property("StatisticsJson") + .HasColumnName("Statistics"); + + b.Property("TotalScore"); + + b.Property("UserID") + .HasColumnName("UserID"); + + b.Property("UserString") + .HasColumnName("User"); + + b.HasKey("ID"); + + b.HasIndex("BeatmapInfoID"); + + b.HasIndex("OnlineScoreID") + .IsUnique(); + + b.HasIndex("RulesetID"); + + b.ToTable("ScoreInfo"); + }); + + modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("FileInfoID"); + + b.Property("Filename") + .IsRequired(); + + b.Property("SkinInfoID"); + + b.HasKey("ID"); + + b.HasIndex("FileInfoID"); + + b.HasIndex("SkinInfoID"); + + b.ToTable("SkinFileInfo"); + }); + + modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Creator"); + + b.Property("DeletePending"); + + b.Property("Hash"); + + b.Property("Name"); + + b.HasKey("ID"); + + b.HasIndex("DeletePending"); + + b.HasIndex("Hash") + .IsUnique(); + + b.ToTable("SkinInfo"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") + .WithMany() + .HasForeignKey("BaseDifficultyID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") + .WithMany("Beatmaps") + .HasForeignKey("BeatmapSetInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") + .WithMany("Beatmaps") + .HasForeignKey("MetadataID"); + + b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") + .WithMany() + .HasForeignKey("RulesetID") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") + .WithMany("Files") + .HasForeignKey("BeatmapSetInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.IO.FileInfo", "FileInfo") + .WithMany() + .HasForeignKey("FileInfoID") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") + .WithMany("BeatmapSets") + .HasForeignKey("MetadataID"); + }); + + modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => + { + b.HasOne("osu.Game.IO.FileInfo", "FileInfo") + .WithMany() + .HasForeignKey("FileInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Scoring.ScoreInfo") + .WithMany("Files") + .HasForeignKey("ScoreInfoID"); + }); + + modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap") + .WithMany("Scores") + .HasForeignKey("BeatmapInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") + .WithMany() + .HasForeignKey("RulesetID") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => + { + b.HasOne("osu.Game.IO.FileInfo", "FileInfo") + .WithMany() + .HasForeignKey("FileInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Skinning.SkinInfo") + .WithMany("Files") + .HasForeignKey("SkinInfoID") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/osu.Game/Migrations/20190225062029_AddUserIDColumn.cs b/osu.Game/Migrations/20190225062029_AddUserIDColumn.cs new file mode 100644 index 0000000000..0720e0eac7 --- /dev/null +++ b/osu.Game/Migrations/20190225062029_AddUserIDColumn.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace osu.Game.Migrations +{ + public partial class AddUserIDColumn : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "UserID", + table: "ScoreInfo", + nullable: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "UserID", + table: "ScoreInfo"); + } + } +} diff --git a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs index 4505444d58..8430e00e4f 100644 --- a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs +++ b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs @@ -338,6 +338,9 @@ namespace osu.Game.Migrations b.Property("TotalScore"); + b.Property("UserID") + .HasColumnName("UserID"); + b.Property("UserString") .HasColumnName("User"); diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 9e84fd6009..4d039e0b8a 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -176,6 +176,7 @@ namespace osu.Game.Online.API lock (queue) { if (queue.Count == 0) break; + req = queue.Dequeue(); } @@ -260,7 +261,7 @@ namespace osu.Game.Online.API public APIState State { - get { return state; } + get => state; private set { APIState oldState = state; diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index 59cd685295..2781a5709b 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -121,7 +121,10 @@ namespace osu.Game.Online.API } public delegate void APIFailureHandler(Exception e); + public delegate void APISuccessHandler(); + public delegate void APIProgressHandler(long current, long total); + public delegate void APISuccessHandler(T content); } diff --git a/osu.Game/Online/API/OAuthToken.cs b/osu.Game/Online/API/OAuthToken.cs index 4c9c7b808f..f103d0917d 100644 --- a/osu.Game/Online/API/OAuthToken.cs +++ b/osu.Game/Online/API/OAuthToken.cs @@ -19,15 +19,8 @@ namespace osu.Game.Online.API [JsonProperty(@"expires_in")] public long ExpiresIn { - get - { - return AccessTokenExpiry - DateTimeOffset.UtcNow.ToUnixTimeSeconds(); - } - - set - { - AccessTokenExpiry = DateTimeOffset.Now.AddSeconds(value).ToUnixTimeSeconds(); - } + get => AccessTokenExpiry - DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + set => AccessTokenExpiry = DateTimeOffset.Now.AddSeconds(value).ToUnixTimeSeconds(); } public bool IsValid => !string.IsNullOrEmpty(AccessToken) && ExpiresIn > 30; @@ -57,6 +50,7 @@ namespace osu.Game.Online.API catch { } + return null; } } diff --git a/osu.Game/Online/Chat/ErrorMessage.cs b/osu.Game/Online/Chat/ErrorMessage.cs index 46e222f11d..a8ff0e9a98 100644 --- a/osu.Game/Online/Chat/ErrorMessage.cs +++ b/osu.Game/Online/Chat/ErrorMessage.cs @@ -5,7 +5,8 @@ namespace osu.Game.Online.Chat { public class ErrorMessage : InfoMessage { - public ErrorMessage(string message) : base(message) + public ErrorMessage(string message) + : base(message) { Sender.Colour = @"ff0000"; } diff --git a/osu.Game/Online/Chat/InfoMessage.cs b/osu.Game/Online/Chat/InfoMessage.cs index 4ef0d5ec65..8dce188804 100644 --- a/osu.Game/Online/Chat/InfoMessage.cs +++ b/osu.Game/Online/Chat/InfoMessage.cs @@ -10,7 +10,8 @@ namespace osu.Game.Online.Chat { private static int infoID = -1; - public InfoMessage(string message) : base(infoID--) + public InfoMessage(string message) + : base(infoID--) { Timestamp = DateTimeOffset.Now; Content = message; diff --git a/osu.Game/Online/Chat/LocalEchoMessage.cs b/osu.Game/Online/Chat/LocalEchoMessage.cs index 639509851d..8a39515575 100644 --- a/osu.Game/Online/Chat/LocalEchoMessage.cs +++ b/osu.Game/Online/Chat/LocalEchoMessage.cs @@ -5,7 +5,8 @@ namespace osu.Game.Online.Chat { public class LocalEchoMessage : LocalMessage { - public LocalEchoMessage() : base(null) + public LocalEchoMessage() + : base(null) { } } diff --git a/osu.Game/Online/Chat/MessageFormatter.cs b/osu.Game/Online/Chat/MessageFormatter.cs index 726f6ad2f0..d35dc07368 100644 --- a/osu.Game/Online/Chat/MessageFormatter.cs +++ b/osu.Game/Online/Chat/MessageFormatter.cs @@ -25,19 +25,19 @@ namespace osu.Game.Online.Chat // This is in the format (, [optional]): // http[s]://.[:port][/path][?query][#fragment] private static readonly Regex advanced_link_regex = new Regex( - // protocol - @"(?[a-z]*?:\/\/" + - // domain + tld - @"(?(?:[a-z0-9]\.|[a-z0-9][a-z0-9-]*[a-z0-9]\.)*[a-z0-9-]*[a-z0-9]" + - // port (optional) - @"(?::\d+)?)" + - // path (optional) - @"(?(?:(?:\/+(?:[a-z0-9$_\.\+!\*\',;:\(\)@&~=-]|%[0-9a-f]{2})*)*" + - // query (optional) - @"(?:\?(?:[a-z0-9$_\+!\*\',;:\(\)@&=\/~-]|%[0-9a-f]{2})*)?)?" + - // fragment (optional) - @"(?:#(?:[a-z0-9$_\+!\*\',;:\(\)@&=\/~-]|%[0-9a-f]{2})*)?)?)", - RegexOptions.IgnoreCase); + // protocol + @"(?[a-z]*?:\/\/" + + // domain + tld + @"(?(?:[a-z0-9]\.|[a-z0-9][a-z0-9-]*[a-z0-9]\.)*[a-z0-9-]*[a-z0-9]" + + // port (optional) + @"(?::\d+)?)" + + // path (optional) + @"(?(?:(?:\/+(?:[a-z0-9$_\.\+!\*\',;:\(\)@&~=-]|%[0-9a-f]{2})*)*" + + // query (optional) + @"(?:\?(?:[a-z0-9$_\+!\*\',;:\(\)@&=\/~-]|%[0-9a-f]{2})*)?)?" + + // fragment (optional) + @"(?:#(?:[a-z0-9$_\+!\*\',;:\(\)@&=\/~-]|%[0-9a-f]{2})*)?)?)", + RegexOptions.IgnoreCase); // 00:00:000 (1,2,3) - test private static readonly Regex time_regex = new Regex(@"\d\d:\d\d:\d\d\d? [^-]*"); @@ -56,14 +56,14 @@ namespace osu.Game.Online.Chat var index = m.Index - captureOffset; var displayText = string.Format(display, - m.Groups[0], - m.Groups.Count > 1 ? m.Groups[1].Value : "", - m.Groups.Count > 2 ? m.Groups[2].Value : "").Trim(); + m.Groups[0], + m.Groups.Count > 1 ? m.Groups[1].Value : "", + m.Groups.Count > 2 ? m.Groups[2].Value : "").Trim(); var linkText = string.Format(link, - m.Groups[0], - m.Groups.Count > 1 ? m.Groups[1].Value : "", - m.Groups.Count > 2 ? m.Groups[2].Value : "").Trim(); + m.Groups[0], + m.Groups.Count > 1 ? m.Groups[1].Value : "", + m.Groups.Count > 2 ? m.Groups[2].Value : "").Trim(); if (displayText.Length == 0 || linkText.Length == 0) continue; diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index 3dbd174760..438bf231c4 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -126,7 +126,7 @@ namespace osu.Game.Online.Chat protected class StandAloneDrawableChannel : DrawableChannel { - public Func CreateChatLineAction; + public Func CreateChatLineAction; protected override ChatLine CreateChatLine(Message m) => CreateChatLineAction(m); @@ -144,7 +144,8 @@ namespace osu.Game.Online.Chat protected override float HorizontalPadding => 10; protected override float MessagePadding => 120; - public StandAloneMessage(Message message) : base(message) + public StandAloneMessage(Message message) + : base(message) { } } diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index f3e7bb5c34..38df0efd6f 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -39,7 +39,7 @@ namespace osu.Game.Online.Leaderboards public IEnumerable Scores { - get { return scores; } + get => scores; set { scores = value; @@ -98,7 +98,7 @@ namespace osu.Game.Online.Leaderboards public TScope Scope { - get { return scope; } + get => scope; set { if (value.Equals(scope)) @@ -117,7 +117,7 @@ namespace osu.Game.Online.Leaderboards /// protected PlaceholderState PlaceholderState { - get { return placeholderState; } + get => placeholderState; set { if (value != PlaceholderState.Successful) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index f9676933cf..cf231f19ce 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using osu.Framework.Configuration; using osu.Framework.Screens; using osu.Game.Configuration; @@ -109,6 +110,8 @@ namespace osu.Game private readonly List overlays = new List(); + private readonly List visibleBlockingOverlays = new List(); + // todo: move this to SongSelect once Screen has the ability to unsuspend. [Cached] [Cached(Type = typeof(IBindable>))] @@ -127,6 +130,22 @@ namespace osu.Game public void ToggleDirect() => direct.ToggleVisibility(); + private void updateBlockingOverlayFade() => + screenContainer.FadeColour(visibleBlockingOverlays.Any() ? OsuColour.Gray(0.5f) : Color4.White, 500, Easing.OutQuint); + + public void AddBlockingOverlay(OverlayContainer overlay) + { + if (!visibleBlockingOverlays.Contains(overlay)) + visibleBlockingOverlays.Add(overlay); + updateBlockingOverlayFade(); + } + + public void RemoveBlockingOverlay(OverlayContainer overlay) + { + visibleBlockingOverlays.Remove(overlay); + updateBlockingOverlayFade(); + } + /// /// Close all game-wide overlays. /// @@ -484,6 +503,7 @@ namespace osu.Game overlay.StateChanged += state => { if (state == Visibility.Hidden) return; + singleDisplaySideOverlays.Where(o => o != overlay).ForEach(o => o.Hide()); }; } @@ -497,6 +517,7 @@ namespace osu.Game overlay.StateChanged += state => { if (state == Visibility.Hidden) return; + informationalOverlays.Where(o => o != overlay).ForEach(o => o.Hide()); }; } @@ -597,21 +618,10 @@ namespace osu.Game } private Task asyncLoadStream; - private int visibleOverlayCount; private void loadComponentSingleFile(T d, Action add) where T : Drawable { - var focused = d as FocusedOverlayContainer; - if (focused != null) - { - focused.StateChanged += s => - { - visibleOverlayCount += s == Visibility.Visible ? 1 : -1; - screenContainer.FadeColour(visibleOverlayCount > 0 ? OsuColour.Gray(0.5f) : Color4.White, 500, Easing.OutQuint); - }; - } - // schedule is here to ensure that all component loads are done after LoadComplete is run (and thus all dependencies are cached). // with some better organisation of LoadComplete to do construction and dependency caching in one step, followed by calls to loadComponentSingleFile, // we could avoid the need for scheduling altogether. @@ -628,7 +638,25 @@ namespace osu.Game try { Logger.Log($"Loading {d}...", level: LogLevel.Debug); - await LoadComponentAsync(d, add); + + // Since this is running in a separate thread, it is possible for OsuGame to be disposed after LoadComponentAsync has been called + // throwing an exception. To avoid this, the call is scheduled on the update thread, which does not run if IsDisposed = true + Task task = null; + var del = new ScheduledDelegate(() => task = LoadComponentAsync(d, add)); + Scheduler.Add(del); + + // The delegate won't complete if OsuGame has been disposed in the meantime + while (!IsDisposed && !del.Completed) + await Task.Delay(10); + + // Either we're disposed or the load process has started successfully + if (IsDisposed) + return; + + Debug.Assert(task != null); + + await task; + Logger.Log($"Loaded {d}!", level: LogLevel.Debug); } catch (OperationCanceledException) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 487ef10ffb..643a673faf 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -75,9 +75,9 @@ namespace osu.Game private Bindable fpsDisplayVisible; - protected AssemblyName AssemblyName => Assembly.GetEntryAssembly()?.GetName() ?? new AssemblyName { Version = new Version() }; + public virtual Version AssemblyVersion => Assembly.GetEntryAssembly()?.GetName().Version ?? new Version(); - public bool IsDeployedBuild => AssemblyName.Version.Major > 0; + public bool IsDeployedBuild => AssemblyVersion.Major > 0; public string Version { @@ -86,8 +86,8 @@ namespace osu.Game if (!IsDeployedBuild) return @"local " + (DebugUtils.IsDebug ? @"debug" : @"release"); - var assembly = AssemblyName; - return $@"{assembly.Version.Major}.{assembly.Version.Minor}.{assembly.Version.Build}"; + var version = AssemblyVersion; + return $@"{version.Major}.{version.Minor}.{version.Build}"; } } diff --git a/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs b/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs index 8a75cfea50..18de87e7b4 100644 --- a/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs +++ b/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs @@ -27,10 +27,11 @@ namespace osu.Game.Overlays.BeatmapSet public BeatmapSetInfo BeatmapSet { - get { return beatmapSet; } + get => beatmapSet; set { if (value == beatmapSet) return; + beatmapSet = value; updateDisplay(); diff --git a/osu.Game/Overlays/BeatmapSet/BasicStats.cs b/osu.Game/Overlays/BeatmapSet/BasicStats.cs index ac2e5497af..9ed9875be9 100644 --- a/osu.Game/Overlays/BeatmapSet/BasicStats.cs +++ b/osu.Game/Overlays/BeatmapSet/BasicStats.cs @@ -21,10 +21,11 @@ namespace osu.Game.Overlays.BeatmapSet public BeatmapSetInfo BeatmapSet { - get { return beatmapSet; } + get => beatmapSet; set { if (value == beatmapSet) return; + beatmapSet = value; updateDisplay(); @@ -35,10 +36,11 @@ namespace osu.Game.Overlays.BeatmapSet public BeatmapInfo Beatmap { - get { return beatmap; } + get => beatmap; set { if (value == beatmap) return; + beatmap = value; updateDisplay(); @@ -95,8 +97,8 @@ namespace osu.Game.Overlays.BeatmapSet public string Value { - get { return value.Text; } - set { this.value.Text = value; } + get => value.Text; + set => this.value.Text = value; } public Statistic(FontAwesome icon, string name) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index 9f4ec0e814..55dee904b4 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -33,12 +33,14 @@ namespace osu.Game.Overlays.BeatmapSet public readonly Bindable Beatmap = new Bindable(); private BeatmapSetInfo beatmapSet; + public BeatmapSetInfo BeatmapSet { - get { return beatmapSet; } + get => beatmapSet; set { if (value == beatmapSet) return; + beatmapSet = value; updateDisplay(); @@ -194,12 +196,14 @@ namespace osu.Game.Overlays.BeatmapSet public event Action StateChanged; private DifficultySelectorState state; + public DifficultySelectorState State { - get { return state; } + get => state; set { if (value == state) return; + state = value; StateChanged?.Invoke(State); @@ -277,9 +281,10 @@ namespace osu.Game.Overlays.BeatmapSet private readonly OsuSpriteText text; private int value; + public int Value { - get { return value; } + get => value; set { this.value = value; diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs index 269342525b..8c884e0950 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs @@ -30,8 +30,8 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons public BeatmapSetInfo BeatmapSet { - get { return playButton.BeatmapSet; } - set { playButton.BeatmapSet = value; } + get => playButton.BeatmapSet; + set => playButton.BeatmapSet = value; } public PreviewButton() diff --git a/osu.Game/Overlays/BeatmapSet/Details.cs b/osu.Game/Overlays/BeatmapSet/Details.cs index 538d327d98..fad5c973b7 100644 --- a/osu.Game/Overlays/BeatmapSet/Details.cs +++ b/osu.Game/Overlays/BeatmapSet/Details.cs @@ -25,10 +25,11 @@ namespace osu.Game.Overlays.BeatmapSet public BeatmapSetInfo BeatmapSet { - get { return beatmapSet; } + get => beatmapSet; set { if (value == beatmapSet) return; + beatmapSet = value; basic.BeatmapSet = preview.BeatmapSet = BeatmapSet; @@ -39,7 +40,7 @@ namespace osu.Game.Overlays.BeatmapSet public BeatmapInfo Beatmap { - get { return beatmap; } + get => beatmap; set { if (value == beatmap) return; diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index b6793d2609..4d974a0b63 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -21,37 +22,20 @@ namespace osu.Game.Overlays.BeatmapSet private const float metadata_width = 225; private const float spacing = 20; - private readonly MetadataSection source, tags; private readonly Box successRateBackground; private readonly SuccessRate successRate; - private BeatmapSetInfo beatmapSet; - public BeatmapSetInfo BeatmapSet - { - get { return beatmapSet; } - set - { - if (value == beatmapSet) return; - beatmapSet = value; - - updateDisplay(); - } - } - - private void updateDisplay() - { - source.Text = BeatmapSet?.Metadata.Source ?? string.Empty; - tags.Text = BeatmapSet?.Metadata.Tags ?? string.Empty; - } + public readonly Bindable BeatmapSet = new Bindable(); public BeatmapInfo Beatmap { - get { return successRate.Beatmap; } - set { successRate.Beatmap = value; } + get => successRate.Beatmap; + set => successRate.Beatmap = value; } public Info() { + MetadataSection source, tags; RelativeSizeAxes = Axes.X; Height = 220; Masking = true; @@ -129,14 +113,18 @@ namespace osu.Game.Overlays.BeatmapSet }, }, }; + + BeatmapSet.ValueChanged += b => + { + source.Text = b.NewValue?.Metadata.Source ?? string.Empty; + tags.Text = b.NewValue?.Metadata.Tags ?? string.Empty; + }; } [BackgroundDependencyLoader] private void load(OsuColour colours) { successRateBackground.Colour = colours.GrayE; - - updateDisplay(); } private class MetadataSection : FillFlowContainer @@ -162,8 +150,8 @@ namespace osu.Game.Overlays.BeatmapSet public Color4 TextColour { - get { return textFlow.Colour; } - set { textFlow.Colour = value; } + get => textFlow.Colour; + set => textFlow.Colour = value; } public MetadataSection(string title) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs b/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs index 7933bfd9b6..31af251877 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs @@ -17,12 +17,14 @@ namespace osu.Game.Overlays.BeatmapSet.Scores private UserProfileOverlay profile; private User user; + public User User { - get { return user; } + get => user; set { if (user == value) return; + user = value; text.Text = user.Username; diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs index c64bda9dfd..78e560cdbe 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs @@ -44,12 +44,14 @@ namespace osu.Game.Overlays.BeatmapSet.Scores private readonly ScoreModsContainer modsContainer; private APIScoreInfo score; + public APIScoreInfo Score { - get { return score; } + get => score; set { if (score == value) return; + score = value; avatar.User = username.User = score.User; @@ -207,9 +209,10 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { if (valueText.Text == value) return; + valueText.Text = value; } - get { return valueText.Text; } + get => valueText.Text; } public InfoColumn(string header) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index ab34d2ba1d..6c65d491af 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -34,7 +34,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores public IEnumerable Scores { - get { return scores; } + get => scores; set { getScoresRequest?.Cancel(); diff --git a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs index 0a844028fe..c89bddca63 100644 --- a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs +++ b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs @@ -21,12 +21,14 @@ namespace osu.Game.Overlays.BeatmapSet private readonly FailRetryGraph graph; private BeatmapInfo beatmap; + public BeatmapInfo Beatmap { - get { return beatmap; } + get => beatmap; set { if (value == beatmap) return; + beatmap = value; updateDisplay(); diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index ff8603c749..55c21b7fc9 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -3,6 +3,7 @@ using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -29,32 +30,20 @@ namespace osu.Game.Overlays public const float RIGHT_WIDTH = 275; private readonly Header header; - private readonly Info info; private APIAccess api; private RulesetStore rulesets; private readonly ScrollContainer scroll; - private BeatmapSetInfo beatmapSet; - - public BeatmapSetInfo BeatmapSet - { - get => beatmapSet; - set - { - if (value == beatmapSet) - return; - - header.BeatmapSet.Value = info.BeatmapSet = beatmapSet = value; - } - } + private readonly Bindable beatmapSet = new Bindable(); // receive input outside our bounds so we can trigger a close event on ourselves. public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; public BeatmapSetOverlay() { + Info info; ScoresContainer scores; Waves.FirstWaveColour = OsuColour.Gray(0.4f); Waves.SecondWaveColour = OsuColour.Gray(0.3f); @@ -101,6 +90,9 @@ namespace osu.Game.Overlays }, }; + header.BeatmapSet.BindTo(beatmapSet); + info.BeatmapSet.BindTo(beatmapSet); + header.Picker.Beatmap.ValueChanged += b => { info.Beatmap = b.NewValue; @@ -124,7 +116,7 @@ namespace osu.Game.Overlays protected override void PopOut() { base.PopOut(); - FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out).OnComplete(_ => BeatmapSet = null); + FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out).OnComplete(_ => beatmapSet.Value = null); } protected override bool OnClick(ClickEvent e) @@ -135,11 +127,11 @@ namespace osu.Game.Overlays public void FetchAndShowBeatmap(int beatmapId) { - BeatmapSet = null; + beatmapSet.Value = null; var req = new GetBeatmapSetRequest(beatmapId, BeatmapSetLookupType.BeatmapId); req.Success += res => { - BeatmapSet = res.ToBeatmapSet(rulesets); + beatmapSet.Value = res.ToBeatmapSet(rulesets); header.Picker.Beatmap.Value = header.BeatmapSet.Value.Beatmaps.First(b => b.OnlineBeatmapID == beatmapId); }; api.Queue(req); @@ -148,16 +140,16 @@ namespace osu.Game.Overlays public void FetchAndShowBeatmapSet(int beatmapSetId) { - BeatmapSet = null; + beatmapSet.Value = null; var req = new GetBeatmapSetRequest(beatmapSetId); - req.Success += res => BeatmapSet = res.ToBeatmapSet(rulesets); + req.Success += res => beatmapSet.Value = res.ToBeatmapSet(rulesets); api.Queue(req); Show(); } public void ShowBeatmapSet(BeatmapSetInfo set) { - BeatmapSet = set; + beatmapSet.Value = set; Show(); scroll.ScrollTo(0); } diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index a679f33e3a..908ec5f026 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -137,7 +137,7 @@ namespace osu.Game.Overlays.Chat { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(size: TextSize * 0.75f, weight: FontWeight.Bold, fixedWidth: true) + Font = OsuFont.GetFont(size: TextSize * 0.75f, weight: FontWeight.SemiBold, fixedWidth: true) }, new MessageSender(message.Sender) { diff --git a/osu.Game/Overlays/Chat/Selection/ChannelListItem.cs b/osu.Game/Overlays/Chat/Selection/ChannelListItem.cs index 1dd888a3e9..a36abc4f99 100644 --- a/osu.Game/Overlays/Chat/Selection/ChannelListItem.cs +++ b/osu.Game/Overlays/Chat/Selection/ChannelListItem.cs @@ -36,12 +36,10 @@ namespace osu.Game.Overlays.Chat.Selection private Color4 hoverColour; public IEnumerable FilterTerms => new[] { channel.Name }; + public bool MatchingFilter { - set - { - this.FadeTo(value ? 1f : 0f, 100); - } + set => this.FadeTo(value ? 1f : 0f, 100); } public Action OnRequestJoin; diff --git a/osu.Game/Overlays/Chat/Selection/ChannelSection.cs b/osu.Game/Overlays/Chat/Selection/ChannelSection.cs index 160bf05a2b..3f979b6309 100644 --- a/osu.Game/Overlays/Chat/Selection/ChannelSection.cs +++ b/osu.Game/Overlays/Chat/Selection/ChannelSection.cs @@ -21,23 +21,21 @@ namespace osu.Game.Overlays.Chat.Selection public IEnumerable FilterableChildren => ChannelFlow.Children; public IEnumerable FilterTerms => Array.Empty(); + public bool MatchingFilter { - set - { - this.FadeTo(value ? 1f : 0f, 100); - } + set => this.FadeTo(value ? 1f : 0f, 100); } public string Header { - get { return header.Text; } - set { header.Text = value.ToUpperInvariant(); } + get => header.Text; + set => header.Text = value.ToUpperInvariant(); } public IEnumerable Channels { - set { ChannelFlow.ChildrenEnumerable = value.Select(c => new ChannelListItem(c)); } + set => ChannelFlow.ChildrenEnumerable = value.Select(c => new ChannelListItem(c)); } public ChannelSection() diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelSelectorTabItem.cs b/osu.Game/Overlays/Chat/Tabs/ChannelSelectorTabItem.cs index 6ac6133fd0..52260506fe 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelSelectorTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelSelectorTabItem.cs @@ -13,7 +13,8 @@ namespace osu.Game.Overlays.Chat.Tabs public override bool IsSwitchable => false; - public ChannelSelectorTabItem(Channel value) : base(value) + public ChannelSelectorTabItem(Channel value) + : base(value) { Depth = float.MaxValue; Width = 45; diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs index 781d1a5b7e..72e3cc4f6a 100644 --- a/osu.Game/Overlays/Dialog/PopupDialog.cs +++ b/osu.Game/Overlays/Dialog/PopupDialog.cs @@ -53,6 +53,7 @@ namespace osu.Game.Overlays.Dialog { if (text == value) return; + text = value; header.Text = value; diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs index d6ac51b2d6..1413f0f885 100644 --- a/osu.Game/Overlays/Direct/DirectGridPanel.cs +++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs @@ -29,7 +29,8 @@ namespace osu.Game.Overlays.Direct protected override PlayButton PlayButton => playButton; protected override Box PreviewBar => progressBar; - public DirectGridPanel(BeatmapSetInfo beatmap) : base(beatmap) + public DirectGridPanel(BeatmapSetInfo beatmap) + : base(beatmap) { Width = 380; Height = 140 + vertical_padding; //full height of all the elements plus vertical padding (autosize uses the image) diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index d7eae000b8..3867886f6d 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -158,7 +158,7 @@ namespace osu.Game.Overlays.Direct public int Value { - get { return value; } + get => value; set { this.value = value; diff --git a/osu.Game/Overlays/Direct/DownloadTrackingComposite.cs b/osu.Game/Overlays/Direct/DownloadTrackingComposite.cs index 813223dbc3..37f13aefc8 100644 --- a/osu.Game/Overlays/Direct/DownloadTrackingComposite.cs +++ b/osu.Game/Overlays/Direct/DownloadTrackingComposite.cs @@ -2,7 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; -using Microsoft.EntityFrameworkCore.Internal; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; @@ -41,7 +41,7 @@ namespace osu.Game.Overlays.Direct { if (setInfo.NewValue == null) attachDownload(null); - else if (beatmaps.QueryBeatmapSets(s => s.OnlineBeatmapSetID == setInfo.NewValue.OnlineBeatmapSetID).Any()) + else if (beatmaps.GetAllUsableBeatmapSetsEnumerable().Any(s => s.OnlineBeatmapSetID == setInfo.NewValue.OnlineBeatmapSetID)) State.Value = DownloadState.LocallyAvailable; else attachDownload(beatmaps.GetExistingDownload(setInfo.NewValue)); @@ -63,8 +63,11 @@ namespace osu.Game.Overlays.Direct { base.Dispose(isDisposing); - beatmaps.BeatmapDownloadBegan -= attachDownload; - beatmaps.ItemAdded -= setAdded; + if (beatmaps != null) + { + beatmaps.BeatmapDownloadBegan -= attachDownload; + beatmaps.ItemAdded -= setAdded; + } State.UnbindAll(); diff --git a/osu.Game/Overlays/Direct/Header.cs b/osu.Game/Overlays/Direct/Header.cs index d1478cf3b6..e85cb3b4ac 100644 --- a/osu.Game/Overlays/Direct/Header.cs +++ b/osu.Game/Overlays/Direct/Header.cs @@ -28,10 +28,13 @@ namespace osu.Game.Overlays.Direct public enum DirectTab { Search, + [Description("Newest Maps")] NewestMaps = DirectSortCriteria.Ranked, + [Description("Top Rated")] TopRated = DirectSortCriteria.Rating, + [Description("Most Played")] MostPlayed = DirectSortCriteria.Plays, } diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index e001c2d3ea..3c5508ba00 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -24,10 +24,11 @@ namespace osu.Game.Overlays.Direct public BeatmapSetInfo BeatmapSet { - get { return beatmapSet; } + get => beatmapSet; set { if (value == beatmapSet) return; + beatmapSet = value; Preview?.Stop(); diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index d3881b6ef8..0dc74b6a88 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Humanizer; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -45,7 +46,7 @@ namespace osu.Game.Overlays public IEnumerable BeatmapSets { - get { return beatmapSets; } + get => beatmapSets; set { if (beatmapSets?.Equals(value) ?? false) return; @@ -72,10 +73,11 @@ namespace osu.Game.Overlays public ResultCounts ResultAmounts { - get { return resultAmounts; } + get => resultAmounts; set { if (value == ResultAmounts) return; + resultAmounts = value; updateResultCounts(); @@ -189,14 +191,9 @@ namespace osu.Game.Overlays resultCountsContainer.FadeTo(ResultAmounts == null ? 0f : 1f, 200, Easing.OutQuint); if (ResultAmounts == null) return; - resultCountsText.Text = pluralize("Artist", ResultAmounts.Artists) + ", " + - pluralize("Song", ResultAmounts.Songs) + ", " + - pluralize("Tag", ResultAmounts.Tags); - } - - private string pluralize(string prefix, int value) - { - return $@"{value} {prefix}" + (value == 1 ? string.Empty : @"s"); + resultCountsText.Text = "Artist".ToQuantity(ResultAmounts.Artists) + ", " + + "Song".ToQuantity(ResultAmounts.Songs) + ", " + + "Tag".ToQuantity(ResultAmounts.Tags); } private void recreatePanels(PanelDisplayStyle displayStyle) diff --git a/osu.Game/Overlays/KeyBinding/GlobalKeyBindingsSection.cs b/osu.Game/Overlays/KeyBinding/GlobalKeyBindingsSection.cs index b67081846c..82e24f550b 100644 --- a/osu.Game/Overlays/KeyBinding/GlobalKeyBindingsSection.cs +++ b/osu.Game/Overlays/KeyBinding/GlobalKeyBindingsSection.cs @@ -33,7 +33,8 @@ namespace osu.Game.Overlays.KeyBinding { protected override string Header => "In Game"; - public InGameKeyBindingsSubsection(GlobalActionContainer manager) : base(null) + public InGameKeyBindingsSubsection(GlobalActionContainer manager) + : base(null) { Defaults = manager.InGameKeyBindings; } diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 8a8ad0d964..ef16c81dfc 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -35,7 +35,7 @@ namespace osu.Game.Overlays.KeyBinding public bool MatchingFilter { - get { return matchingFilter; } + get => matchingFilter; set { matchingFilter = value; @@ -309,10 +309,11 @@ namespace osu.Game.Overlays.KeyBinding public bool IsBinding { - get { return isBinding; } + get => isBinding; set { if (value == isBinding) return; + isBinding = value; updateHoverState(); diff --git a/osu.Game/Overlays/MedalOverlay.cs b/osu.Game/Overlays/MedalOverlay.cs index 76efd74006..a5703eba92 100644 --- a/osu.Game/Overlays/MedalOverlay.cs +++ b/osu.Game/Overlays/MedalOverlay.cs @@ -219,13 +219,11 @@ namespace osu.Game.Overlays { if (drawableMedal.State != DisplayState.Full) drawableMedal.State = DisplayState.Icon; - }) - .Delay(step_duration).Schedule(() => + }).Delay(step_duration).Schedule(() => { if (drawableMedal.State != DisplayState.Full) drawableMedal.State = DisplayState.MedalUnlocked; - }) - .Delay(step_duration).Schedule(() => + }).Delay(step_duration).Schedule(() => { if (drawableMedal.State != DisplayState.Full) drawableMedal.State = DisplayState.Full; diff --git a/osu.Game/Overlays/MedalSplash/DrawableMedal.cs b/osu.Game/Overlays/MedalSplash/DrawableMedal.cs index 2dedef8fb2..eeb42ec991 100644 --- a/osu.Game/Overlays/MedalSplash/DrawableMedal.cs +++ b/osu.Game/Overlays/MedalSplash/DrawableMedal.cs @@ -29,6 +29,7 @@ namespace osu.Game.Overlays.MedalSplash private readonly OsuSpriteText unlocked, name; private readonly TextFlowContainer description; private DisplayState state; + public DrawableMedal(Medal medal) { this.medal = medal; @@ -132,7 +133,7 @@ namespace osu.Game.Overlays.MedalSplash public DisplayState State { - get { return state; } + get => state; set { if (state == value) return; diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index f9cc19419c..23b75caedc 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -107,10 +107,11 @@ namespace osu.Game.Overlays.Mods public Color4 SelectedColour { - get { return selectedColour; } + get => selectedColour; set { if (value == selectedColour) return; + selectedColour = value; if (Selected) foregroundIcon.Colour = value; } @@ -121,7 +122,7 @@ namespace osu.Game.Overlays.Mods public Mod Mod { - get { return mod; } + get => mod; set { mod = value; diff --git a/osu.Game/Overlays/Mods/ModSection.cs b/osu.Game/Overlays/Mods/ModSection.cs index bf9efa75ea..a118357f21 100644 --- a/osu.Game/Overlays/Mods/ModSection.cs +++ b/osu.Game/Overlays/Mods/ModSection.cs @@ -81,6 +81,7 @@ namespace osu.Game.Overlays.Mods { Mod selected = button.SelectedMod; if (selected == null) continue; + foreach (var type in modTypes) if (type.IsInstanceOfType(selected)) { diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index f6cccdef5f..aa41723ca6 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -38,6 +38,8 @@ namespace osu.Game.Overlays.Mods protected override bool BlockNonPositionalInput => false; + protected override bool DimMainContent => false; + protected readonly FillFlowContainer ModSectionsContainer; protected readonly Bindable> SelectedMods = new Bindable>(new Mod[] { }); @@ -168,6 +170,7 @@ namespace osu.Game.Overlays.Mods public void DeselectTypes(Type[] modTypes, bool immediate = false) { if (modTypes.Length == 0) return; + foreach (ModSection section in ModSectionsContainer.Children) section.DeselectTypes(modTypes, immediate); } diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index 65f02e1839..886a202c2a 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -50,12 +50,14 @@ namespace osu.Game.Overlays.Music } private bool selected; + public bool Selected { - get { return selected; } + get => selected; set { if (value == selected) return; + selected = value; FinishTransforms(true); @@ -142,7 +144,7 @@ namespace osu.Game.Overlays.Music public bool MatchingFilter { - get { return matching; } + get => matching; set { if (matching == value) return; diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index 9ace13289b..7846e31725 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -34,8 +34,8 @@ namespace osu.Game.Overlays.Music public new MarginPadding Padding { - get { return base.Padding; } - set { base.Padding = value; } + get => base.Padding; + set => base.Padding = value; } public BeatmapSetInfo FirstVisibleSet => items.FirstVisibleSet; @@ -109,8 +109,8 @@ namespace osu.Game.Overlays.Music public string SearchTerm { - get { return search.SearchTerm; } - set { search.SearchTerm = value; } + get => search.SearchTerm; + set => search.SearchTerm = value; } public BeatmapSetInfo FirstVisibleSet => items.FirstOrDefault(i => i.MatchingFilter)?.BeatmapSetInfo; @@ -130,6 +130,7 @@ namespace osu.Game.Overlays.Music nativeDragPosition = e.ScreenSpaceMousePosition; if (draggedItem == null) return base.OnDrag(e); + return true; } diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 749000349c..c1b742e4e5 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -351,11 +351,11 @@ namespace osu.Game.Overlays queuedDirection = null; } - private void currentTrackCompleted() + private void currentTrackCompleted() => Schedule(() => { - if (!beatmap.Disabled && beatmapSets.Any()) + if (!current.Track.Looping && !beatmap.Disabled && beatmapSets.Any()) next(); - } + }); private ScheduledDelegate pendingBeatmapSwitch; diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 55b1f04528..8f75d3ebf0 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -78,6 +78,7 @@ namespace osu.Game.Overlays } private ScheduledDelegate notificationsEnabler; + private void updateProcessingMode() { bool enabled = OverlayActivationMode.Value == OverlayActivation.All || State == Visibility.Visible; @@ -118,8 +119,7 @@ namespace osu.Game.Overlays notification.Closed += notificationClosed; - var hasCompletionTarget = notification as IHasCompletionTarget; - if (hasCompletionTarget != null) + if (notification is IHasCompletionTarget hasCompletionTarget) hasCompletionTarget.CompletionTarget = Post; var ourType = notification.GetType(); diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index b77b6f837d..ea6e250556 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -151,6 +151,7 @@ namespace osu.Game.Overlays.Notifications public virtual void Close() { if (WasClosed) return; + WasClosed = true; Closed?.Invoke(); @@ -205,7 +206,7 @@ namespace osu.Game.Overlays.Notifications public bool Pulsate { - get { return pulsate; } + get => pulsate; set { if (pulsate == value) return; diff --git a/osu.Game/Overlays/Notifications/NotificationSection.cs b/osu.Game/Overlays/Notifications/NotificationSection.cs index 6b0e17a482..4608d78324 100644 --- a/osu.Game/Overlays/Notifications/NotificationSection.cs +++ b/osu.Game/Overlays/Notifications/NotificationSection.cs @@ -39,7 +39,7 @@ namespace osu.Game.Overlays.Notifications public string ClearText { - get { return clearText; } + get => clearText; set { clearText = value; @@ -51,7 +51,7 @@ namespace osu.Game.Overlays.Notifications public string Title { - get { return title; } + get => title; set { title = value; @@ -153,8 +153,8 @@ namespace osu.Game.Overlays.Notifications public string Text { - get { return text.Text; } - set { text.Text = value.ToUpperInvariant(); } + get => text.Text; + set => text.Text = value.ToUpperInvariant(); } } diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index efb66a7153..75e70b18ea 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -17,18 +17,15 @@ namespace osu.Game.Overlays.Notifications { public string Text { - set - { - Schedule(() => textDrawable.Text = value); - } + set => Schedule(() => textDrawable.Text = value); } public string CompletionText { get; set; } = "Task has completed!"; public float Progress { - get { return progressBar.Progress; } - set { Schedule(() => progressBar.Progress = value); } + get => progressBar.Progress; + set => Schedule(() => progressBar.Progress = value); } protected override void LoadComplete() @@ -41,9 +38,8 @@ namespace osu.Game.Overlays.Notifications public virtual ProgressNotificationState State { - get { return state; } - set - { + get => state; + set => Schedule(() => { bool stateChanged = state != value; @@ -82,7 +78,6 @@ namespace osu.Game.Overlays.Notifications } } }); - } } private ProgressNotificationState state; @@ -178,9 +173,10 @@ namespace osu.Game.Overlays.Notifications private Color4 colourInactive; private float progress; + public float Progress { - get { return progress; } + get => progress; set { if (progress == value) return; @@ -194,7 +190,7 @@ namespace osu.Game.Overlays.Notifications public bool Active { - get { return active; } + get => active; set { active = value; diff --git a/osu.Game/Overlays/Notifications/SimpleNotification.cs b/osu.Game/Overlays/Notifications/SimpleNotification.cs index 91dab14a62..aee056b63d 100644 --- a/osu.Game/Overlays/Notifications/SimpleNotification.cs +++ b/osu.Game/Overlays/Notifications/SimpleNotification.cs @@ -15,9 +15,10 @@ namespace osu.Game.Overlays.Notifications public class SimpleNotification : Notification { private string text = string.Empty; + public string Text { - get { return text; } + get => text; set { text = value; @@ -26,9 +27,10 @@ namespace osu.Game.Overlays.Notifications } private FontAwesome icon = FontAwesome.fa_info_circle; + public FontAwesome Icon { - get { return icon; } + get => icon; set { icon = value; @@ -76,11 +78,7 @@ namespace osu.Game.Overlays.Notifications public override bool Read { - get - { - return base.Read; - } - + get => base.Read; set { if (value == base.Read) return; diff --git a/osu.Game/Overlays/Profile/Header/RankGraph.cs b/osu.Game/Overlays/Profile/Header/RankGraph.cs index 05161de4c0..3df0677576 100644 --- a/osu.Game/Overlays/Profile/Header/RankGraph.cs +++ b/osu.Game/Overlays/Profile/Header/RankGraph.cs @@ -140,6 +140,7 @@ namespace osu.Game.Overlays.Profile.Header graph.UpdateBallPosition(e.MousePosition.X); graph.ShowBall(); } + return base.OnHover(e); } diff --git a/osu.Game/Overlays/Profile/Header/SupporterIcon.cs b/osu.Game/Overlays/Profile/Header/SupporterIcon.cs index 92c8a34728..722c9c9af2 100644 --- a/osu.Game/Overlays/Profile/Header/SupporterIcon.cs +++ b/osu.Game/Overlays/Profile/Header/SupporterIcon.cs @@ -23,35 +23,35 @@ namespace osu.Game.Overlays.Profile.Header Masking = true; Children = new Drawable[] { - new Box { RelativeSizeAxes = Axes.Both }, - new CircularContainer + new Box { RelativeSizeAxes = Axes.Both }, + new CircularContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Scale = new Vector2(0.8f), + Masking = true, + Children = new Drawable[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Scale = new Vector2(0.8f), - Masking = true, - Children = new Drawable[] + background = new Box { RelativeSizeAxes = Axes.Both }, + new Triangles { - background = new Box { RelativeSizeAxes = Axes.Both }, - new Triangles - { - TriangleScale = 0.2f, - ColourLight = OsuColour.FromHex(@"ff7db7"), - ColourDark = OsuColour.FromHex(@"de5b95"), - RelativeSizeAxes = Axes.Both, - Velocity = 0.3f, - }, - } - }, - new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Icon = FontAwesome.fa_heart, - Scale = new Vector2(0.45f), + TriangleScale = 0.2f, + ColourLight = OsuColour.FromHex(@"ff7db7"), + ColourDark = OsuColour.FromHex(@"de5b95"), + RelativeSizeAxes = Axes.Both, + Velocity = 0.3f, + }, } + }, + new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Icon = FontAwesome.fa_heart, + Scale = new Vector2(0.45f), + } }; } diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index 56e34cf296..2641a0551d 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -19,6 +19,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Profile.Components; using osu.Game.Overlays.Profile.Header; using osu.Game.Users; +using Humanizer; namespace osu.Game.Overlays.Profile { @@ -318,7 +319,7 @@ namespace osu.Game.Overlays.Profile public User User { - get { return user; } + get => user; set { user = value; @@ -401,7 +402,7 @@ namespace osu.Game.Overlays.Profile infoTextLeft.NewLine(); infoTextLeft.AddText("Contributed ", lightText); - infoTextLeft.AddLink($@"{user.PostCount} forum posts", url: $"https://osu.ppy.sh/users/{user.Id}/posts", creationParameters: boldItalic); + infoTextLeft.AddLink("forum post".ToQuantity(user.PostCount), url: $"https://osu.ppy.sh/users/{user.Id}/posts", creationParameters: boldItalic); string websiteWithoutProtcol = user.Website; if (!string.IsNullOrEmpty(websiteWithoutProtcol)) diff --git a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs index 64c8260524..bb55816880 100644 --- a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs @@ -47,8 +47,9 @@ namespace osu.Game.Overlays.Profile.Sections { new OsuSpriteText { - Text = new LocalisedString(($"{beatmap.Metadata.TitleUnicode ?? beatmap.Metadata.Title} [{beatmap.Version}] ", - $"{beatmap.Metadata.Title ?? beatmap.Metadata.TitleUnicode} [{beatmap.Version}] ")), + Text = new LocalisedString(( + $"{beatmap.Metadata.TitleUnicode ?? beatmap.Metadata.Title} [{beatmap.Version}] ", + $"{beatmap.Metadata.Title ?? beatmap.Metadata.TitleUnicode} [{beatmap.Version}] ")), Font = OsuFont.GetFont(size: 15, weight: FontWeight.SemiBold, italics: true) }, new OsuSpriteText diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs index 4757f676c8..f2eb32c53b 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs @@ -15,7 +15,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical private GetUserMostPlayedBeatmapsRequest request; public PaginatedMostPlayedBeatmapContainer(Bindable user) - :base(user, "Most Played Beatmaps", "No records. :(") + : base(user, "Most Played Beatmaps", "No records. :(") { ItemsPerPage = 5; diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs index 9d60851f6e..3c69082e9d 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs @@ -78,7 +78,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu public new int Count { - set { valueText.Text = value.ToString(); } + set => valueText.Text = value.ToString(); } public CountSection(string header, string description) diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs index 7164bc7cd1..497d6c3fc4 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs @@ -65,7 +65,7 @@ namespace osu.Game.Overlays.Profile.Sections { Font = OsuFont.GetFont(size: 14), Text = "show more", - Padding = new MarginPadding {Vertical = 10, Horizontal = 15 }, + Padding = new MarginPadding { Vertical = 10, Horizontal = 15 }, } }, ShowMoreLoading = new LoadingAnimation diff --git a/osu.Game/Overlays/SearchableList/HeaderTabControl.cs b/osu.Game/Overlays/SearchableList/HeaderTabControl.cs index 39348a9ad7..2087a72c54 100644 --- a/osu.Game/Overlays/SearchableList/HeaderTabControl.cs +++ b/osu.Game/Overlays/SearchableList/HeaderTabControl.cs @@ -19,7 +19,8 @@ namespace osu.Game.Overlays.SearchableList private class HeaderTabItem : OsuTabItem { - public HeaderTabItem(T value) : base(value) + public HeaderTabItem(T value) + : base(value) { Text.Font = Text.Font.With(size: 16); } diff --git a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs index 4e1130690f..026424e1ff 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs @@ -41,7 +41,7 @@ namespace osu.Game.Overlays.Settings.Sections.General public bool Bounding { - get { return bounding; } + get => bounding; set { bounding = value; @@ -277,6 +277,7 @@ namespace osu.Game.Overlays.Settings.Sections.General { var h = Header as UserDropdownHeader; if (h == null) return; + h.StatusColour = value; } } @@ -338,7 +339,7 @@ namespace osu.Game.Overlays.Settings.Sections.General public Color4 StatusColour { - set { statusIcon.FadeColour(value, 500, Easing.OutQuint); } + set => statusIcon.FadeColour(value, 500, Easing.OutQuint); } public UserDropdownHeader() diff --git a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs index 4d889856f6..188c9c05ef 100644 --- a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs @@ -1,8 +1,8 @@ // 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; using osu.Framework.Allocation; -using osu.Framework.Graphics; using osu.Framework.Platform; using osu.Game.Configuration; @@ -15,19 +15,20 @@ namespace osu.Game.Overlays.Settings.Sections.General [BackgroundDependencyLoader] private void load(Storage storage, OsuConfigManager config) { - Children = new Drawable[] + Add(new SettingsEnumDropdown { - new SettingsEnumDropdown - { - LabelText = "Release stream", - Bindable = config.GetBindable(OsuSetting.ReleaseStream), - }, - new SettingsButton + LabelText = "Release stream", + Bindable = config.GetBindable(OsuSetting.ReleaseStream), + }); + + if (RuntimeInfo.IsDesktop) + { + Add(new SettingsButton { Text = "Open osu! folder", Action = storage.OpenInNativeExplorer, - } - }; + }); + } } } } diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 628cdb944a..58d2eb1f1e 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -11,6 +11,7 @@ using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Platform; using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; @@ -26,10 +27,11 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics private Bindable scalingMode; private Bindable sizeFullscreen; + private readonly BindableList windowModes = new BindableList(); private OsuGameBase game; private SettingsDropdown resolutionDropdown; - private SettingsEnumDropdown windowModeDropdown; + private SettingsDropdown windowModeDropdown; private Bindable scalingPositionX; private Bindable scalingPositionY; @@ -39,7 +41,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics private const int transition_duration = 400; [BackgroundDependencyLoader] - private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, OsuGameBase game) + private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, OsuGameBase game, GameHost host) { this.game = game; @@ -50,14 +52,18 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics scalingPositionX = osuConfig.GetBindable(OsuSetting.ScalingPositionX); scalingPositionY = osuConfig.GetBindable(OsuSetting.ScalingPositionY); + if (host.Window != null) + windowModes.BindTo(host.Window.SupportedWindowModes); + Container resolutionSettingsContainer; Children = new Drawable[] { - windowModeDropdown = new SettingsEnumDropdown + windowModeDropdown = new SettingsDropdown { LabelText = "Screen mode", Bindable = config.GetBindable(FrameworkSetting.WindowMode), + ItemSource = windowModes, }, resolutionSettingsContainer = new Container { @@ -84,7 +90,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics AutoSizeDuration = transition_duration, AutoSizeEasing = Easing.OutQuint, Masking = true, - Children = new [] + Children = new[] { new SettingsSlider { @@ -150,6 +156,19 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics scalingSettings.ForEach(s => s.TransferValueOnCommit = mode.NewValue == ScalingMode.Everything); }, true); + + windowModes.ItemsAdded += _ => windowModesChanged(); + windowModes.ItemsRemoved += _ => windowModesChanged(); + + windowModesChanged(); + } + + private void windowModesChanged() + { + if (windowModes.Count > 1) + windowModeDropdown.Show(); + else + windowModeDropdown.Hide(); } /// @@ -171,6 +190,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics } private Drawable preview; + private void showPreview() { if (preview?.IsAlive != true) @@ -225,6 +245,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics { if (item == new Size(9999, 9999)) return "Default"; + return $"{item.Width}x{item.Height}"; } } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index d512652938..398a091486 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -25,9 +25,9 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance [BackgroundDependencyLoader] private void load(BeatmapManager beatmaps, SkinManager skins, DialogOverlay dialogOverlay) { - Children = new Drawable[] + if (beatmaps.SupportsImportFromStable) { - importBeatmapsButton = new SettingsButton + Add(importBeatmapsButton = new SettingsButton { Text = "Import beatmaps from stable", Action = () => @@ -35,20 +35,25 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance importBeatmapsButton.Enabled.Value = false; beatmaps.ImportFromStableAsync().ContinueWith(t => Schedule(() => importBeatmapsButton.Enabled.Value = true)); } - }, - deleteBeatmapsButton = new DangerousSettingsButton + }); + } + + Add(deleteBeatmapsButton = new DangerousSettingsButton + { + Text = "Delete ALL beatmaps", + Action = () => { - Text = "Delete ALL beatmaps", - Action = () => + dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() => { - dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() => - { - deleteBeatmapsButton.Enabled.Value = false; - Task.Run(() => beatmaps.Delete(beatmaps.GetAllUsableBeatmapSets())).ContinueWith(t => Schedule(() => deleteBeatmapsButton.Enabled.Value = true)); - })); - } - }, - importSkinsButton = new SettingsButton + deleteBeatmapsButton.Enabled.Value = false; + Task.Run(() => beatmaps.Delete(beatmaps.GetAllUsableBeatmapSets())).ContinueWith(t => Schedule(() => deleteBeatmapsButton.Enabled.Value = true)); + })); + } + }); + + if (skins.SupportsImportFromStable) + { + Add(importSkinsButton = new SettingsButton { Text = "Import skins from stable", Action = () => @@ -56,7 +61,11 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance importSkinsButton.Enabled.Value = false; skins.ImportFromStableAsync().ContinueWith(t => Schedule(() => importSkinsButton.Enabled.Value = true)); } - }, + }); + } + + AddRange(new Drawable[] + { deleteSkinsButton = new DangerousSettingsButton { Text = "Delete ALL skins", @@ -91,7 +100,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Task.Run(() => beatmaps.Undelete(beatmaps.QueryBeatmapSets(b => b.DeletePending).ToList())).ContinueWith(t => Schedule(() => undeleteButton.Enabled.Value = true)); } }, - }; + }); } } } diff --git a/osu.Game/Overlays/Settings/SettingsCheckbox.cs b/osu.Game/Overlays/Settings/SettingsCheckbox.cs index 71c197b784..46c23c3bbf 100644 --- a/osu.Game/Overlays/Settings/SettingsCheckbox.cs +++ b/osu.Game/Overlays/Settings/SettingsCheckbox.cs @@ -14,8 +14,8 @@ namespace osu.Game.Overlays.Settings public override string LabelText { - get { return checkbox.LabelText; } - set { checkbox.LabelText = value; } + get => checkbox.LabelText; + set => checkbox.LabelText = value; } } } diff --git a/osu.Game/Overlays/Settings/SettingsDropdown.cs b/osu.Game/Overlays/Settings/SettingsDropdown.cs index 1829bbdcbc..de3f741cd7 100644 --- a/osu.Game/Overlays/Settings/SettingsDropdown.cs +++ b/osu.Game/Overlays/Settings/SettingsDropdown.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Graphics.UserInterface; @@ -26,11 +27,25 @@ namespace osu.Game.Overlays.Settings } } + private IBindableList itemSource; + + public IBindableList ItemSource + { + get => itemSource; + set + { + itemSource = value; + + if (Control != null) + Control.ItemSource = value; + } + } + public override IEnumerable FilterTerms => base.FilterTerms.Concat(Control.Items.Select(i => i.ToString())); protected sealed override Drawable CreateControl() => CreateDropdown(); - protected virtual OsuDropdown CreateDropdown() => new DropdownControl { Items = Items }; + protected virtual OsuDropdown CreateDropdown() => new DropdownControl { Items = Items, ItemSource = ItemSource }; protected class DropdownControl : OsuDropdown { diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index de7e8bbd71..f6517bafd6 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -39,7 +39,7 @@ namespace osu.Game.Overlays.Settings public virtual string LabelText { - get { return text?.Text ?? string.Empty; } + get => text?.Text ?? string.Empty; set { if (text == null) @@ -58,7 +58,7 @@ namespace osu.Game.Overlays.Settings public virtual Bindable Bindable { - get { return bindable; } + get => bindable; set { @@ -76,11 +76,7 @@ namespace osu.Game.Overlays.Settings public bool MatchingFilter { - set - { - // probably needs a better transition. - this.FadeTo(value ? 1 : 0); - } + set => this.FadeTo(value ? 1 : 0); } protected SettingsItem() @@ -115,7 +111,7 @@ namespace osu.Game.Overlays.Settings public Bindable Bindable { - get { return bindable; } + get => bindable; set { bindable = value; diff --git a/osu.Game/Overlays/Settings/SettingsSection.cs b/osu.Game/Overlays/Settings/SettingsSection.cs index cf8544af17..38a8b58a68 100644 --- a/osu.Game/Overlays/Settings/SettingsSection.cs +++ b/osu.Game/Overlays/Settings/SettingsSection.cs @@ -31,7 +31,7 @@ namespace osu.Game.Overlays.Settings public bool MatchingFilter { - set { this.FadeTo(value ? 1 : 0); } + set => this.FadeTo(value ? 1 : 0); } protected SettingsSection() diff --git a/osu.Game/Overlays/Settings/SettingsSubsection.cs b/osu.Game/Overlays/Settings/SettingsSubsection.cs index 9a3eeac5d0..2215e95fec 100644 --- a/osu.Game/Overlays/Settings/SettingsSubsection.cs +++ b/osu.Game/Overlays/Settings/SettingsSubsection.cs @@ -22,12 +22,10 @@ namespace osu.Game.Overlays.Settings public IEnumerable FilterableChildren => Children.OfType(); public IEnumerable FilterTerms => new[] { Header }; + public bool MatchingFilter { - set - { - this.FadeTo(value ? 1 : 0); - } + set => this.FadeTo(value ? 1 : 0); } protected SettingsSubsection() diff --git a/osu.Game/Overlays/Settings/Sidebar.cs b/osu.Game/Overlays/Settings/Sidebar.cs index 960ceaa78f..969686e36d 100644 --- a/osu.Game/Overlays/Settings/Sidebar.cs +++ b/osu.Game/Overlays/Settings/Sidebar.cs @@ -88,7 +88,7 @@ namespace osu.Game.Overlays.Settings public ExpandedState State { - get { return state; } + get => state; set { expandEvent?.Cancel(); diff --git a/osu.Game/Overlays/Settings/SidebarButton.cs b/osu.Game/Overlays/Settings/SidebarButton.cs index c53596cabe..c7736d6047 100644 --- a/osu.Game/Overlays/Settings/SidebarButton.cs +++ b/osu.Game/Overlays/Settings/SidebarButton.cs @@ -26,12 +26,10 @@ namespace osu.Game.Overlays.Settings public new Action Action; private SettingsSection section; + public SettingsSection Section { - get - { - return section; - } + get => section; set { section = value; @@ -41,9 +39,10 @@ namespace osu.Game.Overlays.Settings } private bool selected; + public bool Selected { - get { return selected; } + get => selected; set { selected = value; diff --git a/osu.Game/Overlays/Social/Header.cs b/osu.Game/Overlays/Social/Header.cs index fb72051a41..cf8053ac6e 100644 --- a/osu.Game/Overlays/Social/Header.cs +++ b/osu.Game/Overlays/Social/Header.cs @@ -54,6 +54,7 @@ namespace osu.Game.Overlays.Social { [Description("All Players")] AllPlayers, + [Description("Friends")] Friends, //[Description("Team Members")] diff --git a/osu.Game/Overlays/Social/SocialGridPanel.cs b/osu.Game/Overlays/Social/SocialGridPanel.cs index ccb8870bc9..6f707d640b 100644 --- a/osu.Game/Overlays/Social/SocialGridPanel.cs +++ b/osu.Game/Overlays/Social/SocialGridPanel.cs @@ -7,7 +7,8 @@ namespace osu.Game.Overlays.Social { public class SocialGridPanel : SocialPanel { - public SocialGridPanel(User user) : base(user) + public SocialGridPanel(User user) + : base(user) { Width = 300; } diff --git a/osu.Game/Overlays/Social/SocialListPanel.cs b/osu.Game/Overlays/Social/SocialListPanel.cs index 52c2caaa49..1ba91e9204 100644 --- a/osu.Game/Overlays/Social/SocialListPanel.cs +++ b/osu.Game/Overlays/Social/SocialListPanel.cs @@ -8,7 +8,8 @@ namespace osu.Game.Overlays.Social { public class SocialListPanel : SocialPanel { - public SocialListPanel(User user) : base(user) + public SocialListPanel(User user) + : base(user) { RelativeSizeAxes = Axes.X; } diff --git a/osu.Game/Overlays/Social/SocialPanel.cs b/osu.Game/Overlays/Social/SocialPanel.cs index bf1be29aa1..738f940484 100644 --- a/osu.Game/Overlays/Social/SocialPanel.cs +++ b/osu.Game/Overlays/Social/SocialPanel.cs @@ -15,7 +15,8 @@ namespace osu.Game.Overlays.Social { private const double hover_transition_time = 400; - public SocialPanel(User user) : base(user) + public SocialPanel(User user) + : base(user) { } diff --git a/osu.Game/Overlays/SocialOverlay.cs b/osu.Game/Overlays/SocialOverlay.cs index 9ee255819a..3464058abb 100644 --- a/osu.Game/Overlays/SocialOverlay.cs +++ b/osu.Game/Overlays/SocialOverlay.cs @@ -34,9 +34,10 @@ namespace osu.Game.Overlays protected override SearchableListFilterControl CreateFilterControl() => new FilterControl(); private IEnumerable users; + public IEnumerable Users { - get { return users; } + get => users; set { if (users?.Equals(value) ?? false) @@ -123,6 +124,7 @@ namespace osu.Game.Overlays panel = new SocialListPanel(u); break; } + panel.Status.BindTo(u.Status); return panel; }) @@ -130,7 +132,7 @@ namespace osu.Game.Overlays LoadComponentAsync(newPanels, f => { - if(panels != null) + if (panels != null) ScrollFlow.Remove(panels); ScrollFlow.Add(panels = newPanels); @@ -171,6 +173,7 @@ namespace osu.Game.Overlays api.Queue(getUsersRequest = userRequest); break; } + loading.Show(); } diff --git a/osu.Game/Overlays/Toolbar/ToolbarButton.cs b/osu.Game/Overlays/Toolbar/ToolbarButton.cs index 32ab80d50f..855c7ad823 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarButton.cs @@ -35,34 +35,25 @@ namespace osu.Game.Overlays.Toolbar public FontAwesome Icon { - set { SetIcon(value); } + set => SetIcon(value); } public string Text { - get { return DrawableText.Text; } - set - { - DrawableText.Text = value; - } + get => DrawableText.Text; + set => DrawableText.Text = value; } public string TooltipMain { - get { return tooltip1.Text; } - set - { - tooltip1.Text = value; - } + get => tooltip1.Text; + set => tooltip1.Text = value; } public string TooltipSub { - get { return tooltip2.Text; } - set - { - tooltip2.Text = value; - } + get => tooltip2.Text; + set => tooltip2.Text = value; } protected virtual Anchor TooltipAnchor => Anchor.TopLeft; @@ -75,7 +66,8 @@ namespace osu.Game.Overlays.Toolbar private readonly SpriteText tooltip2; protected FillFlowContainer Flow; - public ToolbarButton() : base(HoverSampleSet.Loud) + public ToolbarButton() + : base(HoverSampleSet.Loud) { Width = WIDTH; RelativeSizeAxes = Axes.Y; @@ -147,6 +139,7 @@ namespace osu.Game.Overlays.Toolbar protected override bool OnClick(ClickEvent e) { HoverBackground.FlashColour(Color4.White.Opacity(100), 500, Easing.OutQuint); + tooltipContainer.FadeOut(100); return base.OnClick(e); } diff --git a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs index 2e1e2c0df8..751045f61c 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs @@ -66,7 +66,7 @@ namespace osu.Game.Overlays.Toolbar public int Count { - get { return count; } + get => count; set { if (count == value) diff --git a/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs b/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs index fc6a54477c..ca86ce7aa7 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs @@ -17,7 +17,7 @@ namespace osu.Game.Overlays.Toolbar public OverlayContainer StateContainer { - get { return stateContainer; } + get => stateContainer; set { stateContainer = value; diff --git a/osu.Game/Overlays/Toolbar/ToolbarRulesetButton.cs b/osu.Game/Overlays/Toolbar/ToolbarRulesetButton.cs index 07a53f0bae..f729810fbc 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarRulesetButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarRulesetButton.cs @@ -10,9 +10,10 @@ namespace osu.Game.Overlays.Toolbar public class ToolbarRulesetButton : ToolbarButton { private RulesetInfo ruleset; + public RulesetInfo Ruleset { - get { return ruleset; } + get => ruleset; set { ruleset = value; diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserArea.cs b/osu.Game/Overlays/Toolbar/ToolbarUserArea.cs index eeb9527b50..f9cf5d4350 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserArea.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserArea.cs @@ -22,7 +22,8 @@ namespace osu.Game.Overlays.Toolbar RelativeSizeAxes = Axes.Y; AutoSizeAxes = Axes.X; - Children = new Drawable[] { + Children = new Drawable[] + { button = new ToolbarUserButton { Action = () => LoginOverlay.ToggleVisibility(), diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index 80ed6128b8..1ff1c2ce91 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -144,6 +144,7 @@ namespace osu.Game.Overlays tabs.Current.Value = lastSection; return; } + if (lastSection != section.NewValue) { lastSection = section.NewValue; @@ -212,7 +213,8 @@ namespace osu.Game.Overlays private class ProfileTabItem : PageTabItem { - public ProfileTabItem(ProfileSection value) : base(value) + public ProfileTabItem(ProfileSection value) + : base(value) { Text.Text = value.Title; } diff --git a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs index a5cb805300..db8bdde6bb 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs @@ -113,12 +113,15 @@ namespace osu.Game.Rulesets.Difficulty case 0: // Initial-case: Empty current set yield return new ModNoMod(); + break; case 1: yield return currentSet.Single(); + break; default: yield return new MultiMod(currentSet.ToArray()); + break; } diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index e557edf49f..025564e249 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -111,8 +111,8 @@ namespace osu.Game.Rulesets.Edit toolboxCollection.Items = CompositionTools.Select(t => new RadioButton(t.Name, () => blueprintContainer.CurrentTool = t)) - .Prepend(new RadioButton("Select", () => blueprintContainer.CurrentTool = null)) - .ToList(); + .Prepend(new RadioButton("Select", () => blueprintContainer.CurrentTool = null)) + .ToList(); toolboxCollection.Items[0].Select(); } diff --git a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs index 434ce4a721..74aa9ace2d 100644 --- a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs +++ b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs @@ -75,6 +75,7 @@ namespace osu.Game.Rulesets.Edit { if (state == value) return; + state = value; if (state == PlacementState.Shown) diff --git a/osu.Game/Rulesets/Mods/ModDaycore.cs b/osu.Game/Rulesets/Mods/ModDaycore.cs index 74216653c7..2eea6a237c 100644 --- a/osu.Game/Rulesets/Mods/ModDaycore.cs +++ b/osu.Game/Rulesets/Mods/ModDaycore.cs @@ -16,8 +16,7 @@ namespace osu.Game.Rulesets.Mods public override void ApplyToClock(IAdjustableClock clock) { - var pitchAdjust = clock as IHasPitchAdjust; - if (pitchAdjust != null) + if (clock is IHasPitchAdjust pitchAdjust) pitchAdjust.PitchAdjust = 0.75; else base.ApplyToClock(clock); diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index 2a416b2705..dfada5614a 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -109,6 +109,7 @@ namespace osu.Game.Rulesets.Mods protected abstract string FragmentShader { get; } private Vector2 flashlightPosition; + protected Vector2 FlashlightPosition { get => flashlightPosition; @@ -122,6 +123,7 @@ namespace osu.Game.Rulesets.Mods } private Vector2 flashlightSize; + protected Vector2 FlashlightSize { get => flashlightSize; diff --git a/osu.Game/Rulesets/Mods/ModHidden.cs b/osu.Game/Rulesets/Mods/ModHidden.cs index 2989ec2304..e526125947 100644 --- a/osu.Game/Rulesets/Mods/ModHidden.cs +++ b/osu.Game/Rulesets/Mods/ModHidden.cs @@ -31,6 +31,8 @@ namespace osu.Game.Rulesets.Mods d.ApplyCustomUpdateState += ApplyHiddenState; } - protected virtual void ApplyHiddenState(DrawableHitObject hitObject, ArmedState state) { } + protected virtual void ApplyHiddenState(DrawableHitObject hitObject, ArmedState state) + { + } } } diff --git a/osu.Game/Rulesets/Mods/ModNightcore.cs b/osu.Game/Rulesets/Mods/ModNightcore.cs index 4dd8972dd6..e6bd532f72 100644 --- a/osu.Game/Rulesets/Mods/ModNightcore.cs +++ b/osu.Game/Rulesets/Mods/ModNightcore.cs @@ -16,8 +16,7 @@ namespace osu.Game.Rulesets.Mods public override void ApplyToClock(IAdjustableClock clock) { - var pitchAdjust = clock as IHasPitchAdjust; - if (pitchAdjust != null) + if (clock is IHasPitchAdjust pitchAdjust) pitchAdjust.PitchAdjust = 1.5; else base.ApplyToClock(clock); diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index fa45f7b60b..e1e76f109d 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -220,6 +220,16 @@ namespace osu.Game.Rulesets.Objects.Drawables OnNewResult?.Invoke(this, Result); } + /// + /// Will called at least once after the of this has been passed. + /// + internal void OnLifetimeEnd() + { + foreach (var nested in NestedHitObjects) + nested.OnLifetimeEnd(); + UpdateResult(false); + } + /// /// Processes this , checking if a scoring result has occurred. /// diff --git a/osu.Game/Rulesets/Objects/HitWindows.cs b/osu.Game/Rulesets/Objects/HitWindows.cs index 6c97f6b6da..c5b7686da6 100644 --- a/osu.Game/Rulesets/Objects/HitWindows.cs +++ b/osu.Game/Rulesets/Objects/HitWindows.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Objects private static readonly IReadOnlyDictionary base_ranges = new Dictionary { { HitResult.Perfect, (44.8, 38.8, 27.8) }, - { HitResult.Great, (128, 98, 68 ) }, + { HitResult.Great, (128, 98, 68) }, { HitResult.Good, (194, 164, 134) }, { HitResult.Ok, (254, 224, 194) }, { HitResult.Meh, (302, 272, 242) }, diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectType.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectType.cs index 6917d009f4..c9f7224643 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectType.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectType.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Objects.Legacy Slider = 1 << 1, NewCombo = 1 << 2, Spinner = 1 << 3, - ComboOffset = 1 << 4 | 1 << 5 | 1 << 6, + ComboOffset = (1 << 4) | (1 << 5) | (1 << 6), Hold = 1 << 7 } } diff --git a/osu.Game/Rulesets/Objects/SliderPath.cs b/osu.Game/Rulesets/Objects/SliderPath.cs index 8cadb38190..1e9767a54f 100644 --- a/osu.Game/Rulesets/Objects/SliderPath.cs +++ b/osu.Game/Rulesets/Objects/SliderPath.cs @@ -125,6 +125,7 @@ namespace osu.Game.Rulesets.Objects { if (isInitialised) return; + isInitialised = true; controlPoints = controlPoints ?? Array.Empty(); @@ -280,6 +281,7 @@ namespace osu.Game.Rulesets.Objects public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; + return obj is SliderPath other && Equals(other); } } diff --git a/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs b/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs index ed4be4b815..c89ac59e10 100644 --- a/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs +++ b/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs @@ -99,6 +99,7 @@ namespace osu.Game.Rulesets.Replays // that would occur as a result of this frame in forward playback if (currentDirection == -1) return CurrentTime = CurrentFrame.Time - 1; + return CurrentTime = CurrentFrame.Time; } } diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 5c8ef41b9a..63e1c93dd5 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -113,6 +113,7 @@ namespace osu.Game.Rulesets.Scoring return ScoreRank.B; if (acc > 0.7) return ScoreRank.C; + return ScoreRank.D; } diff --git a/osu.Game/Rulesets/UI/HitObjectContainer.cs b/osu.Game/Rulesets/UI/HitObjectContainer.cs index 4d5dbf09d1..2f3a384e95 100644 --- a/osu.Game/Rulesets/UI/HitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/HitObjectContainer.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Objects.Drawables; namespace osu.Game.Rulesets.UI { - public class HitObjectContainer : CompositeDrawable + public class HitObjectContainer : LifetimeManagementContainer { public IEnumerable Objects => InternalChildren.Cast().OrderBy(h => h.HitObject.StartTime); public IEnumerable AliveObjects => AliveInternalChildren.Cast().OrderBy(h => h.HitObject.StartTime); @@ -31,5 +31,11 @@ namespace osu.Game.Rulesets.UI int i = yObj.HitObject.StartTime.CompareTo(xObj.HitObject.StartTime); return i == 0 ? CompareReverseChildID(x, y) : i; } + + protected override void OnChildLifetimeBoundaryCrossed(LifetimeBoundaryCrossedEvent e) + { + if (e.Kind == LifetimeBoundaryKind.End && e.Direction == LifetimeBoundaryCrossingDirection.Forward && e.Child is DrawableHitObject hitObject) + hitObject.OnLifetimeEnd(); + } } } diff --git a/osu.Game/Rulesets/UI/ModIcon.cs b/osu.Game/Rulesets/UI/ModIcon.cs index 12b9134f92..9f80dea9f7 100644 --- a/osu.Game/Rulesets/UI/ModIcon.cs +++ b/osu.Game/Rulesets/UI/ModIcon.cs @@ -22,8 +22,8 @@ namespace osu.Game.Rulesets.UI public FontAwesome Icon { - get { return modIcon.Icon; } - set { modIcon.Icon = value; } + get => modIcon.Icon; + set => modIcon.Icon = value; } private readonly ModType type; @@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.UI public bool Highlighted { - get { return highlighted; } + get => highlighted; set { diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index 0065f195fc..fc61d41ab4 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -213,10 +213,12 @@ namespace osu.Game.Rulesets.UI case MouseDownEvent mouseDown when mouseDown.Button == MouseButton.Left || mouseDown.Button == MouseButton.Right: if (mouseDisabled.Value) return false; + break; case MouseUpEvent mouseUp: if (!CurrentState.Mouse.IsPressed(mouseUp.Button)) return false; + break; } diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingDirection.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingDirection.cs index 1a307c29b8..81e1a6c916 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingDirection.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingDirection.cs @@ -9,14 +9,17 @@ namespace osu.Game.Rulesets.UI.Scrolling /// Hit objects will scroll vertically from the bottom of the hitobject container. /// Up, + /// /// Hit objects will scroll vertically from the top of the hitobject container. /// Down, + /// /// Hit objects will scroll horizontally from the right of the hitobject container. /// Left, + /// /// Hit objects will scroll horizontally from the left of the hitobject container. /// diff --git a/osu.Game/Scoring/Legacy/LegacyScoreParser.cs b/osu.Game/Scoring/Legacy/LegacyScoreParser.cs index f89f8e80bf..ace8892330 100644 --- a/osu.Game/Scoring/Legacy/LegacyScoreParser.cs +++ b/osu.Game/Scoring/Legacy/LegacyScoreParser.cs @@ -111,12 +111,14 @@ namespace osu.Game.Scoring.Legacy byte[] properties = new byte[5]; if (replayInStream.Read(properties, 0, 5) != 5) throw new IOException("input .lzma is too short"); + long outSize = 0; for (int i = 0; i < 8; i++) { int v = replayInStream.ReadByte(); if (v < 0) throw new IOException("Can't Read 1"); + outSize |= (long)(byte)v << (8 * i); } @@ -264,6 +266,7 @@ namespace osu.Game.Scoring.Legacy var convertible = currentRuleset.CreateConvertibleReplayFrame(); if (convertible == null) throw new InvalidOperationException($"Legacy replay cannot be converted for the ruleset: {currentRuleset.Description}"); + convertible.ConvertFrom(legacyFrame, currentBeatmap); var frame = (ReplayFrame)convertible; diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs index c3a7f0d4bb..d36f963016 100644 --- a/osu.Game/Scoring/ScoreInfo.cs +++ b/osu.Game/Scoring/ScoreInfo.cs @@ -28,7 +28,7 @@ namespace osu.Game.Scoring public long TotalScore { get; set; } [JsonProperty("accuracy")] - [Column(TypeName="DECIMAL(1,4)")] + [Column(TypeName = "DECIMAL(1,4)")] public double Accuracy { get; set; } [JsonProperty(@"pp")] @@ -109,7 +109,27 @@ namespace osu.Game.Scoring public string UserString { get => User?.Username; - set => User = new User { Username = value }; + set + { + if (User == null) + User = new User(); + + User.Username = value; + } + } + + [JsonIgnore] + [Column("UserID")] + public long? UserID + { + get => User?.Id ?? 1; + set + { + if (User == null) + User = new User(); + + User.Id = value ?? 1; + } } [JsonIgnore] diff --git a/osu.Game/Scoring/ScoreRank.cs b/osu.Game/Scoring/ScoreRank.cs index 05a0efe45c..82c33748bb 100644 --- a/osu.Game/Scoring/ScoreRank.cs +++ b/osu.Game/Scoring/ScoreRank.cs @@ -9,20 +9,28 @@ namespace osu.Game.Scoring { [Description(@"F")] F, + [Description(@"F")] D, + [Description(@"C")] C, + [Description(@"B")] B, + [Description(@"A")] A, + [Description(@"S")] S, + [Description(@"SPlus")] SH, + [Description(@"SS")] X, + [Description(@"SSPlus")] XH, } diff --git a/osu.Game/Scoring/ScoreStore.cs b/osu.Game/Scoring/ScoreStore.cs index 745bb6cc29..9627481f4d 100644 --- a/osu.Game/Scoring/ScoreStore.cs +++ b/osu.Game/Scoring/ScoreStore.cs @@ -8,7 +8,7 @@ using osu.Game.Database; namespace osu.Game.Scoring { - public class ScoreStore : MutableDatabaseBackedStore + public class ScoreStore : MutableDatabaseBackedStoreWithFileIncludes { public ScoreStore(IDatabaseContextFactory factory, Storage storage) : base(factory, storage) @@ -17,7 +17,6 @@ namespace osu.Game.Scoring protected override IQueryable AddIncludesForConsumption(IQueryable query) => base.AddIncludesForConsumption(query) - .Include(s => s.Files).ThenInclude(f => f.FileInfo) .Include(s => s.Beatmap) .Include(s => s.Ruleset); } diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs index 8706cc6668..13d1ff39ef 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs @@ -2,10 +2,12 @@ // 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.Framework.Graphics.Textures; using osu.Game.Beatmaps; using osu.Game.Graphics.Backgrounds; +using osu.Game.Graphics.Containers; namespace osu.Game.Screens.Backgrounds { @@ -13,9 +15,20 @@ namespace osu.Game.Screens.Backgrounds { private WorkingBeatmap beatmap; - public WorkingBeatmap Beatmap + /// + /// Whether or not user dim settings should be applied to this Background. + /// + public readonly Bindable EnableUserDim = new Bindable(); + + public readonly Bindable StoryboardReplacesBackground = new Bindable(); + + private readonly UserDimContainer fadeContainer; + + protected virtual UserDimContainer CreateFadeContainer() => new UserDimContainer { RelativeSizeAxes = Axes.Both }; + + public virtual WorkingBeatmap Beatmap { - get { return beatmap; } + get => beatmap; set { if (beatmap == value && beatmap != null) @@ -37,8 +50,9 @@ namespace osu.Game.Screens.Backgrounds } b.Depth = newDepth; - AddInternal(Background = b); + fadeContainer.Add(Background = b); Background.BlurSigma = BlurTarget; + StoryboardReplacesBackground.BindTo(fadeContainer.StoryboardReplacesBackground); })); }); } @@ -47,6 +61,8 @@ namespace osu.Game.Screens.Backgrounds public BackgroundScreenBeatmap(WorkingBeatmap beatmap = null) { Beatmap = beatmap; + InternalChild = fadeContainer = CreateFadeContainer(); + fadeContainer.EnableUserDim.BindTo(EnableUserDim); } public override bool Equals(BackgroundScreen other) @@ -57,7 +73,7 @@ namespace osu.Game.Screens.Backgrounds return base.Equals(other) && beatmap == otherBeatmapBackground.Beatmap; } - private class BeatmapBackground : Background + protected class BeatmapBackground : Background { private readonly WorkingBeatmap beatmap; diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index 0306f69755..87a6b5d591 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -70,7 +70,8 @@ namespace osu.Game.Screens.Backgrounds { private readonly Skin skin; - public SkinnedBackground(Skin skin, string fallbackTextureName) : base(fallbackTextureName) + public SkinnedBackground(Skin skin, string fallbackTextureName) + : base(fallbackTextureName) { this.skin = skin; } diff --git a/osu.Game/Screens/BlurrableBackgroundScreen.cs b/osu.Game/Screens/BlurrableBackgroundScreen.cs index cbd33136f1..d19e699acb 100644 --- a/osu.Game/Screens/BlurrableBackgroundScreen.cs +++ b/osu.Game/Screens/BlurrableBackgroundScreen.cs @@ -15,6 +15,9 @@ namespace osu.Game.Screens protected Vector2 BlurTarget; public TransformSequence BlurTo(Vector2 sigma, double duration, Easing easing = Easing.None) - => Background?.BlurTo(BlurTarget = sigma, duration, easing); + { + BlurTarget = sigma; + return Background?.BlurTo(BlurTarget, duration, easing); + } } } diff --git a/osu.Game/Screens/Charts/ChartListing.cs b/osu.Game/Screens/Charts/ChartListing.cs index ea60dc4365..18bba6433f 100644 --- a/osu.Game/Screens/Charts/ChartListing.cs +++ b/osu.Game/Screens/Charts/ChartListing.cs @@ -8,8 +8,9 @@ namespace osu.Game.Screens.Charts { public class ChartListing : ScreenWhiteBox { - protected override IEnumerable PossibleChildren => new[] { - typeof(ChartInfo) + protected override IEnumerable PossibleChildren => new[] + { + typeof(ChartInfo) }; } } diff --git a/osu.Game/Screens/Edit/BindableBeatDivisor.cs b/osu.Game/Screens/Edit/BindableBeatDivisor.cs index bea4d9a7a4..ea3b68e3bd 100644 --- a/osu.Game/Screens/Edit/BindableBeatDivisor.cs +++ b/osu.Game/Screens/Edit/BindableBeatDivisor.cs @@ -22,7 +22,7 @@ namespace osu.Game.Screens.Edit public override int Value { - get { return base.Value; } + get => base.Value; set { if (!VALID_DIVISORS.Contains(value)) diff --git a/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs b/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs index ae2ac61c90..752615245e 100644 --- a/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs +++ b/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs @@ -175,6 +175,7 @@ namespace osu.Game.Screens.Edit.Components.Menus { if (Item is EditorMenuItemSpacer) return true; + return base.OnHover(e); } @@ -182,6 +183,7 @@ namespace osu.Game.Screens.Edit.Components.Menus { if (Item is EditorMenuItemSpacer) return true; + return base.OnClick(e); } } diff --git a/osu.Game/Screens/Edit/Components/PlaybackControl.cs b/osu.Game/Screens/Edit/Components/PlaybackControl.cs index 12d17f4f0f..227ad29000 100644 --- a/osu.Game/Screens/Edit/Components/PlaybackControl.cs +++ b/osu.Game/Screens/Edit/Components/PlaybackControl.cs @@ -114,7 +114,8 @@ namespace osu.Game.Screens.Edit.Components private readonly OsuSpriteText text; private readonly OsuSpriteText textBold; - public PlaybackTabItem(double value) : base(value) + public PlaybackTabItem(double value) + : base(value) { RelativeSizeAxes = Axes.Both; diff --git a/osu.Game/Screens/Edit/Components/RadioButtons/RadioButtonCollection.cs b/osu.Game/Screens/Edit/Components/RadioButtons/RadioButtonCollection.cs index c6ecdde7f6..16574c0baf 100644 --- a/osu.Game/Screens/Edit/Components/RadioButtons/RadioButtonCollection.cs +++ b/osu.Game/Screens/Edit/Components/RadioButtons/RadioButtonCollection.cs @@ -12,13 +12,15 @@ namespace osu.Game.Screens.Edit.Components.RadioButtons public class RadioButtonCollection : CompositeDrawable { private IReadOnlyList items; + public IReadOnlyList Items { - get { return items; } + get => items; set { if (ReferenceEquals(items, value)) return; + items = value; buttonContainer.Clear(); @@ -42,6 +44,7 @@ namespace osu.Game.Screens.Edit.Components.RadioButtons } private RadioButton currentlySelected; + private void addButton(RadioButton button) { button.Selected.ValueChanged += selected => diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs index 5bc70746bd..102955657e 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs @@ -26,12 +26,12 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts // Consider all non-timing points as the same type cpi.SamplePoints.Select(c => (ControlPoint)c) - .Concat(cpi.EffectPoints) - .Concat(cpi.DifficultyPoints) - .Distinct() - // Non-timing points should not be added where there are timing points - .Where(c => cpi.TimingPointAt(c.Time).Time != c.Time) - .ForEach(addNonTimingPoint); + .Concat(cpi.EffectPoints) + .Concat(cpi.DifficultyPoints) + .Distinct() + // Non-timing points should not be added where there are timing points + .Where(c => cpi.TimingPointAt(c.Time).Time != c.Time) + .ForEach(addNonTimingPoint); } private void addTimingPoint(ControlPoint controlPoint) => Add(new TimingPointVisualisation(controlPoint)); diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs index 3ac34e227b..07d307f293 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs @@ -32,6 +32,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts protected override bool OnDragStart(DragStartEvent e) => true; protected override bool OnDragEnd(DragEndEvent e) => true; + protected override bool OnDrag(DragEvent e) { seekToPosition(e.ScreenSpaceMousePosition); diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index e7a9d148bb..a1e62cd38b 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -68,6 +68,7 @@ namespace osu.Game.Screens.Edit.Compose.Components { if (currentTool == value) return; + currentTool = value; refreshTool(); @@ -188,6 +189,7 @@ namespace osu.Game.Screens.Edit.Compose.Components { if (!(x is SelectionBlueprint xBlueprint) || !(y is SelectionBlueprint yBlueprint)) return base.Compare(x, y); + return Compare(xBlueprint, yBlueprint); } diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs index 42657ef3f7..3b24925f2c 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs @@ -91,7 +91,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline RelativeSizeAxes = Axes.Y, Height = 0.5f, Icon = FontAwesome.fa_search_plus, - Action = () => timeline.Zoom++ + Action = () => changeZoom(1) }, new TimelineButton { @@ -100,7 +100,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline RelativeSizeAxes = Axes.Y, Height = 0.5f, Icon = FontAwesome.fa_search_minus, - Action = () => timeline.Zoom-- + Action = () => changeZoom(-1) }, } } @@ -124,5 +124,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline timeline.WaveformVisible.BindTo(waveformCheckbox.Current); } + + private void changeZoom(float change) => timeline.Zoom += change; } } diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs index 806a55c931..5ded97393b 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs @@ -19,8 +19,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline public FontAwesome Icon { - get { return button.Icon; } - set { button.Icon = value; } + get => button.Icon; + set => button.Icon = value; } private readonly IconButton button; diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs index 2060fe6694..1e94a20dc7 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs @@ -47,6 +47,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline { if (value < 1) throw new ArgumentException($"{nameof(MinZoom)} must be >= 1.", nameof(value)); + minZoom = value; if (Zoom < value) @@ -66,6 +67,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline { if (value < 1) throw new ArgumentException($"{nameof(MaxZoom)} must be >= 1.", nameof(value)); + maxZoom = value; if (Zoom > value) @@ -108,6 +110,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline } private float zoomTarget = 1; + private void setZoomTarget(float newZoom, float focusPoint) { zoomTarget = MathHelper.Clamp(newZoom, MinZoom, MaxZoom); diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index c922e4ef4a..f2d2381d20 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -22,6 +22,8 @@ using osu.Game.Screens.Edit.Components.Menus; using osu.Game.Screens.Edit.Compose; using osu.Game.Screens.Edit.Design; using osuTK.Input; +using System.Collections.Generic; +using osu.Framework; namespace osu.Game.Screens.Edit { @@ -67,6 +69,15 @@ namespace osu.Game.Screens.Edit SummaryTimeline timeline; PlaybackControl playback; + var fileMenuItems = new List(); + if (RuntimeInfo.IsDesktop) + { + fileMenuItems.Add(new EditorMenuItem("Export", MenuItemType.Standard, exportBeatmap)); + fileMenuItems.Add(new EditorMenuItemSpacer()); + } + + fileMenuItems.Add(new EditorMenuItem("Exit", MenuItemType.Standard, this.Exit)); + InternalChildren = new[] { new Container @@ -94,12 +105,7 @@ namespace osu.Game.Screens.Edit { new MenuItem("File") { - Items = new[] - { - new EditorMenuItem("Export", MenuItemType.Standard, exportBeatmap), - new EditorMenuItemSpacer(), - new EditorMenuItem("Exit", MenuItemType.Standard, this.Exit) - } + Items = fileMenuItems } } } diff --git a/osu.Game/Screens/Edit/EditorScreenMode.cs b/osu.Game/Screens/Edit/EditorScreenMode.cs index 12fd67ebfd..12cfcc605b 100644 --- a/osu.Game/Screens/Edit/EditorScreenMode.cs +++ b/osu.Game/Screens/Edit/EditorScreenMode.cs @@ -9,10 +9,13 @@ namespace osu.Game.Screens.Edit { [Description("setup")] SongSetup, + [Description("compose")] Compose, + [Description("design")] Design, + [Description("timing")] Timing, } diff --git a/osu.Game/Screens/Menu/Button.cs b/osu.Game/Screens/Menu/Button.cs index fc285fb724..a02c2a37fa 100644 --- a/osu.Game/Screens/Menu/Button.cs +++ b/osu.Game/Screens/Menu/Button.cs @@ -242,7 +242,7 @@ namespace osu.Game.Screens.Menu public ButtonState State { - get { return state; } + get => state; set { diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 42d67ceffc..1f68818669 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -206,7 +206,7 @@ namespace osu.Game.Screens.Menu public ButtonSystemState State { - get { return state; } + get => state; set { diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index 14124d283f..89f4f92092 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -5,14 +5,17 @@ using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Screens; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Online.API; using osuTK; using osuTK.Graphics; using osu.Game.Overlays; +using osu.Game.Users; namespace osu.Game.Screens.Menu { @@ -33,13 +36,15 @@ namespace osu.Game.Screens.Menu private const float icon_y = -85; + private readonly Bindable currentUser = new Bindable(); + public Disclaimer() { ValidForResume = false; } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, APIAccess api) { InternalChildren = new Drawable[] { @@ -70,13 +75,13 @@ namespace osu.Game.Screens.Menu textFlow.AddParagraph("Things may not work as expected", t => t.Font = t.Font.With(size: 20)); textFlow.NewParagraph(); - Action format = t => t.Font = OsuFont.GetFont(size: 15, weight: FontWeight.Bold); + Action format = t => t.Font = OsuFont.GetFont(size: 15, weight: FontWeight.SemiBold); textFlow.AddParagraph("Detailed bug reports are welcomed via github issues.", format); textFlow.NewParagraph(); textFlow.AddText("Visit ", format); - textFlow.AddLink("discord.gg/ppy", "https://discord.gg/ppy", creationParameters:format); + textFlow.AddLink("discord.gg/ppy", "https://discord.gg/ppy", creationParameters: format); textFlow.AddText(" to help out or follow progress!", format); textFlow.NewParagraph(); @@ -96,6 +101,13 @@ namespace osu.Game.Screens.Menu }).First()); iconColour = colours.Yellow; + + currentUser.BindTo(api.LocalUser); + currentUser.BindValueChanged(e => + { + if (e.NewValue.IsSupporter) + supporterDrawables.ForEach(d => d.FadeOut(500, Easing.OutQuint).Expire()); + }, true); } protected override void LoadComplete() diff --git a/osu.Game/Screens/Menu/IntroSequence.cs b/osu.Game/Screens/Menu/IntroSequence.cs index 98640ef38c..093d01f12d 100644 --- a/osu.Game/Screens/Menu/IntroSequence.cs +++ b/osu.Game/Screens/Menu/IntroSequence.cs @@ -57,7 +57,7 @@ namespace osu.Game.Screens.Menu Anchor = Anchor.Centre, Origin = Anchor.Centre, AutoSizeAxes = Axes.Both, - Children = new [] + Children = new[] { lineTopLeft = new Box { diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs index a45c80669c..e930f924be 100644 --- a/osu.Game/Screens/Menu/LogoVisualisation.cs +++ b/osu.Game/Screens/Menu/LogoVisualisation.cs @@ -156,7 +156,9 @@ namespace osu.Game.Screens.Menu { public Shader Shader; public Texture Texture; + public VisualiserSharedData Shared; + //Asuming the logo is a circle, we don't need a second dimension. public float Size; @@ -213,6 +215,7 @@ namespace osu.Game.Screens.Menu } } } + Shader.Unbind(); } } diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index e682d5f711..af697d37bd 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -62,7 +62,7 @@ namespace osu.Game.Screens.Menu public bool Triangles { - set { colourAndTriangles.FadeTo(value ? 1 : 0, transition_length, Easing.OutQuint); } + set => colourAndTriangles.FadeTo(value ? 1 : 0, transition_length, Easing.OutQuint); } public bool BeatMatching = true; @@ -71,8 +71,8 @@ namespace osu.Game.Screens.Menu public bool Ripple { - get { return rippleContainer.Alpha > 0; } - set { rippleContainer.FadeTo(value ? 1 : 0, transition_length, Easing.OutQuint); } + get => rippleContainer.Alpha > 0; + set => rippleContainer.FadeTo(value ? 1 : 0, transition_length, Easing.OutQuint); } private readonly Box flashLayer; diff --git a/osu.Game/Screens/Multi/Components/BeatmapTitle.cs b/osu.Game/Screens/Multi/Components/BeatmapTitle.cs index 101ff8bf94..e096fb33da 100644 --- a/osu.Game/Screens/Multi/Components/BeatmapTitle.cs +++ b/osu.Game/Screens/Multi/Components/BeatmapTitle.cs @@ -37,6 +37,7 @@ namespace osu.Game.Screens.Multi.Components { if (textSize == value) return; + textSize = value; updateText(); diff --git a/osu.Game/Screens/Multi/Components/DisableableTabControl.cs b/osu.Game/Screens/Multi/Components/DisableableTabControl.cs index 5bd002f8dc..b6b0332cf3 100644 --- a/osu.Game/Screens/Multi/Components/DisableableTabControl.cs +++ b/osu.Game/Screens/Multi/Components/DisableableTabControl.cs @@ -31,6 +31,7 @@ namespace osu.Game.Screens.Multi.Components { if (!Enabled.Value) return true; + return base.OnClick(e); } } diff --git a/osu.Game/Screens/Multi/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/Multi/Lounge/Components/DrawableRoom.cs index 14d66389ca..e41238a7ff 100644 --- a/osu.Game/Screens/Multi/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/Multi/Lounge/Components/DrawableRoom.cs @@ -43,12 +43,14 @@ namespace osu.Game.Screens.Multi.Lounge.Components public readonly Room Room; private SelectionState state; + public SelectionState State { - get { return state; } + get => state; set { if (value == state) return; + state = value; if (state == SelectionState.Selected) @@ -63,9 +65,10 @@ namespace osu.Game.Screens.Multi.Lounge.Components public IEnumerable FilterTerms => new[] { Room.Name.Value }; private bool matchingFilter; + public bool MatchingFilter { - get { return matchingFilter; } + get => matchingFilter; set { matchingFilter = value; diff --git a/osu.Game/Screens/Multi/Lounge/Components/FilterControl.cs b/osu.Game/Screens/Multi/Lounge/Components/FilterControl.cs index 87c4539756..8e14f76e4b 100644 --- a/osu.Game/Screens/Multi/Lounge/Components/FilterControl.cs +++ b/osu.Game/Screens/Multi/Lounge/Components/FilterControl.cs @@ -54,6 +54,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components public enum PrimaryFilter { Open, + [Description("Recently Ended")] RecentlyEnded, Participated, diff --git a/osu.Game/Screens/Multi/Lounge/Components/ParticipantInfo.cs b/osu.Game/Screens/Multi/Lounge/Components/ParticipantInfo.cs index ca5e5f72c4..40e59de25d 100644 --- a/osu.Game/Screens/Multi/Lounge/Components/ParticipantInfo.cs +++ b/osu.Game/Screens/Multi/Lounge/Components/ParticipantInfo.cs @@ -101,7 +101,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components } }, true); - ParticipantCount.BindValueChanged(count => summary.Text = $"{count.NewValue:#,0}{" participant".Pluralize(count.NewValue == 1)}", true); + ParticipantCount.BindValueChanged(count => summary.Text = "participant".ToQuantity(count.NewValue), true); /*Participants.BindValueChanged(e => { diff --git a/osu.Game/Screens/Multi/Match/Components/MatchTabControl.cs b/osu.Game/Screens/Multi/Match/Components/MatchTabControl.cs index 9e04bb6f60..c700d7b88a 100644 --- a/osu.Game/Screens/Multi/Match/Components/MatchTabControl.cs +++ b/osu.Game/Screens/Multi/Match/Components/MatchTabControl.cs @@ -58,6 +58,7 @@ namespace osu.Game.Screens.Multi.Match.Components { if (!enabled.Value) return true; + return base.OnClick(e); } } diff --git a/osu.Game/Screens/Multi/Match/Components/ReadyButton.cs b/osu.Game/Screens/Multi/Match/Components/ReadyButton.cs index 795557b968..86b4cfbfa7 100644 --- a/osu.Game/Screens/Multi/Match/Components/ReadyButton.cs +++ b/osu.Game/Screens/Multi/Match/Components/ReadyButton.cs @@ -39,6 +39,7 @@ namespace osu.Game.Screens.Multi.Match.Components private void load() { beatmaps.ItemAdded += beatmapAdded; + beatmaps.ItemRemoved += beatmapRemoved; Beatmap.BindValueChanged(b => updateBeatmap(b.NewValue), true); } @@ -62,6 +63,15 @@ namespace osu.Game.Screens.Multi.Match.Components Schedule(() => hasBeatmap = true); } + private void beatmapRemoved(BeatmapSetInfo model) + { + if (Beatmap.Value == null) + return; + + if (model.OnlineBeatmapSetID == Beatmap.Value.BeatmapSet.OnlineBeatmapSetID) + Schedule(() => hasBeatmap = false); + } + protected override void Update() { base.Update(); diff --git a/osu.Game/Screens/Multi/Match/Components/RoomAvailabilityPicker.cs b/osu.Game/Screens/Multi/Match/Components/RoomAvailabilityPicker.cs index e9dbd6982d..8751e27552 100644 --- a/osu.Game/Screens/Multi/Match/Components/RoomAvailabilityPicker.cs +++ b/osu.Game/Screens/Multi/Match/Components/RoomAvailabilityPicker.cs @@ -39,7 +39,8 @@ namespace osu.Game.Screens.Multi.Match.Components private readonly Box hover, selection; - public RoomAvailabilityPickerItem(RoomAvailability value) : base(value) + public RoomAvailabilityPickerItem(RoomAvailability value) + : base(value) { RelativeSizeAxes = Axes.Y; Width = 102; diff --git a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs index 3a7d0f18f5..a71106872e 100644 --- a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs +++ b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs @@ -43,7 +43,7 @@ namespace osu.Game.Screens.Multi.Match protected Bindable CurrentItem { get; private set; } [Resolved] - protected Bindable> CurrentMods { get; private set; } + protected Bindable> SelectedMods { get; private set; } [Resolved] private BeatmapManager beatmapManager { get; set; } @@ -194,7 +194,7 @@ namespace osu.Game.Screens.Multi.Match var localBeatmap = e.NewValue?.Beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == e.NewValue.Beatmap.OnlineBeatmapID); Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap); - CurrentMods.Value = e.NewValue?.RequiredMods ?? Enumerable.Empty(); + SelectedMods.Value = e.NewValue?.RequiredMods ?? Enumerable.Empty(); if (e.NewValue?.Ruleset != null) Ruleset.Value = e.NewValue.Ruleset; } @@ -222,7 +222,7 @@ namespace osu.Game.Screens.Multi.Match private void onStart() { - Beatmap.Value.Mods.Value = CurrentMods.Value.ToArray(); + Beatmap.Value.Mods.Value = SelectedMods.Value.ToArray(); switch (type.Value) { diff --git a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs index d127bdc0ea..6b88403b9e 100644 --- a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs +++ b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs @@ -2,7 +2,9 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Threading; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -11,6 +13,8 @@ using osu.Framework.Screens; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.Multiplayer; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Screens.Multi.Ranking; using osu.Game.Screens.Play; @@ -30,6 +34,12 @@ namespace osu.Game.Screens.Multi.Play [Resolved] private APIAccess api { get; set; } + [Resolved] + private IBindable ruleset { get; set; } + + [Resolved] + private Bindable> selectedMods { get; set; } + public TimeshiftPlayer(PlaylistItem playlistItem) { this.playlistItem = playlistItem; @@ -44,6 +54,16 @@ namespace osu.Game.Screens.Multi.Play bool failed = false; + // Sanity checks to ensure that TimeshiftPlayer matches the settings for the current PlaylistItem + if (Beatmap.Value.BeatmapInfo.OnlineBeatmapID != playlistItem.Beatmap.OnlineBeatmapID) + throw new InvalidOperationException("Current Beatmap does not match PlaylistItem's Beatmap"); + + if (ruleset.Value.ID != playlistItem.Ruleset.ID) + throw new InvalidOperationException("Current Ruleset does not match PlaylistItem's Ruleset"); + + if (!playlistItem.RequiredMods.All(m => selectedMods.Value.Contains(m))) + throw new InvalidOperationException("Current Mods do not match PlaylistItem's RequiredMods"); + var req = new CreateRoomScoreRequest(roomId.Value ?? 0, playlistItem.ID); req.Success += r => token = r.ID; req.Failure += e => diff --git a/osu.Game/Screens/Play/Break/BlurredIcon.cs b/osu.Game/Screens/Play/Break/BlurredIcon.cs index 04b87d123f..53b968959c 100644 --- a/osu.Game/Screens/Play/Break/BlurredIcon.cs +++ b/osu.Game/Screens/Play/Break/BlurredIcon.cs @@ -15,8 +15,8 @@ namespace osu.Game.Screens.Play.Break public FontAwesome Icon { - set { icon.Icon = value; } - get { return icon.Icon; } + set => icon.Icon = value; + get => icon.Icon; } public override Vector2 Size @@ -27,7 +27,7 @@ namespace osu.Game.Screens.Play.Break base.Size = value + BlurSigma * 2.5f; ForceRedraw(); } - get { return base.Size; } + get => base.Size; } public BlurredIcon() diff --git a/osu.Game/Screens/Play/Break/BreakInfoLine.cs b/osu.Game/Screens/Play/Break/BreakInfoLine.cs index 4c5e228fa5..4b07405812 100644 --- a/osu.Game/Screens/Play/Break/BreakInfoLine.cs +++ b/osu.Game/Screens/Play/Break/BreakInfoLine.cs @@ -72,7 +72,8 @@ namespace osu.Game.Screens.Play.Break public class PercentageBreakInfoLine : BreakInfoLine { - public PercentageBreakInfoLine(string name, string prefix = "") : base(name, prefix) + public PercentageBreakInfoLine(string name, string prefix = "") + : base(name, prefix) { } diff --git a/osu.Game/Screens/Play/Break/GlowIcon.cs b/osu.Game/Screens/Play/Break/GlowIcon.cs index 8843373ded..8d918cd225 100644 --- a/osu.Game/Screens/Play/Break/GlowIcon.cs +++ b/osu.Game/Screens/Play/Break/GlowIcon.cs @@ -16,7 +16,7 @@ namespace osu.Game.Screens.Play.Break public override Vector2 Size { - get { return base.Size; } + get => base.Size; set { blurredIcon.Size = spriteIcon.Size = value; @@ -26,14 +26,14 @@ namespace osu.Game.Screens.Play.Break public Vector2 BlurSigma { - get { return blurredIcon.BlurSigma; } - set { blurredIcon.BlurSigma = value; } + get => blurredIcon.BlurSigma; + set => blurredIcon.BlurSigma = value; } public FontAwesome Icon { - get { return spriteIcon.Icon; } - set { spriteIcon.Icon = blurredIcon.Icon = value; } + get => spriteIcon.Icon; + set => spriteIcon.Icon = blurredIcon.Icon = value; } public GlowIcon() diff --git a/osu.Game/Screens/Play/GameplayMenuOverlay.cs b/osu.Game/Screens/Play/GameplayMenuOverlay.cs index bcd7452ba6..5d210446c3 100644 --- a/osu.Game/Screens/Play/GameplayMenuOverlay.cs +++ b/osu.Game/Screens/Play/GameplayMenuOverlay.cs @@ -18,6 +18,7 @@ using System.Linq; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Input.Bindings; +using Humanizer; namespace osu.Game.Screens.Play { @@ -184,7 +185,7 @@ namespace osu.Game.Screens.Play private int selectionIndex { - get { return _selectionIndex; } + get => _selectionIndex; set { if (_selectionIndex == value) @@ -263,14 +264,14 @@ namespace osu.Game.Screens.Play }, new OsuSpriteText { - Text = $"{retries:n0}", + Text = "time".ToQuantity(retries), Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 18), Shadow = true, ShadowColour = new Color4(0, 0, 0, 0.25f), }, new OsuSpriteText { - Text = $" time{(retries == 1 ? "" : "s")} in this session", + Text = " in this session", Shadow = true, ShadowColour = new Color4(0, 0, 0, 0.25f), Font = OsuFont.GetFont(size: 18), diff --git a/osu.Game/Screens/Play/HUD/ComboCounter.cs b/osu.Game/Screens/Play/HUD/ComboCounter.cs index eb9db9745f..5ac3dac5f7 100644 --- a/osu.Game/Screens/Play/HUD/ComboCounter.cs +++ b/osu.Game/Screens/Play/HUD/ComboCounter.cs @@ -78,24 +78,27 @@ namespace osu.Game.Screens.Play.HUD } private int displayedCount; + /// /// Value shown at the current moment. /// public virtual int DisplayedCount { - get { return displayedCount; } + get => displayedCount; protected set { if (displayedCount.Equals(value)) return; + updateDisplayedCount(displayedCount, value, IsRolling); } } private float textSize; + public float TextSize { - get { return textSize; } + get => textSize; set { textSize = value; diff --git a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs index 863fee2257..d3dba88281 100644 --- a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs +++ b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs @@ -17,6 +17,7 @@ namespace osu.Game.Screens.Play.HUD public bool ReplayLoaded; public readonly PlaybackSettings PlaybackSettings; + public readonly VisualSettings VisualSettings; //public readonly CollectionSettings CollectionSettings; //public readonly DiscussionSettings DiscussionSettings; diff --git a/osu.Game/Screens/Play/HUD/StandardHealthDisplay.cs b/osu.Game/Screens/Play/HUD/StandardHealthDisplay.cs index f961e6b227..8f09c2b2bf 100644 --- a/osu.Game/Screens/Play/HUD/StandardHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/StandardHealthDisplay.cs @@ -44,18 +44,20 @@ namespace osu.Game.Screens.Play.HUD public Color4 AccentColour { - get { return fill.Colour; } - set { fill.Colour = value; } + get => fill.Colour; + set => fill.Colour = value; } private Color4 glowColour; + public Color4 GlowColour { - get { return glowColour; } + get => glowColour; set { if (glowColour == value) return; + glowColour = value; fill.EdgeEffect = new EdgeEffectParameters diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index b5f04c3474..130d2ecc95 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -241,8 +241,7 @@ namespace osu.Game.Screens.Play ComboCounter?.Current.BindTo(processor.Combo); HealthDisplay?.Current.BindTo(processor.Health); - var shd = HealthDisplay as StandardHealthDisplay; - if (shd != null) + if (HealthDisplay is StandardHealthDisplay shd) processor.NewJudgement += shd.Flash; } } diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs index 406cd3810e..0e1f938137 100644 --- a/osu.Game/Screens/Play/KeyCounter.cs +++ b/osu.Game/Screens/Play/KeyCounter.cs @@ -27,9 +27,10 @@ namespace osu.Game.Screens.Play public bool IsCounting { get; set; } = true; private int countPresses; + public int CountPresses { - get { return countPresses; } + get => countPresses; private set { if (countPresses != value) @@ -41,9 +42,10 @@ namespace osu.Game.Screens.Play } private bool isLit; + public bool IsLit { - get { return isLit; } + get => isLit; protected set { if (isLit != value) diff --git a/osu.Game/Screens/Play/KeyCounterAction.cs b/osu.Game/Screens/Play/KeyCounterAction.cs index 3a17379da9..8deac653ad 100644 --- a/osu.Game/Screens/Play/KeyCounterAction.cs +++ b/osu.Game/Screens/Play/KeyCounterAction.cs @@ -10,7 +10,8 @@ namespace osu.Game.Screens.Play { public T Action { get; } - public KeyCounterAction(T action) : base($"B{(int)(object)action + 1}") + public KeyCounterAction(T action) + : base($"B{(int)(object)action + 1}") { Action = action; } diff --git a/osu.Game/Screens/Play/KeyCounterCollection.cs b/osu.Game/Screens/Play/KeyCounterCollection.cs index 71e8da06ba..0259258636 100644 --- a/osu.Game/Screens/Play/KeyCounterCollection.cs +++ b/osu.Game/Screens/Play/KeyCounterCollection.cs @@ -58,9 +58,10 @@ namespace osu.Game.Screens.Play } private bool isCounting = true; + public bool IsCounting { - get { return isCounting; } + get => isCounting; set { if (value == isCounting) return; @@ -72,9 +73,10 @@ namespace osu.Game.Screens.Play } private int fadeTime; + public int FadeTime { - get { return fadeTime; } + get => fadeTime; set { if (value != fadeTime) @@ -87,9 +89,10 @@ namespace osu.Game.Screens.Play } private Color4 keyDownTextColor = Color4.DarkGray; + public Color4 KeyDownTextColor { - get { return keyDownTextColor; } + get => keyDownTextColor; set { if (value != keyDownTextColor) @@ -102,9 +105,10 @@ namespace osu.Game.Screens.Play } private Color4 keyUpTextColor = Color4.White; + public Color4 KeyUpTextColor { - get { return keyUpTextColor; } + get => keyUpTextColor; set { if (value != keyUpTextColor) @@ -161,6 +165,7 @@ namespace osu.Game.Screens.Play case MouseUpEvent _: return Target.Children.Any(c => c.TriggerEvent(e)); } + return base.Handle(e); } } diff --git a/osu.Game/Screens/Play/KeyCounterKeyboard.cs b/osu.Game/Screens/Play/KeyCounterKeyboard.cs index 9e8d5b9d39..d9b6dca79d 100644 --- a/osu.Game/Screens/Play/KeyCounterKeyboard.cs +++ b/osu.Game/Screens/Play/KeyCounterKeyboard.cs @@ -9,7 +9,9 @@ namespace osu.Game.Screens.Play public class KeyCounterKeyboard : KeyCounter { public Key Key { get; } - public KeyCounterKeyboard(Key key) : base(key.ToString()) + + public KeyCounterKeyboard(Key key) + : base(key.ToString()) { Key = key; } diff --git a/osu.Game/Screens/Play/KeyCounterMouse.cs b/osu.Game/Screens/Play/KeyCounterMouse.cs index 0fe667b403..13dbe40a8b 100644 --- a/osu.Game/Screens/Play/KeyCounterMouse.cs +++ b/osu.Game/Screens/Play/KeyCounterMouse.cs @@ -11,7 +11,8 @@ namespace osu.Game.Screens.Play { public MouseButton Button { get; } - public KeyCounterMouse(MouseButton button) : base(getStringRepresentation(button)) + public KeyCounterMouse(MouseButton button) + : base(getStringRepresentation(button)) { Button = button; } diff --git a/osu.Game/Screens/Play/PauseContainer.cs b/osu.Game/Screens/Play/PauseContainer.cs index 0222cefdd3..8961d91763 100644 --- a/osu.Game/Screens/Play/PauseContainer.cs +++ b/osu.Game/Screens/Play/PauseContainer.cs @@ -32,7 +32,10 @@ namespace osu.Game.Screens.Play protected override Container Content => content; - public int Retries { set { pauseOverlay.Retries = value; } } + public int Retries + { + set => pauseOverlay.Retries = value; + } public bool CanPause => (CheckCanPause?.Invoke() ?? true) && Time.Current >= lastPauseActionTime + pause_cooldown; public bool IsResuming { get; private set; } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index fbdc382d18..ee59df0e98 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -19,7 +19,6 @@ using osu.Framework.Threading; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Configuration; -using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Cursor; using osu.Game.Online.API; @@ -32,7 +31,6 @@ using osu.Game.Scoring; using osu.Game.Screens.Ranking; using osu.Game.Skinning; using osu.Game.Storyboards.Drawables; -using osuTK.Graphics; namespace osu.Game.Screens.Play { @@ -57,6 +55,8 @@ namespace osu.Game.Screens.Play private Bindable mouseWheelDisabled; private Bindable userAudioOffset; + private readonly Bindable storyboardReplacesBackground = new Bindable(); + public int RestartCount; public CursorContainer Cursor => RulesetContainer.Cursor; @@ -72,7 +72,7 @@ namespace osu.Game.Screens.Play [Resolved] private ScoreManager scoreManager { get; set; } - private PauseContainer pauseContainer; + protected PauseContainer PauseContainer { get; private set; } private RulesetInfo ruleset; @@ -80,14 +80,21 @@ namespace osu.Game.Screens.Play private SampleChannel sampleRestart; - protected ScoreProcessor ScoreProcessor; - protected RulesetContainer RulesetContainer; + protected ScoreProcessor ScoreProcessor { get; private set; } + protected RulesetContainer RulesetContainer { get; private set; } - protected HUDOverlay HUDOverlay; + protected HUDOverlay HUDOverlay { get; private set; } private FailOverlay failOverlay; private DrawableStoryboard storyboard; - private Container storyboardContainer; + protected UserDimContainer StoryboardContainer { get; private set; } + + protected virtual UserDimContainer CreateStoryboardContainer() => new UserDimContainer(true) + { + RelativeSizeAxes = Axes.Both, + Alpha = 1, + EnableUserDim = { Value = true } + }; public bool LoadedBeatmapSuccessfully => RulesetContainer?.Objects.Any() == true; @@ -168,19 +175,15 @@ namespace osu.Game.Screens.Play InternalChildren = new Drawable[] { - pauseContainer = new PauseContainer(offsetClock, adjustableClock) + PauseContainer = new PauseContainer(offsetClock, adjustableClock) { Retries = RestartCount, OnRetry = Restart, OnQuit = performUserRequestedExit, CheckCanPause = () => AllowPause && ValidForResume && !HasFailed && !RulesetContainer.HasReplayLoaded.Value, - Children = new[] + Children = new Container[] { - storyboardContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - }, + StoryboardContainer = CreateStoryboardContainer(), new ScalingContainer(ScalingMode.Gameplay) { Child = new LocalSkinOverrideContainer(working.Skin) @@ -236,7 +239,7 @@ namespace osu.Game.Screens.Play HUDOverlay.HoldToQuit.Action = performUserRequestedExit; HUDOverlay.KeyCounter.Visible.BindTo(RulesetContainer.HasReplayLoaded); - RulesetContainer.IsPaused.BindTo(pauseContainer.IsPaused); + RulesetContainer.IsPaused.BindTo(PauseContainer.IsPaused); if (ShowStoryboard.Value) initializeStoryboard(false); @@ -261,6 +264,7 @@ namespace osu.Game.Screens.Play private void performUserRequestedExit() { if (!this.IsCurrentScreen()) return; + this.Exit(); } @@ -296,7 +300,7 @@ namespace osu.Game.Screens.Play if (RulesetContainer.ReplayScore == null) scoreManager.Import(score); - this.Push(CreateResults(score)); + this.Push(CreateResults(score)); onCompletionEvent = null; }); @@ -345,6 +349,18 @@ namespace osu.Game.Screens.Play .Delay(250) .FadeIn(250); + ShowStoryboard.ValueChanged += enabled => + { + if (enabled.NewValue) initializeStoryboard(true); + }; + + Background.EnableUserDim.Value = true; + + Background.StoryboardReplacesBackground.BindTo(storyboardReplacesBackground); + StoryboardContainer.StoryboardReplacesBackground.BindTo(storyboardReplacesBackground); + + storyboardReplacesBackground.Value = Beatmap.Value.Storyboard.ReplacesBackground && Beatmap.Value.Storyboard.HasDrawable; + Task.Run(() => { sourceClock.Reset(); @@ -356,7 +372,7 @@ namespace osu.Game.Screens.Play this.Delay(750).Schedule(() => { - if (!pauseContainer.IsPaused.Value) + if (!PauseContainer.IsPaused.Value) { adjustableClock.Start(); } @@ -364,8 +380,8 @@ namespace osu.Game.Screens.Play }); }); - pauseContainer.Alpha = 0; - pauseContainer.FadeIn(750, Easing.OutQuint); + PauseContainer.Alpha = 0; + PauseContainer.FadeIn(750, Easing.OutQuint); } public override void OnSuspending(IScreen next) @@ -383,17 +399,16 @@ namespace osu.Game.Screens.Play return true; } - if ((!AllowPause || HasFailed || !ValidForResume || pauseContainer?.IsPaused.Value != false || RulesetContainer?.HasReplayLoaded.Value != false) && (!pauseContainer?.IsResuming ?? true)) + if ((!AllowPause || HasFailed || !ValidForResume || PauseContainer?.IsPaused.Value != false || RulesetContainer?.HasReplayLoaded.Value != false) && (!PauseContainer?.IsResuming ?? true)) { // In the case of replays, we may have changed the playback rate. applyRateFromMods(); - fadeOut(); return base.OnExiting(next); } if (LoadedBeatmapSuccessfully) - pauseContainer?.Pause(); + PauseContainer?.Pause(); return true; } @@ -402,14 +417,16 @@ namespace osu.Game.Screens.Play { float fadeOutDuration = instant ? 0 : 250; this.FadeOut(fadeOutDuration); - Background?.FadeColour(Color4.White, fadeOutDuration, Easing.OutQuint); + + Background.EnableUserDim.Value = false; + storyboardReplacesBackground.Value = false; } - protected override bool OnScroll(ScrollEvent e) => mouseWheelDisabled.Value && !pauseContainer.IsPaused.Value; + protected override bool OnScroll(ScrollEvent e) => mouseWheelDisabled.Value && !PauseContainer.IsPaused.Value; private void initializeStoryboard(bool asyncLoad) { - if (storyboardContainer == null) + if (StoryboardContainer == null || storyboard != null) return; var beatmap = Beatmap.Value; @@ -418,29 +435,9 @@ namespace osu.Game.Screens.Play storyboard.Masking = true; if (asyncLoad) - LoadComponentAsync(storyboard, storyboardContainer.Add); + LoadComponentAsync(storyboard, StoryboardContainer.Add); else - storyboardContainer.Add(storyboard); - } - - protected override void UpdateBackgroundElements() - { - if (!this.IsCurrentScreen()) return; - - base.UpdateBackgroundElements(); - - if (ShowStoryboard.Value && storyboard == null) - initializeStoryboard(true); - - var beatmap = Beatmap.Value; - var storyboardVisible = ShowStoryboard.Value && beatmap.Storyboard.HasDrawable; - - storyboardContainer? - .FadeColour(OsuColour.Gray(BackgroundOpacity), BACKGROUND_FADE_DURATION, Easing.OutQuint) - .FadeTo(storyboardVisible && BackgroundOpacity > 0 ? 1 : 0, BACKGROUND_FADE_DURATION, Easing.OutQuint); - - if (storyboardVisible && beatmap.Storyboard.ReplacesBackground) - Background?.FadeColour(Color4.Black, BACKGROUND_FADE_DURATION, Easing.OutQuint); + StoryboardContainer.Add(storyboard); } protected virtual Results CreateResults(ScoreInfo score) => new SoloResults(score); diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index ac4cc30874..5c9acade7b 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -78,7 +78,7 @@ namespace osu.Game.Screens.Play Margin = new MarginPadding(25), Children = new PlayerSettingsGroup[] { - visualSettings = new VisualSettings(), + VisualSettings = new VisualSettings(), new InputSettings() } } @@ -151,23 +151,31 @@ namespace osu.Game.Screens.Play } private ScheduledDelegate pushDebounce; - private VisualSettings visualSettings; + protected VisualSettings VisualSettings; private bool readyForPush => player.LoadState == LoadState.Ready && IsHovered && GetContainingInputManager()?.DraggedDrawable == null; protected override bool OnHover(HoverEvent e) { // restore our screen defaults - InitializeBackgroundElements(); + if (this.IsCurrentScreen()) + { + InitializeBackgroundElements(); + Background.EnableUserDim.Value = false; + } + return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { - if (GetContainingInputManager()?.HoveredDrawables.Contains(visualSettings) == true) + if (GetContainingInputManager()?.HoveredDrawables.Contains(VisualSettings) == true) { - // show user setting preview + // Update background elements is only being called here because blur logic still exists in Player. + // Will need to be removed when resolving https://github.com/ppy/osu/issues/4322 UpdateBackgroundElements(); + if (this.IsCurrentScreen()) + Background.EnableUserDim.Value = true; } base.OnHoverLost(e); @@ -241,6 +249,8 @@ namespace osu.Game.Screens.Play this.FadeOut(150); cancelLoad(); + Background.EnableUserDim.Value = false; + return base.OnExiting(next); } diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs index 49bcf0b8dc..efaeeea79f 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs @@ -34,10 +34,11 @@ namespace osu.Game.Screens.Play.PlayerSettings public bool Expanded { - get { return expanded; } + get => expanded; set { if (expanded == value) return; + expanded = value; content.ClearTransforms(); diff --git a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs index c28a01155c..328aa1d18e 100644 --- a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs +++ b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs @@ -6,7 +6,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Screens; using osu.Game.Configuration; -using osu.Game.Graphics; using osu.Game.Screens.Backgrounds; using osuTK; @@ -16,15 +15,12 @@ namespace osu.Game.Screens.Play { protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value); - protected new BackgroundScreenBeatmap Background => base.Background as BackgroundScreenBeatmap; + protected new BackgroundScreenBeatmap Background => (BackgroundScreenBeatmap)base.Background; protected const float BACKGROUND_FADE_DURATION = 800; - protected float BackgroundOpacity => 1 - (float)DimLevel.Value; - #region User Settings - protected Bindable DimLevel; protected Bindable BlurLevel; protected Bindable ShowStoryboard; @@ -33,7 +29,6 @@ namespace osu.Game.Screens.Play [BackgroundDependencyLoader] private void load(OsuConfigManager config) { - DimLevel = config.GetBindable(OsuSetting.DimLevel); BlurLevel = config.GetBindable(OsuSetting.BlurLevel); ShowStoryboard = config.GetBindable(OsuSetting.ShowStoryboard); } @@ -41,9 +36,7 @@ namespace osu.Game.Screens.Play public override void OnEntering(IScreen last) { base.OnEntering(last); - DimLevel.ValueChanged += _ => UpdateBackgroundElements(); BlurLevel.ValueChanged += _ => UpdateBackgroundElements(); - ShowStoryboard.ValueChanged += _ => UpdateBackgroundElements(); InitializeBackgroundElements(); } @@ -66,7 +59,6 @@ namespace osu.Game.Screens.Play { if (!this.IsCurrentScreen()) return; - Background?.FadeColour(OsuColour.Gray(BackgroundOpacity), BACKGROUND_FADE_DURATION, Easing.OutQuint); Background?.BlurTo(new Vector2((float)BlurLevel.Value * 25), BACKGROUND_FADE_DURATION, Easing.OutQuint); } } diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index f5983029e2..010d9228de 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -158,7 +158,7 @@ namespace osu.Game.Screens.Play public Visibility State { - get { return state; } + get => state; set { bool stateChanged = value != state; diff --git a/osu.Game/Screens/Play/SongProgress.cs b/osu.Game/Screens/Play/SongProgress.cs index 443df27b42..3c7e3b2067 100644 --- a/osu.Game/Screens/Play/SongProgress.cs +++ b/osu.Game/Screens/Play/SongProgress.cs @@ -35,7 +35,11 @@ namespace osu.Game.Screens.Play public override bool HandlePositionalInput => AllowSeeking; private IClock audioClock; - public IClock AudioClock { set { audioClock = info.AudioClock = value; } } + + public IClock AudioClock + { + set => audioClock = info.AudioClock = value; + } private double lastHitTime => ((objects.Last() as IHasEndTime)?.EndTime ?? objects.Last().StartTime) + 1; @@ -94,7 +98,7 @@ namespace osu.Game.Screens.Play { Alpha = 0, Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, OnSeek = position => OnSeek?.Invoke(position), }, }; @@ -117,11 +121,7 @@ namespace osu.Game.Screens.Play public bool AllowSeeking { - get - { - return allowSeeking; - } - + get => allowSeeking; set { if (allowSeeking == value) return; diff --git a/osu.Game/Screens/Play/SongProgressBar.cs b/osu.Game/Screens/Play/SongProgressBar.cs index ee9d711d54..2e7d452fe7 100644 --- a/osu.Game/Screens/Play/SongProgressBar.cs +++ b/osu.Game/Screens/Play/SongProgressBar.cs @@ -20,22 +20,22 @@ namespace osu.Game.Screens.Play public Color4 FillColour { - set { fill.Colour = value; } + set => fill.Colour = value; } public double StartTime { - set { CurrentNumber.MinValue = value; } + set => CurrentNumber.MinValue = value; } public double EndTime { - set { CurrentNumber.MaxValue = value; } + set => CurrentNumber.MaxValue = value; } public double CurrentTime { - set { CurrentNumber.Value = value; } + set => CurrentNumber.Value = value; } public SongProgressBar(float barHeight, float handleBarHeight, Vector2 handleSize) diff --git a/osu.Game/Screens/Play/SongProgressInfo.cs b/osu.Game/Screens/Play/SongProgressInfo.cs index d24e484001..369abb53c8 100644 --- a/osu.Game/Screens/Play/SongProgressInfo.cs +++ b/osu.Game/Screens/Play/SongProgressInfo.cs @@ -29,8 +29,15 @@ namespace osu.Game.Screens.Play public IClock AudioClock; - public double StartTime { set { startTime = value; } } - public double EndTime { set { endTime = value; } } + public double StartTime + { + set => startTime = value; + } + + public double EndTime + { + set => endTime = value; + } [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game/Screens/Play/SquareGraph.cs b/osu.Game/Screens/Play/SquareGraph.cs index ad52c31108..d10034d552 100644 --- a/osu.Game/Screens/Play/SquareGraph.cs +++ b/osu.Game/Screens/Play/SquareGraph.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using osu.Framework; using osu.Framework.Caching; using osu.Framework.Extensions.Color4Extensions; @@ -12,22 +13,26 @@ using osu.Framework.Graphics.Containers; using osuTK; using osuTK.Graphics; using osu.Framework.Graphics.Shapes; +using osu.Framework.Allocation; +using osu.Framework.Threading; namespace osu.Game.Screens.Play { - public class SquareGraph : BufferedContainer + public class SquareGraph : Container { - private Column[] columns = { }; + private BufferedContainer columns; - public int ColumnCount => columns.Length; + public int ColumnCount => columns?.Children.Count ?? 0; private int progress; + public int Progress { - get { return progress; } + get => progress; set { if (value == progress) return; + progress = value; redrawProgress(); } @@ -36,36 +41,33 @@ namespace osu.Game.Screens.Play private float[] calculatedValues = { }; // values but adjusted to fit the amount of columns private int[] values; + public int[] Values { - get { return values; } + get => values; set { if (value == values) return; + values = value; layout.Invalidate(); } } private Color4 fillColour; + public Color4 FillColour { - get { return fillColour; } + get => fillColour; set { if (value == fillColour) return; + fillColour = value; redrawFilled(); } } - public SquareGraph() - { - CacheDrawnFrameBuffer = true; - } - - private Cached layout = new Cached(); - public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true) { if ((invalidation & Invalidation.DrawSize) > 0) @@ -73,25 +75,70 @@ namespace osu.Game.Screens.Play return base.Invalidate(invalidation, source, shallPropagate); } + private Cached layout = new Cached(); + private ScheduledDelegate scheduledCreate; + protected override void Update() { base.Update(); - if (!layout.IsValid) + if (values != null && !layout.IsValid) { - recreateGraph(); + columns?.FadeOut(500, Easing.OutQuint).Expire(); + + scheduledCreate?.Cancel(); + scheduledCreate = Scheduler.AddDelayed(RecreateGraph, 500); + layout.Validate(); } } + private CancellationTokenSource cts; + + /// + /// Recreates the entire graph. + /// + protected virtual void RecreateGraph() + { + var newColumns = new BufferedContainer + { + CacheDrawnFrameBuffer = true, + RelativeSizeAxes = Axes.Both, + }; + + for (float x = 0; x < DrawWidth; x += Column.WIDTH) + { + newColumns.Add(new Column(DrawHeight) + { + LitColour = fillColour, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Position = new Vector2(x, 0), + State = ColumnState.Dimmed, + }); + } + + cts?.Cancel(); + + LoadComponentAsync(newColumns, c => + { + Child = columns = c; + columns.FadeInFromZero(500, Easing.OutQuint); + + recalculateValues(); + redrawFilled(); + redrawProgress(); + }, (cts = new CancellationTokenSource()).Token); + } + /// /// Redraws all the columns to match their lit/dimmed state. /// private void redrawProgress() { - for (int i = 0; i < columns.Length; i++) + for (int i = 0; i < ColumnCount; i++) columns[i].State = i <= progress ? ColumnState.Lit : ColumnState.Dimmed; - ForceRedraw(); + columns?.ForceRedraw(); } /// @@ -101,7 +148,7 @@ namespace osu.Game.Screens.Play { for (int i = 0; i < ColumnCount; i++) columns[i].Filled = calculatedValues.ElementAtOrDefault(i); - ForceRedraw(); + columns?.ForceRedraw(); } /// @@ -130,34 +177,6 @@ namespace osu.Game.Screens.Play calculatedValues = newValues.ToArray(); } - /// - /// Recreates the entire graph. - /// - private void recreateGraph() - { - var newColumns = new List(); - - for (float x = 0; x < DrawWidth; x += Column.WIDTH) - { - newColumns.Add(new Column - { - LitColour = fillColour, - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Height = DrawHeight, - Position = new Vector2(x, 0), - State = ColumnState.Dimmed, - }); - } - - columns = newColumns.ToArray(); - Children = columns; - - recalculateValues(); - redrawFilled(); - redrawProgress(); - } - public class Column : Container, IStateful { protected readonly Color4 EmptyColour = Color4.White.Opacity(20); @@ -174,14 +193,15 @@ namespace osu.Game.Screens.Play private readonly List drawableRows = new List(); private float filled; + public float Filled { - get { return filled; } + get => filled; set { if (value == filled) return; - filled = value; + filled = value; fillActive(); } } @@ -190,12 +210,12 @@ namespace osu.Game.Screens.Play public ColumnState State { - get { return state; } + get => state; set { if (value == state) return; - state = value; + state = value; if (IsLoaded) fillActive(); @@ -203,27 +223,30 @@ namespace osu.Game.Screens.Play } } - public Column() + public Column(float height) { Width = WIDTH; + Height = height; } - protected override void LoadComplete() + [BackgroundDependencyLoader] + private void load() { - for (int r = 0; r < cubeCount; r++) + drawableRows.AddRange(Enumerable.Range(0, (int)cubeCount).Select(r => new Box { - drawableRows.Add(new Box - { - Size = new Vector2(cube_size), - Position = new Vector2(0, r * WIDTH + padding), - }); - } + Size = new Vector2(cube_size), + Position = new Vector2(0, r * WIDTH + padding), + })); Children = drawableRows; // Reverse drawableRows so when iterating through them they start at the bottom drawableRows.Reverse(); + } + protected override void LoadComplete() + { + base.LoadComplete(); fillActive(); } diff --git a/osu.Game/Screens/Ranking/Pages/ScoreResultsPage.cs b/osu.Game/Screens/Ranking/Pages/ScoreResultsPage.cs index 09b5b7ea49..043bf55d2b 100644 --- a/osu.Game/Screens/Ranking/Pages/ScoreResultsPage.cs +++ b/osu.Game/Screens/Ranking/Pages/ScoreResultsPage.cs @@ -213,14 +213,16 @@ namespace osu.Game.Screens.Ranking.Pages { Children = new Drawable[] { - new OsuSpriteText { + new OsuSpriteText + { Text = statistic.Value.ToString().PadLeft(4, '0'), Colour = colours.Gray7, Font = OsuFont.GetFont(size: 30), Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, }, - new OsuSpriteText { + new OsuSpriteText + { Text = statistic.Key.GetDescription(), Colour = colours.Gray7, Font = OsuFont.GetFont(weight: FontWeight.Bold), @@ -334,7 +336,8 @@ namespace osu.Game.Screens.Ranking.Pages versionMapper.Colour = colours.Gray8; var creator = beatmap.Metadata.Author?.Username; - if (!string.IsNullOrEmpty(creator)) { + if (!string.IsNullOrEmpty(creator)) + { versionMapper.Text = $"mapped by {creator}"; if (!string.IsNullOrEmpty(beatmap.Version)) @@ -388,7 +391,8 @@ namespace osu.Game.Screens.Ranking.Pages protected override Easing RollingEasing => Easing.OutPow10; - public SlowScoreCounter(uint leading = 0) : base(leading) + public SlowScoreCounter(uint leading = 0) + : base(leading) { DisplayedCountSpriteText.Shadow = false; DisplayedCountSpriteText.Font = DisplayedCountSpriteText.Font.With(Typeface.Venera, weight: FontWeight.Light); diff --git a/osu.Game/Screens/ScreenWhiteBox.cs b/osu.Game/Screens/ScreenWhiteBox.cs index c8ca21d4ba..b222b91221 100644 --- a/osu.Game/Screens/ScreenWhiteBox.cs +++ b/osu.Game/Screens/ScreenWhiteBox.cs @@ -169,10 +169,7 @@ namespace osu.Game.Screens Text = $@"{t.Name}", BackgroundColour = getColourFor(t), HoverColour = getColourFor(t).Lighten(0.2f), - Action = delegate - { - this.Push(Activator.CreateInstance(t) as Screen); - } + Action = delegate { this.Push(Activator.CreateInstance(t) as Screen); } }); } } diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 4490818a23..389f614ef2 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -254,6 +254,7 @@ namespace osu.Game.Screens.Select { case CarouselBeatmap beatmap: if (skipDifficulties) continue; + select(beatmap); return; case CarouselBeatmapSet set: @@ -327,6 +328,7 @@ namespace osu.Game.Screens.Select private void select(CarouselItem item) { if (item == null) return; + item.State.Value = CarouselItemState.Selected; } diff --git a/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs b/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs new file mode 100644 index 0000000000..a37327f2c3 --- /dev/null +++ b/osu.Game/Screens/Select/BeatmapClearScoresDialog.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.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Overlays.Dialog; +using osu.Game.Scoring; +using System; +using System.Linq; +using System.Threading.Tasks; + +namespace osu.Game.Screens.Select +{ + public class BeatmapClearScoresDialog : PopupDialog + { + private ScoreManager scoreManager; + + public BeatmapClearScoresDialog(BeatmapInfo beatmap, Action onCompletion) + { + BodyText = $@"{beatmap.Metadata?.Artist} - {beatmap.Metadata?.Title}"; + Icon = FontAwesome.fa_eraser; + HeaderText = @"Clearing all local scores. Are you sure?"; + Buttons = new PopupDialogButton[] + { + new PopupDialogOkButton + { + Text = @"Yes. Please.", + Action = () => + { + Task.Run(() => scoreManager.Delete(scoreManager.QueryScores(s => !s.DeletePending && s.Beatmap.ID == beatmap.ID).ToList())) + .ContinueWith(_ => onCompletion); + } + }, + new PopupDialogCancelButton + { + Text = @"No, I'm still attached.", + }, + }; + } + + [BackgroundDependencyLoader] + private void load(ScoreManager scoreManager) + { + this.scoreManager = scoreManager; + } + } +} diff --git a/osu.Game/Screens/Select/BeatmapDetailArea.cs b/osu.Game/Screens/Select/BeatmapDetailArea.cs index 03e94c86b6..477037355c 100644 --- a/osu.Game/Screens/Select/BeatmapDetailArea.cs +++ b/osu.Game/Screens/Select/BeatmapDetailArea.cs @@ -20,12 +20,10 @@ namespace osu.Game.Screens.Select public readonly BeatmapLeaderboard Leaderboard; private WorkingBeatmap beatmap; + public WorkingBeatmap Beatmap { - get - { - return beatmap; - } + get => beatmap; set { beatmap = value; diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 9f9263927e..604d7a132b 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -41,12 +41,14 @@ namespace osu.Game.Screens.Select private ScheduledDelegate pendingBeatmapSwitch; private BeatmapInfo beatmap; + public BeatmapInfo Beatmap { - get { return beatmap; } + get => beatmap; set { if (value == beatmap) return; + beatmap = value; pendingBeatmapSwitch?.Cancel(); diff --git a/osu.Game/Screens/Select/Carousel/CarouselGroup.cs b/osu.Game/Screens/Select/Carousel/CarouselGroup.cs index edb9d79ddb..5d8f4f0ec6 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselGroup.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselGroup.cs @@ -96,6 +96,7 @@ namespace osu.Game.Screens.Select.Carousel foreach (var b in InternalChildren) { if (item == b) continue; + b.State.Value = CarouselItemState.NotSelected; } diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs index 00fce20ac3..38ca9a9aed 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs @@ -38,7 +38,8 @@ namespace osu.Game.Screens.Select.Carousel private BeatmapSetOverlay beatmapOverlay; - public DrawableCarouselBeatmap(CarouselBeatmap panel) : base(panel) + public DrawableCarouselBeatmap(CarouselBeatmap panel) + : base(panel) { beatmap = panel.Beatmap; Height *= 0.60f; diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index 540d74a8d3..e01149ebc8 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -49,11 +49,11 @@ namespace osu.Game.Screens.Select.Carousel Children = new Drawable[] { new DelayedLoadUnloadWrapper(() => - new PanelBackground(manager.GetWorkingBeatmap(beatmapSet.Beatmaps.FirstOrDefault())) - { - RelativeSizeAxes = Axes.Both, - OnLoadComplete = d => d.FadeInFromZero(1000, Easing.OutQuint), - }, 300, 5000 + new PanelBackground(manager.GetWorkingBeatmap(beatmapSet.Beatmaps.FirstOrDefault())) + { + RelativeSizeAxes = Axes.Both, + OnLoadComplete = d => d.FadeInFromZero(1000, Easing.OutQuint), + }, 300, 5000 ), new FillFlowContainer { diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs index 2d897148c1..52a57dd506 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs @@ -20,12 +20,14 @@ namespace osu.Game.Screens.Select.Details private readonly StatisticRow firstValue, hpDrain, accuracy, approachRate, starDifficulty; private BeatmapInfo beatmap; + public BeatmapInfo Beatmap { - get { return beatmap; } + get => beatmap; set { if (value == beatmap) return; + beatmap = value; //mania specific @@ -83,14 +85,15 @@ namespace osu.Game.Screens.Select.Details public string Title { - get { return name.Text; } - set { name.Text = value; } + get => name.Text; + set => name.Text = value; } private float difficultyValue; + public float Value { - get { return difficultyValue; } + get => difficultyValue; set { difficultyValue = value; @@ -101,8 +104,8 @@ namespace osu.Game.Screens.Select.Details public Color4 AccentColour { - get { return bar.AccentColour; } - set { bar.AccentColour = value; } + get => bar.AccentColour; + set => bar.AccentColour = value; } public StatisticRow(float maxValue = 10, bool forceDecimalPlaces = false) diff --git a/osu.Game/Screens/Select/Details/FailRetryGraph.cs b/osu.Game/Screens/Select/Details/FailRetryGraph.cs index 32067a69a0..34297d89a4 100644 --- a/osu.Game/Screens/Select/Details/FailRetryGraph.cs +++ b/osu.Game/Screens/Select/Details/FailRetryGraph.cs @@ -17,12 +17,14 @@ namespace osu.Game.Screens.Select.Details private readonly BarGraph retryGraph, failGraph; private BeatmapMetrics metrics; + public BeatmapMetrics Metrics { - get { return metrics; } + get => metrics; set { if (value == metrics) return; + metrics = value; var retries = Metrics?.Retries ?? new int[0]; diff --git a/osu.Game/Screens/Select/Details/UserRatings.cs b/osu.Game/Screens/Select/Details/UserRatings.cs index db796ba5d2..b17a3f79e9 100644 --- a/osu.Game/Screens/Select/Details/UserRatings.cs +++ b/osu.Game/Screens/Select/Details/UserRatings.cs @@ -24,10 +24,11 @@ namespace osu.Game.Screens.Select.Details public BeatmapMetrics Metrics { - get { return metrics; } + get => metrics; set { if (value == metrics) return; + metrics = value; const int rating_range = 10; diff --git a/osu.Game/Screens/Select/Filter/GroupMode.cs b/osu.Game/Screens/Select/Filter/GroupMode.cs index 6abb32bbac..d794c215a3 100644 --- a/osu.Game/Screens/Select/Filter/GroupMode.cs +++ b/osu.Game/Screens/Select/Filter/GroupMode.cs @@ -9,32 +9,46 @@ namespace osu.Game.Screens.Select.Filter { [Description("All")] All, + [Description("Artist")] Artist, + [Description("Author")] Author, + [Description("BPM")] BPM, + [Description("Collections")] Collections, + [Description("Date Added")] DateAdded, + [Description("Difficulty")] Difficulty, + [Description("Favourites")] Favourites, + [Description("Length")] Length, + [Description("My Maps")] MyMaps, + [Description("No Grouping")] NoGrouping, + [Description("Rank Achieved")] RankAchieved, + [Description("Ranked Status")] RankedStatus, + [Description("Recently Played")] RecentlyPlayed, + [Description("Title")] Title } diff --git a/osu.Game/Screens/Select/Filter/SortMode.cs b/osu.Game/Screens/Select/Filter/SortMode.cs index 92ae177011..be76fbc3ba 100644 --- a/osu.Game/Screens/Select/Filter/SortMode.cs +++ b/osu.Game/Screens/Select/Filter/SortMode.cs @@ -9,18 +9,25 @@ namespace osu.Game.Screens.Select.Filter { [Description("Artist")] Artist, + [Description("Author")] Author, + [Description("BPM")] BPM, + [Description("Date Added")] DateAdded, + [Description("Difficulty")] Difficulty, + [Description("Length")] Length, + [Description("Rank Achieved")] RankAchieved, + [Description("Title")] Title } diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index 72a15e37e1..bd0b0dd5cd 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -32,7 +32,7 @@ namespace osu.Game.Screens.Select public SortMode Sort { - get { return sort; } + get => sort; set { if (sort != value) @@ -47,7 +47,7 @@ namespace osu.Game.Screens.Select public GroupMode Group { - get { return group; } + get => group; set { if (group != value) diff --git a/osu.Game/Screens/Select/FilterCriteria.cs b/osu.Game/Screens/Select/FilterCriteria.cs index 4c3b77d483..140010ff54 100644 --- a/osu.Game/Screens/Select/FilterCriteria.cs +++ b/osu.Game/Screens/Select/FilterCriteria.cs @@ -22,7 +22,7 @@ namespace osu.Game.Screens.Select public string SearchText { - get { return searchText; } + get => searchText; set { searchText = value; diff --git a/osu.Game/Screens/Select/FooterButton.cs b/osu.Game/Screens/Select/FooterButton.cs index aa8b48588a..9b98e344ce 100644 --- a/osu.Game/Screens/Select/FooterButton.cs +++ b/osu.Game/Screens/Select/FooterButton.cs @@ -20,7 +20,7 @@ namespace osu.Game.Screens.Select public string Text { - get { return spriteText?.Text; } + get => spriteText?.Text; set { if (spriteText != null) @@ -29,9 +29,10 @@ namespace osu.Game.Screens.Select } private Color4 deselectedColour; + public Color4 DeselectedColour { - get { return deselectedColour; } + get => deselectedColour; set { deselectedColour = value; @@ -41,9 +42,10 @@ namespace osu.Game.Screens.Select } private Color4 selectedColour; + public Color4 SelectedColour { - get { return selectedColour; } + get => selectedColour; set { selectedColour = value; diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index 4f1fd0188e..61370f7ce3 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -23,7 +23,7 @@ namespace osu.Game.Screens.Select.Leaderboards public BeatmapInfo Beatmap { - get { return beatmap; } + get => beatmap; set { if (beatmap == value) @@ -55,7 +55,7 @@ namespace osu.Game.Screens.Select.Leaderboards { if (Scope == BeatmapLeaderboardScope.Local) { - Scores = scoreManager.QueryScores(s => s.Beatmap.ID == Beatmap.ID).ToArray(); + Scores = scoreManager.QueryScores(s => !s.DeletePending && s.Beatmap.ID == Beatmap.ID).ToArray(); PlaceholderState = Scores.Any() ? PlaceholderState.Successful : PlaceholderState.NoScores; return null; } diff --git a/osu.Game/Screens/Select/MatchSongSelect.cs b/osu.Game/Screens/Select/MatchSongSelect.cs index cfeaa1785e..f6d758df29 100644 --- a/osu.Game/Screens/Select/MatchSongSelect.cs +++ b/osu.Game/Screens/Select/MatchSongSelect.cs @@ -2,10 +2,15 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using Humanizer; +using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Screens; +using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; +using osu.Game.Rulesets.Mods; using osu.Game.Screens.Multi; namespace osu.Game.Screens.Select @@ -17,6 +22,15 @@ namespace osu.Game.Screens.Select public string ShortTitle => "song selection"; public override string Title => ShortTitle.Humanize(); + [Resolved(typeof(Room))] + protected Bindable CurrentItem { get; private set; } + + [Resolved] + private Bindable> selectedMods { get; set; } + + [Resolved] + private BeatmapManager beatmaps { get; set; } + public MatchSongSelect() { Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING }; @@ -43,10 +57,17 @@ namespace osu.Game.Screens.Select public override bool OnExiting(IScreen next) { + if (base.OnExiting(next)) + return true; + + Beatmap.Value = beatmaps.GetWorkingBeatmap(CurrentItem.Value?.Beatmap); + Beatmap.Value.Mods.Value = selectedMods.Value = CurrentItem.Value?.RequiredMods; + Ruleset.Value = CurrentItem.Value?.Ruleset; + Beatmap.Disabled = true; Ruleset.Disabled = true; - return base.OnExiting(next); + return false; } public override void OnEntering(IScreen last) diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs index 6960739987..758e1c24c3 100644 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs @@ -28,26 +28,26 @@ namespace osu.Game.Screens.Select.Options public Color4 ButtonColour { - get { return background.Colour; } - set { background.Colour = value; } + get => background.Colour; + set => background.Colour = value; } public FontAwesome Icon { - get { return iconText.Icon; } - set { iconText.Icon = value; } + get => iconText.Icon; + set => iconText.Icon = value; } public string FirstLineText { - get { return firstLine.Text; } - set { firstLine.Text = value; } + get => firstLine.Text; + set => firstLine.Text = value; } public string SecondLineText { - get { return secondLine.Text; } - set { secondLine.Text = value; } + get => secondLine.Text; + set => secondLine.Text = value; } public Key? HotKey; diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index b5e9cd5f41..d06436c92e 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -65,7 +65,7 @@ namespace osu.Game.Screens.Select LoadComponentAsync(player = new PlayerLoader(() => new Player()), l => { - if (this.IsCurrentScreen())this.Push(player); + if (this.IsCurrentScreen()) this.Push(player); }); return true; diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 82627d729a..5d4ead69d6 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -1,11 +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 System.Collections.Generic; -using System.Linq; -using osuTK; -using osuTK.Input; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; @@ -13,8 +8,8 @@ using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Logging; using osu.Framework.Input.Events; +using osu.Framework.Logging; using osu.Framework.Screens; using osu.Framework.Threading; using osu.Game.Beatmaps; @@ -31,7 +26,12 @@ using osu.Game.Screens.Menu; using osu.Game.Screens.Play; using osu.Game.Screens.Select.Options; using osu.Game.Skinning; +using osuTK; using osuTK.Graphics; +using osuTK.Input; +using System; +using System.Collections.Generic; +using System.Linq; namespace osu.Game.Screens.Select { @@ -209,7 +209,7 @@ namespace osu.Game.Screens.Select }); } - BeatmapDetails.Leaderboard.ScoreSelected += s =>this.Push(new SoloResults(s)); + BeatmapDetails.Leaderboard.ScoreSelected += s => this.Push(new SoloResults(s)); } [BackgroundDependencyLoader(true)] @@ -226,7 +226,7 @@ namespace osu.Game.Screens.Select BeatmapOptions.AddButton(@"Delete", @"all difficulties", FontAwesome.fa_trash, colours.Pink, () => delete(Beatmap.Value.BeatmapSetInfo), Key.Number4, float.MaxValue); BeatmapOptions.AddButton(@"Remove", @"from unplayed", FontAwesome.fa_times_circle_o, colours.Purple, null, Key.Number1); - BeatmapOptions.AddButton(@"Clear", @"local scores", FontAwesome.fa_eraser, colours.Purple, null, Key.Number2); + BeatmapOptions.AddButton(@"Clear", @"local scores", FontAwesome.fa_eraser, colours.Purple, () => clearScores(Beatmap.Value.BeatmapInfo), Key.Number2); } if (this.beatmaps == null) @@ -285,8 +285,8 @@ namespace osu.Game.Screens.Select public void Edit(BeatmapInfo beatmap = null) { - Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap ?? beatmapNoDebounce); - this.Push(new Editor()); + Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap ?? beatmapNoDebounce); + this.Push(new Editor()); } /// @@ -512,12 +512,6 @@ namespace osu.Game.Screens.Select if (base.OnExiting(next)) return true; - if (ModSelect.State == Visibility.Visible) - { - ModSelect.Hide(); - return true; - } - beatmapInfoWedge.State = Visibility.Hidden; this.FadeOut(100); @@ -623,9 +617,19 @@ namespace osu.Game.Screens.Select private void delete(BeatmapSetInfo beatmap) { if (beatmap == null || beatmap.ID <= 0) return; + dialogOverlay?.Push(new BeatmapDeleteDialog(beatmap)); } + private void clearScores(BeatmapInfo beatmap) + { + if (beatmap == null || beatmap.ID <= 0) return; + + dialogOverlay?.Push(new BeatmapClearScoresDialog(beatmap, () => + // schedule done here rather than inside the dialog as the dialog may fade out and never callback. + Schedule(() => BeatmapDetails.Leaderboard.RefreshScores()))); + } + public override bool OnPressed(GlobalAction action) { if (!this.IsCurrentScreen()) return false; diff --git a/osu.Game/Screens/Tournament/Components/VisualiserContainer.cs b/osu.Game/Screens/Tournament/Components/VisualiserContainer.cs index 854eb809e8..6b0888313b 100644 --- a/osu.Game/Screens/Tournament/Components/VisualiserContainer.cs +++ b/osu.Game/Screens/Tournament/Components/VisualiserContainer.cs @@ -19,7 +19,7 @@ namespace osu.Game.Screens.Tournament.Components /// public int Lines { - get { return allLines.Count; } + get => allLines.Count; set { while (value > allLines.Count) diff --git a/osu.Game/Screens/Tournament/ScrollingTeamContainer.cs b/osu.Game/Screens/Tournament/ScrollingTeamContainer.cs index da2fc7fb5b..0bcf1b1816 100644 --- a/osu.Game/Screens/Tournament/ScrollingTeamContainer.cs +++ b/osu.Game/Screens/Tournament/ScrollingTeamContainer.cs @@ -84,9 +84,10 @@ namespace osu.Game.Screens.Tournament } private ScrollState _scrollState; + private ScrollState scrollState { - get { return _scrollState; } + get => _scrollState; set { @@ -326,9 +327,10 @@ namespace osu.Game.Screens.Tournament private readonly Box outline; private bool selected; + public bool Selected { - get { return selected; } + get => selected; set { diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 5dfefcb777..358b2b222b 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -28,7 +28,8 @@ namespace osu.Game.Skinning { } - protected LegacySkin(SkinInfo skin, IResourceStore storage, AudioManager audioManager, string filename) : base(skin) + protected LegacySkin(SkinInfo skin, IResourceStore storage, AudioManager audioManager, string filename) + : base(skin) { Stream stream = storage.GetStream(filename); if (stream != null) diff --git a/osu.Game/Skinning/LocalSkinOverrideContainer.cs b/osu.Game/Skinning/LocalSkinOverrideContainer.cs index 36e95f4038..955ef7b65b 100644 --- a/osu.Game/Skinning/LocalSkinOverrideContainer.cs +++ b/osu.Game/Skinning/LocalSkinOverrideContainer.cs @@ -35,6 +35,7 @@ namespace osu.Game.Skinning Drawable sourceDrawable; if (beatmapSkins.Value && (sourceDrawable = source.GetDrawableComponent(componentName)) != null) return sourceDrawable; + return fallbackSource?.GetDrawableComponent(componentName); } @@ -43,6 +44,7 @@ namespace osu.Game.Skinning Texture sourceTexture; if (beatmapSkins.Value && (sourceTexture = source.GetTexture(componentName)) != null) return sourceTexture; + return fallbackSource.GetTexture(componentName); } @@ -51,6 +53,7 @@ namespace osu.Game.Skinning SampleChannel sourceChannel; if (beatmapHitsounds.Value && (sourceChannel = source.GetSample(sampleName)) != null) return sourceChannel; + return fallbackSource?.GetSample(sampleName); } @@ -71,31 +74,27 @@ namespace osu.Game.Skinning var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); fallbackSource = dependencies.Get(); + if (fallbackSource != null) + fallbackSource.SourceChanged += onSourceChanged; + dependencies.CacheAs(this); + var config = dependencies.Get(); + + config.BindWith(OsuSetting.BeatmapSkins, beatmapSkins); + config.BindWith(OsuSetting.BeatmapHitsounds, beatmapHitsounds); + + beatmapSkins.BindValueChanged(_ => onSourceChanged()); + beatmapHitsounds.BindValueChanged(_ => onSourceChanged()); + return dependencies; } - [BackgroundDependencyLoader] - private void load(OsuConfigManager config) - { - config.BindWith(OsuSetting.BeatmapSkins, beatmapSkins); - config.BindWith(OsuSetting.BeatmapHitsounds, beatmapHitsounds); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - if (fallbackSource != null) - fallbackSource.SourceChanged += onSourceChanged; - - beatmapSkins.BindValueChanged(_ => onSourceChanged()); - beatmapHitsounds.BindValueChanged(_ => onSourceChanged(), true); - } - protected override void Dispose(bool isDisposing) { + // Must be done before base.Dispose() + SourceChanged = null; + base.Dispose(isDisposing); if (fallbackSource != null) diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index de0374f29a..1d14f9cd6a 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -49,6 +49,7 @@ namespace osu.Game.Skinning { if (isDisposed) return; + isDisposed = true; } diff --git a/osu.Game/Skinning/SkinStore.cs b/osu.Game/Skinning/SkinStore.cs index e80b03b935..31cadb0a24 100644 --- a/osu.Game/Skinning/SkinStore.cs +++ b/osu.Game/Skinning/SkinStore.cs @@ -1,22 +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.Linq; -using Microsoft.EntityFrameworkCore; using osu.Framework.Platform; using osu.Game.Database; namespace osu.Game.Skinning { - public class SkinStore : MutableDatabaseBackedStore + public class SkinStore : MutableDatabaseBackedStoreWithFileIncludes { public SkinStore(DatabaseContextFactory contextFactory, Storage storage = null) : base(contextFactory, storage) { } - - protected override IQueryable AddIncludesForConsumption(IQueryable query) => - base.AddIncludesForConsumption(query) - .Include(s => s.Files).ThenInclude(f => f.FileInfo); } } diff --git a/osu.Game/Skinning/SkinnableSpriteText.cs b/osu.Game/Skinning/SkinnableSpriteText.cs index b380b74e3d..36e646d743 100644 --- a/osu.Game/Skinning/SkinnableSpriteText.cs +++ b/osu.Game/Skinning/SkinnableSpriteText.cs @@ -30,6 +30,7 @@ namespace osu.Game.Skinning { if (text == value) return; + text = value; if (Drawable is IHasText textDrawable) diff --git a/osu.Game/Storyboards/CommandTimeline.cs b/osu.Game/Storyboards/CommandTimeline.cs index 40e4848874..aa1f137cf3 100644 --- a/osu.Game/Storyboards/CommandTimeline.cs +++ b/osu.Game/Storyboards/CommandTimeline.cs @@ -52,6 +52,7 @@ namespace osu.Game.Storyboards { var result = StartTime.CompareTo(other.StartTime); if (result != 0) return result; + return EndTime.CompareTo(other.EndTime); } diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs index c92fe9812e..f5e1f612ca 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs @@ -20,12 +20,14 @@ namespace osu.Game.Storyboards.Drawables protected override Vector2 DrawScale => new Vector2(Parent.DrawHeight / 480); private bool passing = true; + public bool Passing { - get { return passing; } + get => passing; set { if (passing == value) return; + passing = value; updateLayerVisibility(); } @@ -34,6 +36,7 @@ namespace osu.Game.Storyboards.Drawables public override bool RemoveCompletedTransforms => false; private DependencyContainer dependencies; + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs index 02691da9a9..0b9ebaf3a7 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs @@ -78,6 +78,7 @@ namespace osu.Game.Storyboards.Drawables var texture = textureStore.Get(path); AddFrame(texture, Animation.FrameDelay); } + Animation.ApplyTransforms(this); } } diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardLayer.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardLayer.cs index ac80e5f237..106ebfaf5d 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardLayer.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardLayer.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics.Containers; namespace osu.Game.Storyboards.Drawables { - public class DrawableStoryboardLayer : Container + public class DrawableStoryboardLayer : LifetimeManagementContainer { public StoryboardLayer Layer { get; private set; } public bool Enabled; @@ -29,7 +29,7 @@ namespace osu.Game.Storyboards.Drawables foreach (var element in Layer.Elements) { if (element.IsDrawable) - Add(element.CreateDrawable()); + AddInternal(element.CreateDrawable()); } } } diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs index 4128b342c9..0cc753ff7e 100644 --- a/osu.Game/Storyboards/Storyboard.cs +++ b/osu.Game/Storyboards/Storyboard.cs @@ -76,6 +76,7 @@ namespace osu.Game.Storyboards { if (isDisposed) return; + isDisposed = true; } diff --git a/osu.Game/Storyboards/StoryboardSprite.cs b/osu.Game/Storyboards/StoryboardSprite.cs index 3b9ea27e4e..b91b05bd04 100644 --- a/osu.Game/Storyboards/StoryboardSprite.cs +++ b/osu.Game/Storyboards/StoryboardSprite.cs @@ -34,6 +34,7 @@ namespace osu.Game.Storyboards public bool HasCommands => TimelineGroup.HasCommands || loops.Any(l => l.HasCommands); private delegate void DrawablePropertyInitializer(Drawable drawable, T value); + private delegate void DrawableTransformer(Drawable drawable, T value, double duration, Easing easing); public StoryboardSprite(string path, Anchor origin, Vector2 initialPosition) @@ -70,8 +71,7 @@ namespace osu.Game.Storyboards applyCommands(drawable, getCommands(g => g.Alpha, triggeredGroups), (d, value) => d.Alpha = value, (d, value, duration, easing) => d.FadeTo(value, duration, easing)); applyCommands(drawable, getCommands(g => g.BlendingMode, triggeredGroups), (d, value) => d.Blending = value, (d, value, duration, easing) => d.TransformBlendingMode(value, duration), false); - var flippable = drawable as IFlippable; - if (flippable != null) + if (drawable is IFlippable flippable) { applyCommands(drawable, getCommands(g => g.FlipH, triggeredGroups), (d, value) => flippable.FlipH = value, (d, value, duration, easing) => flippable.TransformFlipH(value, duration), false); applyCommands(drawable, getCommands(g => g.FlipV, triggeredGroups), (d, value) => flippable.FlipV = value, (d, value, duration, easing) => flippable.TransformFlipV(value, duration), false); @@ -90,6 +90,7 @@ namespace osu.Game.Storyboards initializeProperty.Invoke(drawable, command.StartValue); initialized = true; } + using (drawable.BeginAbsoluteSequence(command.StartTime)) { transform(drawable, command.StartValue, 0, Easing.None); diff --git a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs index be8dff2296..44ac38044d 100644 --- a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs +++ b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs @@ -39,6 +39,7 @@ namespace osu.Game.Tests.Beatmaps { if (mappingCounter >= ourResult.Mappings.Count && mappingCounter >= expectedResult.Mappings.Count) break; + if (mappingCounter >= ourResult.Mappings.Count) Assert.Fail($"A conversion did not generate any hitobjects, but should have, for hitobject at time: {expectedResult.Mappings[mappingCounter].StartTime}\n"); else if (mappingCounter >= expectedResult.Mappings.Count) @@ -64,6 +65,7 @@ namespace osu.Game.Tests.Beatmaps { if (objectCounter >= ourMapping.Objects.Count && objectCounter >= expectedMapping.Objects.Count) 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"); @@ -189,7 +191,10 @@ namespace osu.Game.Tests.Beatmaps public List Objects = new List(); [JsonProperty("Objects")] - private List setObjects { set => Objects = value; } + private List setObjects + { + set => Objects = value; + } public virtual bool Equals(ConvertMapping other) => StartTime.Equals(other?.StartTime); } diff --git a/osu.Game/Tests/Beatmaps/TestBeatmap.cs b/osu.Game/Tests/Beatmaps/TestBeatmap.cs index c7b24ac83a..d1263984ac 100644 --- a/osu.Game/Tests/Beatmaps/TestBeatmap.cs +++ b/osu.Game/Tests/Beatmaps/TestBeatmap.cs @@ -30,8 +30,7 @@ namespace osu.Game.Tests.Beatmaps return Decoder.GetDecoder(reader).Decode(reader); } - private const string test_beatmap_data = -@"osu file format v14 + private const string test_beatmap_data = @"osu file format v14 [General] AudioLeadIn: 500 diff --git a/osu.Game/Tests/Visual/ScrollingTestContainer.cs b/osu.Game/Tests/Visual/ScrollingTestContainer.cs index 19d1e18939..f2e03208fd 100644 --- a/osu.Game/Tests/Visual/ScrollingTestContainer.cs +++ b/osu.Game/Tests/Visual/ScrollingTestContainer.cs @@ -20,9 +20,15 @@ namespace osu.Game.Tests.Visual { public SortedList ControlPoints => scrollingInfo.Algorithm.ControlPoints; - public ScrollVisualisationMethod ScrollAlgorithm { set => scrollingInfo.Algorithm.Algorithm = value; } + public ScrollVisualisationMethod ScrollAlgorithm + { + set => scrollingInfo.Algorithm.Algorithm = value; + } - public double TimeRange { set => scrollingInfo.TimeRange.Value = value; } + public double TimeRange + { + set => scrollingInfo.TimeRange.Value = value; + } public IScrollingInfo ScrollingInfo => scrollingInfo; diff --git a/osu.Game/Users/Avatar.cs b/osu.Game/Users/Avatar.cs index fb586d6f58..3df5957ff9 100644 --- a/osu.Game/Users/Avatar.cs +++ b/osu.Game/Users/Avatar.cs @@ -80,6 +80,7 @@ namespace osu.Game.Users { if (!Enabled.Value) return false; + return base.OnClick(e); } } diff --git a/osu.Game/Users/Country.cs b/osu.Game/Users/Country.cs index e17afbc77f..b513b460bc 100644 --- a/osu.Game/Users/Country.cs +++ b/osu.Game/Users/Country.cs @@ -33,9 +33,10 @@ namespace osu.Game.Users private TextureStore textures; private Country country; + public Country Country { - get { return country; } + get => country; set { if (value == country) diff --git a/osu.Game/Users/UpdateableAvatar.cs b/osu.Game/Users/UpdateableAvatar.cs index 4039e45e3d..cefb91797b 100644 --- a/osu.Game/Users/UpdateableAvatar.cs +++ b/osu.Game/Users/UpdateableAvatar.cs @@ -23,7 +23,7 @@ namespace osu.Game.Users public User User { - get { return user; } + get => user; set { if (user?.Id == value?.Id) diff --git a/osu.Game/Users/User.cs b/osu.Game/Users/User.cs index 745ebb75fc..292ac90245 100644 --- a/osu.Game/Users/User.cs +++ b/osu.Game/Users/User.cs @@ -34,8 +34,8 @@ namespace osu.Game.Users [JsonProperty(@"cover_url")] public string CoverUrl { - get { return Cover?.Url; } - set { Cover = new UserCover { Url = value }; } + get => Cover?.Url; + set => Cover = new UserCover { Url = value }; } [JsonProperty(@"cover")] diff --git a/osu.Game/Users/UserStatistics.cs b/osu.Game/Users/UserStatistics.cs index 40f9f06cde..2de54ed8be 100644 --- a/osu.Game/Users/UserStatistics.cs +++ b/osu.Game/Users/UserStatistics.cs @@ -23,7 +23,10 @@ namespace osu.Game.Users public decimal? PP; [JsonProperty(@"pp_rank")] // the API sometimes only returns this value in condensed user responses - private int rank { set => Ranks.Global = value; } + private int rank + { + set => Ranks.Global = value; + } [JsonProperty(@"rank")] public UserRanks Ranks; diff --git a/osu.Game/Users/UserStatus.cs b/osu.Game/Users/UserStatus.cs index 1c34303896..14b4538a00 100644 --- a/osu.Game/Users/UserStatus.cs +++ b/osu.Game/Users/UserStatus.cs @@ -39,7 +39,7 @@ namespace osu.Game.Users public override string Message => @"in Multiplayer Lobby"; } - public class UserStatusSoloGame : UserStatusBusy + public class UserStatusSoloGame : UserStatusBusy { public override string Message => @"Solo Game"; } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index f464dafd3f..8f9a7cd14b 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -16,7 +16,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index bf38335e0c..499878347b 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -35,7 +35,7 @@ prompt 4 - iPhone Developer + iPhone Distribution true true Entitlements.plist @@ -105,12 +105,12 @@ - - + + - \ No newline at end of file + diff --git a/osu.iOS/AppDelegate.cs b/osu.iOS/AppDelegate.cs index 97621e1e52..058e246ed8 100644 --- a/osu.iOS/AppDelegate.cs +++ b/osu.iOS/AppDelegate.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using Foundation; @@ -10,6 +10,6 @@ namespace osu.iOS [Register("AppDelegate")] public class AppDelegate : GameAppDelegate { - protected override Framework.Game CreateGame() => new OsuGame(); + protected override Framework.Game CreateGame() => new OsuGameIOS(); } } diff --git a/osu.iOS/Info.plist b/osu.iOS/Info.plist index fe711fc03c..0627feab78 100644 --- a/osu.iOS/Info.plist +++ b/osu.iOS/Info.plist @@ -2,6 +2,14 @@ + CFBundleIdentifier + sh.ppy.osulazer + CFBundleName + osu! + CFBundleShortVersionString + 0.1 + CFBundleVersion + 0.1.0 LSRequiresIPhoneOS MinimumOSVersion @@ -17,6 +25,10 @@ armv7 + UIRequiresFullScreen + + UIStatusBarHidden + UISupportedInterfaceOrientations UIInterfaceOrientationPortrait @@ -26,17 +38,5 @@ XSAppIconAssets Assets.xcassets/AppIcon.appiconset - UIStatusBarHidden - - UIRequiresFullScreen - - CFBundleIdentifier - sh.ppy.osulazer - CFBundleName - osu! - CFBundleShortVersionString - 0.1 - CFBundleVersion - 0.1.1 diff --git a/osu.iOS/OsuGameIOS.cs b/osu.iOS/OsuGameIOS.cs new file mode 100644 index 0000000000..6cf18df9a6 --- /dev/null +++ b/osu.iOS/OsuGameIOS.cs @@ -0,0 +1,14 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using Foundation; +using osu.Game; + +namespace osu.iOS +{ + public class OsuGameIOS : OsuGame + { + public override Version AssemblyVersion => new Version(NSBundle.MainBundle.InfoDictionary["CFBundleVersion"].ToString()); + } +} diff --git a/osu.iOS/osu.iOS.csproj b/osu.iOS/osu.iOS.csproj index 9c69dd40ba..9df3ad5516 100644 --- a/osu.iOS/osu.iOS.csproj +++ b/osu.iOS/osu.iOS.csproj @@ -48,6 +48,7 @@ + diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index ad0d8a55a2..3c6a6dd2a9 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -6,7 +6,11 @@ ExplicitlyExcluded ExplicitlyExcluded SOLUTION - HINT + WARNING + WARNING + WARNING + HINT + HINT WARNING True @@ -16,6 +20,32 @@ HINT HINT 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 @@ -48,6 +78,7 @@ HINT HINT ERROR + WARNING HINT HINT HINT @@ -62,9 +93,17 @@ WARNING WARNING WARNING + WARNING + WARNING + WARNING + WARNING WARNING + WARNING + WARNING + WARNING WARNING HINT + WARNING HINT HINT HINT @@ -75,6 +114,7 @@ WARNING WARNING WARNING + WARNING HINT DO_NOT_SHOW DO_NOT_SHOW @@ -84,6 +124,8 @@ WARNING WARNING WARNING + WARNING + WARNING ERROR WARNING WARNING @@ -137,10 +179,14 @@ WARNING WARNING WARNING + WARNING HINT DO_NOT_SHOW DO_NOT_SHOW DO_NOT_SHOW + WARNING + WARNING + WARNING WARNING WARNING HINT @@ -158,16 +204,22 @@ WARNING WARNING WARNING + + True WARNING WARNING - HINT + WARNING 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) + ExpressionBody + ExpressionBody + True True True True @@ -178,6 +230,8 @@ True NEXT_LINE NEXT_LINE + 1 + 1 True NEVER NEVER