diff --git a/UseLocalFramework.ps1 b/UseLocalFramework.ps1
new file mode 100644
index 0000000000..837685f310
--- /dev/null
+++ b/UseLocalFramework.ps1
@@ -0,0 +1,17 @@
+# Run this script to use a local copy of osu-framework rather than fetching it from nuget.
+# It expects the osu-framework directory to be at the same level as the osu directory
+#
+# https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects
+
+$CSPROJ="osu.Game/osu.Game.csproj"
+$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
+
+$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
diff --git a/UseLocalFramework.sh b/UseLocalFramework.sh
new file mode 100755
index 0000000000..4fd1fdfd1b
--- /dev/null
+++ b/UseLocalFramework.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+# Run this script to use a local copy of osu-framework rather than fetching it from nuget.
+# It expects the osu-framework directory to be at the same level as the osu directory
+#
+# https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects
+
+CSPROJ="osu.Game/osu.Game.csproj"
+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
+
+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
diff --git a/osu.Android.props b/osu.Android.props
index b3c48da2bf..b6ddeeb41a 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -56,6 +56,6 @@
-
+
diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/Checks/TestCheckBananaShowerGap.cs b/osu.Game.Rulesets.Catch.Tests/Editor/Checks/TestCheckBananaShowerGap.cs
index 16361d12c6..ef34a5d664 100644
--- a/osu.Game.Rulesets.Catch.Tests/Editor/Checks/TestCheckBananaShowerGap.cs
+++ b/osu.Game.Rulesets.Catch.Tests/Editor/Checks/TestCheckBananaShowerGap.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 NUnit.Framework;
@@ -18,7 +16,7 @@ namespace osu.Game.Rulesets.Catch.Tests.Editor.Checks
[TestFixture]
public class TestCheckBananaShowerGap
{
- private CheckBananaShowerGap check;
+ private CheckBananaShowerGap check = null!;
[SetUp]
public void Setup()
diff --git a/osu.Game.Rulesets.Catch/Edit/Checks/CheckBananaShowerGap.cs b/osu.Game.Rulesets.Catch/Edit/Checks/CheckBananaShowerGap.cs
index 00fd74c9a8..4b2933c0e1 100644
--- a/osu.Game.Rulesets.Catch/Edit/Checks/CheckBananaShowerGap.cs
+++ b/osu.Game.Rulesets.Catch/Edit/Checks/CheckBananaShowerGap.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.Beatmaps;
diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckLowDiffOverlapsTest.cs b/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckLowDiffOverlapsTest.cs
index 7a361b0821..d035d2bc17 100644
--- a/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckLowDiffOverlapsTest.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckLowDiffOverlapsTest.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 Moq;
@@ -21,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
[TestFixture]
public class CheckLowDiffOverlapsTest
{
- private CheckLowDiffOverlaps check;
+ private CheckLowDiffOverlaps check = null!;
[SetUp]
public void Setup()
diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckOffscreenObjectsTest.cs b/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckOffscreenObjectsTest.cs
index a778b76c67..a72aaa966c 100644
--- a/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckOffscreenObjectsTest.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckOffscreenObjectsTest.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 NUnit.Framework;
@@ -23,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
{
private static readonly Vector2 playfield_centre = OsuPlayfield.BASE_SIZE * 0.5f;
- private CheckOffscreenObjects check;
+ private CheckOffscreenObjects check = null!;
[SetUp]
public void Setup()
diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTimeDistanceEqualityTest.cs b/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTimeDistanceEqualityTest.cs
index 4e8be75779..348243326d 100644
--- a/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTimeDistanceEqualityTest.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTimeDistanceEqualityTest.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 Moq;
@@ -21,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
[TestFixture]
public class CheckTimeDistanceEqualityTest
{
- private CheckTimeDistanceEquality check;
+ private CheckTimeDistanceEquality check = null!;
[SetUp]
public void Setup()
diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTooShortSlidersTest.cs b/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTooShortSlidersTest.cs
index 39a9d5e798..2ec3637bb7 100644
--- a/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTooShortSlidersTest.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTooShortSlidersTest.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 NUnit.Framework;
@@ -20,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
[TestFixture]
public class CheckTooShortSlidersTest
{
- private CheckTooShortSliders check;
+ private CheckTooShortSliders check = null!;
[SetUp]
public void Setup()
diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTooShortSpinnersTest.cs b/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTooShortSpinnersTest.cs
index d044ae732a..f215255bab 100644
--- a/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTooShortSpinnersTest.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTooShortSpinnersTest.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 NUnit.Framework;
@@ -19,8 +17,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
[TestFixture]
public class CheckTooShortSpinnersTest
{
- private CheckTooShortSpinners check;
- private IBeatmapDifficultyInfo difficulty;
+ private CheckTooShortSpinners check = null!;
+ private IBeatmapDifficultyInfo difficulty = null!;
[SetUp]
public void Setup()
diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuComposerSelection.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuComposerSelection.cs
new file mode 100644
index 0000000000..800e6c0711
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuComposerSelection.cs
@@ -0,0 +1,117 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Linq;
+using NUnit.Framework;
+using osu.Framework.Graphics.Cursor;
+using osu.Framework.Graphics.UserInterface;
+using osu.Framework.Testing;
+using osu.Game.Beatmaps;
+using osu.Game.Graphics.UserInterface;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
+using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
+using osu.Game.Rulesets.Osu.Objects;
+using osu.Game.Screens.Edit.Compose.Components;
+using osu.Game.Tests.Beatmaps;
+using osuTK;
+using osuTK.Input;
+
+namespace osu.Game.Rulesets.Osu.Tests.Editor
+{
+ [TestFixture]
+ public class TestSceneOsuComposerSelection : TestSceneOsuEditor
+ {
+ protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false);
+
+ [Test]
+ public void TestContextMenuShownCorrectlyForSelectedSlider()
+ {
+ var slider = new Slider
+ {
+ StartTime = 0,
+ Position = new Vector2(100, 100),
+ Path = new SliderPath
+ {
+ ControlPoints =
+ {
+ new PathControlPoint(),
+ new PathControlPoint(new Vector2(100))
+ }
+ }
+ };
+ AddStep("add slider", () => EditorBeatmap.Add(slider));
+
+ moveMouseToObject(() => slider);
+ AddStep("left click", () => InputManager.Click(MouseButton.Left));
+ AddUntilStep("slider selected", () => EditorBeatmap.SelectedHitObjects.Single() == slider);
+
+ AddStep("move mouse to centre", () => InputManager.MoveMouseTo(blueprintContainer.ChildrenOfType().Single().ScreenSpaceDrawQuad.Centre));
+ AddStep("right click", () => InputManager.Click(MouseButton.Right));
+ AddUntilStep("context menu is visible", () => contextMenuContainer.ChildrenOfType().Single().State == MenuState.Open);
+ }
+
+ [Test]
+ public void TestSelectionIncludingSliderPreservedOnClick()
+ {
+ var firstSlider = new Slider
+ {
+ StartTime = 0,
+ Position = new Vector2(0, 0),
+ Path = new SliderPath
+ {
+ ControlPoints =
+ {
+ new PathControlPoint(),
+ new PathControlPoint(new Vector2(100))
+ }
+ }
+ };
+ var secondSlider = new Slider
+ {
+ StartTime = 1000,
+ Position = new Vector2(100, 100),
+ Path = new SliderPath
+ {
+ ControlPoints =
+ {
+ new PathControlPoint(),
+ new PathControlPoint(new Vector2(100, -100))
+ }
+ }
+ };
+ var hitCircle = new HitCircle
+ {
+ StartTime = 200,
+ Position = new Vector2(300, 0)
+ };
+
+ AddStep("add objects", () => EditorBeatmap.AddRange(new HitObject[] { firstSlider, secondSlider, hitCircle }));
+ AddStep("select last 2 objects", () => EditorBeatmap.SelectedHitObjects.AddRange(new HitObject[] { secondSlider, hitCircle }));
+
+ moveMouseToObject(() => secondSlider);
+ AddStep("click left mouse", () => InputManager.Click(MouseButton.Left));
+ AddAssert("selection preserved", () => EditorBeatmap.SelectedHitObjects.Count == 2);
+ }
+
+ private ComposeBlueprintContainer blueprintContainer
+ => Editor.ChildrenOfType().First();
+
+ private ContextMenuContainer contextMenuContainer
+ => Editor.ChildrenOfType().First();
+
+ private void moveMouseToObject(Func targetFunc)
+ {
+ AddStep("move mouse to object", () =>
+ {
+ var pos = blueprintContainer.SelectionBlueprints
+ .First(s => s.Item == targetFunc())
+ .ChildrenOfType()
+ .First().ScreenSpaceDrawQuad.Centre;
+
+ InputManager.MoveMouseTo(pos);
+ });
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs
index 36ee7c2460..3718f0c6bc 100644
--- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs
@@ -105,8 +105,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
return true;
}
- private bool hasSingleObjectSelected => selectedObjects.Count == 1;
-
protected override void Update()
{
base.Update();
@@ -119,10 +117,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
{
updateVisualDefinition();
- // In the case more than a single object is selected, block hover from arriving at sliders behind this one.
- // Without doing this, the path visualisers of potentially hundreds of sliders will render, which is not only
- // visually noisy but also functionally useless.
- return !hasSingleObjectSelected;
+ return base.OnHover(e);
}
protected override void OnHoverLost(HoverLostEvent e)
@@ -147,8 +142,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
private void updateVisualDefinition()
{
- // To reduce overhead of drawing these blueprints, only add extra detail when hovered or when only this slider is selected.
- if (IsSelected && (hasSingleObjectSelected || IsHovered))
+ // To reduce overhead of drawing these blueprints, only add extra detail when only this slider is selected.
+ if (IsSelected && selectedObjects.Count < 2)
{
if (ControlPointVisualiser == null)
{
diff --git a/osu.Game.Rulesets.Osu/Edit/Checks/CheckLowDiffOverlaps.cs b/osu.Game.Rulesets.Osu/Edit/Checks/CheckLowDiffOverlaps.cs
index 57e6a6ad1d..084a3e5ea1 100644
--- a/osu.Game.Rulesets.Osu/Edit/Checks/CheckLowDiffOverlaps.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Checks/CheckLowDiffOverlaps.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.Beatmaps;
using osu.Game.Rulesets.Edit;
diff --git a/osu.Game.Rulesets.Osu/Edit/Checks/CheckOffscreenObjects.cs b/osu.Game.Rulesets.Osu/Edit/Checks/CheckOffscreenObjects.cs
index af3521c35c..a342c2a821 100644
--- a/osu.Game.Rulesets.Osu/Edit/Checks/CheckOffscreenObjects.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Checks/CheckOffscreenObjects.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.Edit;
using osu.Game.Rulesets.Edit.Checks.Components;
diff --git a/osu.Game.Rulesets.Osu/Edit/Checks/CheckTimeDistanceEquality.cs b/osu.Game.Rulesets.Osu/Edit/Checks/CheckTimeDistanceEquality.cs
index 753ddba710..585bd35bd9 100644
--- a/osu.Game.Rulesets.Osu/Edit/Checks/CheckTimeDistanceEquality.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Checks/CheckTimeDistanceEquality.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.Osu/Edit/Checks/CheckTooShortSliders.cs b/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSliders.cs
index 75eeb91918..159498c479 100644
--- a/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSliders.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSliders.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.Beatmaps;
using osu.Game.Rulesets.Edit;
diff --git a/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSpinners.cs b/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSpinners.cs
index 6b4dc01ab1..f0aade1b7f 100644
--- a/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSpinners.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSpinners.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.Edit;
using osu.Game.Rulesets.Edit.Checks.Components;
diff --git a/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs
index 425f72cadc..5685ac0f60 100644
--- a/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs
@@ -16,13 +16,13 @@ namespace osu.Game.Rulesets.Taiko.Tests
{
protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko";
- [TestCase(3.1098944660126882d, 200, "diffcalc-test")]
- [TestCase(3.1098944660126882d, 200, "diffcalc-test-strong")]
+ [TestCase(3.0920212594351191d, 200, "diffcalc-test")]
+ [TestCase(3.0920212594351191d, 200, "diffcalc-test-strong")]
public void Test(double expectedStarRating, int expectedMaxCombo, string name)
=> base.Test(expectedStarRating, expectedMaxCombo, name);
- [TestCase(4.0974106752474251d, 200, "diffcalc-test")]
- [TestCase(4.0974106752474251d, 200, "diffcalc-test-strong")]
+ [TestCase(4.0789820318081444d, 200, "diffcalc-test")]
+ [TestCase(4.0789820318081444d, 200, "diffcalc-test-strong")]
public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name)
=> Test(expectedStarRating, expectedMaxCombo, name, new TaikoModDoubleTime());
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs
index 7d88be2f70..9f63e84867 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs
@@ -54,11 +54,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
TaikoDifficultyHitObjectColour colour = ((TaikoDifficultyHitObject)hitObject).Colour;
double difficulty = 0.0d;
- if (colour.MonoStreak != null) // Difficulty for MonoStreak
+ if (colour.MonoStreak?.FirstHitObject == hitObject) // Difficulty for MonoStreak
difficulty += EvaluateDifficultyOf(colour.MonoStreak);
- if (colour.AlternatingMonoPattern != null) // Difficulty for AlternatingMonoPattern
+ if (colour.AlternatingMonoPattern?.FirstHitObject == hitObject) // Difficulty for AlternatingMonoPattern
difficulty += EvaluateDifficultyOf(colour.AlternatingMonoPattern);
- if (colour.RepeatingHitPattern != null) // Difficulty for RepeatingHitPattern
+ if (colour.RepeatingHitPattern?.FirstHitObject == hitObject) // Difficulty for RepeatingHitPattern
difficulty += EvaluateDifficultyOf(colour.RepeatingHitPattern);
return difficulty;
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs
index 49b3ae2e19..84d5de4c63 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs
@@ -11,22 +11,43 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
public class StaminaEvaluator
{
///
- /// Applies a speed bonus dependent on the time since the last hit performed using this key.
+ /// Applies a speed bonus dependent on the time since the last hit performed using this finger.
///
- /// The interval between the current and previous note hit using the same key.
+ /// The interval between the current and previous note hit using the same finger.
private static double speedBonus(double interval)
{
- // Cap to 600bpm 1/4, 25ms note interval, 50ms key interval
- // Interval will be capped at a very small value to avoid infinite/negative speed bonuses.
- // TODO - This is a temporary measure as we need to implement methods of detecting playstyle-abuse of SpeedBonus.
- interval = Math.Max(interval, 50);
+ // Interval is capped at a very small value to prevent infinite values.
+ interval = Math.Max(interval, 1);
return 30 / interval;
}
+ ///
+ /// Determines the number of fingers available to hit the current .
+ /// Any mono notes that is more than 300ms apart from a colour change will be considered to have more than 2
+ /// fingers available, since players can hit the same key with multiple fingers.
+ ///
+ private static int availableFingersFor(TaikoDifficultyHitObject hitObject)
+ {
+ DifficultyHitObject? previousColourChange = hitObject.Colour.PreviousColourChange;
+ DifficultyHitObject? nextColourChange = hitObject.Colour.NextColourChange;
+
+ if (previousColourChange != null && hitObject.StartTime - previousColourChange.StartTime < 300)
+ {
+ return 2;
+ }
+
+ if (nextColourChange != null && nextColourChange.StartTime - hitObject.StartTime < 300)
+ {
+ return 2;
+ }
+
+ return 4;
+ }
+
///
/// Evaluates the minimum mechanical stamina required to play the current object. This is calculated using the
- /// maximum possible interval between two hits using the same key, by alternating 2 keys for each colour.
+ /// maximum possible interval between two hits using the same key, by alternating available fingers for each colour.
///
public static double EvaluateDifficultyOf(DifficultyHitObject current)
{
@@ -35,13 +56,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
return 0.0;
}
- // Find the previous hit object hit by the current key, which is two notes of the same colour prior.
+ // Find the previous hit object hit by the current finger, which is n notes prior, n being the number of
+ // available fingers.
TaikoDifficultyHitObject taikoCurrent = (TaikoDifficultyHitObject)current;
- TaikoDifficultyHitObject? keyPrevious = taikoCurrent.PreviousMono(1);
+ TaikoDifficultyHitObject? keyPrevious = taikoCurrent.PreviousMono(availableFingersFor(taikoCurrent) - 1);
if (keyPrevious == null)
{
- // There is no previous hit object hit by the current key
+ // There is no previous hit object hit by the current finger
return 0.0;
}
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs
index 174988bed7..c01a0f6686 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs
@@ -33,6 +33,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data
///
public TaikoDifficultyHitObject FirstHitObject => HitObjects[0];
+ ///
+ /// The last in this .
+ ///
+ public TaikoDifficultyHitObject LastHitObject => HitObjects[^1];
+
///
/// The hit type of all objects encoded within this
///
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPatterns.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPatterns.cs
index fe0dc6dd9a..468a9ab876 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPatterns.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPatterns.cs
@@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data
public readonly List AlternatingMonoPatterns = new List();
///
- /// The parent in this
+ /// The first in this
///
public TaikoDifficultyHitObject FirstHitObject => AlternatingMonoPatterns[0].FirstHitObject;
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs
index d19e05f4e0..18a299ae92 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs
@@ -15,19 +15,15 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour
{
///
/// Processes and encodes a list of s into a list of s,
- /// assigning the appropriate s to each ,
- /// and pre-evaluating colour difficulty of each .
+ /// assigning the appropriate s to each .
///
public static void ProcessAndAssign(List hitObjects)
{
List hitPatterns = encode(hitObjects);
- // Assign indexing and encoding data to all relevant objects. Only the first note of each encoding type is
- // assigned with the relevant encodings.
+ // Assign indexing and encoding data to all relevant objects.
foreach (var repeatingHitPattern in hitPatterns)
{
- repeatingHitPattern.FirstHitObject.Colour.RepeatingHitPattern = repeatingHitPattern;
-
// The outermost loop is kept a ForEach loop since it doesn't need index information, and we want to
// keep i and j for AlternatingMonoPattern's and MonoStreak's index respectively, to keep it in line with
// documentation.
@@ -36,14 +32,19 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour
AlternatingMonoPattern monoPattern = repeatingHitPattern.AlternatingMonoPatterns[i];
monoPattern.Parent = repeatingHitPattern;
monoPattern.Index = i;
- monoPattern.FirstHitObject.Colour.AlternatingMonoPattern = monoPattern;
for (int j = 0; j < monoPattern.MonoStreaks.Count; ++j)
{
MonoStreak monoStreak = monoPattern.MonoStreaks[j];
monoStreak.Parent = monoPattern;
monoStreak.Index = j;
- monoStreak.FirstHitObject.Colour.MonoStreak = monoStreak;
+
+ foreach (var hitObject in monoStreak.HitObjects)
+ {
+ hitObject.Colour.RepeatingHitPattern = repeatingHitPattern;
+ hitObject.Colour.AlternatingMonoPattern = monoPattern;
+ hitObject.Colour.MonoStreak = monoStreak;
+ }
}
}
}
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs
index 9c147eee9c..abf6fb3672 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs
@@ -11,18 +11,28 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour
public class TaikoDifficultyHitObjectColour
{
///
- /// The that encodes this note, only present if this is the first note within a
+ /// The that encodes this note.
///
public MonoStreak? MonoStreak;
///
- /// The that encodes this note, only present if this is the first note within a
+ /// The that encodes this note.
///
public AlternatingMonoPattern? AlternatingMonoPattern;
///
- /// The that encodes this note, only present if this is the first note within a
+ /// The that encodes this note.
///
public RepeatingHitPatterns? RepeatingHitPattern;
+
+ ///
+ /// The closest past that's not the same colour.
+ ///
+ public TaikoDifficultyHitObject? PreviousColourChange => MonoStreak?.FirstHitObject.PreviousNote(0);
+
+ ///
+ /// The closest future that's not the same colour.
+ ///
+ public TaikoDifficultyHitObject? NextColourChange => MonoStreak?.LastHitObject.NextNote(0);
}
}
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs
index 344004bcf6..d04c028fec 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs
@@ -13,9 +13,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
///
/// Calculates the stamina coefficient of taiko difficulty.
///
- ///
- /// The reference play style chosen uses two hands, with full alternating (the hand changes after every hit).
- ///
public class Stamina : StrainDecaySkill
{
protected override double SkillMultiplier => 1.1;
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs
index 2b0b563323..24b5f5939a 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs
@@ -83,15 +83,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
double combinedRating = combined.DifficultyValue() * difficulty_multiplier;
double starRating = rescale(combinedRating * 1.4);
- // TODO: This is temporary measure as we don't detect abuse of multiple-input playstyles of converts within the current system.
- if (beatmap.BeatmapInfo.Ruleset.OnlineID == 0)
- {
- starRating *= 0.925;
- // For maps with low colour variance and high stamina requirement, multiple inputs are more likely to be abused.
- if (colourRating < 2 && staminaRating > 8)
- starRating *= 0.80;
- }
-
HitWindows hitWindows = new TaikoHitWindows();
hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty);
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs
index dc7bad2f75..2d1b2903c9 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs
@@ -43,6 +43,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
if (totalSuccessfulHits > 0)
effectiveMissCount = Math.Max(1.0, 1000.0 / totalSuccessfulHits) * countMiss;
+ // TODO: The detection of rulesets is temporary until the leftover old skills have been reworked.
+ bool isConvert = score.BeatmapInfo.Ruleset.OnlineID != 1;
+
double multiplier = 1.13;
if (score.Mods.Any(m => m is ModHidden))
@@ -51,8 +54,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
if (score.Mods.Any(m => m is ModEasy))
multiplier *= 0.975;
- double difficultyValue = computeDifficultyValue(score, taikoAttributes);
- double accuracyValue = computeAccuracyValue(score, taikoAttributes);
+ double difficultyValue = computeDifficultyValue(score, taikoAttributes, isConvert);
+ double accuracyValue = computeAccuracyValue(score, taikoAttributes, isConvert);
double totalValue =
Math.Pow(
Math.Pow(difficultyValue, 1.1) +
@@ -68,7 +71,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
};
}
- private double computeDifficultyValue(ScoreInfo score, TaikoDifficultyAttributes attributes)
+ private double computeDifficultyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool isConvert)
{
double difficultyValue = Math.Pow(5 * Math.Max(1.0, attributes.StarRating / 0.115) - 4.0, 2.25) / 1150.0;
@@ -80,7 +83,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
if (score.Mods.Any(m => m is ModEasy))
difficultyValue *= 0.985;
- if (score.Mods.Any(m => m is ModHidden))
+ if (score.Mods.Any(m => m is ModHidden) && !isConvert)
difficultyValue *= 1.025;
if (score.Mods.Any(m => m is ModHardRock))
@@ -92,7 +95,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
return difficultyValue * Math.Pow(accuracy, 2.0);
}
- private double computeAccuracyValue(ScoreInfo score, TaikoDifficultyAttributes attributes)
+ private double computeAccuracyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool isConvert)
{
if (attributes.GreatHitWindow <= 0)
return 0;
@@ -102,9 +105,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
double lengthBonus = Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3));
accuracyValue *= lengthBonus;
- // Slight HDFL Bonus for accuracy. A clamp is used to prevent against negative values
- if (score.Mods.Any(m => m is ModFlashlight) && score.Mods.Any(m => m is ModHidden))
- accuracyValue *= Math.Max(1.050, 1.075 * lengthBonus);
+ // Slight HDFL Bonus for accuracy. A clamp is used to prevent against negative values.
+ if (score.Mods.Any(m => m is ModFlashlight) && score.Mods.Any(m => m is ModHidden) && !isConvert)
+ accuracyValue *= Math.Max(1.0, 1.1 * lengthBonus);
return accuracyValue;
}
diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
index cc71ba5401..f2d7811f44 100644
--- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
+++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
@@ -60,8 +60,9 @@ namespace osu.Game.Rulesets.Taiko.UI
///
private BarLinePlayfield barLinePlayfield;
- private Container playfieldContent;
- private Container playfieldOverlay;
+ private Container barLineContent;
+ private Container hitObjectContent;
+ private Container overlayContent;
[BackgroundDependencyLoader]
private void load(OsuColour colours)
@@ -121,22 +122,20 @@ namespace osu.Game.Rulesets.Taiko.UI
}
}
},
- new Container
+ barLineContent = new Container
+ {
+ Name = "Bar line content",
+ RelativeSizeAxes = Axes.Both,
+ Child = barLinePlayfield = new BarLinePlayfield(),
+ },
+ hitObjectContent = new Container
{
Name = "Masked hit objects content",
RelativeSizeAxes = Axes.Both,
Masking = true,
- Child = playfieldContent = new Container
- {
- RelativeSizeAxes = Axes.Both,
- Children = new Drawable[]
- {
- barLinePlayfield = new BarLinePlayfield(),
- HitObjectContainer,
- }
- }
+ Child = HitObjectContainer,
},
- playfieldOverlay = new Container
+ overlayContent = new Container
{
Name = "Elements after hit objects",
RelativeSizeAxes = Axes.Both,
@@ -215,8 +214,9 @@ namespace osu.Game.Rulesets.Taiko.UI
// Padding is required to be updated for elements which are based on "absolute" X sized elements.
// This is basically allowing for correct alignment as relative pieces move around them.
rightArea.Padding = new MarginPadding { Left = inputDrum.Width };
- playfieldContent.Padding = new MarginPadding { Left = HitTarget.DrawWidth / 2 };
- playfieldOverlay.Padding = new MarginPadding { Left = HitTarget.DrawWidth / 2 };
+ barLineContent.Padding = new MarginPadding { Left = HitTarget.DrawWidth / 2 };
+ hitObjectContent.Padding = new MarginPadding { Left = HitTarget.DrawWidth / 2 };
+ overlayContent.Padding = new MarginPadding { Left = HitTarget.DrawWidth / 2 };
mascot.Scale = new Vector2(DrawHeight / DEFAULT_HEIGHT);
}
diff --git a/osu.Game.Tests/Editing/Checks/CheckAudioInVideoTest.cs b/osu.Game.Tests/Editing/Checks/CheckAudioInVideoTest.cs
index 947e884494..9774a8ebb6 100644
--- a/osu.Game.Tests/Editing/Checks/CheckAudioInVideoTest.cs
+++ b/osu.Game.Tests/Editing/Checks/CheckAudioInVideoTest.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.IO;
using System.Linq;
using Moq;
@@ -20,8 +18,8 @@ namespace osu.Game.Tests.Editing.Checks
[TestFixture]
public class CheckAudioInVideoTest
{
- private CheckAudioInVideo check;
- private IBeatmap beatmap;
+ private CheckAudioInVideo check = null!;
+ private IBeatmap beatmap = null!;
[SetUp]
public void Setup()
@@ -84,7 +82,7 @@ namespace osu.Game.Tests.Editing.Checks
Assert.That(issues.Single().Template is CheckAudioInVideo.IssueTemplateMissingFile);
}
- private BeatmapVerifierContext getContext(Stream resourceStream)
+ private BeatmapVerifierContext getContext(Stream? resourceStream)
{
var storyboard = new Storyboard();
var layer = storyboard.GetLayer("Video");
diff --git a/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs b/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs
index 50e6087526..61ee6a3663 100644
--- a/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs
+++ b/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.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 Moq;
using NUnit.Framework;
@@ -19,8 +17,8 @@ namespace osu.Game.Tests.Editing.Checks
[TestFixture]
public class CheckAudioQualityTest
{
- private CheckAudioQuality check;
- private IBeatmap beatmap;
+ private CheckAudioQuality check = null!;
+ private IBeatmap beatmap = null!;
[SetUp]
public void Setup()
@@ -43,7 +41,7 @@ namespace osu.Game.Tests.Editing.Checks
var mock = new Mock();
mock.SetupGet(w => w.Beatmap).Returns(beatmap);
- mock.SetupGet(w => w.Track).Returns((Track)null);
+ mock.SetupGet(w => w.Track).Returns((Track)null!);
Assert.That(check.Run(new BeatmapVerifierContext(beatmap, mock.Object)), Is.Empty);
}
diff --git a/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs b/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs
index f91e83a556..295a10ba5b 100644
--- a/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs
+++ b/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.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.IO;
using System.Linq;
-using JetBrains.Annotations;
using Moq;
using NUnit.Framework;
using osu.Framework.Graphics.Rendering.Dummy;
@@ -21,8 +18,8 @@ namespace osu.Game.Tests.Editing.Checks
[TestFixture]
public class CheckBackgroundQualityTest
{
- private CheckBackgroundQuality check;
- private IBeatmap beatmap;
+ private CheckBackgroundQuality check = null!;
+ private IBeatmap beatmap = null!;
[SetUp]
public void Setup()
@@ -48,7 +45,7 @@ namespace osu.Game.Tests.Editing.Checks
{
// While this is a problem, it is out of scope for this check and is caught by a different one.
beatmap.Metadata.BackgroundFile = string.Empty;
- var context = getContext(null, new MemoryStream(Array.Empty()));
+ var context = getContext(null!, new MemoryStream(Array.Empty()));
Assert.That(check.Run(context), Is.Empty);
}
@@ -118,7 +115,7 @@ namespace osu.Game.Tests.Editing.Checks
stream.Verify(x => x.Close(), Times.Once());
}
- private BeatmapVerifierContext getContext(Texture background, [CanBeNull] Stream stream = null)
+ private BeatmapVerifierContext getContext(Texture background, Stream? stream = null)
{
return new BeatmapVerifierContext(beatmap, getMockWorkingBeatmap(background, stream).Object);
}
@@ -128,7 +125,7 @@ namespace osu.Game.Tests.Editing.Checks
///
/// The texture of the background.
/// The stream representing the background file.
- private Mock getMockWorkingBeatmap(Texture background, [CanBeNull] Stream stream = null)
+ private Mock getMockWorkingBeatmap(Texture background, Stream? stream = null)
{
stream ??= new MemoryStream(new byte[1024 * 1024]);
diff --git a/osu.Game.Tests/Editing/Checks/CheckConcurrentObjectsTest.cs b/osu.Game.Tests/Editing/Checks/CheckConcurrentObjectsTest.cs
index 9c1dd2c1e8..b5c6568583 100644
--- a/osu.Game.Tests/Editing/Checks/CheckConcurrentObjectsTest.cs
+++ b/osu.Game.Tests/Editing/Checks/CheckConcurrentObjectsTest.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 Moq;
@@ -21,7 +19,7 @@ namespace osu.Game.Tests.Editing.Checks
[TestFixture]
public class CheckConcurrentObjectsTest
{
- private CheckConcurrentObjects check;
+ private CheckConcurrentObjects check = null!;
[SetUp]
public void Setup()
diff --git a/osu.Game.Tests/Editing/Checks/CheckFewHitsoundsTest.cs b/osu.Game.Tests/Editing/Checks/CheckFewHitsoundsTest.cs
index 82bb2e59c9..01781b98ad 100644
--- a/osu.Game.Tests/Editing/Checks/CheckFewHitsoundsTest.cs
+++ b/osu.Game.Tests/Editing/Checks/CheckFewHitsoundsTest.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 NUnit.Framework;
@@ -20,10 +18,10 @@ namespace osu.Game.Tests.Editing.Checks
[TestFixture]
public class CheckFewHitsoundsTest
{
- private CheckFewHitsounds check;
+ private CheckFewHitsounds check = null!;
- private List notHitsounded;
- private List hitsounded;
+ private List notHitsounded = null!;
+ private List hitsounded = null!;
[SetUp]
public void Setup()
diff --git a/osu.Game.Tests/Editing/Checks/CheckFilePresenceTest.cs b/osu.Game.Tests/Editing/Checks/CheckFilePresenceTest.cs
index 2f18720a5b..89bb2f9396 100644
--- a/osu.Game.Tests/Editing/Checks/CheckFilePresenceTest.cs
+++ b/osu.Game.Tests/Editing/Checks/CheckFilePresenceTest.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 NUnit.Framework;
using osu.Game.Beatmaps;
@@ -16,8 +14,8 @@ namespace osu.Game.Tests.Editing.Checks
[TestFixture]
public class CheckFilePresenceTest
{
- private CheckBackgroundPresence check;
- private IBeatmap beatmap;
+ private CheckBackgroundPresence check = null!;
+ private IBeatmap beatmap = null!;
[SetUp]
public void Setup()
diff --git a/osu.Game.Tests/Editing/Checks/CheckMutedObjectsTest.cs b/osu.Game.Tests/Editing/Checks/CheckMutedObjectsTest.cs
index 622386405a..1e1c214c30 100644
--- a/osu.Game.Tests/Editing/Checks/CheckMutedObjectsTest.cs
+++ b/osu.Game.Tests/Editing/Checks/CheckMutedObjectsTest.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 NUnit.Framework;
@@ -21,8 +19,8 @@ namespace osu.Game.Tests.Editing.Checks
[TestFixture]
public class CheckMutedObjectsTest
{
- private CheckMutedObjects check;
- private ControlPointInfo cpi;
+ private CheckMutedObjects check = null!;
+ private ControlPointInfo cpi = null!;
private const int volume_regular = 50;
private const int volume_low = 15;
diff --git a/osu.Game.Tests/Editing/Checks/CheckTestHelpers.cs b/osu.Game.Tests/Editing/Checks/CheckTestHelpers.cs
index 405738cd55..9067714ff9 100644
--- a/osu.Game.Tests/Editing/Checks/CheckTestHelpers.cs
+++ b/osu.Game.Tests/Editing/Checks/CheckTestHelpers.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.Models;
namespace osu.Game.Tests.Editing.Checks
diff --git a/osu.Game.Tests/Editing/Checks/CheckTooShortAudioFilesTest.cs b/osu.Game.Tests/Editing/Checks/CheckTooShortAudioFilesTest.cs
index 7d33b92dbe..4918369460 100644
--- a/osu.Game.Tests/Editing/Checks/CheckTooShortAudioFilesTest.cs
+++ b/osu.Game.Tests/Editing/Checks/CheckTooShortAudioFilesTest.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.Diagnostics;
using System.IO;
using System.Linq;
@@ -22,8 +20,8 @@ namespace osu.Game.Tests.Editing.Checks
[TestFixture]
public class CheckTooShortAudioFilesTest
{
- private CheckTooShortAudioFiles check;
- private IBeatmap beatmap;
+ private CheckTooShortAudioFiles check = null!;
+ private IBeatmap beatmap = null!;
[SetUp]
public void Setup()
@@ -109,7 +107,7 @@ namespace osu.Game.Tests.Editing.Checks
}
}
- private BeatmapVerifierContext getContext(Stream resourceStream)
+ private BeatmapVerifierContext getContext(Stream? resourceStream)
{
var mockWorkingBeatmap = new Mock(beatmap, null, null);
mockWorkingBeatmap.Setup(w => w.GetStream(It.IsAny())).Returns(resourceStream);
diff --git a/osu.Game.Tests/Editing/Checks/CheckUnsnappedObjectsTest.cs b/osu.Game.Tests/Editing/Checks/CheckUnsnappedObjectsTest.cs
index f647bf8d8e..c9335dcda5 100644
--- a/osu.Game.Tests/Editing/Checks/CheckUnsnappedObjectsTest.cs
+++ b/osu.Game.Tests/Editing/Checks/CheckUnsnappedObjectsTest.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 Moq;
@@ -21,8 +19,8 @@ namespace osu.Game.Tests.Editing.Checks
[TestFixture]
public class CheckUnsnappedObjectsTest
{
- private CheckUnsnappedObjects check;
- private ControlPointInfo cpi;
+ private CheckUnsnappedObjects check = null!;
+ private ControlPointInfo cpi = null!;
[SetUp]
public void Setup()
diff --git a/osu.Game.Tests/Editing/Checks/CheckZeroByteFilesTest.cs b/osu.Game.Tests/Editing/Checks/CheckZeroByteFilesTest.cs
index 793cc70a3f..a39ef22b72 100644
--- a/osu.Game.Tests/Editing/Checks/CheckZeroByteFilesTest.cs
+++ b/osu.Game.Tests/Editing/Checks/CheckZeroByteFilesTest.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.IO;
using System.Linq;
using Moq;
@@ -17,8 +15,8 @@ namespace osu.Game.Tests.Editing.Checks
[TestFixture]
public class CheckZeroByteFilesTest
{
- private CheckZeroByteFiles check;
- private IBeatmap beatmap;
+ private CheckZeroByteFiles check = null!;
+ private IBeatmap beatmap = null!;
[SetUp]
public void Setup()
@@ -74,7 +72,7 @@ namespace osu.Game.Tests.Editing.Checks
private BeatmapVerifierContext getContextMissing()
{
var mockWorkingBeatmap = new Mock();
- mockWorkingBeatmap.Setup(w => w.GetStream(It.IsAny())).Returns((Stream)null);
+ mockWorkingBeatmap.Setup(w => w.GetStream(It.IsAny())).Returns((Stream)null!);
return new BeatmapVerifierContext(beatmap, mockWorkingBeatmap.Object);
}
diff --git a/osu.Game.Tests/Editing/Checks/CheckZeroLengthObjectsTest.cs b/osu.Game.Tests/Editing/Checks/CheckZeroLengthObjectsTest.cs
index 1c1965ab56..648f02839f 100644
--- a/osu.Game.Tests/Editing/Checks/CheckZeroLengthObjectsTest.cs
+++ b/osu.Game.Tests/Editing/Checks/CheckZeroLengthObjectsTest.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 Moq;
@@ -21,7 +19,7 @@ namespace osu.Game.Tests.Editing.Checks
[TestFixture]
public class CheckZeroLengthObjectsTest
{
- private CheckZeroLengthObjects check;
+ private CheckZeroLengthObjects check = null!;
[SetUp]
public void Setup()
diff --git a/osu.Game.Tests/Editing/Checks/MockNestableHitObject.cs b/osu.Game.Tests/Editing/Checks/MockNestableHitObject.cs
index 6c0306d63d..29938839d3 100644
--- a/osu.Game.Tests/Editing/Checks/MockNestableHitObject.cs
+++ b/osu.Game.Tests/Editing/Checks/MockNestableHitObject.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.Threading;
using osu.Game.Rulesets.Objects;
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs
index a5d115331d..981967e413 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs
@@ -7,10 +7,12 @@ using System;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
+using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
+using osu.Game.Configuration;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
@@ -21,7 +23,6 @@ using osu.Game.Screens.Edit.GameplayTest;
using osu.Game.Screens.Play;
using osu.Game.Storyboards;
using osu.Game.Tests.Beatmaps.IO;
-using osuTK.Graphics;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Editing
@@ -40,6 +41,14 @@ namespace osu.Game.Tests.Visual.Editing
private BeatmapSetInfo importedBeatmapSet;
+ private Bindable editorDim;
+
+ [BackgroundDependencyLoader]
+ private void load(OsuConfigManager config)
+ {
+ editorDim = config.GetBindable(OsuSetting.EditorDim);
+ }
+
public override void SetUpSteps()
{
AddStep("import test beatmap", () => importedBeatmapSet = BeatmapImportHelper.LoadOszIntoOsu(game).GetResultSafely());
@@ -77,7 +86,7 @@ namespace osu.Game.Tests.Visual.Editing
// this test cares about checking the background belonging to the editor specifically, so check that using reference equality
// (as `.Equals()` cannot discern between the two, as they technically share the same database GUID).
var background = this.ChildrenOfType().Single(b => ReferenceEquals(b.Beatmap.BeatmapInfo, EditorBeatmap.BeatmapInfo));
- return background.Colour == Color4.DarkGray && background.BlurAmount.Value == 0;
+ return background.DimWhenUserSettingsIgnored.Value == editorDim.Value && background.BlurAmount.Value == 0;
});
AddAssert("no mods selected", () => SelectedMods.Value.Count == 0);
}
@@ -110,7 +119,7 @@ namespace osu.Game.Tests.Visual.Editing
// this test cares about checking the background belonging to the editor specifically, so check that using reference equality
// (as `.Equals()` cannot discern between the two, as they technically share the same database GUID).
var background = this.ChildrenOfType().Single(b => ReferenceEquals(b.Beatmap.BeatmapInfo, EditorBeatmap.BeatmapInfo));
- return background.Colour == Color4.DarkGray && background.BlurAmount.Value == 0;
+ return background.DimWhenUserSettingsIgnored.Value == editorDim.Value && background.BlurAmount.Value == 0;
});
AddStep("start track", () => EditorClock.Start());
diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs
index 2c9b34e4a7..1e0a09d37a 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs
@@ -198,13 +198,13 @@ namespace osu.Game.Tests.Visual.Online
beatmapSet = CreateAPIBeatmapSet(Ruleset.Value);
beatmapSet.Title = "last beatmap of first page";
- fetchFor(getManyBeatmaps(49).Append(beatmapSet).ToArray(), true);
+ fetchFor(getManyBeatmaps(49).Append(new APIBeatmapSet { Title = "last beatmap of first page", OnlineID = beatmapSet.OnlineID }).ToArray(), true);
});
AddUntilStep("wait for loaded", () => this.ChildrenOfType().Count() == 50);
- AddStep("set next page", () => setSearchResponse(getManyBeatmaps(49).Prepend(beatmapSet).ToArray(), false));
+ AddStep("set next page", () => setSearchResponse(getManyBeatmaps(49).Prepend(new APIBeatmapSet { Title = "this shouldn't show up", OnlineID = beatmapSet.OnlineID }).ToArray(), false));
AddStep("scroll to end", () => overlay.ChildrenOfType().Single().ScrollToEnd());
- AddUntilStep("wait for loaded", () => this.ChildrenOfType().Count() == 99);
+ AddUntilStep("wait for loaded", () => this.ChildrenOfType().Count() >= 99);
AddAssert("beatmap not duplicated", () => overlay.ChildrenOfType().Count(c => c.BeatmapSet.Equals(beatmapSet)) == 1);
}
diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs
index 70312a1535..b9e0a4e6cb 100644
--- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs
+++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs
@@ -14,7 +14,7 @@ using osu.Game.Overlays;
namespace osu.Game.Beatmaps.Drawables.Cards
{
- public abstract class BeatmapCard : OsuClickableContainer, IEquatable
+ public abstract class BeatmapCard : OsuClickableContainer
{
public const float TRANSITION_DURATION = 400;
public const float CORNER_RADIUS = 10;
@@ -96,16 +96,5 @@ namespace osu.Game.Beatmaps.Drawables.Cards
throw new ArgumentOutOfRangeException(nameof(size), size, @"Unsupported card size");
}
}
-
- public bool Equals(BeatmapCard? other)
- {
- if (ReferenceEquals(null, other)) return false;
- if (ReferenceEquals(this, other)) return true;
-
- return BeatmapSet.Equals(other.BeatmapSet);
- }
-
- public override bool Equals(object obj) => obj is BeatmapCard other && Equals(other);
- public override int GetHashCode() => BeatmapSet.GetHashCode();
}
}
diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs
index 093eaa0f31..fccd1a8715 100644
--- a/osu.Game/Configuration/OsuConfigManager.cs
+++ b/osu.Game/Configuration/OsuConfigManager.cs
@@ -171,7 +171,8 @@ namespace osu.Game.Configuration
SetDefault(OsuSetting.DiscordRichPresence, DiscordRichPresenceMode.Full);
- SetDefault(OsuSetting.EditorWaveformOpacity, 0.25f);
+ SetDefault(OsuSetting.EditorDim, 0.25f, 0f, 0.75f, 0.25f);
+ SetDefault(OsuSetting.EditorWaveformOpacity, 0.25f, 0f, 1f, 0.25f);
SetDefault(OsuSetting.LastProcessedMetadataId, -1);
}
@@ -288,6 +289,7 @@ namespace osu.Game.Configuration
GameplayCursorDuringTouch,
DimLevel,
BlurLevel,
+ EditorDim,
LightenDuringBreaks,
ShowStoryboard,
KeyOverlay,
diff --git a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs
index 5c98e22818..9d873762bf 100644
--- a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs
+++ b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs
@@ -111,8 +111,6 @@ namespace osu.Game.Graphics.Backgrounds
private void load(LargeTextureStore textures)
{
Sprite.Texture = textures.Get(url) ?? textures.Get(fallback_texture_name);
- // ensure we're not loading in without a transition.
- this.FadeInFromZero(200, Easing.InOutSine);
}
public override bool Equals(Background other)
diff --git a/osu.Game/Graphics/Containers/UserDimContainer.cs b/osu.Game/Graphics/Containers/UserDimContainer.cs
index d52fb7c60a..0b20159190 100644
--- a/osu.Game/Graphics/Containers/UserDimContainer.cs
+++ b/osu.Game/Graphics/Containers/UserDimContainer.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;
@@ -46,15 +44,20 @@ namespace osu.Game.Graphics.Containers
///
public bool ContentDisplayed { get; private set; }
- protected Bindable UserDimLevel { get; private set; }
+ protected Bindable UserDimLevel { get; private set; } = null!;
- protected Bindable LightenDuringBreaks { get; private set; }
+ ///
+ /// The amount of dim to be used when is true.
+ ///
+ public Bindable DimWhenUserSettingsIgnored { get; set; } = new Bindable();
- protected Bindable ShowStoryboard { get; private set; }
+ protected Bindable LightenDuringBreaks { get; private set; } = null!;
+
+ protected Bindable ShowStoryboard { get; private set; } = null!;
private float breakLightening => LightenDuringBreaks.Value && IsBreakTime.Value ? BREAK_LIGHTEN_AMOUNT : 0;
- protected float DimLevel => Math.Max(!IgnoreUserSettings.Value ? (float)UserDimLevel.Value - breakLightening : 0, 0);
+ protected float DimLevel => Math.Max(!IgnoreUserSettings.Value ? (float)UserDimLevel.Value - breakLightening : DimWhenUserSettingsIgnored.Value, 0);
protected override Container Content => dimContent;
@@ -76,6 +79,7 @@ namespace osu.Game.Graphics.Containers
ShowStoryboard = config.GetBindable(OsuSetting.ShowStoryboard);
UserDimLevel.ValueChanged += _ => UpdateVisuals();
+ DimWhenUserSettingsIgnored.ValueChanged += _ => UpdateVisuals();
LightenDuringBreaks.ValueChanged += _ => UpdateVisuals();
IsBreakTime.ValueChanged += _ => UpdateVisuals();
ShowStoryboard.ValueChanged += _ => UpdateVisuals();
diff --git a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs
index af542989ff..adc0f81daf 100644
--- a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs
+++ b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs
@@ -70,7 +70,8 @@ namespace osu.Game.Graphics.Cursor
private OsuGame? game { get; set; }
private readonly IBindable lastInputWasMouse = new BindableBool();
- private readonly IBindable isIdle = new BindableBool();
+ private readonly IBindable gameActive = new BindableBool(true);
+ private readonly IBindable gameIdle = new BindableBool();
protected override void LoadComplete()
{
@@ -81,8 +82,11 @@ namespace osu.Game.Graphics.Cursor
if (game != null)
{
- isIdle.BindTo(game.IsIdle);
- isIdle.BindValueChanged(_ => updateState());
+ gameIdle.BindTo(game.IsIdle);
+ gameIdle.BindValueChanged(_ => updateState());
+
+ gameActive.BindTo(game.IsActive);
+ gameActive.BindValueChanged(_ => updateState());
}
}
@@ -90,7 +94,7 @@ namespace osu.Game.Graphics.Cursor
private void updateState()
{
- bool combinedVisibility = State.Value == Visibility.Visible && (lastInputWasMouse.Value || !hideCursorOnNonMouseInput) && !isIdle.Value;
+ bool combinedVisibility = getCursorVisibility();
if (visible == combinedVisibility)
return;
@@ -103,6 +107,27 @@ namespace osu.Game.Graphics.Cursor
PopOut();
}
+ private bool getCursorVisibility()
+ {
+ // do not display when explicitly set to hidden state.
+ if (State.Value == Visibility.Hidden)
+ return false;
+
+ // only hide cursor when game is focused, otherwise it should always be displayed.
+ if (gameActive.Value)
+ {
+ // do not display when last input is not mouse.
+ if (hideCursorOnNonMouseInput && !lastInputWasMouse.Value)
+ return false;
+
+ // do not display when game is idle.
+ if (gameIdle.Value)
+ return false;
+ }
+
+ return true;
+ }
+
protected override void Update()
{
base.Update();
diff --git a/osu.Game/Localisation/LayoutSettingsStrings.cs b/osu.Game/Localisation/LayoutSettingsStrings.cs
index 9b8b207c47..a5172ec774 100644
--- a/osu.Game/Localisation/LayoutSettingsStrings.cs
+++ b/osu.Game/Localisation/LayoutSettingsStrings.cs
@@ -15,14 +15,14 @@ namespace osu.Game.Localisation
public static LocalisableString CheckingForFullscreenCapabilities => new TranslatableString(getKey(@"checking_for_fullscreen_capabilities"), @"Checking for fullscreen capabilities...");
///
- /// "osu! is running exclusive fullscreen, guaranteeing low latency!"
+ /// "osu! is running in exclusive fullscreen, guaranteeing low latency!"
///
- public static LocalisableString OsuIsRunningExclusiveFullscreen => new TranslatableString(getKey(@"osu_is_running_exclusive_fullscreen"), @"osu! is running exclusive fullscreen, guaranteeing low latency!");
+ public static LocalisableString OsuIsRunningExclusiveFullscreen => new TranslatableString(getKey(@"osu_is_running_exclusive_fullscreen"), @"osu! is running in exclusive fullscreen, guaranteeing low latency!");
///
- /// "Unable to run exclusive fullscreen. You'll still experience some input latency."
+ /// "Unable to run in exclusive fullscreen. You may experience some input latency."
///
- public static LocalisableString UnableToRunExclusiveFullscreen => new TranslatableString(getKey(@"unable_to_run_exclusive_fullscreen"), @"Unable to run exclusive fullscreen. You'll still experience some input latency.");
+ public static LocalisableString UnableToRunExclusiveFullscreen => new TranslatableString(getKey(@"unable_to_run_exclusive_fullscreen"), @"Unable to run in exclusive fullscreen. You may experience some input latency.");
///
/// "Using fullscreen on macOS makes interacting with the menu bar and spaces no longer work, and may lead to freezes if a system dialog is presented. Using borderless is recommended."
diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs
index 238f41e53d..717a1de6b5 100644
--- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs
+++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs
@@ -149,5 +149,8 @@ namespace osu.Game.Online.API.Requests.Responses
#endregion
public bool Equals(IBeatmapSetInfo? other) => other is APIBeatmapSet b && this.MatchesOnlineID(b);
+
+ // ReSharper disable once NonReadonlyMemberInGetHashCode
+ public override int GetHashCode() => OnlineID.GetHashCode();
}
}
diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs
index 76fcb80eb4..81db3f0d53 100644
--- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs
+++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs
@@ -191,7 +191,6 @@ namespace osu.Game.Online.Chat
{
protected override float TextSize => 15;
protected override float Spacing => 5;
- protected override float TimestampWidth => 45;
protected override float UsernameWidth => 75;
public StandAloneMessage(Message message)
diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs
index c73936da8a..c278c9cb93 100644
--- a/osu.Game/Overlays/BeatmapListingOverlay.cs
+++ b/osu.Game/Overlays/BeatmapListingOverlay.cs
@@ -180,7 +180,9 @@ namespace osu.Game.Overlays
// new results may contain beatmaps from a previous page,
// this is dodgy but matches web behaviour for now.
// see: https://github.com/ppy/osu-web/issues/9270
- newCards = newCards.Except(foundContent);
+ // todo: replace custom equality compraer with ExceptBy in net6.0
+ // newCards = newCards.ExceptBy(foundContent.Select(c => c.BeatmapSet.OnlineID), c => c.BeatmapSet.OnlineID);
+ newCards = newCards.Except(foundContent, BeatmapCardEqualityComparer.Default);
panelLoadTask = LoadComponentsAsync(newCards, loaded =>
{
@@ -394,5 +396,21 @@ namespace osu.Game.Overlays
if (shouldShowMore)
filterControl.FetchNextPage();
}
+
+ private class BeatmapCardEqualityComparer : IEqualityComparer
+ {
+ public static BeatmapCardEqualityComparer Default { get; } = new BeatmapCardEqualityComparer();
+
+ public bool Equals(BeatmapCard x, BeatmapCard y)
+ {
+ if (ReferenceEquals(x, y)) return true;
+ if (ReferenceEquals(x, null)) return false;
+ if (ReferenceEquals(y, null)) return false;
+
+ return x.BeatmapSet.Equals(y.BeatmapSet);
+ }
+
+ public int GetHashCode(BeatmapCard obj) => obj.BeatmapSet.GetHashCode();
+ }
}
}
diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs
index 4c425d3d4c..a991103fac 100644
--- a/osu.Game/Overlays/Chat/ChatLine.cs
+++ b/osu.Game/Overlays/Chat/ChatLine.cs
@@ -5,6 +5,7 @@ using System;
using System.Linq;
using System.Collections.Generic;
using osu.Framework.Allocation;
+using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -12,6 +13,7 @@ using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
+using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
@@ -48,8 +50,6 @@ namespace osu.Game.Overlays.Chat
protected virtual float Spacing => 15;
- protected virtual float TimestampWidth => 60;
-
protected virtual float UsernameWidth => 130;
private Color4 usernameColour;
@@ -62,6 +62,8 @@ namespace osu.Game.Overlays.Chat
private Container? highlight;
+ private readonly Bindable prefer24HourTime = new Bindable();
+
private bool senderHasColour => !string.IsNullOrEmpty(message.Sender.Colour);
private bool messageHasColour => Message.IsAction && senderHasColour;
@@ -80,7 +82,7 @@ namespace osu.Game.Overlays.Chat
}
[BackgroundDependencyLoader]
- private void load(OverlayColourProvider? colourProvider)
+ private void load(OverlayColourProvider? colourProvider, OsuConfigManager configManager)
{
usernameColour = senderHasColour
? Color4Extensions.FromHex(message.Sender.Colour)
@@ -93,38 +95,31 @@ namespace osu.Game.Overlays.Chat
RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) },
ColumnDimensions = new[]
{
- new Dimension(GridSizeMode.Absolute, TimestampWidth + Spacing + UsernameWidth + Spacing),
+ new Dimension(GridSizeMode.AutoSize),
+ new Dimension(GridSizeMode.Absolute, Spacing + UsernameWidth + Spacing),
new Dimension(),
},
Content = new[]
{
new Drawable[]
{
- new Container
+ timestamp = new OsuSpriteText
{
- RelativeSizeAxes = Axes.X,
+ Shadow = false,
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ Font = OsuFont.GetFont(size: TextSize * 0.75f, weight: FontWeight.SemiBold, fixedWidth: true),
+ Colour = colourProvider?.Background1 ?? Colour4.White,
+ AlwaysPresent = true,
+ },
+ new MessageSender(message.Sender)
+ {
+ Width = UsernameWidth,
AutoSizeAxes = Axes.Y,
- Children = new Drawable[]
- {
- timestamp = new OsuSpriteText
- {
- Shadow = false,
- Anchor = Anchor.CentreLeft,
- Origin = Anchor.CentreLeft,
- Font = OsuFont.GetFont(size: TextSize * 0.75f, weight: FontWeight.SemiBold, fixedWidth: true),
- MaxWidth = TimestampWidth,
- Colour = colourProvider?.Background1 ?? Colour4.White,
- },
- new MessageSender(message.Sender)
- {
- Width = UsernameWidth,
- AutoSizeAxes = Axes.Y,
- Origin = Anchor.TopRight,
- Anchor = Anchor.TopRight,
- Child = createUsername(),
- Margin = new MarginPadding { Horizontal = Spacing },
- },
- },
+ Origin = Anchor.TopRight,
+ Anchor = Anchor.TopRight,
+ Child = createUsername(),
+ Margin = new MarginPadding { Horizontal = Spacing },
},
ContentFlow = new LinkFlowContainer(t =>
{
@@ -139,6 +134,8 @@ namespace osu.Game.Overlays.Chat
},
}
};
+
+ configManager.BindWith(OsuSetting.Prefer24HourTime, prefer24HourTime);
}
protected override void LoadComplete()
@@ -147,6 +144,8 @@ namespace osu.Game.Overlays.Chat
updateMessageContent();
FinishTransforms(true);
+
+ prefer24HourTime.BindValueChanged(_ => updateTimestamp());
}
///
@@ -176,7 +175,7 @@ namespace osu.Game.Overlays.Chat
this.FadeTo(message is LocalEchoMessage ? 0.4f : 1.0f, 500, Easing.OutQuint);
timestamp.FadeTo(message is LocalEchoMessage ? 0 : 1, 500, Easing.OutQuint);
- timestamp.Text = $@"{message.Timestamp.LocalDateTime:HH:mm:ss}";
+ updateTimestamp();
username.Text = $@"{message.Sender.Username}";
// remove non-existent channels from the link list
@@ -186,6 +185,13 @@ namespace osu.Game.Overlays.Chat
ContentFlow.AddLinks(message.DisplayContent, message.Links);
}
+ private void updateTimestamp()
+ {
+ timestamp.Text = prefer24HourTime.Value
+ ? $@"{message.Timestamp.LocalDateTime:HH:mm:ss}"
+ : $@"{message.Timestamp.LocalDateTime:hh:mm:ss tt}";
+ }
+
private Drawable createUsername()
{
username = new OsuSpriteText
diff --git a/osu.Game/Rulesets/Edit/Checks/CheckAudioInVideo.cs b/osu.Game/Rulesets/Edit/Checks/CheckAudioInVideo.cs
index a66c00d78b..f712a7867d 100644
--- a/osu.Game/Rulesets/Edit/Checks/CheckAudioInVideo.cs
+++ b/osu.Game/Rulesets/Edit/Checks/CheckAudioInVideo.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.IO;
using osu.Game.Beatmaps;
@@ -45,7 +43,7 @@ namespace osu.Game.Rulesets.Edit.Checks
foreach (string filename in videoPaths)
{
- string storagePath = beatmapSet?.GetPathForFile(filename);
+ string? storagePath = beatmapSet?.GetPathForFile(filename);
if (storagePath == null)
{
diff --git a/osu.Game/Rulesets/Edit/Checks/CheckAudioPresence.cs b/osu.Game/Rulesets/Edit/Checks/CheckAudioPresence.cs
index fa3e114c55..e922ddf023 100644
--- a/osu.Game/Rulesets/Edit/Checks/CheckAudioPresence.cs
+++ b/osu.Game/Rulesets/Edit/Checks/CheckAudioPresence.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.Edit.Checks.Components;
@@ -12,6 +10,6 @@ namespace osu.Game.Rulesets.Edit.Checks
{
protected override CheckCategory Category => CheckCategory.Audio;
protected override string TypeOfFile => "audio";
- protected override string GetFilename(IBeatmap beatmap) => beatmap.Metadata?.AudioFile;
+ protected override string? GetFilename(IBeatmap beatmap) => beatmap.Metadata?.AudioFile;
}
}
diff --git a/osu.Game/Rulesets/Edit/Checks/CheckAudioQuality.cs b/osu.Game/Rulesets/Edit/Checks/CheckAudioQuality.cs
index 96254ba6fd..daa33fb0da 100644
--- a/osu.Game/Rulesets/Edit/Checks/CheckAudioQuality.cs
+++ b/osu.Game/Rulesets/Edit/Checks/CheckAudioQuality.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.Edit.Checks.Components;
@@ -29,7 +27,7 @@ namespace osu.Game.Rulesets.Edit.Checks
public IEnumerable Run(BeatmapVerifierContext context)
{
- string audioFile = context.Beatmap.Metadata?.AudioFile;
+ string? audioFile = context.Beatmap.Metadata?.AudioFile;
if (string.IsNullOrEmpty(audioFile))
yield break;
diff --git a/osu.Game/Rulesets/Edit/Checks/CheckBackgroundPresence.cs b/osu.Game/Rulesets/Edit/Checks/CheckBackgroundPresence.cs
index 96840fd344..4ca93a9807 100644
--- a/osu.Game/Rulesets/Edit/Checks/CheckBackgroundPresence.cs
+++ b/osu.Game/Rulesets/Edit/Checks/CheckBackgroundPresence.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.Edit.Checks.Components;
@@ -12,6 +10,6 @@ namespace osu.Game.Rulesets.Edit.Checks
{
protected override CheckCategory Category => CheckCategory.Resources;
protected override string TypeOfFile => "background";
- protected override string GetFilename(IBeatmap beatmap) => beatmap.Metadata?.BackgroundFile;
+ protected override string? GetFilename(IBeatmap beatmap) => beatmap.Metadata?.BackgroundFile;
}
}
diff --git a/osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.cs b/osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.cs
index be0c4501e7..23fa28e7bc 100644
--- a/osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.cs
+++ b/osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.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.IO;
using osu.Game.Beatmaps;
@@ -35,7 +33,7 @@ namespace osu.Game.Rulesets.Edit.Checks
public IEnumerable Run(BeatmapVerifierContext context)
{
- string backgroundFile = context.Beatmap.Metadata?.BackgroundFile;
+ string? backgroundFile = context.Beatmap.Metadata?.BackgroundFile;
if (backgroundFile == null)
yield break;
@@ -51,7 +49,7 @@ namespace osu.Game.Rulesets.Edit.Checks
else if (texture.Width < low_width || texture.Height < low_height)
yield return new IssueTemplateLowResolution(this).Create(texture.Width, texture.Height);
- string storagePath = context.Beatmap.BeatmapInfo.BeatmapSet?.GetPathForFile(backgroundFile);
+ string? storagePath = context.Beatmap.BeatmapInfo.BeatmapSet?.GetPathForFile(backgroundFile);
using (Stream stream = context.WorkingBeatmap.GetStream(storagePath))
{
diff --git a/osu.Game/Rulesets/Edit/Checks/CheckConcurrentObjects.cs b/osu.Game/Rulesets/Edit/Checks/CheckConcurrentObjects.cs
index 02579b675d..ba5fbcf58d 100644
--- a/osu.Game/Rulesets/Edit/Checks/CheckConcurrentObjects.cs
+++ b/osu.Game/Rulesets/Edit/Checks/CheckConcurrentObjects.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.Edit.Checks.Components;
using osu.Game.Rulesets.Objects;
diff --git a/osu.Game/Rulesets/Edit/Checks/CheckFewHitsounds.cs b/osu.Game/Rulesets/Edit/Checks/CheckFewHitsounds.cs
index b25abb0cfc..3358e81d5f 100644
--- a/osu.Game/Rulesets/Edit/Checks/CheckFewHitsounds.cs
+++ b/osu.Game/Rulesets/Edit/Checks/CheckFewHitsounds.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;
diff --git a/osu.Game/Rulesets/Edit/Checks/CheckFilePresence.cs b/osu.Game/Rulesets/Edit/Checks/CheckFilePresence.cs
index 67d480c28c..9a921ba808 100644
--- a/osu.Game/Rulesets/Edit/Checks/CheckFilePresence.cs
+++ b/osu.Game/Rulesets/Edit/Checks/CheckFilePresence.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.Beatmaps;
using osu.Game.Rulesets.Edit.Checks.Components;
@@ -13,7 +11,7 @@ namespace osu.Game.Rulesets.Edit.Checks
{
protected abstract CheckCategory Category { get; }
protected abstract string TypeOfFile { get; }
- protected abstract string GetFilename(IBeatmap beatmap);
+ protected abstract string? GetFilename(IBeatmap beatmap);
public CheckMetadata Metadata => new CheckMetadata(Category, $"Missing {TypeOfFile}");
@@ -25,7 +23,7 @@ namespace osu.Game.Rulesets.Edit.Checks
public IEnumerable Run(BeatmapVerifierContext context)
{
- string filename = GetFilename(context.Beatmap);
+ string? filename = GetFilename(context.Beatmap);
if (string.IsNullOrEmpty(filename))
{
@@ -35,7 +33,7 @@ namespace osu.Game.Rulesets.Edit.Checks
}
// If the file is set, also make sure it still exists.
- string storagePath = context.Beatmap.BeatmapInfo.BeatmapSet?.GetPathForFile(filename);
+ string? storagePath = context.Beatmap.BeatmapInfo.BeatmapSet?.GetPathForFile(filename);
if (storagePath != null)
yield break;
diff --git a/osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.cs b/osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.cs
index 00b1ca9dc9..5b59a81f91 100644
--- a/osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.cs
+++ b/osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.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;
@@ -59,7 +57,7 @@ namespace osu.Game.Rulesets.Edit.Checks
}
}
- private IEnumerable getVolumeIssues(HitObject hitObject, HitObject sampledHitObject = null)
+ private IEnumerable getVolumeIssues(HitObject hitObject, HitObject? sampledHitObject = null)
{
sampledHitObject ??= hitObject;
if (!sampledHitObject.Samples.Any())
@@ -74,7 +72,7 @@ namespace osu.Game.Rulesets.Edit.Checks
if (edgeType == EdgeType.None)
yield break;
- string postfix = hitObject is IHasDuration ? edgeType.ToString().ToLowerInvariant() : null;
+ string postfix = hitObject is IHasDuration ? edgeType.ToString().ToLowerInvariant() : string.Empty;
if (maxVolume <= muted_threshold)
{
diff --git a/osu.Game/Rulesets/Edit/Checks/CheckTooShortAudioFiles.cs b/osu.Game/Rulesets/Edit/Checks/CheckTooShortAudioFiles.cs
index 2a222aece0..1c2ea36948 100644
--- a/osu.Game/Rulesets/Edit/Checks/CheckTooShortAudioFiles.cs
+++ b/osu.Game/Rulesets/Edit/Checks/CheckTooShortAudioFiles.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.IO;
using System.Linq;
diff --git a/osu.Game/Rulesets/Edit/Checks/CheckUnsnappedObjects.cs b/osu.Game/Rulesets/Edit/Checks/CheckUnsnappedObjects.cs
index a3c52cf547..ded1bb54ca 100644
--- a/osu.Game/Rulesets/Edit/Checks/CheckUnsnappedObjects.cs
+++ b/osu.Game/Rulesets/Edit/Checks/CheckUnsnappedObjects.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.Edit.Checks.Components;
diff --git a/osu.Game/Rulesets/Edit/Checks/CheckZeroByteFiles.cs b/osu.Game/Rulesets/Edit/Checks/CheckZeroByteFiles.cs
index 987711188e..75cb08002f 100644
--- a/osu.Game/Rulesets/Edit/Checks/CheckZeroByteFiles.cs
+++ b/osu.Game/Rulesets/Edit/Checks/CheckZeroByteFiles.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.IO;
using osu.Game.Extensions;
diff --git a/osu.Game/Rulesets/Edit/Checks/CheckZeroLengthObjects.cs b/osu.Game/Rulesets/Edit/Checks/CheckZeroLengthObjects.cs
index 3b30fab934..b9be94736b 100644
--- a/osu.Game/Rulesets/Edit/Checks/CheckZeroLengthObjects.cs
+++ b/osu.Game/Rulesets/Edit/Checks/CheckZeroLengthObjects.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.Edit.Checks.Components;
using osu.Game.Rulesets.Objects;
diff --git a/osu.Game/Rulesets/Edit/Checks/Components/CheckCategory.cs b/osu.Game/Rulesets/Edit/Checks/Components/CheckCategory.cs
index 3e2150fe0b..ae943cfda9 100644
--- a/osu.Game/Rulesets/Edit/Checks/Components/CheckCategory.cs
+++ b/osu.Game/Rulesets/Edit/Checks/Components/CheckCategory.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.Edit.Checks.Components
{
///
diff --git a/osu.Game/Rulesets/Edit/Checks/Components/CheckMetadata.cs b/osu.Game/Rulesets/Edit/Checks/Components/CheckMetadata.cs
index 5c9021ba61..cebb2f5455 100644
--- a/osu.Game/Rulesets/Edit/Checks/Components/CheckMetadata.cs
+++ b/osu.Game/Rulesets/Edit/Checks/Components/CheckMetadata.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.Edit.Checks.Components
{
public class CheckMetadata
diff --git a/osu.Game/Rulesets/Edit/Checks/Components/ICheck.cs b/osu.Game/Rulesets/Edit/Checks/Components/ICheck.cs
index 333ec0a810..141de55f1d 100644
--- a/osu.Game/Rulesets/Edit/Checks/Components/ICheck.cs
+++ b/osu.Game/Rulesets/Edit/Checks/Components/ICheck.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;
namespace osu.Game.Rulesets.Edit.Checks.Components
diff --git a/osu.Game/Rulesets/Edit/Checks/Components/Issue.cs b/osu.Game/Rulesets/Edit/Checks/Components/Issue.cs
index b3f227f364..2bc9930e8f 100644
--- a/osu.Game/Rulesets/Edit/Checks/Components/Issue.cs
+++ b/osu.Game/Rulesets/Edit/Checks/Components/Issue.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/Edit/Checks/Components/IssueTemplate.cs b/osu.Game/Rulesets/Edit/Checks/Components/IssueTemplate.cs
index 9101d83fa7..97df79ecd8 100644
--- a/osu.Game/Rulesets/Edit/Checks/Components/IssueTemplate.cs
+++ b/osu.Game/Rulesets/Edit/Checks/Components/IssueTemplate.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 Humanizer;
using osu.Framework.Graphics;
using osuTK.Graphics;
diff --git a/osu.Game/Rulesets/Edit/Checks/Components/IssueType.cs b/osu.Game/Rulesets/Edit/Checks/Components/IssueType.cs
index a957cbc296..1f708209fe 100644
--- a/osu.Game/Rulesets/Edit/Checks/Components/IssueType.cs
+++ b/osu.Game/Rulesets/Edit/Checks/Components/IssueType.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.Edit.Checks.Components
{
///
diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs
index ca05c8af46..4d84a8194d 100644
--- a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs
+++ b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs
@@ -43,6 +43,11 @@ namespace osu.Game.Screens.Backgrounds
///
public readonly Bindable BlurAmount = new BindableFloat();
+ ///
+ /// The amount of dim to be used when is true.
+ ///
+ public readonly Bindable DimWhenUserSettingsIgnored = new Bindable();
+
internal readonly IBindable IsBreakTime = new Bindable();
private readonly DimmableBackground dimmable;
@@ -58,6 +63,7 @@ namespace osu.Game.Screens.Backgrounds
dimmable.IgnoreUserSettings.BindTo(IgnoreUserSettings);
dimmable.IsBreakTime.BindTo(IsBreakTime);
dimmable.BlurAmount.BindTo(BlurAmount);
+ dimmable.DimWhenUserSettingsIgnored.BindTo(DimWhenUserSettingsIgnored);
StoryboardReplacesBackground.BindTo(dimmable.StoryboardReplacesBackground);
}
diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs
index f8546d6ed0..44b6fcce4a 100644
--- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs
+++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs
@@ -95,14 +95,14 @@ namespace osu.Game.Screens.Backgrounds
nextTask = Scheduler.AddDelayed(() =>
{
LoadComponentAsync(nextBackground, displayNext, cancellationTokenSource.Token);
- }, 100);
+ }, 500);
return true;
}
private void displayNext(Background newBackground)
{
- background?.FadeOut(800, Easing.InOutSine);
+ background?.FadeOut(800, Easing.OutQuint);
background?.Expire();
AddInternal(background = newBackground);
diff --git a/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs b/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs
new file mode 100644
index 0000000000..b5a33f06e7
--- /dev/null
+++ b/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs
@@ -0,0 +1,45 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Collections.Generic;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics.UserInterface;
+using osu.Game.Graphics.UserInterface;
+
+namespace osu.Game.Screens.Edit
+{
+ internal class BackgroundDimMenuItem : MenuItem
+ {
+ private readonly Bindable backgroudDim;
+
+ private readonly Dictionary menuItemLookup = new Dictionary();
+
+ public BackgroundDimMenuItem(Bindable backgroudDim)
+ : base("Background dim")
+ {
+ Items = new[]
+ {
+ createMenuItem(0f),
+ createMenuItem(0.25f),
+ createMenuItem(0.5f),
+ createMenuItem(0.75f),
+ };
+
+ this.backgroudDim = backgroudDim;
+ backgroudDim.BindValueChanged(dim =>
+ {
+ foreach (var kvp in menuItemLookup)
+ kvp.Value.State.Value = kvp.Key == dim.NewValue ? TernaryState.True : TernaryState.False;
+ }, true);
+ }
+
+ private TernaryStateRadioMenuItem createMenuItem(float dim)
+ {
+ var item = new TernaryStateRadioMenuItem($"{dim * 100}%", MenuItemType.Standard, _ => updateOpacity(dim));
+ menuItemLookup[dim] = item;
+ return item;
+ }
+
+ private void updateOpacity(float dim) => backgroudDim.Value = dim;
+ }
+}
diff --git a/osu.Game/Screens/Edit/Components/Menus/DifficultyMenuItem.cs b/osu.Game/Screens/Edit/Components/Menus/DifficultyMenuItem.cs
index e14354222b..6af3ba908d 100644
--- a/osu.Game/Screens/Edit/Components/Menus/DifficultyMenuItem.cs
+++ b/osu.Game/Screens/Edit/Components/Menus/DifficultyMenuItem.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.Sprites;
using osu.Game.Beatmaps;
diff --git a/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs b/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs
index 8321fde171..20b8bba6da 100644
--- a/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs
+++ b/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.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.UserInterface;
diff --git a/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs
index 1085f2c277..0a2c073dcd 100644
--- a/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs
+++ b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.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.Graphics.UserInterface;
diff --git a/osu.Game/Screens/Edit/Components/Menus/EditorMenuItemSpacer.cs b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItemSpacer.cs
index 6af3b99017..4e75a92e19 100644
--- a/osu.Game/Screens/Edit/Components/Menus/EditorMenuItemSpacer.cs
+++ b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItemSpacer.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.Screens.Edit.Components.Menus
{
public class EditorMenuItemSpacer : EditorMenuItem
diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs
index 912681e114..df3c1f7ec4 100644
--- a/osu.Game/Screens/Edit/Editor.cs
+++ b/osu.Game/Screens/Edit/Editor.cs
@@ -51,7 +51,6 @@ using osu.Game.Screens.Edit.Timing;
using osu.Game.Screens.Edit.Verify;
using osu.Game.Screens.Play;
using osu.Game.Users;
-using osuTK.Graphics;
using osuTK.Input;
using CommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings;
@@ -176,6 +175,8 @@ namespace osu.Game.Screens.Edit
[Resolved(canBeNull: true)]
private OnScreenDisplay onScreenDisplay { get; set; }
+ private Bindable editorBackgroundDim;
+
public Editor(EditorLoader loader = null)
{
this.loader = loader;
@@ -260,6 +261,8 @@ namespace osu.Game.Screens.Edit
OsuMenuItem undoMenuItem;
OsuMenuItem redoMenuItem;
+ editorBackgroundDim = config.GetBindable(OsuSetting.EditorDim);
+
AddInternal(new OsuContextMenuContainer
{
RelativeSizeAxes = Axes.Both,
@@ -312,6 +315,7 @@ namespace osu.Game.Screens.Edit
Items = new MenuItem[]
{
new WaveformOpacityMenuItem(config.GetBindable(OsuSetting.EditorWaveformOpacity)),
+ new BackgroundDimMenuItem(editorBackgroundDim),
}
}
}
@@ -331,6 +335,8 @@ namespace osu.Game.Screens.Edit
changeHandler?.CanUndo.BindValueChanged(v => undoMenuItem.Action.Disabled = !v.NewValue, true);
changeHandler?.CanRedo.BindValueChanged(v => redoMenuItem.Action.Disabled = !v.NewValue, true);
+
+ editorBackgroundDim.BindValueChanged(_ => dimBackground());
}
[Resolved]
@@ -630,10 +636,8 @@ namespace osu.Game.Screens.Edit
{
ApplyToBackground(b =>
{
- // todo: temporary. we want to be applying dim using the UserDimContainer eventually.
- b.FadeColour(Color4.DarkGray, 500);
-
b.IgnoreUserSettings.Value = true;
+ b.DimWhenUserSettingsIgnored.Value = editorBackgroundDim.Value;
b.BlurAmount.Value = 0;
});
}
@@ -661,7 +665,11 @@ namespace osu.Game.Screens.Edit
}
}
- ApplyToBackground(b => b.FadeColour(Color4.White, 500));
+ ApplyToBackground(b =>
+ {
+ b.DimWhenUserSettingsIgnored.Value = 0;
+ });
+
resetTrack();
refetchBeatmap();
diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs
index 3b694dbf43..2f99f6acca 100644
--- a/osu.Game/Screens/Select/BeatmapCarousel.cs
+++ b/osu.Game/Screens/Select/BeatmapCarousel.cs
@@ -770,6 +770,26 @@ namespace osu.Game.Screens.Select
{
updateItem(item);
+ if (!item.Item.Filtered.Value)
+ {
+ bool isSelected = item.Item.State.Value == CarouselItemState.Selected;
+
+ // Cheap way of doing animations when entering / exiting song select.
+ const double half_time = 50;
+ const float panel_x_offset_when_inactive = 200;
+
+ if (isSelected || AllowSelection)
+ {
+ item.Alpha = (float)Interpolation.DampContinuously(item.Alpha, 1, half_time, Clock.ElapsedFrameTime);
+ item.X = (float)Interpolation.DampContinuously(item.X, 0, half_time, Clock.ElapsedFrameTime);
+ }
+ else
+ {
+ item.Alpha = (float)Interpolation.DampContinuously(item.Alpha, 0, half_time, Clock.ElapsedFrameTime);
+ item.X = (float)Interpolation.DampContinuously(item.X, panel_x_offset_when_inactive, half_time, Clock.ElapsedFrameTime);
+ }
+ }
+
if (item is DrawableCarouselBeatmapSet set)
{
foreach (var diff in set.DrawableBeatmaps)
diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs
index f5a058e945..4b2417aab4 100644
--- a/osu.Game/Screens/Select/SongSelect.cs
+++ b/osu.Game/Screens/Select/SongSelect.cs
@@ -89,6 +89,8 @@ namespace osu.Game.Screens.Select
protected BeatmapCarousel Carousel { get; private set; }
+ private ParallaxContainer wedgeBackground;
+
protected Container LeftArea { get; private set; }
private BeatmapInfoWedge beatmapInfoWedge;
@@ -165,10 +167,12 @@ namespace osu.Game.Screens.Select
{
new Drawable[]
{
- new ParallaxContainer
+ wedgeBackground = new ParallaxContainer
{
ParallaxAmount = 0.005f,
RelativeSizeAxes = Axes.Both,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
Child = new WedgeBackground
{
RelativeSizeAxes = Axes.Both,
@@ -609,9 +613,15 @@ namespace osu.Game.Screens.Select
}
}
- this.FadeIn(250);
+ LeftArea.MoveToX(0, 400, Easing.OutQuint);
+ LeftArea.FadeIn(100, Easing.OutQuint);
- this.ScaleTo(1, 250, Easing.OutSine);
+ FilterControl.MoveToY(0, 400, Easing.OutQuint);
+ FilterControl.FadeIn(100, Easing.OutQuint);
+
+ this.FadeIn(250, Easing.OutQuint);
+
+ wedgeBackground.ScaleTo(1, 500, Easing.OutQuint);
FilterControl.Activate();
}
@@ -623,17 +633,8 @@ namespace osu.Game.Screens.Select
transferRulesetValue();
ModSelect.SelectedMods.UnbindFrom(selectedMods);
- ModSelect.Hide();
- BeatmapOptions.Hide();
-
- endLooping();
-
- this.ScaleTo(1.1f, 250, Easing.InSine);
-
- this.FadeOut(250);
-
- FilterControl.Deactivate();
+ playExitingTransition();
base.OnSuspending(e);
}
@@ -642,16 +643,31 @@ namespace osu.Game.Screens.Select
if (base.OnExiting(e))
return true;
- beatmapInfoWedge.Hide();
+ playExitingTransition();
+ return false;
+ }
+
+ private void playExitingTransition()
+ {
ModSelect.Hide();
- this.FadeOut(100);
+ BeatmapOptions.Hide();
- FilterControl.Deactivate();
+ Carousel.AllowSelection = false;
endLooping();
- return false;
+ FilterControl.MoveToY(-120, 500, Easing.OutQuint);
+ FilterControl.FadeOut(200, Easing.OutQuint);
+
+ LeftArea.MoveToX(-150, 1800, Easing.OutQuint);
+ LeftArea.FadeOut(200, Easing.OutQuint);
+
+ wedgeBackground.ScaleTo(2.4f, 400, Easing.OutQuint);
+
+ this.FadeOut(400, Easing.OutQuint);
+
+ FilterControl.Deactivate();
}
private bool isHandlingLooping;
diff --git a/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs b/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs
index 3d7ebad831..7d2aa99dbe 100644
--- a/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs
+++ b/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.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.IO;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
@@ -16,7 +14,7 @@ namespace osu.Game.Tests.Beatmaps
public class TestWorkingBeatmap : WorkingBeatmap
{
private readonly IBeatmap beatmap;
- private readonly Storyboard storyboard;
+ private readonly Storyboard? storyboard;
///
/// Create an instance which provides the when requested.
@@ -24,7 +22,7 @@ namespace osu.Game.Tests.Beatmaps
/// The beatmap.
/// An optional storyboard.
/// The .
- public TestWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null, AudioManager audioManager = null)
+ public TestWorkingBeatmap(IBeatmap beatmap, Storyboard? storyboard = null, AudioManager? audioManager = null)
: base(beatmap.BeatmapInfo, audioManager)
{
this.beatmap = beatmap;
@@ -37,12 +35,12 @@ namespace osu.Game.Tests.Beatmaps
protected override Storyboard GetStoryboard() => storyboard ?? base.GetStoryboard();
- protected internal override ISkin GetSkin() => null;
+ protected internal override ISkin? GetSkin() => null;
- public override Stream GetStream(string storagePath) => null;
+ public override Stream? GetStream(string storagePath) => null;
- protected override Texture GetBackground() => null;
+ protected override Texture? GetBackground() => null;
- protected override Track GetBeatmapTrack() => null;
+ protected override Track? GetBeatmapTrack() => null;
}
}
diff --git a/osu.iOS.props b/osu.iOS.props
index b5b488d82e..b2854d7ddd 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -87,6 +87,6 @@
-
+