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