diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 1f937e1837..3cecb0d07c 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -15,13 +15,13 @@
]
},
"codefilesanity": {
- "version": "0.0.36",
+ "version": "0.0.37",
"commands": [
"CodeFileSanity"
]
},
"ppy.localisationanalyser.tools": {
- "version": "2022.809.0",
+ "version": "2023.712.0",
"commands": [
"localisation"
]
diff --git a/.editorconfig b/.editorconfig
index c0ea55f4c8..c249e5e9b3 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -9,6 +9,9 @@ indent_style = space
indent_size = 2
trim_trailing_whitespace = true
+[g_*.cs]
+generated_code = true
+
[*.cs]
end_of_line = crlf
insert_final_newline = true
@@ -191,6 +194,8 @@ csharp_style_prefer_index_operator = false:silent
csharp_style_prefer_range_operator = false:silent
csharp_style_prefer_switch_expression = false:none
+csharp_style_namespace_declarations = block_scoped:warning
+
[*.{yaml,yml}]
insert_final_newline = true
indent_style = space
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index b85862270b..d35d4be412 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -6,3 +6,5 @@
212d78865a6b5f091173a347bad5686834d1d5fe
# Add partial specs in mobile projects too
00c11b2b4e389e48f3995d63484a6bc66a7afbdb
+# Mass NRT enabling
+0ab0c52ad577b3e7b406d09fa6056a56ff997c3e
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 47a6a4c3d3..ec57232126 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -2,7 +2,7 @@ blank_issues_enabled: false
contact_links:
- name: Help
url: https://github.com/ppy/osu/discussions/categories/q-a
- about: osu! not working as you'd expect? Not sure it's a bug? Check the Q&A section!
+ about: osu! not working or performing as you'd expect? Not sure it's a bug? Check the Q&A section!
- name: Suggestions or feature request
url: https://github.com/ppy/osu/discussions/categories/ideas
about: Got something you think should change or be added? Search for or start a new discussion!
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 213c5082ab..a8167ec4db 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -13,17 +13,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
# FIXME: Tools won't run in .NET 6.0 unless you install 3.1.x LTS side by side.
# https://itnext.io/how-to-support-multiple-net-sdks-in-github-actions-workflows-b988daa884e
- name: Install .NET 3.1.x LTS
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v3
with:
dotnet-version: "3.1.x"
- name: Install .NET 6.0.x
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v3
with:
dotnet-version: "6.0.x"
@@ -77,10 +77,10 @@ jobs:
timeout-minutes: 60
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
- name: Install .NET 6.0.x
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v3
with:
dotnet-version: "6.0.x"
@@ -94,7 +94,7 @@ jobs:
# Attempt to upload results even if test fails.
# https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#always
- name: Upload Test Results
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
if: ${{ always() }}
with:
name: osu-test-results-${{matrix.os.prettyname}}-${{matrix.threadingMode}}
@@ -106,10 +106,10 @@ jobs:
timeout-minutes: 60
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
- name: Install .NET 6.0.x
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v3
with:
dotnet-version: "6.0.x"
@@ -121,23 +121,26 @@ jobs:
build-only-ios:
name: Build only (iOS)
- # change to macos-latest once GitHub finishes migrating all repositories to macOS 12.
- runs-on: macos-12
+ # `macos-13` is required, because Xcode 14.3 is required (see below).
+ # TODO: can be changed to `macos-latest` once `macos-13` becomes latest (currently in beta)
+ runs-on: macos-13
timeout-minutes: 60
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
- # see https://github.com/actions/runner-images/issues/6771#issuecomment-1354713617
- # remove once all workflow VMs use Xcode 14.1
- - name: Set Xcode Version
+ # newest Microsoft.iOS.Sdk versions require Xcode 14.3.
+ # 14.3 is currently not the default Xcode version (https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md#xcode),
+ # so set it manually.
+ # TODO: remove when 14.3 becomes the default Xcode version.
+ - name: Set Xcode version
shell: bash
run: |
- sudo xcode-select -s "/Applications/Xcode_14.1.app"
- echo "MD_APPLE_SDK_ROOT=/Applications/Xcode_14.1.app" >> $GITHUB_ENV
+ sudo xcode-select -s "/Applications/Xcode_14.3.app"
+ echo "MD_APPLE_SDK_ROOT=/Applications/Xcode_14.3.app" >> $GITHUB_ENV
- name: Install .NET 6.0.x
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v3
with:
dotnet-version: "6.0.x"
diff --git a/.github/workflows/diffcalc.yml b/.github/workflows/diffcalc.yml
index 9e11ab6663..2c6ec17e18 100644
--- a/.github/workflows/diffcalc.yml
+++ b/.github/workflows/diffcalc.yml
@@ -48,8 +48,8 @@ jobs:
CONTINUE="no"
fi
- echo "::set-output name=continue::${CONTINUE}"
- echo "::set-output name=matrix::${MATRIX_JSON}"
+ echo "continue=${CONTINUE}" >> $GITHUB_OUTPUT
+ echo "matrix=${MATRIX_JSON}" >> $GITHUB_OUTPUT
diffcalc:
name: Run
runs-on: self-hosted
@@ -80,34 +80,34 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
- echo "::set-output name=branchname::$(curl -H "Authorization: token ${GITHUB_TOKEN}" ${{ github.event.issue.pull_request.url }} | jq '.head.ref' | sed 's/\"//g')"
- echo "::set-output name=repo::$(curl -H "Authorization: token ${GITHUB_TOKEN}" ${{ github.event.issue.pull_request.url }} | jq '.head.repo.full_name' | sed 's/\"//g')"
+ echo "branchname=$(curl -H "Authorization: token ${GITHUB_TOKEN}" ${{ github.event.issue.pull_request.url }} | jq '.head.ref' | sed 's/\"//g')" >> $GITHUB_OUTPUT
+ echo "repo=$(curl -H "Authorization: token ${GITHUB_TOKEN}" ${{ github.event.issue.pull_request.url }} | jq '.head.repo.full_name' | sed 's/\"//g')" >> $GITHUB_OUTPUT
# Checkout osu
- name: Checkout osu (master)
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
with:
path: 'master/osu'
- name: Checkout osu (pr)
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
with:
path: 'pr/osu'
repository: ${{ steps.upstreambranch.outputs.repo }}
ref: ${{ steps.upstreambranch.outputs.branchname }}
- name: Checkout osu-difficulty-calculator (master)
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
with:
repository: ppy/osu-difficulty-calculator
path: 'master/osu-difficulty-calculator'
- name: Checkout osu-difficulty-calculator (pr)
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
with:
repository: ppy/osu-difficulty-calculator
path: 'pr/osu-difficulty-calculator'
- name: Install .NET 5.0.x
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v3
with:
dotnet-version: "5.0.x"
diff --git a/.github/workflows/sentry-release.yml b/.github/workflows/sentry-release.yml
index cce3f23e5f..ff4165c414 100644
--- a/.github/workflows/sentry-release.yml
+++ b/.github/workflows/sentry-release.yml
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
with:
fetch-depth: 0
diff --git a/.github/workflows/update-web-mod-definitions.yml b/.github/workflows/update-web-mod-definitions.yml
new file mode 100644
index 0000000000..32d3d37ffe
--- /dev/null
+++ b/.github/workflows/update-web-mod-definitions.yml
@@ -0,0 +1,53 @@
+name: Update osu-web mod definitions
+on:
+ push:
+ tags:
+ - '*'
+
+permissions:
+ contents: read # to fetch code (actions/checkout)
+
+jobs:
+ update-mod-definitions:
+ name: Update osu-web mod definitions
+ runs-on: ubuntu-latest
+ steps:
+ - name: Install .NET 6.0.x
+ uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: "6.0.x"
+
+ - name: Checkout ppy/osu
+ uses: actions/checkout@v3
+ with:
+ path: osu
+
+ - name: Checkout ppy/osu-tools
+ uses: actions/checkout@v3
+ with:
+ repository: ppy/osu-tools
+ path: osu-tools
+
+ - name: Checkout ppy/osu-web
+ uses: actions/checkout@v3
+ with:
+ repository: ppy/osu-web
+ path: osu-web
+
+ - name: Setup local game checkout for tools
+ run: ./UseLocalOsu.sh
+ working-directory: ./osu-tools
+
+ - name: Regenerate mod definitions
+ run: dotnet run --project PerformanceCalculator -- mods > ../osu-web/database/mods.json
+ working-directory: ./osu-tools
+
+ - name: Create pull request with changes
+ uses: peter-evans/create-pull-request@v5
+ with:
+ title: Update mod definitions
+ body: "This PR has been auto-generated to update the mod definitions to match ppy/osu@${{ github.ref_name }}."
+ branch: update-mod-definitions
+ commit-message: Update mod definitions
+ path: osu-web
+ token: ${{ secrets.OSU_WEB_PULL_REQUEST_PAT }}
diff --git a/.gitignore b/.gitignore
index 0c7a18b437..525b3418cd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -339,6 +339,5 @@ inspectcode
# Fody (pulled in by Realm) - schema file
FodyWeavers.xsd
-**/FodyWeavers.xml
.idea/.idea.osu.Desktop/.idea/misc.xml
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c72a3b442e..9f7d88f5c7 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -2,137 +2,87 @@
Thank you for showing interest in the development of osu!. We aim to provide a good collaborating environment for everyone involved, and as such have decided to list some of the most important things to keep in mind in the process. The guidelines below have been chosen based on past experience.
-These are not "official rules" *per se*, but following them will help everyone deal with things in the most efficient manner.
-
## Table of contents
-1. [I would like to submit an issue!](#i-would-like-to-submit-an-issue)
-2. [I would like to submit a pull request!](#i-would-like-to-submit-a-pull-request)
+1. [Reporting bugs](#reporting-bugs)
+2. [Providing general feedback](#providing-general-feedback)
+3. [Issue or discussion?](#issue-or-discussion)
+4. [Submitting pull requests](#submitting-pull-requests)
+5. [Resources](#resources)
-## I would like to submit an issue!
+## Reporting bugs
-Issues, bug reports and feature suggestions are welcomed, though please keep in mind that at any point in time, hundreds of issues are open, which vary in severity and the amount of time needed to address them. As such it's not uncommon for issues to remain unresolved for a long time or even closed outright if they are deemed not important enough to fix in the foreseeable future. Issues that are required to "go live" or otherwise achieve parity with stable are prioritised the most.
+A **bug** is a situation in which there is something clearly *and objectively* wrong with the game. Examples of applicable bug reports are:
-* **Before submitting an issue, try searching existing issues first.**
+- The game crashes to desktop when I start a beatmap
+- Friends appear twice in the friend listing
+- The game slows down a lot when I play this specific map
+- A piece of text is overlapping another piece of text on the screen
- For housekeeping purposes, we close issues that overlap with or duplicate other pre-existing issues - you can help us not to have to do that by searching existing issues yourself first. The issue search box, as well as the issue tag system, are tools you can use to check if an issue has been reported before.
+To track bug reports, we primarily use GitHub **issues**. When opening an issue, please keep in mind the following:
-* **When submitting a bug report, please try to include as much detail as possible.**
+- Before opening the issue, please search for any similar existing issues using the text search bar and the issue labels. This includes both open and closed issues (we may have already fixed something, but the fix hasn't yet been released).
+- When opening the issue, please fill out as much of the issue template as you can. In particular, please make sure to include logs and screenshots as much as possible. The instructions on how to find the log files are included in the issue template.
+- We may ask you for follow-up information to reproduce or debug the problem. Please look out for this and provide follow-up info if we request it.
- Bugs are not equal - some of them will be reproducible every time on pretty much all hardware, while others will be hard to track down due to being specific to particular hardware or even somewhat random in nature. As such, providing as much detail as possible when reporting a bug is hugely appreciated. A good starting set of information consists of:
+If we cannot reproduce the issue, it is deemed low priority, or it is deemed to be specific to your setup in some way, the issue may be downgraded to a discussion. This will be done by a maintainer for you.
- * the in-game logs, which are located at:
- * `%AppData%/osu/logs` (on Windows),
- * `~/.local/share/osu/logs` (on Linux),
- * `~/Library/Application Support/osu/logs` (on macOS),
- * `Android/data/sh.ppy.osulazer/files/logs` (on Android),
- * on iOS they can be obtained by connecting your device to your desktop and [copying the `logs` directory from the app's own document storage using iTunes](https://support.apple.com/en-us/HT201301#copy-to-computer),
- * your system specifications (including the operating system and platform you are playing on),
- * a reproduction scenario (list of steps you have performed leading up to the occurrence of the bug),
- * a video or picture of the bug, if at all possible.
+## Providing general feedback
-* **Provide more information when asked to do so.**
+If you wish to:
- Sometimes when a bug is more elusive or complicated, none of the information listed above will pinpoint a concrete cause of the problem. In this case we will most likely ask you for additional info, such as a Windows Event Log dump or a copy of your local osu! database (`client.db`). Providing that information is beneficial to both parties - we can track down the problem better, and hopefully fix it for you at some point once we know where it is!
+- provide *subjective* feedback on the game (about how the UI looks, about how the default skin works, about game mechanics, about how the PP and scoring systems work, etc.),
+- suggest a new feature to be added to the game,
+- report a non-specific problem with the game that you think may be connected to your hardware or operating system specifically,
-* **When submitting a feature proposal, please describe it in the most understandable way you can.**
+then it is generally best to start with a **discussion** first. Discussions are a good avenue to group subjective feedback on a single topic, or gauge interest in a particular feature request.
- Communicating your idea for a feature can often be hard, and we would like to avoid any misunderstandings. As such, please try to explain your idea in a short, but understandable manner - it's best to avoid jargon or terms and references that could be considered obscure. A mock-up picture (doesn't have to be good!) of the feature can also go a long way in explaining.
+When opening a discussion, please keep in mind the following:
-* **Refrain from posting "+1" comments.**
+- Use the search function to see if your idea has been proposed before, or if there is already a thread about a particular issue you wish to raise.
+- If proposing a feature, please try to explain the feature in as much detail as possible.
+- If you're reporting a non-specific problem, please provide applicable logs, screenshots, or video that illustrate the issue.
- If an issue has already been created, saying that you also experience it without providing any additional details doesn't really help us in any way. To express support for a proposal or indicate that you are also affected by a particular bug, you can use comment reactions instead.
+If a discussion gathers enough traction, then it may be converted into an issue. This will be done by a maintainer for you.
-* **Refrain from asking if an issue has been resolved yet.**
+## Issue or discussion?
- As mentioned above, the issue tracker has hundreds of issues open at any given time. Currently the game is being worked on by two members of the core team, and a handful of outside contributors who offer their free time to help out. As such, it can happen that an issue gets placed on the backburner due to being less important; generally posting a comment demanding its resolution some months or years after it is reported is not very likely to increase its priority.
+We realise that the line between an issue and a discussion may be fuzzy, so while we ask you to use your best judgement based on the description above, please don't think about it too hard either. Feedback in a slightly wrong place is better than no feedback at all.
-* **Avoid long discussions about non-development topics.**
+When in doubt, it's probably best to start with a discussion first. We will escalate to issues as needed.
- GitHub is mostly a developer space, and as such isn't really fit for lengthened discussions about gameplay mechanics (which might not even be in any way confirmed for the final release) and similar non-technical matters. Such matters are probably best addressed at the osu! forums.
+## Submitting pull requests
-## I would like to submit a pull request!
+While pull requests from unaffiliated contributors are welcome, please note that due to significant community interest and limited review throughput, the core team's primary focus is on the issues which are currently [on the roadmap](https://github.com/orgs/ppy/projects/7/views/6). Reviewing PRs that fall outside of the scope of the roadmap is done on a best-effort basis, so please be aware that it may take a while before a core maintainer gets around to review your change.
-We also welcome pull requests from unaffiliated contributors. The [issue tracker](https://github.com/ppy/osu/issues) should provide plenty of issues that you can work on; we also mark issues that we think would be good for newcomers with the [`good-first-issue`](https://github.com/ppy/osu/issues?q=is%3Aissue+is%3Aopen+label%3Agood-first-issue) label.
+The [issue tracker](https://github.com/ppy/osu/issues) should provide plenty of issues to start with. We also have a [`good-first-issue`](https://github.com/ppy/osu/issues?q=is%3Aissue+is%3Aopen+label%3Agood-first-issue) label, although from experience it is not used very often, as it is relatively rare that we can spot an issue that will definitively be a good first issue for a new contributor regardless of their programming experience.
-However, do keep in mind that the core team is committed to bringing osu!(lazer) up to par with osu!(stable) first and foremost, so depending on what your contribution concerns, it might not be merged and released right away. Our approach to managing issues and their priorities is described [in the wiki](https://github.com/ppy/osu/wiki/Project-management).
+In the case of simple issues, a direct PR is okay. However, if you decide to work on an existing issue which doesn't seem trivial, **please ask us first**. This way we can try to estimate if it is a good fit for you and provide the correct direction on how to address it. In addition, note that while we do not rule out external contributors from working on roadmapped issues, we will generally prefer to handle them ourselves unless they're not very time sensitive.
-Here are some key things to note before jumping in:
+If you'd like to propose a subjective change to one of the visual aspects of the game, or there is a bigger task you'd like to work on, but there is no corresponding issue or discussion thread yet for it, **please open a discussion or issue first** to avoid wasted effort. This in particular applies if you want to work on [one of the available designs from the osu! public Figma library](https://www.figma.com/file/6m10GiGEncVFWmgOoSyakH/osu!-Figma-Library).
-* **Make sure you are comfortable with C\# and your development environment.**
+Aside from the above, below is a brief checklist of things to watch out when you're preparing your code changes:
- While we are accepting of all kinds of contributions, we also have a certain quality standard we'd like to uphold and limited time to review your code. Therefore, we would like to avoid providing entry-level advice, and as such if you're not very familiar with C\# as a programming language, we'd recommend that you start off with a few personal projects to get acquainted with the language's syntax, toolchain and principles of object-oriented programming first.
+- Make sure you're comfortable with the principles of object-oriented programming, the syntax of C\# and your development environment.
+- Make sure you are familiar with [git](https://git-scm.com/) and [the pull request workflow](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/proposing-changes-to-your-work-with-pull-requests).
+- Please do not make code changes via the GitHub web interface.
+- Please add tests for your changes. We expect most new features and bugfixes to have test coverage, unless the effort of adding them is prohibitive. The visual testing methodology we use is described in more detail [here](https://github.com/ppy/osu-framework/wiki/Development-and-Testing).
+- Please run tests and code style analysis (via `InspectCode.{ps1,sh}` scripts in the root of this repository) before opening the PR. This is particularly important if you're a first-time contributor, as CI will not run for your PR until we allow it to do so.
- In addition, please take the time to take a look at and get acquainted with the [development and testing](https://github.com/ppy/osu-framework/wiki/Development-and-Testing) procedure we have set up.
+After you're done with your changes and you wish to open the PR, please observe the following recommendations:
-* **Make sure you are familiar with git and the pull request workflow.**
+- Please submit the pull request from a [topic branch](https://git-scm.com/book/en/v2/Git-Branching-Branching-Workflows#_topic_branch) (not `master`), and keep the *Allow edits from maintainers* check box selected, so that we can push fixes to your PR if necessary.
+- Please avoid pushing untested or incomplete code.
+- Please do not force-push or rebase unless we ask you to.
+- Please do not merge `master` continually if there are no conflicts to resolve. We will do this for you when the change is ready for merge.
- [git](https://git-scm.com/) is a distributed version control system that might not be very intuitive at the beginning if you're not familiar with version control. In particular, projects using git have a particular workflow for submitting code changes, which is called the pull request workflow.
+We are highly committed to quality when it comes to the osu! project. This means that contributions from less experienced community members can take multiple rounds of review to get to a mergeable state. We try our utmost best to never conflate a person with the code they authored, and to keep the discussion focused on the code at all times. Please consider our comments and requests a learning experience.
- To make things run more smoothly, we recommend that you look up some online resources to familiarise yourself with the git vocabulary and commands, and practice working with forks and submitting pull requests at your own pace. A high-level overview of the process can be found in [this article by GitHub](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/proposing-changes-to-your-work-with-pull-requests).
+If you're uncertain about some part of the codebase or some inner workings of the game and framework, please reach out either by leaving a comment in the relevant issue, discussion, or PR thread, or by posting a message in the [development Discord server](https://discord.gg/ppy). We will try to help you as much as we can.
-* **Double-check designs before starting work on new functionality.**
+## Resources
- When implementing new features, keep in mind that we already have a lot of the UI designed. If you wish to work on something with the intention of having it included in the official distribution, please open an issue for discussion and we will give you what you need from a design perspective to proceed. If you want to make *changes* to the design, we recommend you open an issue with your intentions before spending too much time to ensure no effort is wasted.
-
-* **Make sure to submit pull requests off of a topic branch.**
-
- As described in the article linked in the previous point, topic branches help you parallelise your work and separate it from the main `master` branch, and additionally are easier for maintainers to work with. Working with multiple `master` branches across many remotes is difficult to keep track of, and it's easy to make a mistake and push to the wrong `master` branch by accident.
-
-* **Refrain from making changes through the GitHub web interface.**
-
- Even though GitHub provides an option to edit code or replace files in the repository using the web interface, we strongly discourage using it in most scenarios. Editing files this way is inefficient and likely to introduce whitespace or file encoding changes that make it more difficult to review the code.
-
- Code written through the web interface will also very likely be questioned outright by the reviewers, as it is likely that it has not been properly tested or that it will fail continuous integration checks. We strongly encourage using an IDE like [Visual Studio](https://visualstudio.microsoft.com/), [Visual Studio Code](https://code.visualstudio.com/) or [JetBrains Rider](https://www.jetbrains.com/rider/) instead.
-
-* **Add tests for your code whenever possible.**
-
- Automated tests are an essential part of a quality and reliable codebase. They help to make the code more maintainable by ensuring it is safe to reorganise (or refactor) the code in various ways, and also prevent regressions - bugs that resurface after having been fixed at some point in the past. If it is viable, please put in the time to add tests, so that the changes you make can last for a (hopefully) very long time.
-
-* **Run tests before opening a pull request.**
-
- Tying into the previous point, sometimes changes in one part of the codebase can result in unpredictable changes in behaviour in other pieces of the code. This is why it is best to always try to run tests before opening a PR.
-
- Continuous integration will always run the tests for you (and us), too, but it is best not to rely on it, as there might be many builds queued at any time. Running tests on your own will help you be more certain that at the point of clicking the "Create pull request" button, your changes are as ready as can be.
-
-* **Run code style analysis before opening a pull request.**
-
- As part of continuous integration, we also run code style analysis, which is supposed to make sure that your code is formatted the same way as all the pre-existing code in the repository. The reason we enforce a particular code style everywhere is to make sure the codebase is consistent in that regard - having one whitespace convention in one place and another one elsewhere causes disorganisation.
-
-* **Make sure that the pull request is complete before opening it.**
-
- Whether it's fixing a bug or implementing new functionality, it's best that you make sure that the change you want to submit as a pull request is as complete as it can be before clicking the *Create pull request* button. Having to track if a pull request is ready for review or not places additional burden on reviewers.
-
- Draft pull requests are an option, but use them sparingly and within reason. They are best suited to discuss code changes that cannot be easily described in natural language or have a potential large impact on the future direction of the project. When in doubt, don't open drafts unless a maintainer asks you to do so.
-
-* **Only push code when it's ready.**
-
- As an extension of the above, when making changes to an already-open PR, please try to only push changes you are reasonably certain of. Pushing after every commit causes the continuous integration build queue to grow in size, slowing down work and taking up time that could be spent verifying other changes.
-
-* **Make sure to keep the *Allow edits from maintainers* check box checked.**
-
- To speed up the merging process, collaborators and team members will sometimes want to push changes to your branch themselves, to make minor code style adjustments or to otherwise refactor the code without having to describe how they'd like the code to look like in painstaking detail. Having the *Allow edits from maintainers* check box checked lets them do that; without it they are forced to report issues back to you and wait for you to address them.
-
-* **Refrain from continually merging the master branch back to the PR.**
-
- Unless there are merge conflicts that need resolution, there is no need to keep merging `master` back to a branch over and over again. One of the maintainers will merge `master` themselves before merging the PR itself anyway, and continual merge commits can cause CI to get overwhelmed due to queueing up too many builds.
-
-* **Refrain from force-pushing to the PR branch.**
-
- Force-pushing should be avoided, as it can lead to accidentally overwriting a maintainer's changes or CI building wrong commits. We value all history in the project, so there is no need to squash or amend commits in most cases.
-
- The cases in which force-pushing is warranted are very rare (such as accidentally leaking sensitive info in one of the files committed, adding unrelated files, or mis-merging a dependent PR).
-
-* **Be patient when waiting for the code to be reviewed and merged.**
-
- As much as we'd like to review all contributions as fast as possible, our time is limited, as team members have to work on their own tasks in addition to reviewing code. As such, work needs to be prioritised, and it can unfortunately take weeks or months for your PR to be merged, depending on how important it is deemed to be.
-
-* **Don't mistake criticism of code for criticism of your person.**
-
- As mentioned before, we are highly committed to quality when it comes to the osu! project. This means that contributions from less experienced community members can take multiple rounds of review to get to a mergeable state. We try our utmost best to never conflate a person with the code they authored, and to keep the discussion focused on the code at all times. Please consider our comments and requests a learning experience, and don't treat it as a personal attack.
-
-* **Feel free to reach out for help.**
-
- If you're uncertain about some part of the codebase or some inner workings of the game and framework, please reach out either by leaving a comment in the relevant issue or PR thread, or by posting a message in the [development Discord server](https://discord.gg/ppy). We will try to help you as much as we can.
-
- When it comes to which form of communication is best, GitHub generally lends better to longer-form discussions, while Discord is better for snappy call-and-response answers. Use your best discretion when deciding, and try to keep a single discussion in one place instead of moving back and forth.
+- [Development roadmap](https://github.com/orgs/ppy/projects/7/views/6): What the core team is currently working on
+- [`ppy/osu-framework` wiki](https://github.com/ppy/osu-framework/wiki): Contains introductory information about osu!framework, the bespoke 2D game framework we use for the game
+- [`ppy/osu` wiki](https://github.com/ppy/osu/wiki): Contains articles about various technical aspects of the game
+- [Public Figma library](https://www.figma.com/file/6m10GiGEncVFWmgOoSyakH/osu!-Figma-Library): Contains finished and draft designs for osu!
diff --git a/Directory.Build.props b/Directory.Build.props
index 235feea8ce..734374c840 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,7 +1,7 @@
- 9.0
+ 10.0
true
enable
@@ -17,7 +17,7 @@
-
+
diff --git a/Gemfile b/Gemfile
deleted file mode 100644
index cdd3a6b349..0000000000
--- a/Gemfile
+++ /dev/null
@@ -1,6 +0,0 @@
-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
deleted file mode 100644
index 07ca3542f9..0000000000
--- a/Gemfile.lock
+++ /dev/null
@@ -1,234 +0,0 @@
-GEM
- remote: https://rubygems.org/
- specs:
- CFPropertyList (3.0.5)
- rexml
- addressable (2.8.1)
- public_suffix (>= 2.0.2, < 6.0)
- artifactory (3.0.15)
- atomos (0.1.3)
- aws-eventstream (1.2.0)
- aws-partitions (1.653.0)
- aws-sdk-core (3.166.0)
- aws-eventstream (~> 1, >= 1.0.2)
- aws-partitions (~> 1, >= 1.651.0)
- aws-sigv4 (~> 1.5)
- jmespath (~> 1, >= 1.6.1)
- aws-sdk-kms (1.59.0)
- aws-sdk-core (~> 3, >= 3.165.0)
- aws-sigv4 (~> 1.1)
- aws-sdk-s3 (1.117.1)
- aws-sdk-core (~> 3, >= 3.165.0)
- aws-sdk-kms (~> 1)
- aws-sigv4 (~> 1.4)
- aws-sigv4 (1.5.2)
- aws-eventstream (~> 1, >= 1.0.2)
- babosa (1.0.4)
- claide (1.1.0)
- colored (1.2)
- colored2 (3.1.2)
- commander (4.6.0)
- highline (~> 2.0.0)
- declarative (0.0.20)
- digest-crc (0.6.4)
- rake (>= 12.0.0, < 14.0.0)
- domain_name (0.5.20190701)
- unf (>= 0.0.5, < 1.0.0)
- dotenv (2.8.1)
- emoji_regex (3.2.3)
- excon (0.93.1)
- faraday (1.10.2)
- faraday-em_http (~> 1.0)
- faraday-em_synchrony (~> 1.0)
- faraday-excon (~> 1.1)
- faraday-httpclient (~> 1.0)
- faraday-multipart (~> 1.0)
- faraday-net_http (~> 1.0)
- faraday-net_http_persistent (~> 1.0)
- faraday-patron (~> 1.0)
- faraday-rack (~> 1.0)
- faraday-retry (~> 1.0)
- ruby2_keywords (>= 0.0.4)
- faraday-cookie_jar (0.0.7)
- faraday (>= 0.8.0)
- http-cookie (~> 1.0.0)
- faraday-em_http (1.0.0)
- faraday-em_synchrony (1.0.0)
- faraday-excon (1.1.0)
- faraday-httpclient (1.0.1)
- faraday-multipart (1.0.4)
- multipart-post (~> 2)
- faraday-net_http (1.0.1)
- faraday-net_http_persistent (1.2.0)
- faraday-patron (1.0.0)
- faraday-rack (1.0.0)
- faraday-retry (1.0.3)
- faraday_middleware (1.2.0)
- faraday (~> 1.0)
- fastimage (2.2.6)
- fastlane (2.210.1)
- CFPropertyList (>= 2.3, < 4.0.0)
- addressable (>= 2.8, < 3.0.0)
- artifactory (~> 3.0)
- aws-sdk-s3 (~> 1.0)
- babosa (>= 1.0.3, < 2.0.0)
- bundler (>= 1.12.0, < 3.0.0)
- colored
- commander (~> 4.6)
- dotenv (>= 2.1.1, < 3.0.0)
- emoji_regex (>= 0.1, < 4.0)
- excon (>= 0.71.0, < 1.0.0)
- faraday (~> 1.0)
- faraday-cookie_jar (~> 0.0.6)
- faraday_middleware (~> 1.0)
- fastimage (>= 2.1.0, < 3.0.0)
- gh_inspector (>= 1.1.2, < 2.0.0)
- google-apis-androidpublisher_v3 (~> 0.3)
- google-apis-playcustomapp_v1 (~> 0.1)
- google-cloud-storage (~> 1.31)
- highline (~> 2.0)
- json (< 3.0.0)
- jwt (>= 2.1.0, < 3)
- mini_magick (>= 4.9.4, < 5.0.0)
- multipart-post (~> 2.0.0)
- naturally (~> 2.2)
- optparse (~> 0.1.1)
- plist (>= 3.1.0, < 4.0.0)
- rubyzip (>= 2.0.0, < 3.0.0)
- security (= 0.1.3)
- simctl (~> 1.6.3)
- terminal-notifier (>= 2.0.0, < 3.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.13.0, < 2.0.0)
- xcpretty (~> 0.3.0)
- xcpretty-travis-formatter (>= 0.0.3)
- fastlane-plugin-clean_testflight_testers (0.3.0)
- fastlane-plugin-souyuz (0.11.1)
- souyuz (= 0.11.1)
- fastlane-plugin-xamarin (0.6.3)
- gh_inspector (1.1.3)
- google-apis-androidpublisher_v3 (0.29.0)
- google-apis-core (>= 0.9.0, < 2.a)
- google-apis-core (0.9.1)
- addressable (~> 2.5, >= 2.5.1)
- googleauth (>= 0.16.2, < 2.a)
- httpclient (>= 2.8.1, < 3.a)
- mini_mime (~> 1.0)
- representable (~> 3.0)
- retriable (>= 2.0, < 4.a)
- rexml
- webrick
- google-apis-iamcredentials_v1 (0.15.0)
- google-apis-core (>= 0.9.0, < 2.a)
- google-apis-playcustomapp_v1 (0.12.0)
- google-apis-core (>= 0.9.1, < 2.a)
- google-apis-storage_v1 (0.19.0)
- google-apis-core (>= 0.9.0, < 2.a)
- google-cloud-core (1.6.0)
- google-cloud-env (~> 1.0)
- google-cloud-errors (~> 1.0)
- google-cloud-env (1.6.0)
- faraday (>= 0.17.3, < 3.0)
- google-cloud-errors (1.3.0)
- google-cloud-storage (1.43.0)
- addressable (~> 2.8)
- digest-crc (~> 0.4)
- google-apis-iamcredentials_v1 (~> 0.1)
- google-apis-storage_v1 (~> 0.19.0)
- google-cloud-core (~> 1.6)
- googleauth (>= 0.16.2, < 2.a)
- mini_mime (~> 1.0)
- googleauth (1.3.0)
- faraday (>= 0.17.3, < 3.a)
- jwt (>= 1.4, < 3.0)
- memoist (~> 0.16)
- multi_json (~> 1.11)
- os (>= 0.9, < 2.0)
- signet (>= 0.16, < 2.a)
- highline (2.0.3)
- http-cookie (1.0.5)
- domain_name (~> 0.5)
- httpclient (2.8.3)
- jmespath (1.6.1)
- json (2.6.2)
- jwt (2.5.0)
- memoist (0.16.2)
- mini_magick (4.11.0)
- mini_mime (1.1.2)
- mini_portile2 (2.8.0)
- multi_json (1.15.0)
- multipart-post (2.0.0)
- nanaimo (0.3.0)
- naturally (2.2.1)
- nokogiri (1.13.9)
- mini_portile2 (~> 2.8.0)
- racc (~> 1.4)
- optparse (0.1.1)
- os (1.1.4)
- plist (3.6.0)
- public_suffix (5.0.0)
- racc (1.6.0)
- rake (13.0.6)
- representable (3.2.0)
- declarative (< 0.1.0)
- trailblazer-option (>= 0.1.1, < 0.2.0)
- uber (< 0.2.0)
- retriable (3.1.2)
- rexml (3.2.5)
- rouge (2.0.7)
- ruby2_keywords (0.0.5)
- rubyzip (2.3.2)
- security (0.1.3)
- signet (0.17.0)
- addressable (~> 2.8)
- faraday (>= 0.17.5, < 3.a)
- jwt (>= 1.5, < 3.0)
- multi_json (~> 1.10)
- simctl (1.6.8)
- CFPropertyList
- naturally
- souyuz (0.11.1)
- fastlane (>= 2.182.0)
- highline (~> 2.0)
- nokogiri (~> 1.7)
- terminal-notifier (2.0.0)
- terminal-table (1.8.0)
- unicode-display_width (~> 1.1, >= 1.1.1)
- trailblazer-option (0.1.2)
- tty-cursor (0.7.1)
- tty-screen (0.8.1)
- tty-spinner (0.9.3)
- tty-cursor (~> 0.7)
- uber (0.1.0)
- unf (0.1.4)
- unf_ext
- unf_ext (0.0.8.2)
- unicode-display_width (1.8.0)
- webrick (1.7.0)
- word_wrap (1.0.0)
- xcodeproj (1.22.0)
- CFPropertyList (>= 2.3.3, < 4.0)
- atomos (~> 0.1.3)
- claide (>= 1.0.2, < 2.0)
- colored2 (~> 3.1)
- nanaimo (~> 0.3.0)
- rexml (~> 3.2.4)
- xcpretty (0.3.0)
- rouge (~> 2.0.7)
- xcpretty-travis-formatter (1.0.1)
- 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 0de82eba75..792e2d646a 100644
--- a/README.md
+++ b/README.md
@@ -16,21 +16,20 @@ The future of [osu!](https://osu.ppy.sh) and the beginning of an open era! Curre
## Status
-This project is under heavy development, but is in a stable state. Users are encouraged to try it out and keep it installed alongside the stable *osu!* client. It will continue to evolve to the point of eventually replacing the existing stable client as an update.
+This project is under constant development, but we aim to keep things in a stable state. Users are encouraged to try it out and keep it installed alongside the stable *osu!* client. It will continue to evolve to the point of eventually replacing the existing stable client as an update.
-**IMPORTANT:** Gameplay mechanics (and other features which you may have come to know and love) are in a constant state of flux. Game balance and final quality-of-life passes come at the end of development, preceded by experimentation and changes which may potentially **reduce playability or usability**. This is done in order to allow us to move forward as developers and designers more efficiently. If this offends you, please consider sticking to the stable releases of osu! (found on the website). We are not yet open to heated discussion over game mechanics and will not be using github as a forum for such discussions just yet.
+**IMPORTANT:** Gameplay mechanics (and other features which you may have come to know and love) are in a constant state of flux. Game balance and final quality-of-life passes come at the end of development, preceded by experimentation and changes which may potentially **reduce playability or usability**. This is done in order to allow us to move forward as developers and designers more efficiently. If this offends you, please consider sticking to a [stable release](https://osu.ppy.sh/home/download) of osu!. We are not yet open to heated discussion over game mechanics and will not be using github as a forum for such discussions just yet.
We are accepting bug reports (please report with as much detail as possible and follow the existing issue templates). Feature requests are also welcome, but understand that our focus is on completing the game to feature parity before adding new features. A few resources are available as starting points to getting involved and understanding the project:
- Detailed release changelogs are available on the [official osu! site](https://osu.ppy.sh/home/changelog/lazer).
- You can learn more about our approach to [project management](https://github.com/ppy/osu/wiki/Project-management).
-- Read peppy's [blog post](https://blog.ppy.sh/a-definitive-lazer-faq/) exploring where the project is currently and the roadmap going forward.
## Running osu!
-If you are looking to install or test osu! without setting up a development environment, you can consume our [binary releases](https://github.com/ppy/osu/releases). Handy links below will download the latest version for your operating system of choice:
+If you are looking to install or test osu! without setting up a development environment, you can consume our [releases](https://github.com/ppy/osu/releases). You can also generally download a version for your current device from the [osu! site](https://osu.ppy.sh/home/download). Failing that, you may use the links below to download the latest version for your operating system of choice:
-**Latest build:**
+**Latest release:**
| [Windows 8.1+ (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | macOS 10.15+ ([Intel](https://github.com/ppy/osu/releases/latest/download/osu.app.Intel.zip), [Apple Silicon](https://github.com/ppy/osu/releases/latest/download/osu.app.Apple.Silicon.zip)) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS 13.4+](https://osu.ppy.sh/home/testflight) | [Android 5+](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk) |
| ------------- | ------------- | ------------- | ------------- | ------------- |
@@ -50,9 +49,8 @@ You can see some examples of custom rulesets by visiting the [custom ruleset dir
Please make sure you have the following prerequisites:
- A desktop platform with the [.NET 6.0 SDK](https://dotnet.microsoft.com/download) installed.
-- When developing with mobile, [Xamarin](https://docs.microsoft.com/en-us/xamarin/) is required, which is shipped together with Visual Studio or [Visual Studio for Mac](https://visualstudio.microsoft.com/vs/mac/).
-- When working with the codebase, we recommend using an IDE with intelligent code completion and syntax highlighting, such as the latest version of [Visual Studio](https://visualstudio.microsoft.com/vs/), [JetBrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/).
-- When running on Linux, please have a system-wide FFmpeg installation available to support video decoding.
+
+When working with the codebase, we recommend using an IDE with intelligent code completion and syntax highlighting, such as the latest version of [Visual Studio](https://visualstudio.microsoft.com/vs/), [JetBrains Rider](https://www.jetbrains.com/rider/), or [Visual Studio Code](https://code.visualstudio.com/) with the [EditorConfig](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig) and [C#](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp) plugin installed.
### Downloading the source code
@@ -89,7 +87,29 @@ _Due to a historical feature gap between .NET Core and Xamarin, running `dotnet`
### 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.
+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 quickly achieved using included commands:
+
+Windows:
+
+```ps
+UseLocalFramework.ps1
+UseLocalResources.ps1
+```
+
+macOS / Linux:
+
+```ps
+UseLocalFramework.sh
+UseLocalResources.sh
+```
+
+Note that these commands assume you have the relevant project(s) checked out in adjacent directories:
+
+```
+|- osu // this repository
+|- osu-framework
+|- osu-resources
+```
### Code analysis
@@ -101,13 +121,11 @@ JetBrains ReSharper InspectCode is also used for wider rule sets. You can run it
## Contributing
-When it comes to contributing to the project, the two main things you can do to help out are reporting issues and submitting pull requests. Based on past experiences, we have prepared a [list of contributing guidelines](CONTRIBUTING.md) that should hopefully ease you into our collaboration process and answer the most frequently-asked questions.
-
-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, or with any processes involved with contributing, *please* bring it up. We welcome all feedback so we can make contributing to this project as painless as possible.
+When it comes to contributing to the project, the two main things you can do to help out are reporting issues and submitting pull requests. Please refer to the [contributing guidelines](CONTRIBUTING.md) to understand how to help in the most effective way possible.
If you wish to help with localisation efforts, head over to [crowdin](https://crowdin.com/project/osu-web).
-For those interested, we love to reward quality contributions via [bounties](https://docs.google.com/spreadsheets/d/1jNXfj_S3Pb5PErA-czDdC9DUu4IgUbe1Lt8E7CYUJuE/view?&rm=minimal#gid=523803337), paid out via PayPal or osu!supporter tags. Don't hesitate to [request a bounty](https://docs.google.com/forms/d/e/1FAIpQLSet_8iFAgPMG526pBZ2Kic6HSh7XPM3fE8xPcnWNkMzINDdYg/viewform) for your work on this project.
+We love to reward quality contributions. If you have made a large contribution, or are a regular contributor, you are welcome to [submit an expense via opencollective](https://opencollective.com/ppy/expenses/new). If you have any questions, feel free to [reach out to peppy](mailto:pe@ppy.sh) before doing so.
## Licence
diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj
index 52b728a115..a1c53ece03 100644
--- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj
+++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj
@@ -9,9 +9,9 @@
false
-
+
-
+
diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
index 95b96adab0..683e9fd5e8 100644
--- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
+++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
@@ -9,9 +9,9 @@
false
-
+
-
+
diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Objects/Drawables/DrawablePippidonHitObject.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Objects/Drawables/DrawablePippidonHitObject.cs
index 29203f0a20..c5ada4288d 100644
--- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Objects/Drawables/DrawablePippidonHitObject.cs
+++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Objects/Drawables/DrawablePippidonHitObject.cs
@@ -8,7 +8,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Audio;
-using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
using osuTK;
@@ -44,7 +43,7 @@ namespace osu.Game.Rulesets.Pippidon.Objects.Drawables
public override IEnumerable GetSamples() => new[]
{
- new HitSampleInfo(HitSampleInfo.HIT_NORMAL, SampleControlPoint.DEFAULT_BANK)
+ new HitSampleInfo(HitSampleInfo.HIT_NORMAL)
};
protected override void CheckForResult(bool userTriggered, double timeOffset)
diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj
index d12403016d..b7a7fff18a 100644
--- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj
+++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj
@@ -9,9 +9,9 @@
false
-
+
-
+
diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
index 95b96adab0..683e9fd5e8 100644
--- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
+++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
@@ -9,9 +9,9 @@
false
-
+
-
+
diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Objects/Drawables/DrawablePippidonHitObject.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Objects/Drawables/DrawablePippidonHitObject.cs
index 554d03c79f..d198fa81cb 100644
--- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Objects/Drawables/DrawablePippidonHitObject.cs
+++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Objects/Drawables/DrawablePippidonHitObject.cs
@@ -8,7 +8,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Audio;
-using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Pippidon.UI;
using osu.Game.Rulesets.Scoring;
@@ -44,7 +43,7 @@ namespace osu.Game.Rulesets.Pippidon.Objects.Drawables
public override IEnumerable GetSamples() => new[]
{
- new HitSampleInfo(HitSampleInfo.HIT_NORMAL, SampleControlPoint.DEFAULT_BANK)
+ new HitSampleInfo(HitSampleInfo.HIT_NORMAL)
};
protected override void CheckForResult(bool userTriggered, double timeOffset)
diff --git a/UseLocalFramework.ps1 b/UseLocalFramework.ps1
index 837685f310..9f4547d980 100644
--- a/UseLocalFramework.ps1
+++ b/UseLocalFramework.ps1
@@ -3,15 +3,53 @@
#
# https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects
-$CSPROJ="osu.Game/osu.Game.csproj"
+$GAME_CSPROJ="osu.Game/osu.Game.csproj"
+$ANDROID_PROPS="osu.Android.props"
+$IOS_PROPS="osu.iOS.props"
$SLN="osu.sln"
-dotnet remove $CSPROJ package ppy.osu.Framework;
-dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj;
-dotnet add $CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj
+dotnet remove $GAME_CSPROJ reference ppy.osu.Framework;
+dotnet remove $ANDROID_PROPS reference ppy.osu.Framework.Android;
+dotnet remove $IOS_PROPS reference ppy.osu.Framework.iOS;
+
+dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj `
+ ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj `
+ ../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj `
+ ../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj;
+
+dotnet add $GAME_CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj;
+dotnet add $ANDROID_PROPS reference ../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj;
+dotnet add $IOS_PROPS reference ../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj;
+
+# workaround for dotnet add not inserting $(MSBuildThisFileDirectory) on props files
+(Get-Content "osu.Android.props") -replace "`"..\\osu-framework", "`"`$(MSBuildThisFileDirectory)..\osu-framework" | Set-Content "osu.Android.props"
+(Get-Content "osu.iOS.props") -replace "`"..\\osu-framework", "`"`$(MSBuildThisFileDirectory)..\osu-framework" | Set-Content "osu.iOS.props"
+
+# needed because iOS framework nupkg includes a set of properties to work around certain issues during building,
+# and those get ignored when referencing framework via project, threfore we have to manually include it via props reference.
+(Get-Content "osu.iOS.props") |
+ Foreach-Object {
+ if ($_ -match "")
+ {
+ " "
+ }
+
+ $_
+ } | Set-Content "osu.iOS.props"
+
+$TMP=New-TemporaryFile
$SLNF=Get-Content "osu.Desktop.slnf" | ConvertFrom-Json
-$TMP=New-TemporaryFile
$SLNF.solution.projects += ("../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj")
ConvertTo-Json $SLNF | Out-File $TMP -Encoding UTF8
Move-Item -Path $TMP -Destination "osu.Desktop.slnf" -Force
+
+$SLNF=Get-Content "osu.Android.slnf" | ConvertFrom-Json
+$SLNF.solution.projects += ("../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj")
+ConvertTo-Json $SLNF | Out-File $TMP -Encoding UTF8
+Move-Item -Path $TMP -Destination "osu.Android.slnf" -Force
+
+$SLNF=Get-Content "osu.iOS.slnf" | ConvertFrom-Json
+$SLNF.solution.projects += ("../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj")
+ConvertTo-Json $SLNF | Out-File $TMP -Encoding UTF8
+Move-Item -Path $TMP -Destination "osu.iOS.slnf" -Force
diff --git a/UseLocalFramework.sh b/UseLocalFramework.sh
index 4fd1fdfd1b..c12b388e96 100755
--- a/UseLocalFramework.sh
+++ b/UseLocalFramework.sh
@@ -5,14 +5,41 @@
#
# https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects
-CSPROJ="osu.Game/osu.Game.csproj"
+GAME_CSPROJ="osu.Game/osu.Game.csproj"
+ANDROID_PROPS="osu.Android.props"
+IOS_PROPS="osu.iOS.props"
SLN="osu.sln"
-dotnet remove $CSPROJ package ppy.osu.Framework
-dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj
-dotnet add $CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj
+dotnet remove $GAME_CSPROJ reference ppy.osu.Framework
+dotnet remove $ANDROID_PROPS reference ppy.osu.Framework.Android
+dotnet remove $IOS_PROPS reference ppy.osu.Framework.iOS
+
+dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj \
+ ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj \
+ ../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj \
+ ../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj
+
+dotnet add $GAME_CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj
+dotnet add $ANDROID_PROPS reference ../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj
+dotnet add $IOS_PROPS reference ../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj
+
+# workaround for dotnet add not inserting $(MSBuildThisFileDirectory) on props files
+sed -i.bak 's:"..\\osu-framework:"$(MSBuildThisFileDirectory)..\\osu-framework:g' ./osu.Android.props && rm osu.Android.props.bak
+sed -i.bak 's:"..\\osu-framework:"$(MSBuildThisFileDirectory)..\\osu-framework:g' ./osu.iOS.props && rm osu.iOS.props.bak
+
+# needed because iOS framework nupkg includes a set of properties to work around certain issues during building,
+# and those get ignored when referencing framework via project, threfore we have to manually include it via props reference.
+sed -i.bak '/<\/Project>/i\
+ \
+' ./osu.iOS.props && rm osu.iOS.props.bak
-SLNF="osu.Desktop.slnf"
tmp=$(mktemp)
+
jq '.solution.projects += ["../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj"]' osu.Desktop.slnf > $tmp
-mv -f $tmp $SLNF
+mv -f $tmp osu.Desktop.slnf
+
+jq '.solution.projects += ["../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj"]' osu.Android.slnf > $tmp
+mv -f $tmp osu.Android.slnf
+
+jq '.solution.projects += ["../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj"]' osu.iOS.slnf > $tmp
+mv -f $tmp osu.iOS.slnf
diff --git a/app.manifest b/app.manifest
index 533c6ff208..088ad1dde7 100644
--- a/app.manifest
+++ b/app.manifest
@@ -1,6 +1,7 @@
+ 1
@@ -14,33 +15,10 @@
-
-
-
-
-
-
-
+
-
-
- true
-
-
-
-
-
-
-
diff --git a/fastlane/Appfile b/fastlane/Appfile
deleted file mode 100644
index 083de66985..0000000000
--- a/fastlane/Appfile
+++ /dev/null
@@ -1,2 +0,0 @@
-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
deleted file mode 100644
index 716115e5c6..0000000000
--- a/fastlane/Fastfile
+++ /dev/null
@@ -1,147 +0,0 @@
-update_fastlane
-
-platform :android do
-desc 'Deploy to play store'
- lane :beta do |options|
-
- update_version(
- version: options[:version],
- build: options[:build],
- )
-
- build(options)
-
- supply(
- apk: './osu.Android/bin/Release/sh.ppy.osulazer-Signed.apk',
- package_name: 'sh.ppy.osulazer',
- track: 'alpha', # upload to alpha, we can promote it later
- json_key: options[:json_key],
- )
- end
-
- desc 'Deploy to github release'
- lane :build_github do |options|
-
- update_version(
- version: options[:version],
- build: options[:build],
- )
-
- build(options)
-
- client = HTTPClient.new
- changelog = client.get_content 'https://gist.githubusercontent.com/peppy/aaa2ec1a323554b619671cac6dbbb776/raw'
- changelog.gsub!('$BUILD_ID', options[:build])
-
- set_github_release(
- repository_name: "ppy/osu",
- api_token: ENV["GITHUB_TOKEN"],
- name: options[:build],
- tag_name: options[:build],
- is_draft: true,
- description: changelog,
- commitish: "master",
- upload_assets: ["osu.Android/bin/Release/sh.ppy.osulazer.apk"]
- )
-
- end
-
- desc 'Compile the project'
- lane :build do |options|
- nuget_restore(project_path: 'osu.Android/osu.Android.csproj')
- nuget_restore(project_path: 'osu.Game/osu.Game.csproj')
- nuget_restore(project_path: 'osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj')
- nuget_restore(project_path: 'osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj')
- nuget_restore(project_path: 'osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj')
- nuget_restore(project_path: 'osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj')
-
- souyuz(
- build_configuration: 'Release',
- solution_path: 'osu.sln',
- platform: "android",
- output_path: "osu.Android/bin/Release/",
- keystore_path: options[:keystore_path],
- keystore_alias: options[:keystore_alias],
- keystore_password: ENV["KEYSTORE_PASSWORD"]
- )
- end
-
- lane :update_version do |options|
-
- split = options[:build].split('.')
- split[1] = split[1].to_s.rjust(4, '0')
- android_build = split.join('')
-
- app_version(
- solution_path: 'osu.sln',
- version: options[:version],
- build: android_build,
- )
- end
-
-end
-
-platform :ios do
- 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,
- groups: ['osu! supporters', 'public'],
- distribute_external: true,
- ipa: './osu.iOS/bin/iPhone/Release/osu.iOS.ipa'
- )
- end
-
- desc 'Compile the project'
- lane :build do
- nuget_restore(project_path: 'osu.iOS/osu.iOS.csproj')
- nuget_restore(project_path: 'osu.Game/osu.Game.csproj')
- nuget_restore(project_path: 'osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj')
- nuget_restore(project_path: 'osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj')
- nuget_restore(project_path: 'osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj')
- nuget_restore(project_path: 'osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj')
-
- souyuz(
- platform: "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
-
- lane :update_version do |options|
- options[:plist_path] = 'osu.iOS/Info.plist'
- app_version(options)
- end
-
- lane :testflight_prune_dry do
- clean_testflight_testers(days_of_inactivity:30, dry_run: true)
- end
-
- lane :testflight_prune do
- clean_testflight_testers(days_of_inactivity: 30)
- end
-end
diff --git a/fastlane/Matchfile b/fastlane/Matchfile
deleted file mode 100644
index 40c974b09e..0000000000
--- a/fastlane/Matchfile
+++ /dev/null
@@ -1 +0,0 @@
-git_url('https://github.com/peppy/apple-certificates')
diff --git a/fastlane/Pluginfile b/fastlane/Pluginfile
deleted file mode 100644
index 9f4f47f213..0000000000
--- a/fastlane/Pluginfile
+++ /dev/null
@@ -1,7 +0,0 @@
-# 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
deleted file mode 100644
index 9d5e11f7cb..0000000000
--- a/fastlane/README.md
+++ /dev/null
@@ -1,109 +0,0 @@
-fastlane documentation
-----
-
-# Installation
-
-Make sure you have the latest version of the Xcode command line tools installed:
-
-```sh
-xcode-select --install
-```
-
-For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane)
-
-# Available Actions
-
-## Android
-
-### android beta
-
-```sh
-[bundle exec] fastlane android beta
-```
-
-Deploy to play store
-
-### android build_github
-
-```sh
-[bundle exec] fastlane android build_github
-```
-
-Deploy to github release
-
-### android build
-
-```sh
-[bundle exec] fastlane android build
-```
-
-Compile the project
-
-### android update_version
-
-```sh
-[bundle exec] fastlane android update_version
-```
-
-
-
-----
-
-
-## iOS
-
-### ios beta
-
-```sh
-[bundle exec] fastlane ios beta
-```
-
-Deploy to testflight
-
-### ios build
-
-```sh
-[bundle exec] fastlane ios build
-```
-
-Compile the project
-
-### ios provision
-
-```sh
-[bundle exec] fastlane ios provision
-```
-
-Install provisioning profiles using match
-
-### ios update_version
-
-```sh
-[bundle exec] fastlane ios update_version
-```
-
-
-
-### ios testflight_prune_dry
-
-```sh
-[bundle exec] fastlane ios testflight_prune_dry
-```
-
-
-
-### ios testflight_prune
-
-```sh
-[bundle exec] fastlane ios testflight_prune
-```
-
-
-
-----
-
-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/global.json b/global.json
new file mode 100644
index 0000000000..5dcd5f425a
--- /dev/null
+++ b/global.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "6.0.100",
+ "rollForward": "latestFeature"
+ }
+}
+
diff --git a/osu.Android.props b/osu.Android.props
index c6cf7812d1..2d15bce85a 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -10,7 +10,7 @@
true
-
+
+
+
\ No newline at end of file
diff --git a/osu.Android/GameplayScreenRotationLocker.cs b/osu.Android/GameplayScreenRotationLocker.cs
index 3c39a820cc..e5fc354db7 100644
--- a/osu.Android/GameplayScreenRotationLocker.cs
+++ b/osu.Android/GameplayScreenRotationLocker.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using Android.Content.PM;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@@ -13,10 +11,10 @@ namespace osu.Android
{
public partial class GameplayScreenRotationLocker : Component
{
- private Bindable localUserPlaying;
+ private Bindable localUserPlaying = null!;
[Resolved]
- private OsuGameActivity gameActivity { get; set; }
+ private OsuGameActivity gameActivity { get; set; } = null!;
[BackgroundDependencyLoader]
private void load(OsuGame game)
diff --git a/osu.Android/OsuGameActivity.cs b/osu.Android/OsuGameActivity.cs
index ca3d628447..33ffed432e 100644
--- a/osu.Android/OsuGameActivity.cs
+++ b/osu.Android/OsuGameActivity.cs
@@ -1,11 +1,8 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
-using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
@@ -14,9 +11,9 @@ using Android.Content;
using Android.Content.PM;
using Android.Graphics;
using Android.OS;
-using Android.Provider;
using Android.Views;
using osu.Framework.Android;
+using osu.Framework.Extensions.ObjectExtensions;
using osu.Game.Database;
using Debug = System.Diagnostics.Debug;
using Uri = Android.Net.Uri;
@@ -53,11 +50,11 @@ namespace osu.Android
/// Adjusted on startup to match expected UX for the current device type (phone/tablet).
public ScreenOrientation DefaultOrientation = ScreenOrientation.Unspecified;
- private OsuGameAndroid game;
+ private OsuGameAndroid game = null!;
protected override Framework.Game CreateGame() => game = new OsuGameAndroid(this);
- protected override void OnCreate(Bundle savedInstanceState)
+ protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
@@ -94,15 +91,15 @@ namespace osu.Android
Assembly.Load("osu.Game.Rulesets.Mania");
}
- protected override void OnNewIntent(Intent intent) => handleIntent(intent);
+ protected override void OnNewIntent(Intent? intent) => handleIntent(intent);
- private void handleIntent(Intent intent)
+ private void handleIntent(Intent? intent)
{
- switch (intent.Action)
+ switch (intent?.Action)
{
case Intent.ActionDefault:
if (intent.Scheme == ContentResolver.SchemeContent)
- handleImportFromUris(intent.Data);
+ handleImportFromUris(intent.Data.AsNonNull());
else if (osu_url_schemes.Contains(intent.Scheme))
game.HandleLink(intent.DataString);
break;
@@ -116,7 +113,7 @@ namespace osu.Android
{
var content = intent.ClipData?.GetItemAt(i);
if (content != null)
- uris.Add(content.Uri);
+ uris.Add(content.Uri.AsNonNull());
}
handleImportFromUris(uris.ToArray());
@@ -131,28 +128,14 @@ namespace osu.Android
await Task.WhenAll(uris.Select(async uri =>
{
- // there are more performant overloads of this method, but this one is the most backwards-compatible
- // (dates back to API 1).
- var cursor = ContentResolver?.Query(uri, null, null, null, null);
+ var task = await AndroidImportTask.Create(ContentResolver!, uri).ConfigureAwait(false);
- if (cursor == null)
- return;
-
- cursor.MoveToFirst();
-
- int filenameColumn = cursor.GetColumnIndex(IOpenableColumns.DisplayName);
- string filename = cursor.GetString(filenameColumn);
-
- // SharpCompress requires archive streams to be seekable, which the stream opened by
- // OpenInputStream() seems to not necessarily be.
- // copy to an arbitrary-access memory stream to be able to proceed with the import.
- var copy = new MemoryStream();
- using (var stream = ContentResolver.OpenInputStream(uri))
- await stream.CopyToAsync(copy).ConfigureAwait(false);
-
- lock (tasks)
+ if (task != null)
{
- tasks.Add(new ImportTask(copy, filename));
+ lock (tasks)
+ {
+ tasks.Add(task);
+ }
}
})).ConfigureAwait(false);
diff --git a/osu.Android/OsuGameAndroid.cs b/osu.Android/OsuGameAndroid.cs
index 0227d2aec2..dea70e6b27 100644
--- a/osu.Android/OsuGameAndroid.cs
+++ b/osu.Android/OsuGameAndroid.cs
@@ -1,13 +1,12 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using Android.App;
using Microsoft.Maui.Devices;
using osu.Framework.Allocation;
using osu.Framework.Android.Input;
+using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Input.Handlers;
using osu.Framework.Platform;
using osu.Game;
@@ -32,7 +31,7 @@ namespace osu.Android
{
get
{
- var packageInfo = Application.Context.ApplicationContext.PackageManager.GetPackageInfo(Application.Context.ApplicationContext.PackageName, 0);
+ var packageInfo = Application.Context.ApplicationContext!.PackageManager!.GetPackageInfo(Application.Context.ApplicationContext.PackageName!, 0).AsNonNull();
try
{
@@ -45,7 +44,7 @@ namespace osu.Android
// Basic conversion format (as done in Fastfile): 2020.606.0 -> 202006060
// https://stackoverflow.com/questions/52977079/android-sdk-28-versioncode-in-packageinfo-has-been-deprecated
- string versionName = string.Empty;
+ string versionName;
if (OperatingSystem.IsAndroidVersionAtLeast(28))
{
@@ -68,7 +67,7 @@ namespace osu.Android
{
}
- return new Version(packageInfo.VersionName);
+ return new Version(packageInfo.VersionName.AsNonNull());
}
}
diff --git a/osu.Android/Properties/AssemblyInfo.cs b/osu.Android/Properties/AssemblyInfo.cs
index f65b1b239f..1632087fb1 100644
--- a/osu.Android/Properties/AssemblyInfo.cs
+++ b/osu.Android/Properties/AssemblyInfo.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using Android;
using Android.App;
diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs
index 2c4577f239..caf0a1d9fd 100644
--- a/osu.Desktop/DiscordRichPresence.cs
+++ b/osu.Desktop/DiscordRichPresence.cs
@@ -54,9 +54,6 @@ namespace osu.Desktop
client.OnReady += onReady;
- // safety measure for now, until we performance test / improve backoff for failed connections.
- client.OnConnectionFailed += (_, _) => client.Deinitialize();
-
client.OnError += (_, e) => Logger.Log($"An error occurred with Discord RPC Client: {e.Code} {e.Message}", LoggingTarget.Network);
config.BindWith(OsuSetting.DiscordRichPresence, privacyMode);
@@ -98,7 +95,7 @@ namespace osu.Desktop
if (status.Value is UserStatusOnline && activity.Value != null)
{
- presence.State = truncate(activity.Value.Status);
+ presence.State = truncate(activity.Value.GetStatus(privacyMode.Value == DiscordRichPresenceMode.Limited));
presence.Details = truncate(getDetails(activity.Value));
if (getBeatmap(activity.Value) is IBeatmapInfo beatmap && beatmap.OnlineID > 0)
@@ -169,7 +166,7 @@ namespace osu.Desktop
case UserActivity.InGame game:
return game.BeatmapInfo;
- case UserActivity.Editing edit:
+ case UserActivity.EditingBeatmap edit:
return edit.BeatmapInfo;
}
@@ -183,9 +180,12 @@ namespace osu.Desktop
case UserActivity.InGame game:
return game.BeatmapInfo.ToString() ?? string.Empty;
- case UserActivity.Editing edit:
+ case UserActivity.EditingBeatmap edit:
return edit.BeatmapInfo.ToString() ?? string.Empty;
+ case UserActivity.WatchingReplay watching:
+ return watching.BeatmapInfo?.ToString() ?? string.Empty;
+
case UserActivity.InLobby lobby:
return privacyMode.Value == DiscordRichPresenceMode.Limited ? string.Empty : lobby.Room.Name.Value;
}
diff --git a/osu.Desktop/LegacyIpc/LegacyTcpIpcProvider.cs b/osu.Desktop/LegacyIpc/LegacyTcpIpcProvider.cs
index 5d950eef55..d1ac42f22b 100644
--- a/osu.Desktop/LegacyIpc/LegacyTcpIpcProvider.cs
+++ b/osu.Desktop/LegacyIpc/LegacyTcpIpcProvider.cs
@@ -75,7 +75,7 @@ namespace osu.Desktop.LegacyIpc
case LegacyIpcDifficultyCalculationRequest req:
try
{
- WorkingBeatmap beatmap = new FlatFileWorkingBeatmap(req.BeatmapFile);
+ WorkingBeatmap beatmap = new FlatWorkingBeatmap(req.BeatmapFile);
var ruleset = beatmap.BeatmapInfo.Ruleset.CreateInstance();
Mod[] mods = ruleset.ConvertFromLegacyMods((LegacyMods)req.Mods).ToArray();
diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs
index 4c93c2286f..a0db896f46 100644
--- a/osu.Desktop/OsuGameDesktop.cs
+++ b/osu.Desktop/OsuGameDesktop.cs
@@ -2,13 +2,10 @@
// See the LICENCE file in the repository root for full licence text.
using System;
-using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
-using System.Linq;
using System.Reflection;
using System.Runtime.Versioning;
-using System.Threading.Tasks;
using Microsoft.Win32;
using osu.Desktop.Security;
using osu.Framework.Platform;
@@ -18,9 +15,9 @@ using osu.Framework;
using osu.Framework.Logging;
using osu.Game.Updater;
using osu.Desktop.Windows;
-using osu.Framework.Threading;
using osu.Game.IO;
using osu.Game.IPC;
+using osu.Game.Online.Multiplayer;
using osu.Game.Utils;
using SDL2;
@@ -29,6 +26,7 @@ namespace osu.Desktop
internal partial class OsuGameDesktop : OsuGame
{
private OsuSchemeLinkIPCChannel? osuSchemeLinkIPCChannel;
+ private ArchiveImportIPCChannel? archiveImportIPCChannel;
public OsuGameDesktop(string[]? args = null)
: base(args)
@@ -111,6 +109,25 @@ namespace osu.Desktop
}
}
+ public override bool RestartAppWhenExited()
+ {
+ switch (RuntimeInfo.OS)
+ {
+ case RuntimeInfo.Platform.Windows:
+ Debug.Assert(OperatingSystem.IsWindows());
+
+ // Of note, this is an async method in squirrel that adds an arbitrary delay before returning
+ // likely to ensure the external process is in a good state.
+ //
+ // We're not waiting on that here, but the outro playing before the actual exit should be enough
+ // to cover this.
+ Squirrel.UpdateManager.RestartAppWhenExited().FireAndForget();
+ return true;
+ }
+
+ return base.RestartAppWhenExited();
+ }
+
protected override void LoadComplete()
{
base.LoadComplete();
@@ -123,64 +140,28 @@ namespace osu.Desktop
LoadComponentAsync(new ElevatedPrivilegesChecker(), Add);
osuSchemeLinkIPCChannel = new OsuSchemeLinkIPCChannel(Host, this);
+ archiveImportIPCChannel = new ArchiveImportIPCChannel(Host, this);
}
public override void SetHost(GameHost host)
{
base.SetHost(host);
- var desktopWindow = (SDL2DesktopWindow)host.Window;
-
var iconStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico");
if (iconStream != null)
- desktopWindow.SetIconFromStream(iconStream);
+ host.Window.SetIconFromStream(iconStream);
- desktopWindow.CursorState |= CursorState.Hidden;
- desktopWindow.Title = Name;
- desktopWindow.DragDrop += f => fileDrop(new[] { f });
+ host.Window.CursorState |= CursorState.Hidden;
+ host.Window.Title = Name;
}
protected override BatteryInfo CreateBatteryInfo() => new SDL2BatteryInfo();
- private readonly List importableFiles = new List();
- private ScheduledDelegate? importSchedule;
-
- private void fileDrop(string[] filePaths)
- {
- lock (importableFiles)
- {
- string firstExtension = Path.GetExtension(filePaths.First());
-
- if (filePaths.Any(f => Path.GetExtension(f) != firstExtension)) return;
-
- importableFiles.AddRange(filePaths);
-
- Logger.Log($"Adding {filePaths.Length} files for import");
-
- // File drag drop operations can potentially trigger hundreds or thousands of these calls on some platforms.
- // In order to avoid spawning multiple import tasks for a single drop operation, debounce a touch.
- importSchedule?.Cancel();
- importSchedule = Scheduler.AddDelayed(handlePendingImports, 100);
- }
- }
-
- private void handlePendingImports()
- {
- lock (importableFiles)
- {
- Logger.Log($"Handling batch import of {importableFiles.Count} files");
-
- string[] paths = importableFiles.ToArray();
- importableFiles.Clear();
-
- Task.Factory.StartNew(() => Import(paths), TaskCreationOptions.LongRunning);
- }
- }
-
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
osuSchemeLinkIPCChannel?.Dispose();
+ archiveImportIPCChannel?.Dispose();
}
private class SDL2BatteryInfo : BatteryInfo
diff --git a/osu.Desktop/Program.cs b/osu.Desktop/Program.cs
index 5a1373e040..a33e845f5b 100644
--- a/osu.Desktop/Program.cs
+++ b/osu.Desktop/Program.cs
@@ -85,7 +85,7 @@ namespace osu.Desktop
}
}
- using (DesktopGameHost host = Host.GetSuitableDesktopHost(gameName, new HostOptions { BindIPC = true }))
+ using (DesktopGameHost host = Host.GetSuitableDesktopHost(gameName, new HostOptions { BindIPC = !tournamentClient }))
{
if (!host.IsPrimaryInstance)
{
diff --git a/osu.Desktop/Updater/SquirrelUpdateManager.cs b/osu.Desktop/Updater/SquirrelUpdateManager.cs
index 3d4db88471..941ab335e8 100644
--- a/osu.Desktop/Updater/SquirrelUpdateManager.cs
+++ b/osu.Desktop/Updater/SquirrelUpdateManager.cs
@@ -9,6 +9,7 @@ using osu.Framework.Logging;
using osu.Game;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
+using osu.Game.Screens.Play;
using Squirrel;
using Squirrel.SimpleSplat;
using LogLevel = Squirrel.SimpleSplat.LogLevel;
@@ -36,6 +37,9 @@ namespace osu.Desktop.Updater
[Resolved]
private OsuGameBase game { get; set; } = null!;
+ [Resolved]
+ private ILocalUserPlayInfo? localUserInfo { get; set; }
+
[BackgroundDependencyLoader]
private void load(INotificationOverlay notifications)
{
@@ -55,6 +59,10 @@ namespace osu.Desktop.Updater
try
{
+ // Avoid any kind of update checking while gameplay is running.
+ if (localUserInfo?.IsPlaying.Value == true)
+ return false;
+
updateManager ??= new GithubUpdateManager(@"https://github.com/ppy/osu", false, github_token, @"osulazer");
var info = await updateManager.CheckForUpdate(!useDeltaPatching).ConfigureAwait(false);
diff --git a/osu.Desktop/app.manifest b/osu.Desktop/app.manifest
deleted file mode 100644
index a11cee132c..0000000000
--- a/osu.Desktop/app.manifest
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
-
diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj
index 1f4544098b..25f4cff00e 100644
--- a/osu.Desktop/osu.Desktop.csproj
+++ b/osu.Desktop/osu.Desktop.csproj
@@ -8,7 +8,6 @@
osu!
osu!(lazer)
lazer.ico
- app.manifest
0.0.0
0.0.0
@@ -26,8 +25,8 @@
-
-
+
+
diff --git a/osu.Game.Benchmarks/BenchmarkCarouselFilter.cs b/osu.Game.Benchmarks/BenchmarkCarouselFilter.cs
new file mode 100644
index 0000000000..8f7027da17
--- /dev/null
+++ b/osu.Game.Benchmarks/BenchmarkCarouselFilter.cs
@@ -0,0 +1,123 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using BenchmarkDotNet.Attributes;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets;
+using osu.Game.Screens.Select;
+using osu.Game.Screens.Select.Carousel;
+
+namespace osu.Game.Benchmarks
+{
+ public class BenchmarkCarouselFilter : BenchmarkTest
+ {
+ private BeatmapInfo getExampleBeatmap() => new BeatmapInfo
+ {
+ Ruleset = new RulesetInfo
+ {
+ ShortName = "osu",
+ OnlineID = 0
+ },
+ StarRating = 4.0d,
+ Difficulty = new BeatmapDifficulty
+ {
+ ApproachRate = 5.0f,
+ DrainRate = 3.0f,
+ CircleSize = 2.0f,
+ },
+ Metadata = new BeatmapMetadata
+ {
+ Artist = "The Artist",
+ ArtistUnicode = "check unicode too",
+ Title = "Title goes here",
+ TitleUnicode = "Title goes here",
+ Author = { Username = "The Author" },
+ Source = "unit tests",
+ Tags = "look for tags too",
+ },
+ DifficultyName = "version as well",
+ Length = 2500,
+ BPM = 160,
+ BeatDivisor = 12,
+ Status = BeatmapOnlineStatus.Loved
+ };
+
+ private CarouselBeatmap carouselBeatmap = null!;
+ private FilterCriteria criteria1 = null!;
+ private FilterCriteria criteria2 = null!;
+ private FilterCriteria criteria3 = null!;
+ private FilterCriteria criteria4 = null!;
+ private FilterCriteria criteria5 = null!;
+ private FilterCriteria criteria6 = null!;
+
+ public override void SetUp()
+ {
+ var beatmap = getExampleBeatmap();
+ beatmap.OnlineID = 20201010;
+ beatmap.BeatmapSet = new BeatmapSetInfo { OnlineID = 1535 };
+ carouselBeatmap = new CarouselBeatmap(beatmap);
+ criteria1 = new FilterCriteria();
+ criteria2 = new FilterCriteria
+ {
+ Ruleset = new RulesetInfo { ShortName = "catch" }
+ };
+ criteria3 = new FilterCriteria
+ {
+ Ruleset = new RulesetInfo { OnlineID = 6 },
+ AllowConvertedBeatmaps = true,
+ BPM = new FilterCriteria.OptionalRange
+ {
+ IsUpperInclusive = false,
+ Max = 160d
+ }
+ };
+ criteria4 = new FilterCriteria
+ {
+ Ruleset = new RulesetInfo { OnlineID = 6 },
+ AllowConvertedBeatmaps = true,
+ SearchText = "an artist"
+ };
+ criteria5 = new FilterCriteria
+ {
+ Creator = new FilterCriteria.OptionalTextFilter { SearchTerm = "the author AND then something else" }
+ };
+ criteria6 = new FilterCriteria { SearchText = "20201010" };
+ }
+
+ [Benchmark]
+ public void CarouselBeatmapFilter()
+ {
+ carouselBeatmap.Filter(criteria1);
+ }
+
+ [Benchmark]
+ public void CriteriaMatchingSpecificRuleset()
+ {
+ carouselBeatmap.Filter(criteria2);
+ }
+
+ [Benchmark]
+ public void CriteriaMatchingRangeMax()
+ {
+ carouselBeatmap.Filter(criteria3);
+ }
+
+ [Benchmark]
+ public void CriteriaMatchingTerms()
+ {
+ carouselBeatmap.Filter(criteria4);
+ }
+
+ [Benchmark]
+ public void CriteriaMatchingCreator()
+ {
+ carouselBeatmap.Filter(criteria5);
+ }
+
+ [Benchmark]
+ public void CriteriaMatchingBeatmapIDs()
+ {
+ carouselBeatmap.Filter(criteria6);
+ }
+ }
+}
diff --git a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj
index f47b069373..4719d54138 100644
--- a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj
+++ b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj
@@ -7,9 +7,9 @@
-
+
-
+
diff --git a/osu.Game.Rulesets.Catch.Tests.Android/AndroidManifest.xml b/osu.Game.Rulesets.Catch.Tests.Android/AndroidManifest.xml
index bf7c0bfeca..52b34959b9 100644
--- a/osu.Game.Rulesets.Catch.Tests.Android/AndroidManifest.xml
+++ b/osu.Game.Rulesets.Catch.Tests.Android/AndroidManifest.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Catch.Tests.Android/MainActivity.cs b/osu.Game.Rulesets.Catch.Tests.Android/MainActivity.cs
index 64c71c9ecd..d8b729576d 100644
--- a/osu.Game.Rulesets.Catch.Tests.Android/MainActivity.cs
+++ b/osu.Game.Rulesets.Catch.Tests.Android/MainActivity.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using Android.App;
using osu.Framework.Android;
using osu.Game.Tests;
diff --git a/osu.Game.Rulesets.Catch.Tests.iOS/AppDelegate.cs b/osu.Game.Rulesets.Catch.Tests.iOS/AppDelegate.cs
deleted file mode 100644
index 64ff3f7151..0000000000
--- a/osu.Game.Rulesets.Catch.Tests.iOS/AppDelegate.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-#nullable disable
-
-using Foundation;
-using osu.Framework.iOS;
-using osu.Game.Tests;
-
-namespace osu.Game.Rulesets.Catch.Tests.iOS
-{
- [Register("AppDelegate")]
- public class AppDelegate : GameAppDelegate
- {
- protected override Framework.Game CreateGame() => new OsuTestBrowser();
- }
-}
diff --git a/osu.Game.Rulesets.Catch.Tests.iOS/Application.cs b/osu.Game.Rulesets.Catch.Tests.iOS/Application.cs
index 1fcb0aa427..d097c6a698 100644
--- a/osu.Game.Rulesets.Catch.Tests.iOS/Application.cs
+++ b/osu.Game.Rulesets.Catch.Tests.iOS/Application.cs
@@ -1,9 +1,8 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
-using UIKit;
+using osu.Framework.iOS;
+using osu.Game.Tests;
namespace osu.Game.Rulesets.Catch.Tests.iOS
{
@@ -11,7 +10,7 @@ namespace osu.Game.Rulesets.Catch.Tests.iOS
{
public static void Main(string[] args)
{
- UIApplication.Main(args, null, typeof(AppDelegate));
+ GameApplication.Main(new OsuTestBrowser());
}
}
}
diff --git a/osu.Game.Rulesets.Catch.Tests.iOS/Info.plist b/osu.Game.Rulesets.Catch.Tests.iOS/Info.plist
index 5ace6c07f5..f87043e1d1 100644
--- a/osu.Game.Rulesets.Catch.Tests.iOS/Info.plist
+++ b/osu.Game.Rulesets.Catch.Tests.iOS/Info.plist
@@ -5,7 +5,7 @@
CFBundleName
osu.Game.Rulesets.Catch.Tests.iOS
CFBundleIdentifier
- ppy.osu-Game-Rulesets-Catch-Tests-iOS
+ sh.ppy.catch-ruleset-tests
CFBundleShortVersionString
1.0
CFBundleVersion
@@ -42,4 +42,4 @@
CADisableMinimumFrameDurationOnPhone
-
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs
index b6cb351c1e..baca8166d1 100644
--- a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs
+++ b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
diff --git a/osu.Game.Rulesets.Catch.Tests/CatchDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchDifficultyCalculatorTest.cs
index cf030f6e13..880316f177 100644
--- a/osu.Game.Rulesets.Catch.Tests/CatchDifficultyCalculatorTest.cs
+++ b/osu.Game.Rulesets.Catch.Tests/CatchDifficultyCalculatorTest.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Difficulty;
diff --git a/osu.Game.Rulesets.Catch.Tests/CatchLegacyModConversionTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchLegacyModConversionTest.cs
index b9d6f28228..dacfd649ef 100644
--- a/osu.Game.Rulesets.Catch.Tests/CatchLegacyModConversionTest.cs
+++ b/osu.Game.Rulesets.Catch.Tests/CatchLegacyModConversionTest.cs
@@ -1,12 +1,11 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using NUnit.Framework;
using osu.Game.Beatmaps.Legacy;
using osu.Game.Rulesets.Catch.Mods;
+using osu.Game.Rulesets.Mods;
using osu.Game.Tests.Beatmaps;
namespace osu.Game.Rulesets.Catch.Tests
@@ -26,7 +25,8 @@ namespace osu.Game.Rulesets.Catch.Tests
new object[] { LegacyMods.HalfTime, new[] { typeof(CatchModHalfTime) } },
new object[] { LegacyMods.Flashlight, new[] { typeof(CatchModFlashlight) } },
new object[] { LegacyMods.Autoplay, new[] { typeof(CatchModAutoplay) } },
- new object[] { LegacyMods.HardRock | LegacyMods.DoubleTime, new[] { typeof(CatchModHardRock), typeof(CatchModDoubleTime) } }
+ new object[] { LegacyMods.HardRock | LegacyMods.DoubleTime, new[] { typeof(CatchModHardRock), typeof(CatchModDoubleTime) } },
+ new object[] { LegacyMods.ScoreV2, new[] { typeof(ModScoreV2) } },
};
[TestCaseSource(nameof(catch_mod_mapping))]
diff --git a/osu.Game.Rulesets.Catch.Tests/CatchSkinColourDecodingTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchSkinColourDecodingTest.cs
index f30b216d8d..72011042bc 100644
--- a/osu.Game.Rulesets.Catch.Tests/CatchSkinColourDecodingTest.cs
+++ b/osu.Game.Rulesets.Catch.Tests/CatchSkinColourDecodingTest.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using NUnit.Framework;
using osu.Framework.IO.Stores;
using osu.Game.Rulesets.Catch.Skinning;
diff --git a/osu.Game.Rulesets.Catch.Tests/CatchSkinnableTestScene.cs b/osu.Game.Rulesets.Catch.Tests/CatchSkinnableTestScene.cs
index 2af851a561..4306cc7d9d 100644
--- a/osu.Game.Rulesets.Catch.Tests/CatchSkinnableTestScene.cs
+++ b/osu.Game.Rulesets.Catch.Tests/CatchSkinnableTestScene.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Catch.Tests
diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/CatchEditorTestSceneContainer.cs b/osu.Game.Rulesets.Catch.Tests/Editor/CatchEditorTestSceneContainer.cs
index 39508359a4..058d4eb6b9 100644
--- a/osu.Game.Rulesets.Catch.Tests/Editor/CatchEditorTestSceneContainer.cs
+++ b/osu.Game.Rulesets.Catch.Tests/Editor/CatchEditorTestSceneContainer.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs b/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs
index 033dca587e..6dfc74e75c 100644
--- a/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs
+++ b/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneBananaShowerPlacementBlueprint.cs b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneBananaShowerPlacementBlueprint.cs
index 2db4102513..ed37ff4ef3 100644
--- a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneBananaShowerPlacementBlueprint.cs
+++ b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneBananaShowerPlacementBlueprint.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using System.Linq;
using NUnit.Framework;
using osu.Framework.Testing;
diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneCatchDistanceSnapGrid.cs b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneCatchDistanceSnapGrid.cs
index 1e057cf3fb..8052b8e3f7 100644
--- a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneCatchDistanceSnapGrid.cs
+++ b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneCatchDistanceSnapGrid.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneEditor.cs b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneEditor.cs
index 5593f3d319..c9ba127569 100644
--- a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneEditor.cs
+++ b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneEditor.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using NUnit.Framework;
using osu.Game.Tests.Visual;
diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneFruitPlacementBlueprint.cs b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneFruitPlacementBlueprint.cs
index 93b24d92fb..75d3c3753a 100644
--- a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneFruitPlacementBlueprint.cs
+++ b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneFruitPlacementBlueprint.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using System.Linq;
using NUnit.Framework;
using osu.Framework.Utils;
diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamPlacementBlueprint.cs b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamPlacementBlueprint.cs
index 18d3d29bdc..2426f8c886 100644
--- a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamPlacementBlueprint.cs
+++ b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamPlacementBlueprint.cs
@@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Catch.Tests.Editor
AddAssert("end time is correct", () => Precision.AlmostEquals(lastObject.EndTime, times[1]));
AddAssert("start position is correct", () => Precision.AlmostEquals(lastObject.OriginalX, positions[0]));
AddAssert("end position is correct", () => Precision.AlmostEquals(lastObject.EndX, positions[1]));
- AddAssert("default slider velocity", () => lastObject.DifficultyControlPoint.SliderVelocityBindable.IsDefault);
+ AddAssert("default slider velocity", () => lastObject.SliderVelocityBindable.IsDefault);
}
[Test]
@@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Catch.Tests.Editor
addPlacementSteps(times, positions);
addPathCheckStep(times, positions);
- AddAssert("slider velocity changed", () => !lastObject.DifficultyControlPoint.SliderVelocityBindable.IsDefault);
+ AddAssert("slider velocity changed", () => !lastObject.SliderVelocityBindable.IsDefault);
}
[Test]
diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamSelectionBlueprint.cs b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamSelectionBlueprint.cs
index f25b66c360..beba5811fe 100644
--- a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamSelectionBlueprint.cs
@@ -108,11 +108,11 @@ namespace osu.Game.Rulesets.Catch.Tests.Editor
double[] times = { 100, 300 };
float[] positions = { 200, 300 };
addBlueprintStep(times, positions);
- AddAssert("default slider velocity", () => hitObject.DifficultyControlPoint.SliderVelocityBindable.IsDefault);
+ AddAssert("default slider velocity", () => hitObject.SliderVelocityBindable.IsDefault);
addDragStartStep(times[1], positions[1]);
AddMouseMoveStep(times[1], 400);
- AddAssert("slider velocity changed", () => !hitObject.DifficultyControlPoint.SliderVelocityBindable.IsDefault);
+ AddAssert("slider velocity changed", () => !hitObject.SliderVelocityBindable.IsDefault);
}
[Test]
diff --git a/osu.Game.Rulesets.Catch.Tests/JuiceStreamPathTest.cs b/osu.Game.Rulesets.Catch.Tests/JuiceStreamPathTest.cs
index 0de992c1df..95b4fdc07e 100644
--- a/osu.Game.Rulesets.Catch.Tests/JuiceStreamPathTest.cs
+++ b/osu.Game.Rulesets.Catch.Tests/JuiceStreamPathTest.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs
index 40dc7d2403..3261fb656e 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using System.Linq;
using osu.Game.Audio;
@@ -45,7 +43,7 @@ namespace osu.Game.Rulesets.Catch.Tests
NewCombo = i % 8 == 0,
Samples = new List(new[]
{
- new HitSampleInfo(HitSampleInfo.HIT_NORMAL, "normal", volume: 100)
+ new HitSampleInfo(HitSampleInfo.HIT_NORMAL)
})
});
}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs
index 402f8f548d..569c69a633 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects;
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchModHidden.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchModHidden.cs
index 05d3361dc3..a44575a46e 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchModHidden.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchModHidden.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayer.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayer.cs
index 01cce88d9d..a82edc1df8 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayer.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayer.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using NUnit.Framework;
using osu.Game.Tests.Visual;
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs
index 8f3f39be9b..5406230359 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using System.Linq;
using NUnit.Framework;
using osu.Framework.Extensions.IEnumerableExtensions;
@@ -26,7 +24,7 @@ namespace osu.Game.Rulesets.Catch.Tests
if (withModifiedSkin)
{
AddStep("change component scale", () => Player.ChildrenOfType().First().Scale = new Vector2(2f));
- AddStep("update target", () => Player.ChildrenOfType().ForEach(LegacySkin.UpdateDrawableTarget));
+ AddStep("update target", () => Player.ChildrenOfType().ForEach(LegacySkin.UpdateDrawableTarget));
AddStep("exit player", () => Player.Exit());
CreateTest();
}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchReplay.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchReplay.cs
index cbf900ebc0..1d2ea4610d 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchReplay.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchReplay.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchStacker.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchStacker.cs
index c8979381fe..af38956002 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchStacker.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchStacker.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects;
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs
index e8231b07ad..f60ae29f77 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs
@@ -60,26 +60,24 @@ namespace osu.Game.Rulesets.Catch.Tests
[Test]
public void TestCatcherHyperStateReverted()
{
- DrawableCatchHitObject drawableObject1 = null;
- DrawableCatchHitObject drawableObject2 = null;
JudgementResult result1 = null;
JudgementResult result2 = null;
AddStep("catch hyper fruit", () =>
{
- attemptCatch(new Fruit { HyperDashTarget = new Fruit { X = 100 } }, out drawableObject1, out result1);
+ result1 = attemptCatch(new Fruit { HyperDashTarget = new Fruit { X = 100 } });
});
AddStep("catch normal fruit", () =>
{
- attemptCatch(new Fruit(), out drawableObject2, out result2);
+ result2 = attemptCatch(new Fruit());
});
AddStep("revert second result", () =>
{
- catcher.OnRevertResult(drawableObject2, result2);
+ catcher.OnRevertResult(result2);
});
checkHyperDash(true);
AddStep("revert first result", () =>
{
- catcher.OnRevertResult(drawableObject1, result1);
+ catcher.OnRevertResult(result1);
});
checkHyperDash(false);
}
@@ -87,16 +85,15 @@ namespace osu.Game.Rulesets.Catch.Tests
[Test]
public void TestCatcherAnimationStateReverted()
{
- DrawableCatchHitObject drawableObject = null;
JudgementResult result = null;
AddStep("catch kiai fruit", () =>
{
- attemptCatch(new TestKiaiFruit(), out drawableObject, out result);
+ result = attemptCatch(new TestKiaiFruit());
});
checkState(CatcherAnimationState.Kiai);
AddStep("revert result", () =>
{
- catcher.OnRevertResult(drawableObject, result);
+ catcher.OnRevertResult(result);
});
checkState(CatcherAnimationState.Idle);
}
@@ -268,23 +265,19 @@ namespace osu.Game.Rulesets.Catch.Tests
private void checkHyperDash(bool state) => AddAssert($"catcher is {(state ? "" : "not ")}hyper dashing", () => catcher.HyperDashing == state);
- private void attemptCatch(CatchHitObject hitObject)
- {
- attemptCatch(() => hitObject, 1);
- }
-
private void attemptCatch(Func hitObject, int count)
{
for (int i = 0; i < count; i++)
- attemptCatch(hitObject(), out _, out _);
+ attemptCatch(hitObject());
}
- private void attemptCatch(CatchHitObject hitObject, out DrawableCatchHitObject drawableObject, out JudgementResult result)
+ private JudgementResult attemptCatch(CatchHitObject hitObject)
{
hitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
- drawableObject = createDrawableObject(hitObject);
- result = createResult(hitObject);
+ var drawableObject = createDrawableObject(hitObject);
+ var result = createResult(hitObject);
applyResult(drawableObject, result);
+ return result;
}
private void applyResult(DrawableCatchHitObject drawableObject, JudgementResult result)
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjectsHidden.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjectsHidden.cs
index 007f309f3f..23fcd49863 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjectsHidden.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjectsHidden.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using NUnit.Framework;
using osu.Game.Rulesets.Catch.Mods;
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs
index 223c4e57fc..fda4136a37 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs
index 995daaceb1..8e7f77285c 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using NUnit.Framework;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Objects.Drawables;
@@ -28,6 +26,8 @@ namespace osu.Game.Rulesets.Catch.Tests
AddSliderStep("start time", 500, 600, 0, x =>
{
drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = x;
+ drawableFruit.RefreshStateTransforms();
+ drawableBanana.RefreshStateTransforms();
});
}
@@ -46,6 +46,8 @@ namespace osu.Game.Rulesets.Catch.Tests
AddStep("Initialize start time", () =>
{
drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = initial_start_time;
+ drawableFruit.RefreshStateTransforms();
+ drawableBanana.RefreshStateTransforms();
fruitRotation = drawableFruit.DisplayRotation;
bananaRotation = drawableBanana.DisplayRotation;
@@ -56,6 +58,8 @@ namespace osu.Game.Rulesets.Catch.Tests
AddStep("change start time", () =>
{
drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = another_start_time;
+ drawableFruit.RefreshStateTransforms();
+ drawableBanana.RefreshStateTransforms();
});
AddAssert("fruit rotation is changed", () => drawableFruit.DisplayRotation != fruitRotation);
@@ -66,6 +70,8 @@ namespace osu.Game.Rulesets.Catch.Tests
AddStep("reset start time", () =>
{
drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = initial_start_time;
+ drawableFruit.RefreshStateTransforms();
+ drawableBanana.RefreshStateTransforms();
});
AddAssert("rotation and size restored", () =>
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitVisualChange.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitVisualChange.cs
index 4b2873e0a8..1534d91e77 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitVisualChange.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitVisualChange.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Bindables;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Objects.Drawables;
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs
index f8c43a221e..3c222662f5 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Linq;
using NUnit.Framework;
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneJuiceStream.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneJuiceStream.cs
index c91f07891c..c31a7ca99f 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneJuiceStream.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneJuiceStream.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using System.Collections.Generic;
using NUnit.Framework;
using osu.Game.Beatmaps;
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneLegacyBeatmapSkin.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneLegacyBeatmapSkin.cs
index aa66fc8741..871da28142 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneLegacyBeatmapSkin.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneLegacyBeatmapSkin.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
@@ -21,7 +19,7 @@ namespace osu.Game.Rulesets.Catch.Tests
public partial class TestSceneLegacyBeatmapSkin : LegacyBeatmapSkinColourTest
{
[Resolved]
- private AudioManager audio { get; set; }
+ private AudioManager audio { get; set; } = null!;
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
index 5a2e8e0bf0..01922b2a96 100644
--- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
+++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
@@ -1,9 +1,9 @@
-
+
-
+
WinExe
diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmap.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmap.cs
index ac39b91f00..f009c10a9c 100644
--- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmap.cs
+++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmap.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps;
diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs
index 9f5d007114..2c8ef9eae0 100644
--- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs
+++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects;
using System.Collections.Generic;
@@ -28,6 +26,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
var xPositionData = obj as IHasXPosition;
var yPositionData = obj as IHasYPosition;
var comboData = obj as IHasCombo;
+ var sliderVelocityData = obj as IHasSliderVelocity;
switch (obj)
{
@@ -43,7 +42,8 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
NewCombo = comboData?.NewCombo ?? false,
ComboOffset = comboData?.ComboOffset ?? 0,
LegacyLastTickOffset = (obj as IHasLegacyLastTickOffset)?.LegacyLastTickOffset ?? 0,
- LegacyConvertedY = yPositionData?.Y ?? CatchHitObject.DEFAULT_LEGACY_CONVERT_Y
+ LegacyConvertedY = yPositionData?.Y ?? CatchHitObject.DEFAULT_LEGACY_CONVERT_Y,
+ SliderVelocity = sliderVelocityData?.SliderVelocity ?? 1
}.Yield();
case IHasDuration endTime:
diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
index 835f7c2d27..ab61b14ac4 100644
--- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
+++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs
index e0f7820262..bd6b857fe8 100644
--- a/osu.Game.Rulesets.Catch/CatchRuleset.cs
+++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs
@@ -26,6 +26,8 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Replays.Types;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
+using osu.Game.Scoring;
+using osu.Game.Screens.Ranking.Statistics;
using osu.Game.Skinning;
namespace osu.Game.Rulesets.Catch
@@ -91,6 +93,9 @@ namespace osu.Game.Rulesets.Catch
if (mods.HasFlagFast(LegacyMods.Relax))
yield return new CatchModRelax();
+
+ if (mods.HasFlagFast(LegacyMods.ScoreV2))
+ yield return new ModScoreV2();
}
public override IEnumerable GetModsFor(ModType type)
@@ -113,6 +118,7 @@ namespace osu.Game.Rulesets.Catch
new MultiMod(new CatchModDoubleTime(), new CatchModNightcore()),
new CatchModHidden(),
new CatchModFlashlight(),
+ new ModAccuracyChallenge(),
};
case ModType.Conversion:
@@ -139,6 +145,12 @@ namespace osu.Game.Rulesets.Catch
new CatchModNoScope(),
};
+ case ModType.System:
+ return new Mod[]
+ {
+ new ModScoreV2(),
+ };
+
default:
return Array.Empty();
}
@@ -201,10 +213,24 @@ namespace osu.Game.Rulesets.Catch
public int LegacyID => 2;
+ public ILegacyScoreSimulator CreateLegacyScoreSimulator() => new CatchLegacyScoreSimulator();
+
public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new CatchReplayFrame();
public override HitObjectComposer CreateHitObjectComposer() => new CatchHitObjectComposer(this);
public override IBeatmapVerifier CreateBeatmapVerifier() => new CatchBeatmapVerifier();
+
+ public override StatisticItem[] CreateStatisticsForScore(ScoreInfo score, IBeatmap playableBeatmap)
+ {
+ return new[]
+ {
+ new StatisticItem("Performance Breakdown", () => new PerformanceBreakdownChart(score, playableBeatmap)
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y
+ }),
+ };
+ }
}
}
diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs
index 2d01153f98..5c64643fd4 100644
--- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs
+++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs
@@ -27,7 +27,6 @@ namespace osu.Game.Rulesets.Catch.Difficulty
// Todo: osu!catch should not output star rating in the 'aim' attribute.
yield return (ATTRIB_ID_AIM, StarRating);
yield return (ATTRIB_ID_APPROACH_RATE, ApproachRate);
- yield return (ATTRIB_ID_MAX_COMBO, MaxCombo);
}
public override void FromDatabaseAttributes(IReadOnlyDictionary values, IBeatmapOnlineInfo onlineInfo)
@@ -36,7 +35,6 @@ namespace osu.Game.Rulesets.Catch.Difficulty
StarRating = values[ATTRIB_ID_AIM];
ApproachRate = values[ATTRIB_ID_APPROACH_RATE];
- MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO];
}
}
}
diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs
index f37479f84a..0b56405299 100644
--- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs
+++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Linq;
@@ -27,9 +25,12 @@ namespace osu.Game.Rulesets.Catch.Difficulty
public override int Version => 20220701;
+ private readonly IWorkingBeatmap workingBeatmap;
+
public CatchDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
: base(ruleset, beatmap)
{
+ workingBeatmap = beatmap;
}
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
@@ -40,18 +41,29 @@ namespace osu.Game.Rulesets.Catch.Difficulty
// this is the same as osu!, so there's potential to share the implementation... maybe
double preempt = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.ApproachRate, 1800, 1200, 450) / clockRate;
- return new CatchDifficultyAttributes
+ CatchDifficultyAttributes attributes = new CatchDifficultyAttributes
{
StarRating = Math.Sqrt(skills[0].DifficultyValue()) * star_scaling_factor,
Mods = mods,
ApproachRate = preempt > 1200.0 ? -(preempt - 1800.0) / 120.0 : -(preempt - 1200.0) / 150.0 + 5.0,
MaxCombo = beatmap.HitObjects.Count(h => h is Fruit) + beatmap.HitObjects.OfType().SelectMany(j => j.NestedHitObjects).Count(h => !(h is TinyDroplet)),
};
+
+ if (ComputeLegacyScoringValues)
+ {
+ CatchLegacyScoreSimulator sv1Simulator = new CatchLegacyScoreSimulator();
+ sv1Simulator.Simulate(workingBeatmap, beatmap, mods);
+ attributes.LegacyAccuracyScore = sv1Simulator.AccuracyScore;
+ attributes.LegacyComboScore = sv1Simulator.ComboScore;
+ attributes.LegacyBonusScoreRatio = sv1Simulator.BonusScoreRatio;
+ }
+
+ return attributes;
}
protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate)
{
- CatchHitObject lastObject = null;
+ CatchHitObject? lastObject = null;
List objects = new List();
diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchLegacyScoreSimulator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchLegacyScoreSimulator.cs
new file mode 100644
index 0000000000..c79fd36d96
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Difficulty/CatchLegacyScoreSimulator.cs
@@ -0,0 +1,142 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Judgements;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Objects.Types;
+using osu.Game.Rulesets.Scoring;
+
+namespace osu.Game.Rulesets.Catch.Difficulty
+{
+ internal class CatchLegacyScoreSimulator : ILegacyScoreSimulator
+ {
+ public int AccuracyScore { get; private set; }
+
+ public int ComboScore { get; private set; }
+
+ public double BonusScoreRatio => legacyBonusScore == 0 ? 0 : (double)modernBonusScore / legacyBonusScore;
+
+ private int legacyBonusScore;
+ private int modernBonusScore;
+ private int combo;
+
+ private double scoreMultiplier;
+
+ public void Simulate(IWorkingBeatmap workingBeatmap, IBeatmap playableBeatmap, IReadOnlyList mods)
+ {
+ IBeatmap baseBeatmap = workingBeatmap.Beatmap;
+
+ int countNormal = 0;
+ int countSlider = 0;
+ int countSpinner = 0;
+
+ foreach (HitObject obj in baseBeatmap.HitObjects)
+ {
+ switch (obj)
+ {
+ case IHasPath:
+ countSlider++;
+ break;
+
+ case IHasDuration:
+ countSpinner++;
+ break;
+
+ default:
+ countNormal++;
+ break;
+ }
+ }
+
+ int objectCount = countNormal + countSlider + countSpinner;
+
+ int drainLength = 0;
+
+ if (baseBeatmap.HitObjects.Count > 0)
+ {
+ int breakLength = baseBeatmap.Breaks.Select(b => (int)Math.Round(b.EndTime) - (int)Math.Round(b.StartTime)).Sum();
+ drainLength = ((int)Math.Round(baseBeatmap.HitObjects[^1].StartTime) - (int)Math.Round(baseBeatmap.HitObjects[0].StartTime) - breakLength) / 1000;
+ }
+
+ int difficultyPeppyStars = (int)Math.Round(
+ (baseBeatmap.Difficulty.DrainRate
+ + baseBeatmap.Difficulty.OverallDifficulty
+ + baseBeatmap.Difficulty.CircleSize
+ + Math.Clamp((float)objectCount / drainLength * 8, 0, 16)) / 38 * 5);
+
+ scoreMultiplier = difficultyPeppyStars * mods.Aggregate(1.0, (current, mod) => current * mod.ScoreMultiplier);
+
+ foreach (var obj in playableBeatmap.HitObjects)
+ simulateHit(obj);
+ }
+
+ private void simulateHit(HitObject hitObject)
+ {
+ bool increaseCombo = true;
+ bool addScoreComboMultiplier = false;
+
+ bool isBonus = false;
+ HitResult bonusResult = HitResult.None;
+
+ int scoreIncrease = 0;
+
+ switch (hitObject)
+ {
+ case TinyDroplet:
+ scoreIncrease = 10;
+ increaseCombo = false;
+ break;
+
+ case Droplet:
+ scoreIncrease = 100;
+ break;
+
+ case Fruit:
+ scoreIncrease = 300;
+ addScoreComboMultiplier = true;
+ increaseCombo = true;
+ break;
+
+ case Banana:
+ scoreIncrease = 1100;
+ increaseCombo = false;
+ isBonus = true;
+ bonusResult = HitResult.LargeBonus;
+ break;
+
+ case JuiceStream:
+ foreach (var nested in hitObject.NestedHitObjects)
+ simulateHit(nested);
+ return;
+
+ case BananaShower:
+ foreach (var nested in hitObject.NestedHitObjects)
+ simulateHit(nested);
+ return;
+ }
+
+ if (addScoreComboMultiplier)
+ {
+ // ReSharper disable once PossibleLossOfFraction (intentional to match osu-stable...)
+ ComboScore += (int)(Math.Max(0, combo - 1) * (scoreIncrease / 25 * scoreMultiplier));
+ }
+
+ if (isBonus)
+ {
+ legacyBonusScore += scoreIncrease;
+ modernBonusScore += Judgement.ToNumericResult(bonusResult);
+ }
+ else
+ AccuracyScore += scoreIncrease;
+
+ if (increaseCombo)
+ combo++;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceAttributes.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceAttributes.cs
index ccdfd30200..1335fc2d23 100644
--- a/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceAttributes.cs
+++ b/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceAttributes.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Difficulty;
namespace osu.Game.Rulesets.Catch.Difficulty
diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs
index 2a07b8019e..b30b85be2d 100644
--- a/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs
+++ b/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/osu.Game.Rulesets.Catch/Difficulty/Preprocessing/CatchDifficultyHitObject.cs b/osu.Game.Rulesets.Catch/Difficulty/Preprocessing/CatchDifficultyHitObject.cs
index c44480776f..3bcfce3a56 100644
--- a/osu.Game.Rulesets.Catch/Difficulty/Preprocessing/CatchDifficultyHitObject.cs
+++ b/osu.Game.Rulesets.Catch/Difficulty/Preprocessing/CatchDifficultyHitObject.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
using osu.Game.Rulesets.Catch.Objects;
diff --git a/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs b/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs
index 827c28f7de..cfb3fe40be 100644
--- a/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs
+++ b/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using osu.Game.Rulesets.Catch.Difficulty.Preprocessing;
using osu.Game.Rulesets.Difficulty.Preprocessing;
diff --git a/osu.Game.Rulesets.Catch/Edit/BananaShowerCompositionTool.cs b/osu.Game.Rulesets.Catch/Edit/BananaShowerCompositionTool.cs
index e64a51f03a..31075db7d1 100644
--- a/osu.Game.Rulesets.Catch/Edit/BananaShowerCompositionTool.cs
+++ b/osu.Game.Rulesets.Catch/Edit/BananaShowerCompositionTool.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Edit.Blueprints;
diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerPlacementBlueprint.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerPlacementBlueprint.cs
index 166fa44303..1e63d32c41 100644
--- a/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerPlacementBlueprint.cs
+++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerPlacementBlueprint.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Catch.Edit.Blueprints.Components;
@@ -19,6 +17,8 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints
private double placementStartTime;
private double placementEndTime;
+ protected override bool IsValidForPlacement => HitObject.Duration > 0;
+
public BananaShowerPlacementBlueprint()
{
InternalChild = outline = new TimeSpanOutline();
@@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints
case PlacementState.Active:
if (e.Button != MouseButton.Right) break;
- EndPlacement(HitObject.Duration > 0);
+ EndPlacement(true);
return true;
}
diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerSelectionBlueprint.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerSelectionBlueprint.cs
index 2c545e8f0e..f6dd67889e 100644
--- a/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerSelectionBlueprint.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Catch.Objects;
namespace osu.Game.Rulesets.Catch.Edit.Blueprints
diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/CatchPlacementBlueprint.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/CatchPlacementBlueprint.cs
index 94373147d2..1a2990e4ac 100644
--- a/osu.Game.Rulesets.Catch/Edit/Blueprints/CatchPlacementBlueprint.cs
+++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/CatchPlacementBlueprint.cs
@@ -1,14 +1,11 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Allocation;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling;
-using osuTK;
namespace osu.Game.Rulesets.Catch.Edit.Blueprints
{
@@ -20,13 +17,11 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints
protected ScrollingHitObjectContainer HitObjectContainer => (ScrollingHitObjectContainer)playfield.HitObjectContainer;
[Resolved]
- private Playfield playfield { get; set; }
+ private Playfield playfield { get; set; } = null!;
public CatchPlacementBlueprint()
: base(new THitObject())
{
}
-
- public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
}
}
diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/CatchSelectionBlueprint.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/CatchSelectionBlueprint.cs
index 87c33a9cb8..8220fb88b4 100644
--- a/osu.Game.Rulesets.Catch/Edit/Blueprints/CatchSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/CatchSelectionBlueprint.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Allocation;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Edit;
@@ -31,7 +29,7 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints
protected ScrollingHitObjectContainer HitObjectContainer => (ScrollingHitObjectContainer)playfield.HitObjectContainer;
[Resolved]
- private Playfield playfield { get; set; }
+ private Playfield playfield { get; set; } = null!;
protected CatchSelectionBlueprint(THitObject hitObject)
: base(hitObject)
diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/EditablePath.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/EditablePath.cs
index 006ea6e9cf..7a577f8a83 100644
--- a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/EditablePath.cs
+++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/EditablePath.cs
@@ -1,13 +1,10 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
-using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -42,9 +39,8 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints.Components
private readonly List previousVertexStates = new List();
- [Resolved(CanBeNull = true)]
- [CanBeNull]
- private IBeatSnapProvider beatSnapProvider { get; set; }
+ [Resolved]
+ private IBeatSnapProvider? beatSnapProvider { get; set; }
protected EditablePath(Func positionToTime)
{
@@ -95,7 +91,7 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints.Components
public void UpdateHitObjectFromPath(JuiceStream hitObject)
{
// The SV setting may need to be changed for the current path.
- var svBindable = hitObject.DifficultyControlPoint.SliderVelocityBindable;
+ var svBindable = hitObject.SliderVelocityBindable;
double svToVelocityFactor = hitObject.Velocity / svBindable.Value;
double requiredVelocity = path.ComputeRequiredVelocity();
diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/FruitOutline.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/FruitOutline.cs
index dc2b038e01..c7805544ea 100644
--- a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/FruitOutline.cs
+++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/FruitOutline.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/NestedOutlineContainer.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/NestedOutlineContainer.cs
index ac0c850bca..c1f46539fa 100644
--- a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/NestedOutlineContainer.cs
+++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/NestedOutlineContainer.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics;
diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/PlacementEditablePath.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/PlacementEditablePath.cs
index ba2f5ed0eb..3a7d6d87f2 100644
--- a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/PlacementEditablePath.cs
+++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/PlacementEditablePath.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using osu.Game.Rulesets.Catch.Objects;
using osuTK;
diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/ScrollingPath.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/ScrollingPath.cs
index 6deb5a174f..a22abcb76d 100644
--- a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/ScrollingPath.cs
+++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/ScrollingPath.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics;
diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/SelectionEditablePath.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/SelectionEditablePath.cs
index 3a44f7ac8a..c7a26ca15a 100644
--- a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/SelectionEditablePath.cs
+++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/SelectionEditablePath.cs
@@ -1,12 +1,9 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Linq;
-using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.UserInterface;
@@ -25,9 +22,8 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints.Components
// To handle when the editor is scrolled while dragging.
private Vector2 dragStartPosition;
- [Resolved(CanBeNull = true)]
- [CanBeNull]
- private IEditorChangeHandler changeHandler { get; set; }
+ [Resolved]
+ private IEditorChangeHandler? changeHandler { get; set; }
public SelectionEditablePath(Func positionToTime)
: base(positionToTime)
diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/TimeSpanOutline.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/TimeSpanOutline.cs
index a1d5d7ae3e..9d450cd355 100644
--- a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/TimeSpanOutline.cs
+++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/TimeSpanOutline.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/VertexPiece.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/VertexPiece.cs
index 49570d3735..07d7c72698 100644
--- a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/VertexPiece.cs
+++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/VertexPiece.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
@@ -15,7 +13,7 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints.Components
public partial class VertexPiece : Circle
{
[Resolved]
- private OsuColour osuColour { get; set; }
+ private OsuColour osuColour { get; set; } = null!;
public VertexPiece()
{
diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/FruitPlacementBlueprint.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/FruitPlacementBlueprint.cs
index af75023e68..72592891fb 100644
--- a/osu.Game.Rulesets.Catch/Edit/Blueprints/FruitPlacementBlueprint.cs
+++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/FruitPlacementBlueprint.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Catch.Edit.Blueprints.Components;
using osu.Game.Rulesets.Catch.Objects;
diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/FruitSelectionBlueprint.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/FruitSelectionBlueprint.cs
index 319b1b5e20..2737b283ef 100644
--- a/osu.Game.Rulesets.Catch/Edit/Blueprints/FruitSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/FruitSelectionBlueprint.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Catch.Edit.Blueprints.Components;
using osu.Game.Rulesets.Catch.Objects;
diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamPlacementBlueprint.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamPlacementBlueprint.cs
index 0e2ee334ff..9e50b5a80f 100644
--- a/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamPlacementBlueprint.cs
+++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamPlacementBlueprint.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Graphics;
using osu.Framework.Input;
using osu.Framework.Input.Events;
@@ -24,7 +22,9 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints
private int lastEditablePathId = -1;
- private InputManager inputManager;
+ private InputManager inputManager = null!;
+
+ protected override bool IsValidForPlacement => HitObject.Duration > 0;
public JuiceStreamPlacementBlueprint()
{
@@ -72,7 +72,7 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints
return true;
case MouseButton.Right:
- EndPlacement(HitObject.Duration > 0);
+ EndPlacement(true);
return true;
}
diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamSelectionBlueprint.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamSelectionBlueprint.cs
index 99ec5e2b0c..49d778ad08 100644
--- a/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamSelectionBlueprint.cs
@@ -1,11 +1,8 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using System.Linq;
-using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Caching;
using osu.Framework.Graphics;
@@ -53,9 +50,8 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints
private Vector2 rightMouseDownPosition;
- [Resolved(CanBeNull = true)]
- [CanBeNull]
- private EditorBeatmap editorBeatmap { get; set; }
+ [Resolved]
+ private EditorBeatmap? editorBeatmap { get; set; }
public JuiceStreamSelectionBlueprint(JuiceStream hitObject)
: base(hitObject)
diff --git a/osu.Game.Rulesets.Catch/Edit/CatchBeatSnapGrid.cs b/osu.Game.Rulesets.Catch/Edit/CatchBeatSnapGrid.cs
new file mode 100644
index 0000000000..6862696b3a
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Edit/CatchBeatSnapGrid.cs
@@ -0,0 +1,180 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using osu.Framework.Allocation;
+using osu.Framework.Caching;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics;
+using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Rulesets.Edit;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.UI.Scrolling;
+using osu.Game.Screens.Edit;
+using osuTK.Graphics;
+
+namespace osu.Game.Rulesets.Catch.Edit
+{
+ ///
+ /// A grid which displays coloured beat divisor lines in proximity to the selection or placement cursor.
+ ///
+ ///
+ /// This class heavily borrows from osu!mania's implementation (ManiaBeatSnapGrid).
+ /// If further changes are to be made, they should also be applied there.
+ /// If the scale of the changes are large enough, abstracting may be a good path.
+ ///
+ public partial class CatchBeatSnapGrid : Component
+ {
+ private const double visible_range = 750;
+
+ ///
+ /// The range of time values of the current selection.
+ ///
+ public (double start, double end)? SelectionTimeRange
+ {
+ set
+ {
+ if (value == selectionTimeRange)
+ return;
+
+ selectionTimeRange = value;
+ lineCache.Invalidate();
+ }
+ }
+
+ [Resolved]
+ private EditorBeatmap beatmap { get; set; } = null!;
+
+ [Resolved]
+ private OsuColour colours { get; set; } = null!;
+
+ [Resolved]
+ private BindableBeatDivisor beatDivisor { get; set; } = null!;
+
+ private readonly Cached lineCache = new Cached();
+
+ private (double start, double end)? selectionTimeRange;
+
+ private ScrollingHitObjectContainer lineContainer = null!;
+
+ [BackgroundDependencyLoader]
+ private void load(HitObjectComposer composer)
+ {
+ lineContainer = new ScrollingHitObjectContainer();
+
+ ((CatchPlayfield)composer.Playfield).UnderlayElements.Add(lineContainer);
+
+ beatDivisor.BindValueChanged(_ => createLines(), true);
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+
+ if (!lineCache.IsValid)
+ {
+ lineCache.Validate();
+ createLines();
+ }
+ }
+
+ private readonly Stack availableLines = new Stack();
+
+ private void createLines()
+ {
+ foreach (var line in lineContainer.Objects.OfType())
+ availableLines.Push(line);
+
+ lineContainer.Clear();
+
+ if (selectionTimeRange == null)
+ return;
+
+ var range = selectionTimeRange.Value;
+
+ var timingPoint = beatmap.ControlPointInfo.TimingPointAt(range.start - visible_range);
+
+ double time = timingPoint.Time;
+ int beat = 0;
+
+ // progress time until in the visible range.
+ while (time < range.start - visible_range)
+ {
+ time += timingPoint.BeatLength / beatDivisor.Value;
+ beat++;
+ }
+
+ while (time < range.end + visible_range)
+ {
+ var nextTimingPoint = beatmap.ControlPointInfo.TimingPointAt(time);
+
+ // switch to the next timing point if we have reached it.
+ if (nextTimingPoint.Time > timingPoint.Time)
+ {
+ beat = 0;
+ time = nextTimingPoint.Time;
+ timingPoint = nextTimingPoint;
+ }
+
+ Color4 colour = BindableBeatDivisor.GetColourFor(
+ BindableBeatDivisor.GetDivisorForBeatIndex(beat, beatDivisor.Value), colours);
+
+ if (!availableLines.TryPop(out var line))
+ line = new DrawableGridLine();
+
+ line.HitObject.StartTime = time;
+ line.Colour = colour;
+
+ lineContainer.Add(line);
+
+ beat++;
+ time += timingPoint.BeatLength / beatDivisor.Value;
+ }
+
+ // required to update ScrollingHitObjectContainer's cache.
+ lineContainer.UpdateSubTree();
+
+ foreach (var line in lineContainer.Objects.OfType())
+ {
+ time = line.HitObject.StartTime;
+
+ if (time >= range.start && time <= range.end)
+ line.Alpha = 1;
+ else
+ {
+ double timeSeparation = time < range.start ? range.start - time : time - range.end;
+ line.Alpha = (float)Math.Max(0, 1 - timeSeparation / visible_range);
+ }
+ }
+ }
+
+ private partial class DrawableGridLine : DrawableHitObject
+ {
+ public DrawableGridLine()
+ : base(new HitObject())
+ {
+ RelativeSizeAxes = Axes.X;
+ Height = 2;
+
+ AddInternal(new Box { RelativeSizeAxes = Axes.Both });
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Origin = Anchor.BottomLeft;
+ Anchor = Anchor.BottomLeft;
+ }
+
+ protected override void UpdateInitialTransforms()
+ {
+ // don't perform any fading – we are handling that ourselves.
+ LifetimeEnd = HitObject.StartTime + visible_range;
+ }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Edit/CatchBeatmapVerifier.cs b/osu.Game.Rulesets.Catch/Edit/CatchBeatmapVerifier.cs
index 6570a19a92..c7a41a4e22 100644
--- a/osu.Game.Rulesets.Catch/Edit/CatchBeatmapVerifier.cs
+++ b/osu.Game.Rulesets.Catch/Edit/CatchBeatmapVerifier.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using System.Linq;
using osu.Game.Rulesets.Catch.Edit.Checks;
diff --git a/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs b/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs
index 9408a9f95c..3979d30616 100644
--- a/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs
+++ b/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Catch.Edit.Blueprints;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Edit;
@@ -20,7 +18,7 @@ namespace osu.Game.Rulesets.Catch.Edit
protected override SelectionHandler CreateSelectionHandler() => new CatchSelectionHandler();
- public override HitObjectSelectionBlueprint CreateHitObjectBlueprintFor(HitObject hitObject)
+ public override HitObjectSelectionBlueprint? CreateHitObjectBlueprintFor(HitObject hitObject)
{
switch (hitObject)
{
diff --git a/osu.Game.Rulesets.Catch/Edit/CatchDistanceSnapGrid.cs b/osu.Game.Rulesets.Catch/Edit/CatchDistanceSnapGrid.cs
index 43918bda57..cf6ddc66ed 100644
--- a/osu.Game.Rulesets.Catch/Edit/CatchDistanceSnapGrid.cs
+++ b/osu.Game.Rulesets.Catch/Edit/CatchDistanceSnapGrid.cs
@@ -1,12 +1,9 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Linq;
-using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -39,7 +36,7 @@ namespace osu.Game.Rulesets.Catch.Edit
private readonly List verticalLineVertices = new List();
[Resolved]
- private Playfield playfield { get; set; }
+ private Playfield playfield { get; set; } = null!;
private ScrollingHitObjectContainer hitObjectContainer => (ScrollingHitObjectContainer)playfield.HitObjectContainer;
@@ -106,8 +103,7 @@ namespace osu.Game.Rulesets.Catch.Edit
}
}
- [CanBeNull]
- public SnapResult GetSnappedPosition(Vector2 screenSpacePosition)
+ public SnapResult? GetSnappedPosition(Vector2 screenSpacePosition)
{
double time = hitObjectContainer.TimeAtScreenSpacePosition(screenSpacePosition);
diff --git a/osu.Game.Rulesets.Catch/Edit/CatchEditorPlayfield.cs b/osu.Game.Rulesets.Catch/Edit/CatchEditorPlayfield.cs
index bca89c6024..c9481c2757 100644
--- a/osu.Game.Rulesets.Catch/Edit/CatchEditorPlayfield.cs
+++ b/osu.Game.Rulesets.Catch/Edit/CatchEditorPlayfield.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.UI;
diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs
index bbdffbf39c..f2877572e8 100644
--- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs
+++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs
@@ -1,12 +1,9 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Linq;
-using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.EnumExtensions;
@@ -32,9 +29,11 @@ namespace osu.Game.Rulesets.Catch.Edit
{
private const float distance_snap_radius = 50;
- private CatchDistanceSnapGrid distanceSnapGrid;
+ private CatchDistanceSnapGrid distanceSnapGrid = null!;
- private InputManager inputManager;
+ private InputManager inputManager = null!;
+
+ private CatchBeatSnapGrid beatSnapGrid = null!;
private readonly BindableDouble timeRangeMultiplier = new BindableDouble(1)
{
@@ -51,7 +50,6 @@ namespace osu.Game.Rulesets.Catch.Edit
private void load()
{
// todo: enable distance spacing once catch supports applying it to its existing distance snap grid implementation.
- RightSideToolboxContainer.Alpha = 0;
DistanceSpacingMultiplier.Disabled = true;
LayerBelowRuleset.Add(new PlayfieldBorder
@@ -69,6 +67,8 @@ namespace osu.Game.Rulesets.Catch.Edit
Catcher.BASE_DASH_SPEED, -Catcher.BASE_DASH_SPEED,
Catcher.BASE_WALK_SPEED, -Catcher.BASE_WALK_SPEED,
}));
+
+ AddInternal(beatSnapGrid = new CatchBeatSnapGrid());
}
protected override void LoadComplete()
@@ -78,6 +78,29 @@ namespace osu.Game.Rulesets.Catch.Edit
inputManager = GetContainingInputManager();
}
+ protected override void UpdateAfterChildren()
+ {
+ base.UpdateAfterChildren();
+
+ if (BlueprintContainer.CurrentTool is SelectTool)
+ {
+ if (EditorBeatmap.SelectedHitObjects.Any())
+ {
+ beatSnapGrid.SelectionTimeRange = (EditorBeatmap.SelectedHitObjects.Min(h => h.StartTime), EditorBeatmap.SelectedHitObjects.Max(h => h.GetEndTime()));
+ }
+ else
+ beatSnapGrid.SelectionTimeRange = null;
+ }
+ else
+ {
+ var result = FindSnappedPositionAndTime(inputManager.CurrentState.Mouse.Position);
+ if (result.Time is double time)
+ beatSnapGrid.SelectionTimeRange = (time, time);
+ else
+ beatSnapGrid.SelectionTimeRange = null;
+ }
+ }
+
protected override double ReadCurrentDistanceSnap(HitObject before, HitObject after)
{
// osu!catch's distance snap implementation is limited, in that a custom spacing cannot be specified.
@@ -117,7 +140,7 @@ namespace osu.Game.Rulesets.Catch.Edit
return base.OnPressed(e);
}
- protected override DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null) =>
+ protected override DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList? mods = null) =>
new DrawableCatchEditorRuleset(ruleset, beatmap, mods)
{
TimeRangeMultiplier = { BindTarget = timeRangeMultiplier, }
@@ -136,7 +159,7 @@ namespace osu.Game.Rulesets.Catch.Edit
result.ScreenSpacePosition.X = screenSpacePosition.X;
- if (snapType.HasFlagFast(SnapType.Grids))
+ if (snapType.HasFlagFast(SnapType.RelativeGrids))
{
if (distanceSnapGrid.IsPresent && distanceSnapGrid.GetSnappedPosition(result.ScreenSpacePosition) is SnapResult snapResult &&
Vector2.Distance(snapResult.ScreenSpacePosition, result.ScreenSpacePosition) < distance_snap_radius)
@@ -150,8 +173,7 @@ namespace osu.Game.Rulesets.Catch.Edit
protected override ComposeBlueprintContainer CreateBlueprintContainer() => new CatchBlueprintContainer(this);
- [CanBeNull]
- private PalpableCatchHitObject getLastSnappableHitObject(double time)
+ private PalpableCatchHitObject? getLastSnappableHitObject(double time)
{
var hitObject = EditorBeatmap.HitObjects.OfType().LastOrDefault(h => h.GetEndTime() < time && !(h is BananaShower));
@@ -168,8 +190,7 @@ namespace osu.Game.Rulesets.Catch.Edit
}
}
- [CanBeNull]
- private PalpableCatchHitObject getDistanceSnapGridSourceHitObject()
+ private PalpableCatchHitObject? getDistanceSnapGridSourceHitObject()
{
switch (BlueprintContainer.CurrentTool)
{
@@ -188,7 +209,8 @@ namespace osu.Game.Rulesets.Catch.Edit
if (EditorBeatmap.PlacementObject.Value is JuiceStream)
{
// Juice stream path is not subject to snapping.
- return null;
+ if (BlueprintContainer.CurrentPlacement.PlacementActive is PlacementBlueprint.PlacementState.Active)
+ return null;
}
double timeAtCursor = ((CatchPlayfield)Playfield).TimeAtScreenSpacePosition(inputManager.CurrentState.Mouse.Position);
diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectUtils.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectUtils.cs
index 889d3909bd..bd33080109 100644
--- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectUtils.cs
+++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectUtils.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using System.Linq;
using osu.Game.Rulesets.Catch.Objects;
diff --git a/osu.Game.Rulesets.Catch/Edit/CatchSelectionHandler.cs b/osu.Game.Rulesets.Catch/Edit/CatchSelectionHandler.cs
index d9d7047920..418351e2f3 100644
--- a/osu.Game.Rulesets.Catch/Edit/CatchSelectionHandler.cs
+++ b/osu.Game.Rulesets.Catch/Edit/CatchSelectionHandler.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Linq;
@@ -23,7 +21,7 @@ namespace osu.Game.Rulesets.Catch.Edit
protected ScrollingHitObjectContainer HitObjectContainer => (ScrollingHitObjectContainer)playfield.HitObjectContainer;
[Resolved]
- private Playfield playfield { get; set; }
+ private Playfield playfield { get; set; } = null!;
public override bool HandleMovement(MoveSelectionEvent moveEvent)
{
diff --git a/osu.Game.Rulesets.Catch/Edit/DrawableCatchEditorRuleset.cs b/osu.Game.Rulesets.Catch/Edit/DrawableCatchEditorRuleset.cs
index 0a50ad1df4..7ad2106ab9 100644
--- a/osu.Game.Rulesets.Catch/Edit/DrawableCatchEditorRuleset.cs
+++ b/osu.Game.Rulesets.Catch/Edit/DrawableCatchEditorRuleset.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using osu.Framework.Bindables;
using osu.Game.Beatmaps;
@@ -16,7 +14,7 @@ namespace osu.Game.Rulesets.Catch.Edit
{
public readonly BindableDouble TimeRangeMultiplier = new BindableDouble(1);
- public DrawableCatchEditorRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null)
+ public DrawableCatchEditorRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList? mods = null)
: base(ruleset, beatmap, mods)
{
}
diff --git a/osu.Game.Rulesets.Catch/Edit/FruitCompositionTool.cs b/osu.Game.Rulesets.Catch/Edit/FruitCompositionTool.cs
index 5c13692b51..f776fe39c1 100644
--- a/osu.Game.Rulesets.Catch/Edit/FruitCompositionTool.cs
+++ b/osu.Game.Rulesets.Catch/Edit/FruitCompositionTool.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Edit.Blueprints;
diff --git a/osu.Game.Rulesets.Catch/Edit/JuiceStreamCompositionTool.cs b/osu.Game.Rulesets.Catch/Edit/JuiceStreamCompositionTool.cs
index 85cf89f700..cb66e2952e 100644
--- a/osu.Game.Rulesets.Catch/Edit/JuiceStreamCompositionTool.cs
+++ b/osu.Game.Rulesets.Catch/Edit/JuiceStreamCompositionTool.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Edit.Blueprints;
diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchBananaJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchBananaJudgement.cs
index 15f6e4a64d..b919102215 100644
--- a/osu.Game.Rulesets.Catch/Judgements/CatchBananaJudgement.cs
+++ b/osu.Game.Rulesets.Catch/Judgements/CatchBananaJudgement.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchDropletJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchDropletJudgement.cs
index 90aa6f41a1..8fd7b93e4c 100644
--- a/osu.Game.Rulesets.Catch/Judgements/CatchDropletJudgement.cs
+++ b/osu.Game.Rulesets.Catch/Judgements/CatchDropletJudgement.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Judgements
diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs
index e5d6429660..ccafe0abc4 100644
--- a/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs
+++ b/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Scoring;
diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchJudgementResult.cs b/osu.Game.Rulesets.Catch/Judgements/CatchJudgementResult.cs
index 6cc79f9619..4cec61d016 100644
--- a/osu.Game.Rulesets.Catch/Judgements/CatchJudgementResult.cs
+++ b/osu.Game.Rulesets.Catch/Judgements/CatchJudgementResult.cs
@@ -1,9 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
-using JetBrains.Annotations;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
@@ -22,7 +19,7 @@ namespace osu.Game.Rulesets.Catch.Judgements
///
public bool CatcherHyperDash;
- public CatchJudgementResult([NotNull] HitObject hitObject, [NotNull] Judgement judgement)
+ public CatchJudgementResult(HitObject hitObject, Judgement judgement)
: base(hitObject, judgement)
{
}
diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchTinyDropletJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchTinyDropletJudgement.cs
index c9052e3c39..d957d4171b 100644
--- a/osu.Game.Rulesets.Catch/Judgements/CatchTinyDropletJudgement.cs
+++ b/osu.Game.Rulesets.Catch/Judgements/CatchTinyDropletJudgement.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Judgements
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModDaycore.cs b/osu.Game.Rulesets.Catch/Mods/CatchModDaycore.cs
index cae19e9468..180cb98ed7 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModDaycore.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModDaycore.cs
@@ -7,6 +7,5 @@ namespace osu.Game.Rulesets.Catch.Mods
{
public class CatchModDaycore : ModDaycore
{
- public override double ScoreMultiplier => 0.3;
}
}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs b/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs
index e59a0a0431..6efb415880 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs
@@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Catch.Mods
public DifficultyBindable CircleSize { get; } = new DifficultyBindable
{
Precision = 0.1f,
- MinValue = 1,
+ MinValue = 0,
MaxValue = 10,
ExtendedMaxValue = 11,
ReadCurrentFromDifficulty = diff => diff.CircleSize,
@@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Catch.Mods
public DifficultyBindable ApproachRate { get; } = new DifficultyBindable
{
Precision = 0.1f,
- MinValue = 1,
+ MinValue = 0,
MaxValue = 10,
ExtendedMaxValue = 11,
ReadCurrentFromDifficulty = diff => diff.ApproachRate,
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModDoubleTime.cs b/osu.Game.Rulesets.Catch/Mods/CatchModDoubleTime.cs
index 57c06e1cd1..83db9f665b 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModDoubleTime.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModDoubleTime.cs
@@ -7,6 +7,5 @@ namespace osu.Game.Rulesets.Catch.Mods
{
public class CatchModDoubleTime : ModDoubleTime
{
- public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1;
}
}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModFloatingFruits.cs b/osu.Game.Rulesets.Catch/Mods/CatchModFloatingFruits.cs
index e12181d051..dd6757eac9 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModFloatingFruits.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModFloatingFruits.cs
@@ -21,10 +21,10 @@ namespace osu.Game.Rulesets.Catch.Mods
public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
{
- drawableRuleset.Anchor = Anchor.Centre;
- drawableRuleset.Origin = Anchor.Centre;
+ drawableRuleset.PlayfieldAdjustmentContainer.Anchor = Anchor.Centre;
+ drawableRuleset.PlayfieldAdjustmentContainer.Origin = Anchor.Centre;
- drawableRuleset.Scale = new Vector2(1, -1);
+ drawableRuleset.PlayfieldAdjustmentContainer.Scale = new Vector2(1, -1);
}
}
}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModHalfTime.cs b/osu.Game.Rulesets.Catch/Mods/CatchModHalfTime.cs
index ce06b841aa..3afb8c3d89 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModHalfTime.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModHalfTime.cs
@@ -7,6 +7,5 @@ namespace osu.Game.Rulesets.Catch.Mods
{
public class CatchModHalfTime : ModHalfTime
{
- public override double ScoreMultiplier => 0.3;
}
}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModNightcore.cs b/osu.Game.Rulesets.Catch/Mods/CatchModNightcore.cs
index 9e38913be7..c537897439 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModNightcore.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModNightcore.cs
@@ -8,6 +8,5 @@ namespace osu.Game.Rulesets.Catch.Mods
{
public class CatchModNightcore : ModNightcore
{
- public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1;
}
}
diff --git a/osu.Game.Rulesets.Catch/Objects/Banana.cs b/osu.Game.Rulesets.Catch/Objects/Banana.cs
index af03c9acab..b80527f379 100644
--- a/osu.Game.Rulesets.Catch/Objects/Banana.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Banana.cs
@@ -22,11 +22,11 @@ namespace osu.Game.Rulesets.Catch.Objects
public override Judgement CreateJudgement() => new CatchBananaJudgement();
- private static readonly List samples = new List { new BananaHitSampleInfo() };
+ private static readonly IList default_banana_samples = new List { new BananaHitSampleInfo() }.AsReadOnly();
public Banana()
{
- Samples = samples;
+ Samples = default_banana_samples;
}
// override any external colour changes with banananana
@@ -47,18 +47,18 @@ namespace osu.Game.Rulesets.Catch.Objects
}
}
- private class BananaHitSampleInfo : HitSampleInfo, IEquatable
+ public class BananaHitSampleInfo : HitSampleInfo, IEquatable
{
private static readonly string[] lookup_names = { "Gameplay/metronomelow", "Gameplay/catch-banana" };
public override IEnumerable LookupNames => lookup_names;
- public BananaHitSampleInfo(int volume = 0)
+ public BananaHitSampleInfo(int volume = 100)
: base(string.Empty, volume: volume)
{
}
- public sealed override HitSampleInfo With(Optional newName = default, Optional newBank = default, Optional newSuffix = default, Optional newVolume = default)
+ public sealed override HitSampleInfo With(Optional newName = default, Optional newBank = default, Optional newSuffix = default, Optional newVolume = default)
=> new BananaHitSampleInfo(newVolume.GetOr(Volume));
public bool Equals(BananaHitSampleInfo? other)
diff --git a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
index e5541e49c1..b05c8e5f77 100644
--- a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
+++ b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
@@ -1,9 +1,9 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
+using System.Collections.Generic;
using System.Threading;
+using osu.Game.Audio;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Types;
@@ -41,6 +41,7 @@ namespace osu.Game.Rulesets.Catch.Objects
{
StartTime = time,
BananaIndex = i,
+ Samples = new List { new Banana.BananaHitSampleInfo(CreateHitSampleInfo().Volume) }
});
time += spacing;
diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
index cd2b8348e2..f4bd515995 100644
--- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
+++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using Newtonsoft.Json;
using osu.Framework.Bindables;
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtBanana.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtBanana.cs
index 65d91bffe2..bfeb37b1b7 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtBanana.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtBanana.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Catch.Skinning.Default;
namespace osu.Game.Rulesets.Catch.Objects.Drawables
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtDroplet.cs
index ed8bf17747..d228c629c0 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtDroplet.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtDroplet.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Catch.Skinning.Default;
namespace osu.Game.Rulesets.Catch.Objects.Drawables
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtFruit.cs
index d296052220..99dcac5268 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtFruit.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtFruit.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Catch.Skinning.Default;
namespace osu.Game.Rulesets.Catch.Objects.Drawables
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs
index 436edf6367..0c26c52171 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@@ -19,7 +17,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
[Cached(typeof(IHasCatchObjectState))]
public abstract partial class CaughtObject : SkinnableDrawable, IHasCatchObjectState
{
- public PalpableCatchHitObject HitObject { get; private set; }
+ public PalpableCatchHitObject HitObject { get; private set; } = null!;
public Bindable AccentColour { get; } = new Bindable();
public Bindable HyperDash { get; } = new Bindable();
public Bindable IndexInBeatmap { get; } = new Bindable();
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs
index 51addaebd5..26e304cf3f 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs
@@ -1,9 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
-using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Catch.Skinning.Default;
@@ -18,7 +15,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
{
}
- public DrawableBanana([CanBeNull] Banana h)
+ public DrawableBanana(Banana? h)
: base(h)
{
}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBananaShower.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBananaShower.cs
index c5ae1b5526..03adbce885 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBananaShower.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBananaShower.cs
@@ -1,9 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
-using JetBrains.Annotations;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Objects.Drawables;
@@ -19,7 +16,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
{
}
- public DrawableBananaShower([CanBeNull] BananaShower s)
+ public DrawableBananaShower(BananaShower? s)
: base(s)
{
RelativeSizeAxes = Axes.X;
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs
index c25bc7d076..7f8c17861d 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs
@@ -53,6 +53,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
XOffsetBindable.UnbindFrom(HitObject.XOffsetBindable);
}
+ [CanBeNull]
public Func CheckPosition;
protected override JudgementResult CreateResult(Judgement judgement) => new CatchJudgementResult(HitObject, judgement);
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs
index e8b0c4a9fb..8f32cdcc31 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs
@@ -1,9 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
-using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Catch.Skinning.Default;
@@ -18,7 +15,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
{
}
- public DrawableDroplet([CanBeNull] CatchHitObject h)
+ public DrawableDroplet(CatchHitObject? h)
: base(h)
{
}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs
index 4347c77383..52c53523e6 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs
@@ -1,9 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
-using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Catch.Skinning.Default;
@@ -18,7 +15,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
{
}
- public DrawableFruit([CanBeNull] Fruit h)
+ public DrawableFruit(Fruit? h)
: base(h)
{
}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableJuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableJuiceStream.cs
index 1ad1664122..41ecf59276 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableJuiceStream.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableJuiceStream.cs
@@ -1,9 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
-using JetBrains.Annotations;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Objects.Drawables;
@@ -19,7 +16,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
{
}
- public DrawableJuiceStream([CanBeNull] JuiceStream s)
+ public DrawableJuiceStream(JuiceStream? s)
: base(s)
{
RelativeSizeAxes = Axes.X;
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawablePalpableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawablePalpableCatchHitObject.cs
index 8468cc0a6a..4a9661f108 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawablePalpableCatchHitObject.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawablePalpableCatchHitObject.cs
@@ -1,9 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
-using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@@ -42,7 +39,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
public float DisplayRotation => ScalingContainer.Rotation;
- protected DrawablePalpableCatchHitObject([CanBeNull] CatchHitObject h)
+ protected DrawablePalpableCatchHitObject(CatchHitObject? h)
: base(h)
{
Origin = Anchor.Centre;
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableTinyDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableTinyDroplet.cs
index 8e98efdbda..f820ccdc62 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableTinyDroplet.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableTinyDroplet.cs
@@ -1,10 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
-using JetBrains.Annotations;
-
namespace osu.Game.Rulesets.Catch.Objects.Drawables
{
public partial class DrawableTinyDroplet : DrawableDroplet
@@ -16,7 +12,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
{
}
- public DrawableTinyDroplet([CanBeNull] TinyDroplet h)
+ public DrawableTinyDroplet(TinyDroplet? h)
: base(h)
{
}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/IHasCatchObjectState.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/IHasCatchObjectState.cs
index f30ef0831a..18fc0db6e3 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawables/IHasCatchObjectState.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/IHasCatchObjectState.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Bindables;
using osuTK;
using osuTK.Graphics;
diff --git a/osu.Game.Rulesets.Catch/Objects/Droplet.cs b/osu.Game.Rulesets.Catch/Objects/Droplet.cs
index ecaa4bfaf4..9c1004a04b 100644
--- a/osu.Game.Rulesets.Catch/Objects/Droplet.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Droplet.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Judgements;
diff --git a/osu.Game.Rulesets.Catch/Objects/Fruit.cs b/osu.Game.Rulesets.Catch/Objects/Fruit.cs
index bdf8b3f28d..4818fe2cad 100644
--- a/osu.Game.Rulesets.Catch/Objects/Fruit.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Fruit.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Judgements;
diff --git a/osu.Game.Rulesets.Catch/Objects/FruitVisualRepresentation.cs b/osu.Game.Rulesets.Catch/Objects/FruitVisualRepresentation.cs
index e5d013dafc..7ec7050245 100644
--- a/osu.Game.Rulesets.Catch/Objects/FruitVisualRepresentation.cs
+++ b/osu.Game.Rulesets.Catch/Objects/FruitVisualRepresentation.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
namespace osu.Game.Rulesets.Catch.Objects
{
public enum FruitVisualRepresentation
diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
index 015457e84f..169e99c90c 100644
--- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
+++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
@@ -1,13 +1,12 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Newtonsoft.Json;
+using osu.Framework.Bindables;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
@@ -18,7 +17,7 @@ using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Rulesets.Catch.Objects
{
- public class JuiceStream : CatchHitObject, IHasPathWithRepeats
+ public class JuiceStream : CatchHitObject, IHasPathWithRepeats, IHasSliderVelocity
{
///
/// Positional distance that results in a duration of one second, before any speed adjustments.
@@ -29,6 +28,19 @@ namespace osu.Game.Rulesets.Catch.Objects
public int RepeatCount { get; set; }
+ public BindableNumber SliderVelocityBindable { get; } = new BindableDouble(1)
+ {
+ Precision = 0.01,
+ MinValue = 0.1,
+ MaxValue = 10
+ };
+
+ public double SliderVelocity
+ {
+ get => SliderVelocityBindable.Value;
+ set => SliderVelocityBindable.Value = value;
+ }
+
[JsonIgnore]
private double velocityFactor;
@@ -36,10 +48,10 @@ namespace osu.Game.Rulesets.Catch.Objects
private double tickDistanceFactor;
[JsonIgnore]
- public double Velocity => velocityFactor * DifficultyControlPoint.SliderVelocity;
+ public double Velocity => velocityFactor * SliderVelocity;
[JsonIgnore]
- public double TickDistance => tickDistanceFactor * DifficultyControlPoint.SliderVelocity;
+ public double TickDistance => tickDistanceFactor * SliderVelocity;
///
/// The length of one span of this .
@@ -142,13 +154,8 @@ namespace osu.Game.Rulesets.Catch.Objects
set
{
path.ControlPoints.Clear();
- path.ExpectedDistance.Value = null;
-
- if (value != null)
- {
- path.ControlPoints.AddRange(value.ControlPoints.Select(c => new PathControlPoint(c.Position, c.Type)));
- path.ExpectedDistance.Value = value.ExpectedDistance.Value;
- }
+ path.ControlPoints.AddRange(value.ControlPoints.Select(c => new PathControlPoint(c.Position, c.Type)));
+ path.ExpectedDistance.Value = value.ExpectedDistance.Value;
}
}
diff --git a/osu.Game.Rulesets.Catch/Objects/PalpableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/PalpableCatchHitObject.cs
index c9bc9ca2ac..197029aeeb 100644
--- a/osu.Game.Rulesets.Catch/Objects/PalpableCatchHitObject.cs
+++ b/osu.Game.Rulesets.Catch/Objects/PalpableCatchHitObject.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using Newtonsoft.Json;
using osu.Framework.Bindables;
using osu.Game.Rulesets.Objects;
@@ -34,13 +32,13 @@ namespace osu.Game.Rulesets.Catch.Objects
///
public bool HyperDash => hyperDash.Value;
- private CatchHitObject hyperDashTarget;
+ private CatchHitObject? hyperDashTarget;
///
/// The target fruit if we are to initiate a hyperdash.
///
[JsonIgnore]
- public CatchHitObject HyperDashTarget
+ public CatchHitObject? HyperDashTarget
{
get => hyperDashTarget;
set
diff --git a/osu.Game.Rulesets.Catch/Objects/TinyDroplet.cs b/osu.Game.Rulesets.Catch/Objects/TinyDroplet.cs
index 6bd5f0ac2a..1bf160b5a6 100644
--- a/osu.Game.Rulesets.Catch/Objects/TinyDroplet.cs
+++ b/osu.Game.Rulesets.Catch/Objects/TinyDroplet.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Judgements;
diff --git a/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs b/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs
index 6c7f0478a7..26f20b223a 100644
--- a/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs
+++ b/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Runtime.CompilerServices;
// We publish our internal attributes to other sub-projects of the framework.
diff --git a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs
index b784fc4c19..9323296b7f 100644
--- a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs
+++ b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs
@@ -1,19 +1,30 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
+using System;
+using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Scoring
{
public partial class CatchScoreProcessor : ScoreProcessor
{
+ private const int combo_cap = 200;
+ private const double combo_base = 4;
+
public CatchScoreProcessor()
: base(new CatchRuleset())
{
}
- protected override double ClassicScoreMultiplier => 28;
+ protected override double ComputeTotalScore(double comboProgress, double accuracyProgress, double bonusPortion)
+ {
+ return 600000 * comboProgress
+ + 400000 * Accuracy.Value * accuracyProgress
+ + bonusPortion;
+ }
+
+ protected override double GetComboScoreChange(JudgementResult result)
+ => Judgement.ToNumericResult(result.Type) * Math.Min(Math.Max(0.5, Math.Log(result.ComboAfterJudgement, combo_base)), Math.Log(combo_cap, combo_base));
}
}
diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs
index 08ac55508a..fb8af9bdb6 100644
--- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs
+++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs
@@ -4,6 +4,7 @@
using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
using osu.Game.Skinning;
using osuTK.Graphics;
@@ -27,12 +28,12 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
public override Drawable? GetDrawableComponent(ISkinComponentLookup lookup)
{
- if (lookup is GlobalSkinComponentLookup targetComponent)
+ if (lookup is SkinComponentsContainerLookup containerLookup)
{
- switch (targetComponent.Lookup)
+ switch (containerLookup.Target)
{
- case GlobalSkinComponentLookup.LookupType.MainHUDComponents:
- var components = base.GetDrawableComponent(lookup) as SkinnableTargetComponentsContainer;
+ case SkinComponentsContainerLookup.TargetArea.MainHUDComponents:
+ var components = base.GetDrawableComponent(lookup) as Container;
if (providesComboCounter && components != null)
{
diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchComboCounter.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchComboCounter.cs
index eba837a52d..f38b9b430e 100644
--- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchComboCounter.cs
+++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchComboCounter.cs
@@ -2,8 +2,9 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
+using osu.Game.Graphics.Containers;
using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Screens.Play;
using osu.Game.Skinning;
using osuTK;
using osuTK.Graphics;
@@ -13,7 +14,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
///
/// A combo counter implementation that visually behaves almost similar to stable's osu!catch combo counter.
///
- public partial class LegacyCatchComboCounter : CompositeDrawable, ICatchComboCounter
+ public partial class LegacyCatchComboCounter : UprightAspectMaintainingContainer, ICatchComboCounter
{
private readonly LegacyRollingCounter counter;
@@ -59,7 +60,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
lastDisplayedCombo = combo;
- if (Time.Elapsed < 0)
+ if ((Clock as IGameplayClock)?.IsRewinding == true)
{
// needs more work to make rewind somehow look good.
// basically we want the previous increment to play... or turning off RemoveCompletedTransforms (not feasible from a performance angle).
diff --git a/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs
index ffdc5299d0..3d0062d32f 100644
--- a/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs
@@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Catch.UI
{
}
- [Resolved(canBeNull: true)]
+ [Resolved]
private Player? player { get; set; }
protected override void LoadComplete()
@@ -63,12 +63,12 @@ namespace osu.Game.Rulesets.Catch.UI
updateCombo(result.ComboAtJudgement + 1, judgedObject.AccentColour.Value);
}
- public void OnRevertResult(DrawableCatchHitObject judgedObject, JudgementResult result)
+ public void OnRevertResult(JudgementResult result)
{
if (!result.Type.AffectsCombo() || !result.HasResult)
return;
- updateCombo(result.ComboAtJudgement, judgedObject.AccentColour.Value);
+ updateCombo(result.ComboAtJudgement, null);
}
private void updateCombo(int newCombo, Color4? hitObjectColour)
diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
index 6167ee53f6..f091dee845 100644
--- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
@@ -1,10 +1,9 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Allocation;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Objects.Drawables;
@@ -39,9 +38,11 @@ namespace osu.Game.Rulesets.Catch.UI
// only check the X position; handle all vertical space.
base.ReceivePositionalInputAt(new Vector2(screenSpacePos.X, ScreenSpaceDrawQuad.Centre.Y));
- internal Catcher Catcher { get; private set; }
+ internal Catcher Catcher { get; private set; } = null!;
- internal CatcherArea CatcherArea { get; private set; }
+ internal CatcherArea CatcherArea { get; private set; } = null!;
+
+ public Container UnderlayElements { get; private set; } = null!;
private readonly IBeatmapDifficultyInfo difficulty;
@@ -64,6 +65,10 @@ namespace osu.Game.Rulesets.Catch.UI
AddRangeInternal(new[]
{
+ UnderlayElements = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
droppedObjectContainer,
Catcher.CreateProxiedContent(),
HitObjectContainer.CreateProxy(),
@@ -105,7 +110,7 @@ namespace osu.Game.Rulesets.Catch.UI
private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
=> CatcherArea.OnNewResult((DrawableCatchHitObject)judgedObject, result);
- private void onRevertResult(DrawableHitObject judgedObject, JudgementResult result)
- => CatcherArea.OnRevertResult((DrawableCatchHitObject)judgedObject, result);
+ private void onRevertResult(JudgementResult result)
+ => CatcherArea.OnRevertResult(result);
}
}
diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs
index c03179dc50..74cbc665c0 100644
--- a/osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.UI;
diff --git a/osu.Game.Rulesets.Catch/UI/CatchReplayRecorder.cs b/osu.Game.Rulesets.Catch/UI/CatchReplayRecorder.cs
index 9ea150a2cf..32ede8f205 100644
--- a/osu.Game.Rulesets.Catch/UI/CatchReplayRecorder.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatchReplayRecorder.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using osu.Game.Rulesets.Catch.Replays;
using osu.Game.Rulesets.Replays;
diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs
index 086b4ff285..f77dab56c8 100644
--- a/osu.Game.Rulesets.Catch/UI/Catcher.cs
+++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs
@@ -1,11 +1,9 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
+using System.Diagnostics;
using System.Linq;
-using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@@ -123,7 +121,7 @@ namespace osu.Game.Rulesets.Catch.UI
private double hyperDashModifier = 1;
private int hyperDashDirection;
private float hyperDashTargetPosition;
- private Bindable hitLighting;
+ private Bindable hitLighting = null!;
private readonly HitExplosionContainer hitExplosionContainer;
@@ -131,13 +129,14 @@ namespace osu.Game.Rulesets.Catch.UI
private readonly DrawablePool caughtBananaPool;
private readonly DrawablePool caughtDropletPool;
- public Catcher([NotNull] DroppedObjectContainer droppedObjectTarget, IBeatmapDifficultyInfo difficulty = null)
+ public Catcher(DroppedObjectContainer droppedObjectTarget, IBeatmapDifficultyInfo? difficulty = null)
{
this.droppedObjectTarget = droppedObjectTarget;
Origin = Anchor.TopCentre;
Size = new Vector2(BASE_SIZE);
+
if (difficulty != null)
Scale = calculateScale(difficulty);
@@ -231,9 +230,8 @@ namespace osu.Game.Rulesets.Catch.UI
// droplet doesn't affect the catcher state
if (hitObject is TinyDroplet) return;
- if (result.IsHit && hitObject.HyperDash)
+ if (result.IsHit && hitObject.HyperDashTarget is CatchHitObject target)
{
- var target = hitObject.HyperDashTarget;
double timeDifference = target.StartTime - hitObject.StartTime;
double positionDifference = target.EffectiveX - X;
double velocity = positionDifference / Math.Max(1.0, timeDifference - 1000.0 / 60.0);
@@ -257,7 +255,7 @@ namespace osu.Game.Rulesets.Catch.UI
}
}
- public void OnRevertResult(DrawableCatchHitObject drawableObject, JudgementResult result)
+ public void OnRevertResult(JudgementResult result)
{
var catchResult = (CatchJudgementResult)result;
@@ -271,8 +269,8 @@ namespace osu.Game.Rulesets.Catch.UI
SetHyperDashState();
}
- caughtObjectContainer.RemoveAll(d => d.HitObject == drawableObject.HitObject, false);
- droppedObjectTarget.RemoveAll(d => d.HitObject == drawableObject.HitObject, false);
+ caughtObjectContainer.RemoveAll(d => d.HitObject == result.HitObject, false);
+ droppedObjectTarget.RemoveAll(d => d.HitObject == result.HitObject, false);
}
///
@@ -336,8 +334,11 @@ namespace osu.Game.Rulesets.Catch.UI
base.Update();
var scaleFromDirection = new Vector2((int)VisualDirection, 1);
+
body.Scale = scaleFromDirection;
- caughtObjectContainer.Scale = hitExplosionContainer.Scale = flipCatcherPlate ? scaleFromDirection : Vector2.One;
+ // Inverse of catcher scale is applied here, as catcher gets scaled by circle size and so do the incoming fruit.
+ caughtObjectContainer.Scale = (1 / Scale.X) * (flipCatcherPlate ? scaleFromDirection : Vector2.One);
+ hitExplosionContainer.Scale = flipCatcherPlate ? scaleFromDirection : Vector2.One;
// Correct overshooting.
if ((hyperDashDirection > 0 && hyperDashTargetPosition < X) ||
@@ -385,7 +386,7 @@ namespace osu.Game.Rulesets.Catch.UI
private void addLighting(JudgementResult judgementResult, Color4 colour, float x) =>
hitExplosionContainer.Add(new HitExplosionEntry(Time.Current, judgementResult, colour, x));
- private CaughtObject getCaughtObject(PalpableCatchHitObject source)
+ private CaughtObject? getCaughtObject(PalpableCatchHitObject source)
{
switch (source)
{
@@ -406,6 +407,7 @@ namespace osu.Game.Rulesets.Catch.UI
private CaughtObject getDroppedObject(CaughtObject caughtObject)
{
var droppedObject = getCaughtObject(caughtObject.HitObject);
+ Debug.Assert(droppedObject != null);
droppedObject.CopyStateFrom(caughtObject);
droppedObject.Anchor = Anchor.TopLeft;
@@ -416,10 +418,13 @@ namespace osu.Game.Rulesets.Catch.UI
private void clearPlate(DroppedObjectAnimation animation)
{
- var droppedObjects = caughtObjectContainer.Children.Select(getDroppedObject).ToArray();
+ var caughtObjects = caughtObjectContainer.Children.ToArray();
caughtObjectContainer.Clear(false);
+ // Use the already returned PoolableDrawables for new objects
+ var droppedObjects = caughtObjects.Select(getDroppedObject).ToArray();
+
droppedObjectTarget.AddRange(droppedObjects);
foreach (var droppedObject in droppedObjects)
@@ -428,10 +433,10 @@ namespace osu.Game.Rulesets.Catch.UI
private void removeFromPlate(CaughtObject caughtObject, DroppedObjectAnimation animation)
{
- var droppedObject = getDroppedObject(caughtObject);
-
caughtObjectContainer.Remove(caughtObject, false);
+ var droppedObject = getDroppedObject(caughtObject);
+
droppedObjectTarget.Add(droppedObject);
applyDropAnimation(droppedObject, animation);
@@ -454,6 +459,8 @@ namespace osu.Game.Rulesets.Catch.UI
break;
}
+ // Define lifetime start for dropped objects to be disposed correctly when rewinding replay
+ d.LifetimeStart = Clock.CurrentTime;
d.Expire();
}
diff --git a/osu.Game.Rulesets.Catch/UI/CatcherAnimationState.cs b/osu.Game.Rulesets.Catch/UI/CatcherAnimationState.cs
index 82591eb47f..566e9d1911 100644
--- a/osu.Game.Rulesets.Catch/UI/CatcherAnimationState.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatcherAnimationState.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
namespace osu.Game.Rulesets.Catch.UI
{
public enum CatcherAnimationState
diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
index d0da05bc44..567c288b47 100644
--- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -12,6 +10,7 @@ using osu.Game.Rulesets.Catch.Objects.Drawables;
using osu.Game.Rulesets.Catch.Replays;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.UI;
+using osu.Game.Screens.Play;
using osuTK;
namespace osu.Game.Rulesets.Catch.UI
@@ -35,7 +34,7 @@ namespace osu.Game.Rulesets.Catch.UI
private readonly CatcherTrailDisplay catcherTrails;
- private Catcher catcher;
+ private Catcher catcher = null!;
///
/// -1 when only left button is pressed.
@@ -75,10 +74,10 @@ namespace osu.Game.Rulesets.Catch.UI
comboDisplay.OnNewResult(hitObject, result);
}
- public void OnRevertResult(DrawableCatchHitObject hitObject, JudgementResult result)
+ public void OnRevertResult(JudgementResult result)
{
- comboDisplay.OnRevertResult(hitObject, result);
- Catcher.OnRevertResult(hitObject, result);
+ comboDisplay.OnRevertResult(result);
+ Catcher.OnRevertResult(result);
}
protected override void Update()
@@ -98,7 +97,7 @@ namespace osu.Game.Rulesets.Catch.UI
comboDisplay.X = Catcher.X;
- if (Time.Elapsed <= 0)
+ if ((Clock as IGameplayClock)?.IsRewinding == true)
{
// This is probably a wrong value, but currently the true value is not recorded.
// Setting `true` will prevent generation of false-positive after-images (with more false-negatives).
diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrail.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrail.cs
index f486633e12..762f95828a 100644
--- a/osu.Game.Rulesets.Catch/UI/CatcherTrail.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatcherTrail.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Graphics;
using osu.Framework.Timing;
using osu.Game.Rulesets.Objects.Pooling;
diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrailAnimation.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrailAnimation.cs
index 02bc5be863..0a5281cd10 100644
--- a/osu.Game.Rulesets.Catch/UI/CatcherTrailAnimation.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatcherTrailAnimation.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
namespace osu.Game.Rulesets.Catch.UI
{
public enum CatcherTrailAnimation
diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs
index e982be53d8..e3e01c1b39 100644
--- a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs
@@ -1,10 +1,9 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using osu.Framework.Allocation;
+using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Pooling;
@@ -41,7 +40,7 @@ namespace osu.Game.Rulesets.Catch.UI
private readonly Container hyperDashAfterImages;
[Resolved]
- private ISkinSource skin { get; set; }
+ private ISkinSource skin { get; set; } = null!;
public CatcherTrailDisplay()
{
@@ -130,7 +129,7 @@ namespace osu.Game.Rulesets.Catch.UI
{
base.Dispose(isDisposing);
- if (skin != null)
+ if (skin.IsNotNull())
skin.SourceChanged -= skinSourceChanged;
}
}
diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrailEntry.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrailEntry.cs
index 78d6979b78..3a40ab26cc 100644
--- a/osu.Game.Rulesets.Catch/UI/CatcherTrailEntry.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatcherTrailEntry.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Graphics.Performance;
using osuTK;
diff --git a/osu.Game.Rulesets.Catch/UI/Direction.cs b/osu.Game.Rulesets.Catch/UI/Direction.cs
index 15e4aed86b..65f064b7fb 100644
--- a/osu.Game.Rulesets.Catch/UI/Direction.cs
+++ b/osu.Game.Rulesets.Catch/UI/Direction.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
namespace osu.Game.Rulesets.Catch.UI
{
public enum Direction
diff --git a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs
index 0be271b236..7930a07551 100644
--- a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs
+++ b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
@@ -27,7 +25,7 @@ namespace osu.Game.Rulesets.Catch.UI
protected override bool UserScrollSpeedAdjustment => false;
- public DrawableCatchRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null)
+ public DrawableCatchRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList? mods = null)
: base(ruleset, beatmap, mods)
{
Direction.Value = ScrollingDirection.Down;
@@ -54,6 +52,6 @@ namespace osu.Game.Rulesets.Catch.UI
protected override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo);
- public override DrawableHitObject CreateDrawableRepresentation(CatchHitObject h) => null;
+ public override DrawableHitObject? CreateDrawableRepresentation(CatchHitObject h) => null;
}
}
diff --git a/osu.Game.Rulesets.Catch/UI/DroppedObjectContainer.cs b/osu.Game.Rulesets.Catch/UI/DroppedObjectContainer.cs
index cb2d8498cc..df1e932ad5 100644
--- a/osu.Game.Rulesets.Catch/UI/DroppedObjectContainer.cs
+++ b/osu.Game.Rulesets.Catch/UI/DroppedObjectContainer.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Catch.Objects.Drawables;
diff --git a/osu.Game.Rulesets.Catch/UI/HitExplosionContainer.cs b/osu.Game.Rulesets.Catch/UI/HitExplosionContainer.cs
index e1dd665bf2..1e2d94433c 100644
--- a/osu.Game.Rulesets.Catch/UI/HitExplosionContainer.cs
+++ b/osu.Game.Rulesets.Catch/UI/HitExplosionContainer.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Graphics;
using osu.Framework.Graphics.Pooling;
using osu.Game.Rulesets.Objects.Pooling;
diff --git a/osu.Game.Rulesets.Catch/UI/ICatchComboCounter.cs b/osu.Game.Rulesets.Catch/UI/ICatchComboCounter.cs
index 5d027edbaa..cfb6879067 100644
--- a/osu.Game.Rulesets.Catch/UI/ICatchComboCounter.cs
+++ b/osu.Game.Rulesets.Catch/UI/ICatchComboCounter.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Graphics;
using osuTK.Graphics;
diff --git a/osu.Game.Rulesets.Catch/UI/SkinnableCatcher.cs b/osu.Game.Rulesets.Catch/UI/SkinnableCatcher.cs
index 78a71f26a2..bcc59a5e4f 100644
--- a/osu.Game.Rulesets.Catch/UI/SkinnableCatcher.cs
+++ b/osu.Game.Rulesets.Catch/UI/SkinnableCatcher.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
diff --git a/osu.Game.Rulesets.Mania.Tests.Android/AndroidManifest.xml b/osu.Game.Rulesets.Mania.Tests.Android/AndroidManifest.xml
index 4a1545a423..f5a49210ea 100644
--- a/osu.Game.Rulesets.Mania.Tests.Android/AndroidManifest.xml
+++ b/osu.Game.Rulesets.Mania.Tests.Android/AndroidManifest.xml
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Mania.Tests.Android/MainActivity.cs b/osu.Game.Rulesets.Mania.Tests.Android/MainActivity.cs
index 789fc9e22d..518071fd49 100644
--- a/osu.Game.Rulesets.Mania.Tests.Android/MainActivity.cs
+++ b/osu.Game.Rulesets.Mania.Tests.Android/MainActivity.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using Android.App;
using osu.Framework.Android;
using osu.Game.Tests;
diff --git a/osu.Game.Rulesets.Mania.Tests.iOS/AppDelegate.cs b/osu.Game.Rulesets.Mania.Tests.iOS/AppDelegate.cs
deleted file mode 100644
index a528634f3b..0000000000
--- a/osu.Game.Rulesets.Mania.Tests.iOS/AppDelegate.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-#nullable disable
-
-using Foundation;
-using osu.Framework.iOS;
-using osu.Game.Tests;
-
-namespace osu.Game.Rulesets.Mania.Tests.iOS
-{
- [Register("AppDelegate")]
- public class AppDelegate : GameAppDelegate
- {
- protected override Framework.Game CreateGame() => new OsuTestBrowser();
- }
-}
diff --git a/osu.Game.Rulesets.Mania.Tests.iOS/Application.cs b/osu.Game.Rulesets.Mania.Tests.iOS/Application.cs
index a508198f7f..75a5a73058 100644
--- a/osu.Game.Rulesets.Mania.Tests.iOS/Application.cs
+++ b/osu.Game.Rulesets.Mania.Tests.iOS/Application.cs
@@ -1,9 +1,8 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
-using UIKit;
+using osu.Framework.iOS;
+using osu.Game.Tests;
namespace osu.Game.Rulesets.Mania.Tests.iOS
{
@@ -11,7 +10,7 @@ namespace osu.Game.Rulesets.Mania.Tests.iOS
{
public static void Main(string[] args)
{
- UIApplication.Main(args, null, typeof(AppDelegate));
+ GameApplication.Main(new OsuTestBrowser());
}
}
}
diff --git a/osu.Game.Rulesets.Mania.Tests.iOS/Info.plist b/osu.Game.Rulesets.Mania.Tests.iOS/Info.plist
index ff5dde856e..740036309f 100644
--- a/osu.Game.Rulesets.Mania.Tests.iOS/Info.plist
+++ b/osu.Game.Rulesets.Mania.Tests.iOS/Info.plist
@@ -5,7 +5,7 @@
CFBundleName
osu.Game.Rulesets.Mania.Tests.iOS
CFBundleIdentifier
- ppy.osu-Game-Rulesets-Mania-Tests-iOS
+ sh.ppy.mania-ruleset-tests
CFBundleShortVersionString
1.0
CFBundleVersion
@@ -42,4 +42,4 @@
CADisableMinimumFrameDurationOnPhone
-
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/ManiaSelectionBlueprintTestScene.cs b/osu.Game.Rulesets.Mania.Tests/Editor/ManiaSelectionBlueprintTestScene.cs
index 2fda012f07..80e1b753ea 100644
--- a/osu.Game.Rulesets.Mania.Tests/Editor/ManiaSelectionBlueprintTestScene.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Editor/ManiaSelectionBlueprintTestScene.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
@@ -19,7 +17,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
{
protected override Container Content => blueprints ?? base.Content;
- private readonly Container blueprints;
+ private readonly Container? blueprints;
[Cached(typeof(Playfield))]
public Playfield Playfield { get; }
diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneEditor.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneEditor.cs
index 0a21098d0d..762238be47 100644
--- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneEditor.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneEditor.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneHoldNotePlacementBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneHoldNotePlacementBlueprint.cs
index 4b332c3faa..b79bcb7682 100644
--- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneHoldNotePlacementBlueprint.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneHoldNotePlacementBlueprint.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Mania.Edit.Blueprints;
using osu.Game.Rulesets.Mania.Objects;
diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneHoldNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneHoldNoteSelectionBlueprint.cs
index a65f949cec..c75095237e 100644
--- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneHoldNoteSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneHoldNoteSelectionBlueprint.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Mania.Edit.Blueprints;
diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaBeatSnapGrid.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaBeatSnapGrid.cs
index aca555552f..fbc0ed1785 100644
--- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaBeatSnapGrid.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaBeatSnapGrid.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs
index a1f4b234c4..8f623d1fc6 100644
--- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using System;
using System.Linq;
using NUnit.Framework;
@@ -25,7 +23,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
public partial class TestSceneManiaComposeScreen : EditorClockTestScene
{
[Resolved]
- private SkinManager skins { get; set; }
+ private SkinManager skins { get; set; } = null!;
[Cached]
private EditorClipboard clipboard = new EditorClipboard();
diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneNoteSelectionBlueprint.cs
index 86e87e7486..9d56d31329 100644
--- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneNoteSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneNoteSelectionBlueprint.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Mania.Edit.Blueprints;
diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs
new file mode 100644
index 0000000000..13a116b209
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs
@@ -0,0 +1,67 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Linq;
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Testing;
+using osu.Game.Configuration;
+using osu.Game.Rulesets.Mania.UI;
+using osu.Game.Tests.Visual;
+using osuTK.Input;
+
+namespace osu.Game.Rulesets.Mania.Tests.Editor
+{
+ public partial class TestSceneObjectPlacement : EditorTestScene
+ {
+ protected override Ruleset CreateEditorRuleset() => new ManiaRuleset();
+
+ [Resolved]
+ private OsuConfigManager config { get; set; } = null!;
+
+ [Test]
+ public void TestPlacementBeforeTrackStart()
+ {
+ AddStep("Seek to 0", () => EditorClock.Seek(0));
+ AddStep("Select note", () => InputManager.Key(Key.Number2));
+ AddStep("Hover negative span", () =>
+ {
+ InputManager.MoveMouseTo(this.ChildrenOfType().First(x => x.Name == "Icons").Children[0]);
+ });
+ AddStep("Click", () => InputManager.Click(MouseButton.Left));
+ AddAssert("No notes placed", () => EditorBeatmap.HitObjects.All(x => x.StartTime >= 0));
+ }
+
+ [Test]
+ public void TestSeekOnNotePlacement()
+ {
+ double? initialTime = null;
+
+ AddStep("store initial time", () => initialTime = EditorClock.CurrentTime);
+ AddStep("change seek setting to true", () => config.SetValue(OsuSetting.EditorAutoSeekOnPlacement, true));
+ placeObject();
+ AddUntilStep("wait for seek to complete", () => !EditorClock.IsSeeking);
+ AddAssert("seeked forward to object", () => EditorClock.CurrentTime, () => Is.GreaterThan(initialTime));
+ }
+
+ [Test]
+ public void TestNoSeekOnNotePlacement()
+ {
+ double? initialTime = null;
+
+ AddStep("store initial time", () => initialTime = EditorClock.CurrentTime);
+ AddStep("change seek setting to false", () => config.SetValue(OsuSetting.EditorAutoSeekOnPlacement, false));
+ placeObject();
+ AddAssert("not seeking", () => !EditorClock.IsSeeking);
+ AddAssert("time is unchanged", () => EditorClock.CurrentTime, () => Is.EqualTo(initialTime));
+ }
+
+ private void placeObject()
+ {
+ AddStep("select note placement tool", () => InputManager.Key(Key.Number2));
+ AddStep("move mouse to centre of last column", () => InputManager.MoveMouseTo(this.ChildrenOfType().Last().ScreenSpaceDrawQuad.Centre));
+ AddStep("place note", () => InputManager.Click(MouseButton.Left));
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Mania.Tests/ManiaDifficultyCalculatorTest.cs
index 4ae6cb9c7c..7b0171a9ee 100644
--- a/osu.Game.Rulesets.Mania.Tests/ManiaDifficultyCalculatorTest.cs
+++ b/osu.Game.Rulesets.Mania.Tests/ManiaDifficultyCalculatorTest.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Difficulty;
diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaInputTestScene.cs b/osu.Game.Rulesets.Mania.Tests/ManiaInputTestScene.cs
index c85583c1fd..62591ce4ca 100644
--- a/osu.Game.Rulesets.Mania.Tests/ManiaInputTestScene.cs
+++ b/osu.Game.Rulesets.Mania.Tests/ManiaInputTestScene.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -14,7 +12,8 @@ namespace osu.Game.Rulesets.Mania.Tests
{
public abstract partial class ManiaInputTestScene : OsuTestScene
{
- private readonly Container content;
+ private readonly Container? content;
+
protected override Container Content => content ?? base.Content;
protected ManiaInputTestScene(int keys)
diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaLegacyModConversionTest.cs b/osu.Game.Rulesets.Mania.Tests/ManiaLegacyModConversionTest.cs
index 9dee861e66..cb2abc1595 100644
--- a/osu.Game.Rulesets.Mania.Tests/ManiaLegacyModConversionTest.cs
+++ b/osu.Game.Rulesets.Mania.Tests/ManiaLegacyModConversionTest.cs
@@ -1,12 +1,11 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using NUnit.Framework;
using osu.Game.Beatmaps.Legacy;
using osu.Game.Rulesets.Mania.Mods;
+using osu.Game.Rulesets.Mods;
using osu.Game.Tests.Beatmaps;
namespace osu.Game.Rulesets.Mania.Tests
@@ -38,7 +37,8 @@ namespace osu.Game.Rulesets.Mania.Tests
new object[] { LegacyMods.Key3, new[] { typeof(ManiaModKey3) } },
new object[] { LegacyMods.Key2, new[] { typeof(ManiaModKey2) } },
new object[] { LegacyMods.Mirror, new[] { typeof(ManiaModMirror) } },
- new object[] { LegacyMods.HardRock | LegacyMods.DoubleTime, new[] { typeof(ManiaModHardRock), typeof(ManiaModDoubleTime) } }
+ new object[] { LegacyMods.HardRock | LegacyMods.DoubleTime, new[] { typeof(ManiaModHardRock), typeof(ManiaModDoubleTime) } },
+ new object[] { LegacyMods.ScoreV2, new[] { typeof(ModScoreV2) } },
};
[TestCaseSource(nameof(mania_mod_mapping))]
diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaLegacyReplayTest.cs b/osu.Game.Rulesets.Mania.Tests/ManiaLegacyReplayTest.cs
index 7d1a934456..641631d05e 100644
--- a/osu.Game.Rulesets.Mania.Tests/ManiaLegacyReplayTest.cs
+++ b/osu.Game.Rulesets.Mania.Tests/ManiaLegacyReplayTest.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using NUnit.Framework;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Replays;
diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaSpecialColumnTest.cs b/osu.Game.Rulesets.Mania.Tests/ManiaSpecialColumnTest.cs
index 3bd654e75e..ff1f9e6894 100644
--- a/osu.Game.Rulesets.Mania.Tests/ManiaSpecialColumnTest.cs
+++ b/osu.Game.Rulesets.Mania.Tests/ManiaSpecialColumnTest.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using System.Collections.Generic;
using osu.Game.Rulesets.Mania.Beatmaps;
using NUnit.Framework;
diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModDoubleTime.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModDoubleTime.cs
new file mode 100644
index 0000000000..00b79529a9
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModDoubleTime.cs
@@ -0,0 +1,63 @@
+// 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 NUnit.Framework;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Mania.Mods;
+using osu.Game.Rulesets.Mania.Objects;
+using osu.Game.Rulesets.Mania.Replays;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Replays;
+using osu.Game.Tests.Visual;
+
+namespace osu.Game.Rulesets.Mania.Tests.Mods
+{
+ public partial class TestSceneManiaModDoubleTime : ModTestScene
+ {
+ private const double offset = 18;
+
+ protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset();
+
+ [Test]
+ public void TestHitWindowWithoutDoubleTime() => CreateModTest(new ModTestData
+ {
+ PassCondition = () => Player.ScoreProcessor.JudgedHits > 0 && Player.ScoreProcessor.Accuracy.Value != 1,
+ Autoplay = false,
+ Beatmap = new Beatmap
+ {
+ BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo },
+ Difficulty = { OverallDifficulty = 10 },
+ HitObjects = new List
+ {
+ new Note { StartTime = 1000 }
+ },
+ },
+ ReplayFrames = new List
+ {
+ new ManiaReplayFrame(1000 + offset, ManiaAction.Key1)
+ }
+ });
+
+ [Test]
+ public void TestHitWindowWithDoubleTime() => CreateModTest(new ModTestData
+ {
+ Mod = new ManiaModDoubleTime(),
+ PassCondition = () => Player.ScoreProcessor.JudgedHits > 0 && Player.ScoreProcessor.Accuracy.Value == 1,
+ Autoplay = false,
+ Beatmap = new Beatmap
+ {
+ BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo },
+ Difficulty = { OverallDifficulty = 10 },
+ HitObjects = new List
+ {
+ new Note { StartTime = 1000 }
+ },
+ },
+ ReplayFrames = new List
+ {
+ new ManiaReplayFrame(1000 + offset, ManiaAction.Key1)
+ }
+ });
+ }
+}
diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFadeIn.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFadeIn.cs
new file mode 100644
index 0000000000..2c8c151e7f
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFadeIn.cs
@@ -0,0 +1,19 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Game.Rulesets.Mania.Mods;
+using osu.Game.Tests.Visual;
+
+namespace osu.Game.Rulesets.Mania.Tests.Mods
+{
+ public partial class TestSceneManiaModFadeIn : ModTestScene
+ {
+ protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset();
+
+ [TestCase(0.5f)]
+ [TestCase(0.1f)]
+ [TestCase(0.7f)]
+ public void TestCoverage(float coverage) => CreateModTest(new ModTestData { Mod = new ManiaModFadeIn { Coverage = { Value = coverage } }, PassCondition = () => true });
+ }
+}
diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs
new file mode 100644
index 0000000000..204f26f151
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs
@@ -0,0 +1,19 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Game.Rulesets.Mania.Mods;
+using osu.Game.Tests.Visual;
+
+namespace osu.Game.Rulesets.Mania.Tests.Mods
+{
+ public partial class TestSceneManiaModHidden : ModTestScene
+ {
+ protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset();
+
+ [TestCase(0.5f)]
+ [TestCase(0.2f)]
+ [TestCase(0.8f)]
+ public void TestCoverage(float coverage) => CreateModTest(new ModTestData { Mod = new ManiaModHidden { Coverage = { Value = coverage } }, PassCondition = () => true });
+ }
+}
diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHoldOff.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHoldOff.cs
index 3011a93755..f5117b61af 100644
--- a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHoldOff.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHoldOff.cs
@@ -6,7 +6,6 @@ using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Tests.Visual;
-using System.Collections.Generic;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Mania.Beatmaps;
@@ -24,21 +23,6 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods
Assert.False(testBeatmap.HitObjects.OfType().Any());
}
- [Test]
- public void TestCorrectNoteValues()
- {
- var testBeatmap = createRawBeatmap();
- var noteValues = new List(testBeatmap.HitObjects.OfType().Count());
-
- foreach (HoldNote h in testBeatmap.HitObjects.OfType())
- {
- noteValues.Add(ManiaModHoldOff.GetNoteDurationInBeatLength(h, testBeatmap));
- }
-
- noteValues.Sort();
- Assert.AreEqual(noteValues, new List { 0.125, 0.250, 0.500, 1.000, 2.000 });
- }
-
[Test]
public void TestCorrectObjectCount()
{
@@ -47,25 +31,8 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods
var rawBeatmap = createRawBeatmap();
var testBeatmap = createModdedBeatmap();
- // Calculate expected number of objects
- int expectedObjectCount = 0;
-
- foreach (ManiaHitObject h in rawBeatmap.HitObjects)
- {
- // Both notes and hold notes account for at least one object
- expectedObjectCount++;
-
- if (h.GetType() == typeof(HoldNote))
- {
- double noteValue = ManiaModHoldOff.GetNoteDurationInBeatLength((HoldNote)h, rawBeatmap);
-
- if (noteValue >= ManiaModHoldOff.END_NOTE_ALLOW_THRESHOLD)
- {
- // Should generate an end note if it's longer than the minimum note value
- expectedObjectCount++;
- }
- }
- }
+ // Both notes and hold notes account for at least one object
+ int expectedObjectCount = rawBeatmap.HitObjects.Count;
Assert.That(testBeatmap.HitObjects.Count == expectedObjectCount);
}
diff --git a/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/LongNoteTailWang.png b/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/LongNoteTailWang.png
new file mode 100644
index 0000000000..982cc1d259
Binary files /dev/null and b/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/LongNoteTailWang.png differ
diff --git a/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/skin.ini b/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/skin.ini
index 9c987efc60..7c51036d69 100644
--- a/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/skin.ini
+++ b/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/skin.ini
@@ -14,4 +14,6 @@ Hit200: mania/hit200@2x
Hit300: mania/hit300@2x
Hit300g: mania/hit300g@2x
StageLeft: mania/stage-left
-StageRight: mania/stage-right
\ No newline at end of file
+StageRight: mania/stage-right
+NoteImage0L: LongNoteTailWang
+NoteImage1L: LongNoteTailWang
diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs
index 0c55cebf0d..465d4a49f0 100644
--- a/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaHitObjectTestScene.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaHitObjectTestScene.cs
index 25e120edc5..dd494dfc82 100644
--- a/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaHitObjectTestScene.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaHitObjectTestScene.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaSkinnableTestScene.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaSkinnableTestScene.cs
index 30bd600d9d..ba0c97a121 100644
--- a/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaSkinnableTestScene.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaSkinnableTestScene.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs
index 3881aae22e..47923d0733 100644
--- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs
@@ -1,8 +1,6 @@
-// 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.
-#nullable disable
-
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnHitObjectArea.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnHitObjectArea.cs
index 9cccc2dd86..d4bbc8acb6 100644
--- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnHitObjectArea.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnHitObjectArea.cs
@@ -1,8 +1,6 @@
-// Copyright (c) ppy Pty Ltd