1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 11:07:52 +08:00

Merge branch 'master' into JudgementCounter

This commit is contained in:
MK56 2023-01-17 09:55:45 +01:00 committed by GitHub
commit a55ce9b586
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
270 changed files with 2371 additions and 1497 deletions

View File

@ -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!

View File

@ -101,9 +101,7 @@ 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).

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects;
using System.Collections.Generic;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq;
@ -51,7 +49,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty
protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate)
{
CatchHitObject lastObject = null;
CatchHitObject? lastObject = null;
List<DifficultyHitObject> objects = new List<DifficultyHitObject>();

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Game.Rulesets.Difficulty;
namespace osu.Game.Rulesets.Catch.Difficulty

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using System.Collections.Generic;
using osu.Game.Rulesets.Catch.Objects;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using osu.Game.Rulesets.Catch.Difficulty.Preprocessing;
using osu.Game.Rulesets.Difficulty.Preprocessing;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Edit.Blueprints;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Catch.Edit.Blueprints.Components;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Game.Rulesets.Catch.Objects;
namespace osu.Game.Rulesets.Catch.Edit.Blueprints

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Framework.Allocation;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Edit;
@ -20,7 +18,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!;
public CatchPlacementBlueprint()
: base(new THitObject())

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#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)

View File

@ -1,13 +1,10 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#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<VertexState> previousVertexStates = new List<VertexState>();
[Resolved(CanBeNull = true)]
[CanBeNull]
private IBeatSnapProvider beatSnapProvider { get; set; }
[Resolved]
private IBeatSnapProvider? beatSnapProvider { get; set; }
protected EditablePath(Func<float, double> positionToTime)
{

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using osu.Game.Rulesets.Catch.Objects;
using osuTK;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics;

View File

@ -1,12 +1,9 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#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<float, double> positionToTime)
: base(positionToTime)

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#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()
{

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Catch.Edit.Blueprints.Components;
using osu.Game.Rulesets.Catch.Objects;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Game.Rulesets.Catch.Edit.Blueprints.Components;
using osu.Game.Rulesets.Catch.Objects;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Framework.Graphics;
using osu.Framework.Input;
using osu.Framework.Input.Events;
@ -24,7 +22,7 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints
private int lastEditablePathId = -1;
private InputManager inputManager;
private InputManager inputManager = null!;
public JuiceStreamPlacementBlueprint()
{

View File

@ -1,11 +1,8 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#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)

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic;
using System.Linq;
using osu.Game.Rulesets.Catch.Edit.Checks;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#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<HitObject> CreateSelectionHandler() => new CatchSelectionHandler();
public override HitObjectSelectionBlueprint CreateHitObjectBlueprintFor(HitObject hitObject)
public override HitObjectSelectionBlueprint? CreateHitObjectBlueprintFor(HitObject hitObject)
{
switch (hitObject)
{

View File

@ -1,12 +1,9 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#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<Vector2[]> verticalLineVertices = new List<Vector2[]>();
[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);

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.UI;

View File

@ -1,12 +1,9 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#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,9 @@ 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 readonly BindableDouble timeRangeMultiplier = new BindableDouble(1)
{
@ -117,7 +114,7 @@ namespace osu.Game.Rulesets.Catch.Edit
return base.OnPressed(e);
}
protected override DrawableRuleset<CatchHitObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null) =>
protected override DrawableRuleset<CatchHitObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod>? mods = null) =>
new DrawableCatchEditorRuleset(ruleset, beatmap, mods)
{
TimeRangeMultiplier = { BindTarget = timeRangeMultiplier, }
@ -150,8 +147,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<CatchHitObject>().LastOrDefault(h => h.GetEndTime() < time && !(h is BananaShower));
@ -168,8 +164,7 @@ namespace osu.Game.Rulesets.Catch.Edit
}
}
[CanBeNull]
private PalpableCatchHitObject getDistanceSnapGridSourceHitObject()
private PalpableCatchHitObject? getDistanceSnapGridSourceHitObject()
{
switch (BlueprintContainer.CurrentTool)
{
@ -188,7 +183,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);

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic;
using System.Linq;
using osu.Game.Rulesets.Catch.Objects;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#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<HitObject> moveEvent)
{

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#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<Mod> mods = null)
public DrawableCatchEditorRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod>? mods = null)
: base(ruleset, beatmap, mods)
{
}

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Edit.Blueprints;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Edit.Blueprints;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Judgements

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Scoring;

View File

@ -1,9 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#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
/// </summary>
public bool CatcherHyperDash;
public CatchJudgementResult([NotNull] HitObject hitObject, [NotNull] Judgement judgement)
public CatchJudgementResult(HitObject hitObject, Judgement judgement)
: base(hitObject, judgement)
{
}

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Judgements

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Threading;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Types;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using Newtonsoft.Json;
using osu.Framework.Bindables;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Game.Rulesets.Catch.Skinning.Default;
namespace osu.Game.Rulesets.Catch.Objects.Drawables

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Game.Rulesets.Catch.Skinning.Default;
namespace osu.Game.Rulesets.Catch.Objects.Drawables

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Game.Rulesets.Catch.Skinning.Default;
namespace osu.Game.Rulesets.Catch.Objects.Drawables

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#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<Color4> AccentColour { get; } = new Bindable<Color4>();
public Bindable<bool> HyperDash { get; } = new Bindable<bool>();
public Bindable<int> IndexInBeatmap { get; } = new Bindable<int>();

View File

@ -1,9 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#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)
{
}

View File

@ -1,9 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#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;

View File

@ -53,6 +53,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
XOffsetBindable.UnbindFrom(HitObject.XOffsetBindable);
}
[CanBeNull]
public Func<CatchHitObject, bool> CheckPosition;
protected override JudgementResult CreateResult(Judgement judgement) => new CatchJudgementResult(HitObject, judgement);

View File

@ -1,9 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#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)
{
}

View File

@ -1,9 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#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)
{
}

View File

@ -1,9 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#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;

View File

@ -1,9 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#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;

View File

@ -1,10 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#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)
{
}

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Framework.Bindables;
using osuTK;
using osuTK.Graphics;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Judgements;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Judgements;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
namespace osu.Game.Rulesets.Catch.Objects
{
public enum FruitVisualRepresentation

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq;
@ -142,13 +140,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;
}
}

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using Newtonsoft.Json;
using osu.Framework.Bindables;
using osu.Game.Rulesets.Objects;
@ -34,13 +32,13 @@ namespace osu.Game.Rulesets.Catch.Objects
/// </summary>
public bool HyperDash => hyperDash.Value;
private CatchHitObject hyperDashTarget;
private CatchHitObject? hyperDashTarget;
/// <summary>
/// The target fruit if we are to initiate a hyperdash.
/// </summary>
[JsonIgnore]
public CatchHitObject HyperDashTarget
public CatchHitObject? HyperDashTarget
{
get => hyperDashTarget;
set

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Judgements;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Runtime.CompilerServices;
// We publish our internal attributes to other sub-projects of the framework.

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Scoring

View File

@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Catch.UI
{
}
[Resolved(canBeNull: true)]
[Resolved]
private Player? player { get; set; }
protected override void LoadComplete()

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
@ -39,9 +37,9 @@ 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!;
private readonly IBeatmapDifficultyInfo difficulty;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.UI;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic;
using osu.Game.Rulesets.Catch.Replays;
using osu.Game.Rulesets.Replays;

View File

@ -1,11 +1,9 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#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<bool> hitLighting;
private Bindable<bool> hitLighting = null!;
private readonly HitExplosionContainer hitExplosionContainer;
@ -131,7 +129,7 @@ namespace osu.Game.Rulesets.Catch.UI
private readonly DrawablePool<CaughtBanana> caughtBananaPool;
private readonly DrawablePool<CaughtDroplet> caughtDropletPool;
public Catcher([NotNull] DroppedObjectContainer droppedObjectTarget, IBeatmapDifficultyInfo difficulty = null)
public Catcher(DroppedObjectContainer droppedObjectTarget, IBeatmapDifficultyInfo? difficulty = null)
{
this.droppedObjectTarget = droppedObjectTarget;
@ -231,9 +229,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);
@ -385,7 +382,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 +403,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;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
namespace osu.Game.Rulesets.Catch.UI
{
public enum CatcherAnimationState

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@ -35,7 +33,7 @@ namespace osu.Game.Rulesets.Catch.UI
private readonly CatcherTrailDisplay catcherTrails;
private Catcher catcher;
private Catcher catcher = null!;
/// <summary>
/// <c>-1</c> when only left button is pressed.

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Framework.Graphics;
using osu.Framework.Timing;
using osu.Game.Rulesets.Objects.Pooling;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
namespace osu.Game.Rulesets.Catch.UI
{
public enum CatcherTrailAnimation

View File

@ -1,10 +1,9 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#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<CatcherTrail> 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;
}
}

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Framework.Graphics.Performance;
using osuTK;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
namespace osu.Game.Rulesets.Catch.UI
{
public enum Direction

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#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<Mod> mods = null)
public DrawableCatchRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod>? 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<CatchHitObject> CreateDrawableRepresentation(CatchHitObject h) => null;
public override DrawableHitObject<CatchHitObject>? CreateDrawableRepresentation(CatchHitObject h) => null;
}
}

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Catch.Objects.Drawables;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Framework.Graphics;
using osu.Framework.Graphics.Pooling;
using osu.Game.Rulesets.Objects.Pooling;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Framework.Graphics;
using osuTK.Graphics;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;

View File

@ -0,0 +1,30 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Tests.Visual;
using osuTK.Input;
namespace osu.Game.Rulesets.Mania.Tests.Editor
{
public partial class TestScenePlacementBeforeTrackStart : EditorTestScene
{
protected override Ruleset CreateEditorRuleset() => new ManiaRuleset();
[Test]
public void TestPlacement()
{
AddStep("Seek to 0", () => EditorClock.Seek(0));
AddStep("Select note", () => InputManager.Key(Key.Number2));
AddStep("Hover negative span", () =>
{
InputManager.MoveMouseTo(this.ChildrenOfType<Container>().First(x => x.Name == "Icons").Children[0]);
});
AddStep("Click", () => InputManager.Click(MouseButton.Left));
AddAssert("No notes placed", () => EditorBeatmap.HitObjects.All(x => x.StartTime >= 0));
}
}
}

View File

@ -4,6 +4,7 @@
using System;
using osu.Framework.Configuration.Tracking;
using osu.Game.Configuration;
using osu.Game.Localisation;
using osu.Game.Rulesets.Configuration;
using osu.Game.Rulesets.Mania.UI;
@ -30,8 +31,8 @@ namespace osu.Game.Rulesets.Mania.Configuration
new TrackedSetting<double>(ManiaRulesetSetting.ScrollTime,
scrollTime => new SettingDescription(
rawValue: scrollTime,
name: "Scroll Speed",
value: $"{scrollTime}ms (speed {(int)Math.Round(DrawableManiaRuleset.MAX_TIME_RANGE / scrollTime)})"
name: RulesetSettingsStrings.ScrollSpeed,
value: RulesetSettingsStrings.ScrollSpeedTooltip(scrollTime, (int)Math.Round(DrawableManiaRuleset.MAX_TIME_RANGE / scrollTime))
)
)
};

View File

@ -6,6 +6,7 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Localisation;
using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets.Mania.Configuration;
using osu.Game.Rulesets.Mania.UI;
@ -30,18 +31,18 @@ namespace osu.Game.Rulesets.Mania
{
new SettingsEnumDropdown<ManiaScrollingDirection>
{
LabelText = "Scrolling direction",
LabelText = RulesetSettingsStrings.ScrollingDirection,
Current = config.GetBindable<ManiaScrollingDirection>(ManiaRulesetSetting.ScrollDirection)
},
new SettingsSlider<double, ManiaScrollSlider>
{
LabelText = "Scroll speed",
LabelText = RulesetSettingsStrings.ScrollSpeed,
Current = config.GetBindable<double>(ManiaRulesetSetting.ScrollTime),
KeyboardStep = 5
},
new SettingsCheckbox
{
LabelText = "Timing-based note colouring",
LabelText = RulesetSettingsStrings.TimingBasedColouring,
Current = config.GetBindable<bool>(ManiaRulesetSetting.TimingBasedNoteColouring),
}
};
@ -49,7 +50,7 @@ namespace osu.Game.Rulesets.Mania
private partial class ManiaScrollSlider : OsuSliderBar<double>
{
public override LocalisableString TooltipText => $"{Current.Value}ms (speed {(int)Math.Round(DrawableManiaRuleset.MAX_TIME_RANGE / Current.Value)})";
public override LocalisableString TooltipText => RulesetSettingsStrings.ScrollSpeedTooltip(Current.Value, (int)Math.Round(DrawableManiaRuleset.MAX_TIME_RANGE / Current.Value));
}
}
}

View File

@ -1,15 +1,18 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Framework.Localisation;
using osu.Game.Localisation;
using osu.Game.Rulesets.UI.Scrolling;
namespace osu.Game.Rulesets.Mania.UI
{
public enum ManiaScrollingDirection
{
[LocalisableDescription(typeof(RulesetSettingsStrings), nameof(RulesetSettingsStrings.ScrollingDirectionUp))]
Up = ScrollingDirection.Up,
[LocalisableDescription(typeof(RulesetSettingsStrings), nameof(RulesetSettingsStrings.ScrollingDirectionDown))]
Down = ScrollingDirection.Down
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.ObjectExtensions;
@ -29,8 +30,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
private readonly bool hasNumber;
protected Drawable CircleSprite = null!;
protected Drawable OverlaySprite = null!;
protected LegacyKiaiFlashingDrawable CircleSprite = null!;
protected LegacyKiaiFlashingDrawable OverlaySprite = null!;
protected Container OverlayLayer { get; private set; } = null!;
@ -65,7 +66,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
// at this point, any further texture fetches should be correctly using the priority source if the base texture was retrieved using it.
// the conditional above handles the case where a sliderendcircle.png is retrieved from the skin, but sliderendcircleoverlay.png doesn't exist.
// expected behaviour in this scenario is not showing the overlay, rather than using hitcircleoverlay.png.
InternalChildren = new[]
{
CircleSprite = new LegacyKiaiFlashingDrawable(() => new Sprite { Texture = skin.GetTexture(circleName) })
@ -114,7 +114,21 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
{
base.LoadComplete();
accentColour.BindValueChanged(colour => CircleSprite.Colour = LegacyColourCompatibility.DisallowZeroAlpha(colour.NewValue), true);
accentColour.BindValueChanged(colour =>
{
Color4 objectColour = colour.NewValue;
int add = Math.Max(25, 300 - (int)(objectColour.R * 255) - (int)(objectColour.G * 255) - (int)(objectColour.B * 255));
var kiaiTintColour = new Color4(
(byte)Math.Min((byte)(objectColour.R * 255) + add, 255),
(byte)Math.Min((byte)(objectColour.G * 255) + add, 255),
(byte)Math.Min((byte)(objectColour.B * 255) + add, 255),
255);
CircleSprite.Colour = LegacyColourCompatibility.DisallowZeroAlpha(colour.NewValue);
OverlaySprite.KiaiGlowColour = CircleSprite.KiaiGlowColour = LegacyColourCompatibility.DisallowZeroAlpha(kiaiTintColour);
}, true);
if (hasNumber)
indexInCurrentCombo.BindValueChanged(index => hitCircleText.Text = (index.NewValue + 1).ToString(), true);

View File

@ -1,11 +1,10 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Localisation;
using osu.Game.Localisation;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets.Osu.Configuration;
using osu.Game.Rulesets.UI;
@ -30,23 +29,23 @@ namespace osu.Game.Rulesets.Osu.UI
{
new SettingsCheckbox
{
LabelText = "Snaking in sliders",
LabelText = RulesetSettingsStrings.SnakingInSliders,
Current = config.GetBindable<bool>(OsuRulesetSetting.SnakingInSliders)
},
new SettingsCheckbox
{
ClassicDefault = false,
LabelText = "Snaking out sliders",
LabelText = RulesetSettingsStrings.SnakingOutSliders,
Current = config.GetBindable<bool>(OsuRulesetSetting.SnakingOutSliders)
},
new SettingsCheckbox
{
LabelText = "Cursor trail",
LabelText = RulesetSettingsStrings.CursorTrail,
Current = config.GetBindable<bool>(OsuRulesetSetting.ShowCursorTrail)
},
new SettingsEnumDropdown<PlayfieldBorderStyle>
{
LabelText = "Playfield border style",
LabelText = RulesetSettingsStrings.PlayfieldBorderStyle,
Current = config.GetBindable<PlayfieldBorderStyle>(OsuRulesetSetting.PlayfieldBorderStyle),
},
};

View File

@ -75,6 +75,8 @@ namespace osu.Game.Tests.Chat
return false;
};
});
AddUntilStep("wait for notifications client", () => channelManager.NotificationsConnected);
}
[Test]

View File

@ -0,0 +1,79 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
using osu.Game.Beatmaps.ControlPoints;
namespace osu.Game.Tests.Editing
{
[TestFixture]
public class TestSceneSnappingNearZero
{
private readonly ControlPointInfo cpi = new ControlPointInfo();
[Test]
public void TestOnZero()
{
test(0, 500, 0, 0);
test(0, 500, 100, 0);
test(0, 500, 250, 500);
test(0, 500, 600, 500);
test(0, 500, -600, 0);
}
[Test]
public void TestAlmostOnZero()
{
test(50, 500, 0, 50);
test(50, 500, 50, 50);
test(50, 500, 100, 50);
test(50, 500, 299, 50);
test(50, 500, 300, 550);
test(50, 500, -500, 50);
}
[Test]
public void TestAlmostOnOne()
{
test(499, 500, -1, 499);
test(499, 500, 0, 499);
test(499, 500, 1, 499);
test(499, 500, 499, 499);
test(499, 500, 600, 499);
test(499, 500, 800, 999);
}
[Test]
public void TestOnOne()
{
test(500, 500, -500, 0);
test(500, 500, 0, 0);
test(500, 500, 200, 0);
test(500, 500, 400, 500);
test(500, 500, 500, 500);
test(500, 500, 600, 500);
test(500, 500, 900, 1000);
}
[Test]
public void TestNegative()
{
test(-600, 500, -600, 400);
test(-600, 500, -100, 400);
test(-600, 500, 0, 400);
test(-600, 500, 200, 400);
test(-600, 500, 400, 400);
test(-600, 500, 600, 400);
test(-600, 500, 1000, 900);
}
private void test(double pointTime, double beatLength, double from, double expected)
{
cpi.Clear();
cpi.Add(pointTime, new TimingControlPoint { BeatLength = beatLength });
Assert.That(cpi.GetClosestSnappedTime(from, 1), Is.EqualTo(expected), $"From: {from}");
}
}
}

View File

@ -73,16 +73,6 @@ namespace osu.Game.Tests.Gameplay
}
[Test]
[FlakyTest]
/*
* Fail rate around 0.15%
*
* TearDown : osu.Framework.Testing.Drawables.Steps.AssertButton+TracedException : gameplay clock time = 2500
* --TearDown
* at osu.Framework.Threading.ScheduledDelegate.RunTaskInternal()
* at osu.Framework.Threading.Scheduler.Update()
* at osu.Framework.Graphics.Drawable.UpdateSubTree()
*/
public void TestSeekPerformsInGameplayTime(
[Values(1.0, 0.5, 2.0)] double clockRate,
[Values(0.0, 200.0, -200.0)] double userOffset,
@ -92,6 +82,9 @@ namespace osu.Game.Tests.Gameplay
ClockBackedTestWorkingBeatmap working = null;
GameplayClockContainer gameplayClockContainer = null;
// ReSharper disable once NotAccessedVariable
BindableDouble trackAdjustment = null; // keeping a reference for track adjustment
if (setAudioOffsetBeforeConstruction)
AddStep($"preset audio offset to {userOffset}", () => localConfig.SetValue(OsuSetting.AudioOffset, userOffset));
@ -103,16 +96,16 @@ namespace osu.Game.Tests.Gameplay
gameplayClockContainer.Reset(startClock: !whileStopped);
});
AddStep($"set clock rate to {clockRate}", () => working.Track.AddAdjustment(AdjustableProperty.Frequency, new BindableDouble(clockRate)));
AddStep($"set clock rate to {clockRate}", () => working.Track.AddAdjustment(AdjustableProperty.Frequency, trackAdjustment = new BindableDouble(clockRate)));
if (!setAudioOffsetBeforeConstruction)
AddStep($"set audio offset to {userOffset}", () => localConfig.SetValue(OsuSetting.AudioOffset, userOffset));
AddStep("seek to 2500", () => gameplayClockContainer.Seek(2500));
AddStep("gameplay clock time = 2500", () => Assert.AreEqual(gameplayClockContainer.CurrentTime, 2500, 10f));
AddAssert("gameplay clock time = 2500", () => gameplayClockContainer.CurrentTime, () => Is.EqualTo(2500).Within(10f));
AddStep("seek to 10000", () => gameplayClockContainer.Seek(10000));
AddStep("gameplay clock time = 10000", () => Assert.AreEqual(gameplayClockContainer.CurrentTime, 10000, 10f));
AddAssert("gameplay clock time = 10000", () => gameplayClockContainer.CurrentTime, () => Is.EqualTo(10000).Within(10f));
}
protected override void Dispose(bool isDisposing)

View File

@ -17,7 +17,7 @@ namespace osu.Game.Tests.NonVisual
public void TestExactDivisors()
{
var cpi = new ControlPointInfo();
cpi.Add(-1000, new TimingControlPoint { BeatLength = 1000 });
cpi.Add(0, new TimingControlPoint { BeatLength = 1000 });
double[] divisors = { 3, 1, 16, 12, 8, 6, 4, 3, 2, 1 };
@ -47,7 +47,7 @@ namespace osu.Game.Tests.NonVisual
public void TestExactDivisorsHighBPMStream()
{
var cpi = new ControlPointInfo();
cpi.Add(-50, new TimingControlPoint { BeatLength = 50 }); // 1200 BPM 1/4 (limit testing)
cpi.Add(0, new TimingControlPoint { BeatLength = 50 }); // 1200 BPM 1/4 (limit testing)
// A 1/4 stream should land on 1/1, 1/2 and 1/4 divisors.
double[] divisors = { 4, 4, 4, 4, 4, 4, 4, 4 };
@ -60,7 +60,7 @@ namespace osu.Game.Tests.NonVisual
public void TestApproximateDivisors()
{
var cpi = new ControlPointInfo();
cpi.Add(-1000, new TimingControlPoint { BeatLength = 1000 });
cpi.Add(0, new TimingControlPoint { BeatLength = 1000 });
double[] divisors = { 3.03d, 0.97d, 14, 13, 7.94d, 6.08d, 3.93d, 2.96d, 2.02d, 64 };
double[] closestDivisors = { 3, 1, 16, 12, 8, 6, 4, 3, 2, 1 };
@ -68,7 +68,7 @@ namespace osu.Game.Tests.NonVisual
assertClosestDivisors(divisors, closestDivisors, cpi);
}
private void assertClosestDivisors(IReadOnlyList<double> divisors, IReadOnlyList<double> closestDivisors, ControlPointInfo cpi, double step = 1)
private static void assertClosestDivisors(IReadOnlyList<double> divisors, IReadOnlyList<double> closestDivisors, ControlPointInfo cpi, double step = 1)
{
List<HitObject> hitobjects = new List<HitObject>();
double offset = cpi.TimingPoints[0].Time;

View File

@ -12,6 +12,7 @@ using System.Threading;
using NUnit.Framework;
using osu.Framework.Extensions;
using osu.Framework.IO.Stores;
using osu.Framework.Logging;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
@ -93,10 +94,12 @@ namespace osu.Game.Tests.Resources
{
// Create random metadata, then we can check if sorting works based on these
Artist = "Some Artist " + RNG.Next(0, 9),
Title = $"Some Song (set id {setId}) {Guid.NewGuid()}",
Title = $"Some Song (set id {setId:000}) {Guid.NewGuid()}",
Author = { Username = "Some Guy " + RNG.Next(0, 9) },
};
Logger.Log($"🛠️ Generating beatmap set \"{metadata}\" for test consumption.");
var beatmapSet = new BeatmapSetInfo
{
OnlineID = setId,

View File

@ -20,6 +20,8 @@ using osu.Game.Rulesets.Catch;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.Taiko;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Setup;
using osu.Game.Storyboards;
@ -395,5 +397,52 @@ namespace osu.Game.Tests.Visual.Editing
return set != null && set.PerformRead(s => s.Beatmaps.Count == 2 && s.Files.Count == 2);
});
}
[Test]
public void TestCreateNewDifficultyForInconvertibleRuleset()
{
Guid setId = Guid.Empty;
AddStep("retrieve set ID", () => setId = EditorBeatmap.BeatmapInfo.BeatmapSet!.ID);
AddStep("save beatmap", () => Editor.Save());
AddStep("try to create new taiko difficulty", () => Editor.CreateNewDifficulty(new TaikoRuleset().RulesetInfo));
AddUntilStep("wait for created", () =>
{
string? difficultyName = Editor.ChildrenOfType<EditorBeatmap>().SingleOrDefault()?.BeatmapInfo.DifficultyName;
return difficultyName != null && difficultyName == "New Difficulty";
});
AddAssert("new difficulty persisted", () =>
{
var set = beatmapManager.QueryBeatmapSet(s => s.ID == setId);
return set != null && set.PerformRead(s => s.Beatmaps.Count == 2 && s.Files.Count == 2);
});
AddStep("add timing point", () => EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 }));
AddStep("add hitobjects", () => EditorBeatmap.AddRange(new[]
{
new Hit
{
StartTime = 0
},
new Hit
{
StartTime = 1000
}
}));
AddStep("save beatmap", () => Editor.Save());
AddStep("try to create new catch difficulty", () => Editor.CreateNewDifficulty(new CatchRuleset().RulesetInfo));
AddUntilStep("wait for created", () =>
{
string? difficultyName = Editor.ChildrenOfType<EditorBeatmap>().SingleOrDefault()?.BeatmapInfo.DifficultyName;
return difficultyName != null && difficultyName == "New Difficulty (1)";
});
AddAssert("new difficulty persisted", () =>
{
var set = beatmapManager.QueryBeatmapSet(s => s.ID == setId);
return set != null && set.PerformRead(s => s.Beatmaps.Count == 3 && s.Files.Count == 3);
});
}
}
}

View File

@ -144,7 +144,7 @@ namespace osu.Game.Tests.Visual.Editing
double lastStarRating = 0;
double lastLength = 0;
AddStep("Add timing point", () => EditorBeatmap.ControlPointInfo.Add(500, new TimingControlPoint()));
AddStep("Add timing point", () => EditorBeatmap.ControlPointInfo.Add(200, new TimingControlPoint { BeatLength = 600 }));
AddStep("Change to placement mode", () => InputManager.Key(Key.Number2));
AddStep("Move to playfield", () => InputManager.MoveMouseTo(Game.ScreenSpaceDrawQuad.Centre));
AddStep("Place single hitcircle", () => InputManager.Click(MouseButton.Left));

View File

@ -181,7 +181,8 @@ namespace osu.Game.Tests.Visual.Gameplay
AddUntilStep("wait for fail", () => Player.GameplayState.HasFailed);
AddStep("exit", () => Player.Exit());
AddAssert("ensure failing submission", () => Player.SubmittedScore?.ScoreInfo.Passed == false);
AddUntilStep("wait for submission", () => Player.SubmittedScore != null);
AddAssert("ensure failing submission", () => Player.SubmittedScore.ScoreInfo.Passed == false);
}
[Test]
@ -209,7 +210,9 @@ namespace osu.Game.Tests.Visual.Gameplay
addFakeHit();
AddStep("exit", () => Player.Exit());
AddAssert("ensure failing submission", () => Player.SubmittedScore?.ScoreInfo.Passed == false);
AddUntilStep("wait for submission", () => Player.SubmittedScore != null);
AddAssert("ensure failing submission", () => Player.SubmittedScore.ScoreInfo.Passed == false);
}
[Test]

View File

@ -34,6 +34,24 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
[Test]
public void TestSingleItemExpiredAfterGameplay()
{
RunGameplay();
AddUntilStep("playlist has only one item", () => MultiplayerClient.ClientAPIRoom?.Playlist.Count == 1);
AddUntilStep("playlist item is expired", () => MultiplayerClient.ClientAPIRoom?.Playlist[0].Expired == true);
AddUntilStep("last item selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID);
}
[Test]
[FlakyTest]
/*
* TearDown : System.TimeoutException : "wait for ongoing operation to complete" timed out
* --TearDown
* at osu.Framework.Testing.Drawables.Steps.UntilStepButton.<>c__DisplayClass11_0.<.ctor>b__0()
* at osu.Framework.Testing.Drawables.Steps.StepButton.PerformStep(Boolean userTriggered)
* at osu.Framework.Testing.TestScene.runNextStep(Action onCompletion, Action`1 onError, Func`2 stopCondition)
*/
public void TestItemAddedToTheEndOfQueue()
{
addItem(() => OtherBeatmap);
@ -46,16 +64,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
[Test]
public void TestSingleItemExpiredAfterGameplay()
{
RunGameplay();
AddUntilStep("playlist has only one item", () => MultiplayerClient.ClientAPIRoom?.Playlist.Count == 1);
AddUntilStep("playlist item is expired", () => MultiplayerClient.ClientAPIRoom?.Playlist[0].Expired == true);
AddUntilStep("last item selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID);
}
[Test]
[FlakyTest] // See above
public void TestNextItemSelectedAfterGameplayFinish()
{
addItem(() => OtherBeatmap);
@ -73,6 +82,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
[Test]
[FlakyTest] // See above
public void TestItemsNotClearedWhenSwitchToHostOnlyMode()
{
addItem(() => OtherBeatmap);
@ -88,6 +98,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
[Test]
[FlakyTest] // See above
public void TestCorrectItemSelectedAfterNewItemAdded()
{
addItem(() => OtherBeatmap);
@ -95,6 +106,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
[Test]
[FlakyTest] // See above
public void TestCorrectRulesetSelectedAfterNewItemAdded()
{
addItem(() => OtherBeatmap, new CatchRuleset().RulesetInfo);
@ -112,6 +124,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
[Test]
[FlakyTest] // See above
public void TestCorrectModsSelectedAfterNewItemAdded()
{
addItem(() => OtherBeatmap, mods: new Mod[] { new OsuModDoubleTime() });

View File

@ -27,22 +27,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep("first item selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID);
}
[Test]
public void TestItemStillSelectedAfterChangeToSameBeatmap()
{
selectNewItem(() => InitialBeatmap);
AddUntilStep("playlist item still selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID);
}
[Test]
public void TestItemStillSelectedAfterChangeToOtherBeatmap()
{
selectNewItem(() => OtherBeatmap);
AddUntilStep("playlist item still selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID);
}
[Test]
public void TestNewItemCreatedAfterGameplayFinished()
{
@ -54,20 +38,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep("second playlist item selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[1].ID);
}
[Test]
public void TestOnlyLastItemChangedAfterGameplayFinished()
{
RunGameplay();
IBeatmapInfo firstBeatmap = null;
AddStep("get first playlist item beatmap", () => firstBeatmap = MultiplayerClient.ServerAPIRoom?.Playlist[0].Beatmap);
selectNewItem(() => OtherBeatmap);
AddUntilStep("first playlist item hasn't changed", () => MultiplayerClient.ServerAPIRoom?.Playlist[0].Beatmap == firstBeatmap);
AddUntilStep("second playlist item changed", () => MultiplayerClient.ClientAPIRoom?.Playlist[1].Beatmap != firstBeatmap);
}
[Test]
public void TestSettingsUpdatedWhenChangingQueueMode()
{
@ -80,6 +50,47 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
[Test]
[FlakyTest]
/*
* TearDown : System.TimeoutException : "wait for ongoing operation to complete" timed out
* --TearDown
* at osu.Framework.Testing.Drawables.Steps.UntilStepButton.<>c__DisplayClass11_0.<.ctor>b__0()
* at osu.Framework.Testing.Drawables.Steps.StepButton.PerformStep(Boolean userTriggered)
* at osu.Framework.Testing.TestScene.runNextStep(Action onCompletion, Action`1 onError, Func`2 stopCondition)
*/
public void TestItemStillSelectedAfterChangeToSameBeatmap()
{
selectNewItem(() => InitialBeatmap);
AddUntilStep("playlist item still selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID);
}
[Test]
[FlakyTest] // See above
public void TestItemStillSelectedAfterChangeToOtherBeatmap()
{
selectNewItem(() => OtherBeatmap);
AddUntilStep("playlist item still selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID);
}
[Test]
[FlakyTest] // See above
public void TestOnlyLastItemChangedAfterGameplayFinished()
{
RunGameplay();
IBeatmapInfo firstBeatmap = null;
AddStep("get first playlist item beatmap", () => firstBeatmap = MultiplayerClient.ServerAPIRoom?.Playlist[0].Beatmap);
selectNewItem(() => OtherBeatmap);
AddUntilStep("first playlist item hasn't changed", () => MultiplayerClient.ServerAPIRoom?.Playlist[0].Beatmap == firstBeatmap);
AddUntilStep("second playlist item changed", () => MultiplayerClient.ClientAPIRoom?.Playlist[1].Beatmap != firstBeatmap);
}
[Test]
[FlakyTest] // See above
public void TestAddItemsAsHost()
{
addItem(() => OtherBeatmap);

View File

@ -377,6 +377,17 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
[Test]
[FlakyTest]
/*
* On a slight investigation, this is occurring due to the ready button
* not receiving the click input generated by the manual input manager.
*
* TearDown : System.TimeoutException : "wait for ready button to be enabled" timed out
* --TearDown
* at osu.Framework.Testing.Drawables.Steps.UntilStepButton.<>c__DisplayClass11_0.<.ctor>b__0()
* at osu.Framework.Testing.Drawables.Steps.StepButton.PerformStep(Boolean userTriggered)
* at osu.Framework.Testing.TestScene.runNextStep(Action onCompletion, Action`1 onError, Func`2 stopCondition)
*/
public void TestUserSetToIdleWhenBeatmapDeleted()
{
createRoom(() => new Room
@ -398,6 +409,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
[Test]
[FlakyTest] // See above
public void TestPlayStartsWithCorrectBeatmapWhileAtSongSelect()
{
PlaylistItem? item = null;
@ -438,6 +450,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
[Test]
[FlakyTest] // See above
public void TestPlayStartsWithCorrectRulesetWhileAtSongSelect()
{
PlaylistItem? item = null;
@ -478,6 +491,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
[Test]
[FlakyTest] // See above
public void TestPlayStartsWithCorrectModsWhileAtSongSelect()
{
PlaylistItem? item = null;
@ -651,6 +665,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
[Test]
[FlakyTest] // See above
public void TestGameplayFlow()
{
createRoom(() => new Room
@ -678,6 +693,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
[Test]
[FlakyTest] // See above
public void TestGameplayExitFlow()
{
Bindable<double>? holdDelay = null;
@ -715,6 +731,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
[Test]
[FlakyTest] // See above
public void TestGameplayDoesntStartWithNonLoadedUser()
{
createRoom(() => new Room
@ -796,6 +813,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
[Test]
[FlakyTest] // See above
public void TestSpectatingStateResetOnBackButtonDuringGameplay()
{
createRoom(() => new Room
@ -831,6 +849,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
[Test]
[FlakyTest] // See above
public void TestSpectatingStateNotResetOnBackButtonOutsideOfGameplay()
{
createRoom(() => new Room
@ -869,6 +888,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
[Test]
[FlakyTest] // See above
public void TestItemAddedByOtherUserDuringGameplay()
{
createRoom(() => new Room
@ -899,6 +919,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
[Test]
[FlakyTest] // See above
public void TestItemAddedAndDeletedByOtherUserDuringGameplay()
{
createRoom(() => new Room

View File

@ -195,11 +195,17 @@ namespace osu.Game.Tests.Visual.Navigation
AddUntilStep("wait for player", () =>
{
DismissAnyNotifications();
return (player = Game.ScreenStack.CurrentScreen as Player) != null;
player = Game.ScreenStack.CurrentScreen as Player;
return player?.IsLoaded == true;
});
AddAssert("retry count is 0", () => player.RestartCount == 0);
// todo: see https://github.com/ppy/osu/issues/22220
// tests are supposed to be immune to this edge case by the logic in TestPlayer,
// but we're running a full game instance here, so we have to work around it manually.
AddStep("end spectator before retry", () => Game.SpectatorClient.EndPlaying(player.GameplayState));
AddStep("attempt to retry", () => player.ChildrenOfType<HotkeyRetryOverlay>().First().Action());
AddUntilStep("wait for old player gone", () => Game.ScreenStack.CurrentScreen != player);

Some files were not shown because too many files have changed in this diff Show More