1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-13 13:32:54 +08:00

Merge branch 'master' into song-select-transition-improvement

This commit is contained in:
Salman Ahmed 2022-11-08 03:36:19 +03:00 committed by GitHub
commit 1465d043f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
70 changed files with 353 additions and 255 deletions

17
UseLocalFramework.ps1 Normal file
View File

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

18
UseLocalFramework.sh Executable file
View File

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

View File

@ -56,6 +56,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup Label="Transitive Dependencies"> <ItemGroup Label="Transitive Dependencies">
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. --> <!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
<PackageReference Include="Realm" Version="10.17.0" /> <PackageReference Include="Realm" Version="10.18.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
@ -18,7 +16,7 @@ namespace osu.Game.Rulesets.Catch.Tests.Editor.Checks
[TestFixture] [TestFixture]
public class TestCheckBananaShowerGap public class TestCheckBananaShowerGap
{ {
private CheckBananaShowerGap check; private CheckBananaShowerGap check = null!;
[SetUp] [SetUp]
public void Setup() public void Setup()

View File

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

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Moq; using Moq;
@ -21,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
[TestFixture] [TestFixture]
public class CheckLowDiffOverlapsTest public class CheckLowDiffOverlapsTest
{ {
private CheckLowDiffOverlaps check; private CheckLowDiffOverlaps check = null!;
[SetUp] [SetUp]
public void Setup() public void Setup()

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; 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 static readonly Vector2 playfield_centre = OsuPlayfield.BASE_SIZE * 0.5f;
private CheckOffscreenObjects check; private CheckOffscreenObjects check = null!;
[SetUp] [SetUp]
public void Setup() public void Setup()

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Moq; using Moq;
@ -21,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
[TestFixture] [TestFixture]
public class CheckTimeDistanceEqualityTest public class CheckTimeDistanceEqualityTest
{ {
private CheckTimeDistanceEquality check; private CheckTimeDistanceEquality check = null!;
[SetUp] [SetUp]
public void Setup() public void Setup()

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
@ -20,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
[TestFixture] [TestFixture]
public class CheckTooShortSlidersTest public class CheckTooShortSlidersTest
{ {
private CheckTooShortSliders check; private CheckTooShortSliders check = null!;
[SetUp] [SetUp]
public void Setup() public void Setup()

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
@ -19,8 +17,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
[TestFixture] [TestFixture]
public class CheckTooShortSpinnersTest public class CheckTooShortSpinnersTest
{ {
private CheckTooShortSpinners check; private CheckTooShortSpinners check = null!;
private IBeatmapDifficultyInfo difficulty; private IBeatmapDifficultyInfo difficulty = null!;
[SetUp] [SetUp]
public void Setup() public void Setup()

View File

@ -0,0 +1,117 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using 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<SliderBodyPiece>().Single().ScreenSpaceDrawQuad.Centre));
AddStep("right click", () => InputManager.Click(MouseButton.Right));
AddUntilStep("context menu is visible", () => contextMenuContainer.ChildrenOfType<OsuContextMenu>().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<ComposeBlueprintContainer>().First();
private ContextMenuContainer contextMenuContainer
=> Editor.ChildrenOfType<ContextMenuContainer>().First();
private void moveMouseToObject(Func<HitObject> targetFunc)
{
AddStep("move mouse to object", () =>
{
var pos = blueprintContainer.SelectionBlueprints
.First(s => s.Item == targetFunc())
.ChildrenOfType<HitCirclePiece>()
.First().ScreenSpaceDrawQuad.Centre;
InputManager.MoveMouseTo(pos);
});
}
}
}

View File

@ -105,8 +105,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
return true; return true;
} }
private bool hasSingleObjectSelected => selectedObjects.Count == 1;
protected override void Update() protected override void Update()
{ {
base.Update(); base.Update();
@ -119,10 +117,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
{ {
updateVisualDefinition(); updateVisualDefinition();
// In the case more than a single object is selected, block hover from arriving at sliders behind this one. return base.OnHover(e);
// 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;
} }
protected override void OnHoverLost(HoverLostEvent e) protected override void OnHoverLost(HoverLostEvent e)
@ -147,8 +142,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
private void updateVisualDefinition() private void updateVisualDefinition()
{ {
// To reduce overhead of drawing these blueprints, only add extra detail when hovered or when only this slider is selected. // To reduce overhead of drawing these blueprints, only add extra detail when only this slider is selected.
if (IsSelected && (hasSingleObjectSelected || IsHovered)) if (IsSelected && selectedObjects.Count < 2)
{ {
if (ControlPointVisualiser == null) if (ControlPointVisualiser == null)
{ {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,13 +16,13 @@ namespace osu.Game.Rulesets.Taiko.Tests
{ {
protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko"; protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko";
[TestCase(3.1098944660126882d, 200, "diffcalc-test")] [TestCase(3.0920212594351191d, 200, "diffcalc-test")]
[TestCase(3.1098944660126882d, 200, "diffcalc-test-strong")] [TestCase(3.0920212594351191d, 200, "diffcalc-test-strong")]
public void Test(double expectedStarRating, int expectedMaxCombo, string name) public void Test(double expectedStarRating, int expectedMaxCombo, string name)
=> base.Test(expectedStarRating, expectedMaxCombo, name); => base.Test(expectedStarRating, expectedMaxCombo, name);
[TestCase(4.0974106752474251d, 200, "diffcalc-test")] [TestCase(4.0789820318081444d, 200, "diffcalc-test")]
[TestCase(4.0974106752474251d, 200, "diffcalc-test-strong")] [TestCase(4.0789820318081444d, 200, "diffcalc-test-strong")]
public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name) public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name)
=> Test(expectedStarRating, expectedMaxCombo, name, new TaikoModDoubleTime()); => Test(expectedStarRating, expectedMaxCombo, name, new TaikoModDoubleTime());

View File

@ -54,11 +54,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
TaikoDifficultyHitObjectColour colour = ((TaikoDifficultyHitObject)hitObject).Colour; TaikoDifficultyHitObjectColour colour = ((TaikoDifficultyHitObject)hitObject).Colour;
double difficulty = 0.0d; double difficulty = 0.0d;
if (colour.MonoStreak != null) // Difficulty for MonoStreak if (colour.MonoStreak?.FirstHitObject == hitObject) // Difficulty for MonoStreak
difficulty += EvaluateDifficultyOf(colour.MonoStreak); difficulty += EvaluateDifficultyOf(colour.MonoStreak);
if (colour.AlternatingMonoPattern != null) // Difficulty for AlternatingMonoPattern if (colour.AlternatingMonoPattern?.FirstHitObject == hitObject) // Difficulty for AlternatingMonoPattern
difficulty += EvaluateDifficultyOf(colour.AlternatingMonoPattern); difficulty += EvaluateDifficultyOf(colour.AlternatingMonoPattern);
if (colour.RepeatingHitPattern != null) // Difficulty for RepeatingHitPattern if (colour.RepeatingHitPattern?.FirstHitObject == hitObject) // Difficulty for RepeatingHitPattern
difficulty += EvaluateDifficultyOf(colour.RepeatingHitPattern); difficulty += EvaluateDifficultyOf(colour.RepeatingHitPattern);
return difficulty; return difficulty;

View File

@ -11,22 +11,43 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
public class StaminaEvaluator public class StaminaEvaluator
{ {
/// <summary> /// <summary>
/// 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.
/// </summary> /// </summary>
/// <param name="interval">The interval between the current and previous note hit using the same key.</param> /// <param name="interval">The interval between the current and previous note hit using the same finger.</param>
private static double speedBonus(double interval) private static double speedBonus(double interval)
{ {
// Cap to 600bpm 1/4, 25ms note interval, 50ms key interval // Interval is capped at a very small value to prevent infinite values.
// Interval will be capped at a very small value to avoid infinite/negative speed bonuses. interval = Math.Max(interval, 1);
// TODO - This is a temporary measure as we need to implement methods of detecting playstyle-abuse of SpeedBonus.
interval = Math.Max(interval, 50);
return 30 / interval; return 30 / interval;
} }
/// <summary>
/// Determines the number of fingers available to hit the current <see cref="TaikoDifficultyHitObject"/>.
/// 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.
/// </summary>
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;
}
/// <summary> /// <summary>
/// Evaluates the minimum mechanical stamina required to play the current object. This is calculated using the /// 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.
/// </summary> /// </summary>
public static double EvaluateDifficultyOf(DifficultyHitObject current) public static double EvaluateDifficultyOf(DifficultyHitObject current)
{ {
@ -35,13 +56,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
return 0.0; 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 taikoCurrent = (TaikoDifficultyHitObject)current;
TaikoDifficultyHitObject? keyPrevious = taikoCurrent.PreviousMono(1); TaikoDifficultyHitObject? keyPrevious = taikoCurrent.PreviousMono(availableFingersFor(taikoCurrent) - 1);
if (keyPrevious == null) 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; return 0.0;
} }

View File

@ -33,6 +33,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data
/// </summary> /// </summary>
public TaikoDifficultyHitObject FirstHitObject => HitObjects[0]; public TaikoDifficultyHitObject FirstHitObject => HitObjects[0];
/// <summary>
/// The last <see cref="TaikoDifficultyHitObject"/> in this <see cref="MonoStreak"/>.
/// </summary>
public TaikoDifficultyHitObject LastHitObject => HitObjects[^1];
/// <summary> /// <summary>
/// The hit type of all objects encoded within this <see cref="MonoStreak"/> /// The hit type of all objects encoded within this <see cref="MonoStreak"/>
/// </summary> /// </summary>

View File

@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data
public readonly List<AlternatingMonoPattern> AlternatingMonoPatterns = new List<AlternatingMonoPattern>(); public readonly List<AlternatingMonoPattern> AlternatingMonoPatterns = new List<AlternatingMonoPattern>();
/// <summary> /// <summary>
/// The parent <see cref="TaikoDifficultyHitObject"/> in this <see cref="RepeatingHitPatterns"/> /// The first <see cref="TaikoDifficultyHitObject"/> in this <see cref="RepeatingHitPatterns"/>
/// </summary> /// </summary>
public TaikoDifficultyHitObject FirstHitObject => AlternatingMonoPatterns[0].FirstHitObject; public TaikoDifficultyHitObject FirstHitObject => AlternatingMonoPatterns[0].FirstHitObject;

View File

@ -15,19 +15,15 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour
{ {
/// <summary> /// <summary>
/// Processes and encodes a list of <see cref="TaikoDifficultyHitObject"/>s into a list of <see cref="TaikoDifficultyHitObjectColour"/>s, /// Processes and encodes a list of <see cref="TaikoDifficultyHitObject"/>s into a list of <see cref="TaikoDifficultyHitObjectColour"/>s,
/// assigning the appropriate <see cref="TaikoDifficultyHitObjectColour"/>s to each <see cref="TaikoDifficultyHitObject"/>, /// assigning the appropriate <see cref="TaikoDifficultyHitObjectColour"/>s to each <see cref="TaikoDifficultyHitObject"/>.
/// and pre-evaluating colour difficulty of each <see cref="TaikoDifficultyHitObject"/>.
/// </summary> /// </summary>
public static void ProcessAndAssign(List<DifficultyHitObject> hitObjects) public static void ProcessAndAssign(List<DifficultyHitObject> hitObjects)
{ {
List<RepeatingHitPatterns> hitPatterns = encode(hitObjects); List<RepeatingHitPatterns> hitPatterns = encode(hitObjects);
// Assign indexing and encoding data to all relevant objects. Only the first note of each encoding type is // Assign indexing and encoding data to all relevant objects.
// assigned with the relevant encodings.
foreach (var repeatingHitPattern in hitPatterns) 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 // 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 // keep i and j for AlternatingMonoPattern's and MonoStreak's index respectively, to keep it in line with
// documentation. // documentation.
@ -36,14 +32,19 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour
AlternatingMonoPattern monoPattern = repeatingHitPattern.AlternatingMonoPatterns[i]; AlternatingMonoPattern monoPattern = repeatingHitPattern.AlternatingMonoPatterns[i];
monoPattern.Parent = repeatingHitPattern; monoPattern.Parent = repeatingHitPattern;
monoPattern.Index = i; monoPattern.Index = i;
monoPattern.FirstHitObject.Colour.AlternatingMonoPattern = monoPattern;
for (int j = 0; j < monoPattern.MonoStreaks.Count; ++j) for (int j = 0; j < monoPattern.MonoStreaks.Count; ++j)
{ {
MonoStreak monoStreak = monoPattern.MonoStreaks[j]; MonoStreak monoStreak = monoPattern.MonoStreaks[j];
monoStreak.Parent = monoPattern; monoStreak.Parent = monoPattern;
monoStreak.Index = j; 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;
}
} }
} }
} }

View File

@ -11,18 +11,28 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour
public class TaikoDifficultyHitObjectColour public class TaikoDifficultyHitObjectColour
{ {
/// <summary> /// <summary>
/// The <see cref="MonoStreak"/> that encodes this note, only present if this is the first note within a <see cref="MonoStreak"/> /// The <see cref="MonoStreak"/> that encodes this note.
/// </summary> /// </summary>
public MonoStreak? MonoStreak; public MonoStreak? MonoStreak;
/// <summary> /// <summary>
/// The <see cref="AlternatingMonoPattern"/> that encodes this note, only present if this is the first note within a <see cref="AlternatingMonoPattern"/> /// The <see cref="AlternatingMonoPattern"/> that encodes this note.
/// </summary> /// </summary>
public AlternatingMonoPattern? AlternatingMonoPattern; public AlternatingMonoPattern? AlternatingMonoPattern;
/// <summary> /// <summary>
/// The <see cref="RepeatingHitPattern"/> that encodes this note, only present if this is the first note within a <see cref="RepeatingHitPattern"/> /// The <see cref="RepeatingHitPattern"/> that encodes this note.
/// </summary> /// </summary>
public RepeatingHitPatterns? RepeatingHitPattern; public RepeatingHitPatterns? RepeatingHitPattern;
/// <summary>
/// The closest past <see cref="TaikoDifficultyHitObject"/> that's not the same colour.
/// </summary>
public TaikoDifficultyHitObject? PreviousColourChange => MonoStreak?.FirstHitObject.PreviousNote(0);
/// <summary>
/// The closest future <see cref="TaikoDifficultyHitObject"/> that's not the same colour.
/// </summary>
public TaikoDifficultyHitObject? NextColourChange => MonoStreak?.LastHitObject.NextNote(0);
} }
} }

View File

@ -13,9 +13,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
/// <summary> /// <summary>
/// Calculates the stamina coefficient of taiko difficulty. /// Calculates the stamina coefficient of taiko difficulty.
/// </summary> /// </summary>
/// <remarks>
/// The reference play style chosen uses two hands, with full alternating (the hand changes after every hit).
/// </remarks>
public class Stamina : StrainDecaySkill public class Stamina : StrainDecaySkill
{ {
protected override double SkillMultiplier => 1.1; protected override double SkillMultiplier => 1.1;

View File

@ -83,15 +83,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
double combinedRating = combined.DifficultyValue() * difficulty_multiplier; double combinedRating = combined.DifficultyValue() * difficulty_multiplier;
double starRating = rescale(combinedRating * 1.4); 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 hitWindows = new TaikoHitWindows();
hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty); hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty);

View File

@ -43,6 +43,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
if (totalSuccessfulHits > 0) if (totalSuccessfulHits > 0)
effectiveMissCount = Math.Max(1.0, 1000.0 / totalSuccessfulHits) * countMiss; 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; double multiplier = 1.13;
if (score.Mods.Any(m => m is ModHidden)) 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)) if (score.Mods.Any(m => m is ModEasy))
multiplier *= 0.975; multiplier *= 0.975;
double difficultyValue = computeDifficultyValue(score, taikoAttributes); double difficultyValue = computeDifficultyValue(score, taikoAttributes, isConvert);
double accuracyValue = computeAccuracyValue(score, taikoAttributes); double accuracyValue = computeAccuracyValue(score, taikoAttributes, isConvert);
double totalValue = double totalValue =
Math.Pow( Math.Pow(
Math.Pow(difficultyValue, 1.1) + 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; 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)) if (score.Mods.Any(m => m is ModEasy))
difficultyValue *= 0.985; difficultyValue *= 0.985;
if (score.Mods.Any(m => m is ModHidden)) if (score.Mods.Any(m => m is ModHidden) && !isConvert)
difficultyValue *= 1.025; difficultyValue *= 1.025;
if (score.Mods.Any(m => m is ModHardRock)) 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); 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) if (attributes.GreatHitWindow <= 0)
return 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)); double lengthBonus = Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3));
accuracyValue *= lengthBonus; accuracyValue *= lengthBonus;
// Slight HDFL Bonus for accuracy. A clamp is used to prevent against negative values // Slight HDFL Bonus for accuracy. A clamp is used to prevent against negative values.
if (score.Mods.Any(m => m is ModFlashlight<TaikoHitObject>) && score.Mods.Any(m => m is ModHidden)) if (score.Mods.Any(m => m is ModFlashlight<TaikoHitObject>) && score.Mods.Any(m => m is ModHidden) && !isConvert)
accuracyValue *= Math.Max(1.050, 1.075 * lengthBonus); accuracyValue *= Math.Max(1.0, 1.1 * lengthBonus);
return accuracyValue; return accuracyValue;
} }

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Moq; using Moq;
@ -20,8 +18,8 @@ namespace osu.Game.Tests.Editing.Checks
[TestFixture] [TestFixture]
public class CheckAudioInVideoTest public class CheckAudioInVideoTest
{ {
private CheckAudioInVideo check; private CheckAudioInVideo check = null!;
private IBeatmap beatmap; private IBeatmap beatmap = null!;
[SetUp] [SetUp]
public void Setup() public void Setup()
@ -84,7 +82,7 @@ namespace osu.Game.Tests.Editing.Checks
Assert.That(issues.Single().Template is CheckAudioInVideo.IssueTemplateMissingFile); Assert.That(issues.Single().Template is CheckAudioInVideo.IssueTemplateMissingFile);
} }
private BeatmapVerifierContext getContext(Stream resourceStream) private BeatmapVerifierContext getContext(Stream? resourceStream)
{ {
var storyboard = new Storyboard(); var storyboard = new Storyboard();
var layer = storyboard.GetLayer("Video"); var layer = storyboard.GetLayer("Video");

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Linq; using System.Linq;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
@ -19,8 +17,8 @@ namespace osu.Game.Tests.Editing.Checks
[TestFixture] [TestFixture]
public class CheckAudioQualityTest public class CheckAudioQualityTest
{ {
private CheckAudioQuality check; private CheckAudioQuality check = null!;
private IBeatmap beatmap; private IBeatmap beatmap = null!;
[SetUp] [SetUp]
public void Setup() public void Setup()
@ -43,7 +41,7 @@ namespace osu.Game.Tests.Editing.Checks
var mock = new Mock<IWorkingBeatmap>(); var mock = new Mock<IWorkingBeatmap>();
mock.SetupGet(w => w.Beatmap).Returns(beatmap); 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); Assert.That(check.Run(new BeatmapVerifierContext(beatmap, mock.Object)), Is.Empty);
} }

View File

@ -1,12 +1,9 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using JetBrains.Annotations;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Graphics.Rendering.Dummy; using osu.Framework.Graphics.Rendering.Dummy;
@ -21,8 +18,8 @@ namespace osu.Game.Tests.Editing.Checks
[TestFixture] [TestFixture]
public class CheckBackgroundQualityTest public class CheckBackgroundQualityTest
{ {
private CheckBackgroundQuality check; private CheckBackgroundQuality check = null!;
private IBeatmap beatmap; private IBeatmap beatmap = null!;
[SetUp] [SetUp]
public void 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. // 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; beatmap.Metadata.BackgroundFile = string.Empty;
var context = getContext(null, new MemoryStream(Array.Empty<byte>())); var context = getContext(null!, new MemoryStream(Array.Empty<byte>()));
Assert.That(check.Run(context), Is.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()); 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); return new BeatmapVerifierContext(beatmap, getMockWorkingBeatmap(background, stream).Object);
} }
@ -128,7 +125,7 @@ namespace osu.Game.Tests.Editing.Checks
/// </summary> /// </summary>
/// <param name="background">The texture of the background.</param> /// <param name="background">The texture of the background.</param>
/// <param name="stream">The stream representing the background file.</param> /// <param name="stream">The stream representing the background file.</param>
private Mock<IWorkingBeatmap> getMockWorkingBeatmap(Texture background, [CanBeNull] Stream stream = null) private Mock<IWorkingBeatmap> getMockWorkingBeatmap(Texture background, Stream? stream = null)
{ {
stream ??= new MemoryStream(new byte[1024 * 1024]); stream ??= new MemoryStream(new byte[1024 * 1024]);

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Moq; using Moq;
@ -21,7 +19,7 @@ namespace osu.Game.Tests.Editing.Checks
[TestFixture] [TestFixture]
public class CheckConcurrentObjectsTest public class CheckConcurrentObjectsTest
{ {
private CheckConcurrentObjects check; private CheckConcurrentObjects check = null!;
[SetUp] [SetUp]
public void Setup() public void Setup()

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
@ -20,10 +18,10 @@ namespace osu.Game.Tests.Editing.Checks
[TestFixture] [TestFixture]
public class CheckFewHitsoundsTest public class CheckFewHitsoundsTest
{ {
private CheckFewHitsounds check; private CheckFewHitsounds check = null!;
private List<HitSampleInfo> notHitsounded; private List<HitSampleInfo> notHitsounded = null!;
private List<HitSampleInfo> hitsounded; private List<HitSampleInfo> hitsounded = null!;
[SetUp] [SetUp]
public void Setup() public void Setup()

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
@ -16,8 +14,8 @@ namespace osu.Game.Tests.Editing.Checks
[TestFixture] [TestFixture]
public class CheckFilePresenceTest public class CheckFilePresenceTest
{ {
private CheckBackgroundPresence check; private CheckBackgroundPresence check = null!;
private IBeatmap beatmap; private IBeatmap beatmap = null!;
[SetUp] [SetUp]
public void Setup() public void Setup()

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
@ -21,8 +19,8 @@ namespace osu.Game.Tests.Editing.Checks
[TestFixture] [TestFixture]
public class CheckMutedObjectsTest public class CheckMutedObjectsTest
{ {
private CheckMutedObjects check; private CheckMutedObjects check = null!;
private ControlPointInfo cpi; private ControlPointInfo cpi = null!;
private const int volume_regular = 50; private const int volume_regular = 50;
private const int volume_low = 15; private const int volume_low = 15;

View File

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

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -22,8 +20,8 @@ namespace osu.Game.Tests.Editing.Checks
[TestFixture] [TestFixture]
public class CheckTooShortAudioFilesTest public class CheckTooShortAudioFilesTest
{ {
private CheckTooShortAudioFiles check; private CheckTooShortAudioFiles check = null!;
private IBeatmap beatmap; private IBeatmap beatmap = null!;
[SetUp] [SetUp]
public void 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<TestWorkingBeatmap>(beatmap, null, null); var mockWorkingBeatmap = new Mock<TestWorkingBeatmap>(beatmap, null, null);
mockWorkingBeatmap.Setup(w => w.GetStream(It.IsAny<string>())).Returns(resourceStream); mockWorkingBeatmap.Setup(w => w.GetStream(It.IsAny<string>())).Returns(resourceStream);

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Moq; using Moq;
@ -21,8 +19,8 @@ namespace osu.Game.Tests.Editing.Checks
[TestFixture] [TestFixture]
public class CheckUnsnappedObjectsTest public class CheckUnsnappedObjectsTest
{ {
private CheckUnsnappedObjects check; private CheckUnsnappedObjects check = null!;
private ControlPointInfo cpi; private ControlPointInfo cpi = null!;
[SetUp] [SetUp]
public void Setup() public void Setup()

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Moq; using Moq;
@ -17,8 +15,8 @@ namespace osu.Game.Tests.Editing.Checks
[TestFixture] [TestFixture]
public class CheckZeroByteFilesTest public class CheckZeroByteFilesTest
{ {
private CheckZeroByteFiles check; private CheckZeroByteFiles check = null!;
private IBeatmap beatmap; private IBeatmap beatmap = null!;
[SetUp] [SetUp]
public void Setup() public void Setup()
@ -74,7 +72,7 @@ namespace osu.Game.Tests.Editing.Checks
private BeatmapVerifierContext getContextMissing() private BeatmapVerifierContext getContextMissing()
{ {
var mockWorkingBeatmap = new Mock<IWorkingBeatmap>(); var mockWorkingBeatmap = new Mock<IWorkingBeatmap>();
mockWorkingBeatmap.Setup(w => w.GetStream(It.IsAny<string>())).Returns((Stream)null); mockWorkingBeatmap.Setup(w => w.GetStream(It.IsAny<string>())).Returns((Stream)null!);
return new BeatmapVerifierContext(beatmap, mockWorkingBeatmap.Object); return new BeatmapVerifierContext(beatmap, mockWorkingBeatmap.Object);
} }

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Moq; using Moq;
@ -21,7 +19,7 @@ namespace osu.Game.Tests.Editing.Checks
[TestFixture] [TestFixture]
public class CheckZeroLengthObjectsTest public class CheckZeroLengthObjectsTest
{ {
private CheckZeroLengthObjects check; private CheckZeroLengthObjects check = null!;
[SetUp] [SetUp]
public void Setup() public void Setup()

View File

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

View File

@ -198,13 +198,13 @@ namespace osu.Game.Tests.Visual.Online
beatmapSet = CreateAPIBeatmapSet(Ruleset.Value); beatmapSet = CreateAPIBeatmapSet(Ruleset.Value);
beatmapSet.Title = "last beatmap of first page"; 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<BeatmapCard>().Count() == 50); AddUntilStep("wait for loaded", () => this.ChildrenOfType<BeatmapCard>().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<OverlayScrollContainer>().Single().ScrollToEnd()); AddStep("scroll to end", () => overlay.ChildrenOfType<OverlayScrollContainer>().Single().ScrollToEnd());
AddUntilStep("wait for loaded", () => this.ChildrenOfType<BeatmapCard>().Count() == 99); AddUntilStep("wait for loaded", () => this.ChildrenOfType<BeatmapCard>().Count() >= 99);
AddAssert("beatmap not duplicated", () => overlay.ChildrenOfType<BeatmapCard>().Count(c => c.BeatmapSet.Equals(beatmapSet)) == 1); AddAssert("beatmap not duplicated", () => overlay.ChildrenOfType<BeatmapCard>().Count(c => c.BeatmapSet.Equals(beatmapSet)) == 1);
} }

View File

@ -14,7 +14,7 @@ using osu.Game.Overlays;
namespace osu.Game.Beatmaps.Drawables.Cards namespace osu.Game.Beatmaps.Drawables.Cards
{ {
public abstract class BeatmapCard : OsuClickableContainer, IEquatable<BeatmapCard> public abstract class BeatmapCard : OsuClickableContainer
{ {
public const float TRANSITION_DURATION = 400; public const float TRANSITION_DURATION = 400;
public const float CORNER_RADIUS = 10; 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"); 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();
} }
} }

View File

@ -111,8 +111,6 @@ namespace osu.Game.Graphics.Backgrounds
private void load(LargeTextureStore textures) private void load(LargeTextureStore textures)
{ {
Sprite.Texture = textures.Get(url) ?? textures.Get(fallback_texture_name); 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) public override bool Equals(Background other)

View File

@ -15,14 +15,14 @@ namespace osu.Game.Localisation
public static LocalisableString CheckingForFullscreenCapabilities => new TranslatableString(getKey(@"checking_for_fullscreen_capabilities"), @"Checking for fullscreen capabilities..."); public static LocalisableString CheckingForFullscreenCapabilities => new TranslatableString(getKey(@"checking_for_fullscreen_capabilities"), @"Checking for fullscreen capabilities...");
/// <summary> /// <summary>
/// "osu! is running exclusive fullscreen, guaranteeing low latency!" /// "osu! is running in exclusive fullscreen, guaranteeing low latency!"
/// </summary> /// </summary>
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!");
/// <summary> /// <summary>
/// "Unable to run exclusive fullscreen. You&#39;ll still experience some input latency." /// "Unable to run in exclusive fullscreen. You may experience some input latency."
/// </summary> /// </summary>
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.");
/// <summary> /// <summary>
/// "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." /// "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."

View File

@ -149,5 +149,8 @@ namespace osu.Game.Online.API.Requests.Responses
#endregion #endregion
public bool Equals(IBeatmapSetInfo? other) => other is APIBeatmapSet b && this.MatchesOnlineID(b); public bool Equals(IBeatmapSetInfo? other) => other is APIBeatmapSet b && this.MatchesOnlineID(b);
// ReSharper disable once NonReadonlyMemberInGetHashCode
public override int GetHashCode() => OnlineID.GetHashCode();
} }
} }

View File

@ -191,7 +191,6 @@ namespace osu.Game.Online.Chat
{ {
protected override float TextSize => 15; protected override float TextSize => 15;
protected override float Spacing => 5; protected override float Spacing => 5;
protected override float TimestampWidth => 45;
protected override float UsernameWidth => 75; protected override float UsernameWidth => 75;
public StandAloneMessage(Message message) public StandAloneMessage(Message message)

View File

@ -180,7 +180,9 @@ namespace osu.Game.Overlays
// new results may contain beatmaps from a previous page, // new results may contain beatmaps from a previous page,
// this is dodgy but matches web behaviour for now. // this is dodgy but matches web behaviour for now.
// see: https://github.com/ppy/osu-web/issues/9270 // 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 => panelLoadTask = LoadComponentsAsync(newCards, loaded =>
{ {
@ -394,5 +396,21 @@ namespace osu.Game.Overlays
if (shouldShowMore) if (shouldShowMore)
filterControl.FetchNextPage(); filterControl.FetchNextPage();
} }
private class BeatmapCardEqualityComparer : IEqualityComparer<BeatmapCard>
{
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();
}
} }
} }

View File

@ -5,6 +5,7 @@ using System;
using System.Linq; using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -12,6 +13,7 @@ using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
using osu.Game.Configuration;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
@ -48,8 +50,6 @@ namespace osu.Game.Overlays.Chat
protected virtual float Spacing => 15; protected virtual float Spacing => 15;
protected virtual float TimestampWidth => 60;
protected virtual float UsernameWidth => 130; protected virtual float UsernameWidth => 130;
private Color4 usernameColour; private Color4 usernameColour;
@ -62,6 +62,8 @@ namespace osu.Game.Overlays.Chat
private Container? highlight; private Container? highlight;
private readonly Bindable<bool> prefer24HourTime = new Bindable<bool>();
private bool senderHasColour => !string.IsNullOrEmpty(message.Sender.Colour); private bool senderHasColour => !string.IsNullOrEmpty(message.Sender.Colour);
private bool messageHasColour => Message.IsAction && senderHasColour; private bool messageHasColour => Message.IsAction && senderHasColour;
@ -80,7 +82,7 @@ namespace osu.Game.Overlays.Chat
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OverlayColourProvider? colourProvider) private void load(OverlayColourProvider? colourProvider, OsuConfigManager configManager)
{ {
usernameColour = senderHasColour usernameColour = senderHasColour
? Color4Extensions.FromHex(message.Sender.Colour) ? Color4Extensions.FromHex(message.Sender.Colour)
@ -93,38 +95,31 @@ namespace osu.Game.Overlays.Chat
RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) },
ColumnDimensions = new[] ColumnDimensions = new[]
{ {
new Dimension(GridSizeMode.Absolute, TimestampWidth + Spacing + UsernameWidth + Spacing), new Dimension(GridSizeMode.AutoSize),
new Dimension(GridSizeMode.Absolute, Spacing + UsernameWidth + Spacing),
new Dimension(), new Dimension(),
}, },
Content = new[] Content = new[]
{ {
new Drawable[] 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, AutoSizeAxes = Axes.Y,
Children = new Drawable[] Origin = Anchor.TopRight,
{ Anchor = Anchor.TopRight,
timestamp = new OsuSpriteText Child = createUsername(),
{ Margin = new MarginPadding { Horizontal = Spacing },
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 },
},
},
}, },
ContentFlow = new LinkFlowContainer(t => ContentFlow = new LinkFlowContainer(t =>
{ {
@ -139,6 +134,8 @@ namespace osu.Game.Overlays.Chat
}, },
} }
}; };
configManager.BindWith(OsuSetting.Prefer24HourTime, prefer24HourTime);
} }
protected override void LoadComplete() protected override void LoadComplete()
@ -147,6 +144,8 @@ namespace osu.Game.Overlays.Chat
updateMessageContent(); updateMessageContent();
FinishTransforms(true); FinishTransforms(true);
prefer24HourTime.BindValueChanged(_ => updateTimestamp());
} }
/// <summary> /// <summary>
@ -176,7 +175,7 @@ namespace osu.Game.Overlays.Chat
this.FadeTo(message is LocalEchoMessage ? 0.4f : 1.0f, 500, Easing.OutQuint); this.FadeTo(message is LocalEchoMessage ? 0.4f : 1.0f, 500, Easing.OutQuint);
timestamp.FadeTo(message is LocalEchoMessage ? 0 : 1, 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}"; username.Text = $@"{message.Sender.Username}";
// remove non-existent channels from the link list // remove non-existent channels from the link list
@ -186,6 +185,13 @@ namespace osu.Game.Overlays.Chat
ContentFlow.AddLinks(message.DisplayContent, message.Links); 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() private Drawable createUsername()
{ {
username = new OsuSpriteText username = new OsuSpriteText

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
@ -45,7 +43,7 @@ namespace osu.Game.Rulesets.Edit.Checks
foreach (string filename in videoPaths) foreach (string filename in videoPaths)
{ {
string storagePath = beatmapSet?.GetPathForFile(filename); string? storagePath = beatmapSet?.GetPathForFile(filename);
if (storagePath == null) if (storagePath == null)
{ {

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Edit.Checks.Components; 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 CheckCategory Category => CheckCategory.Audio;
protected override string TypeOfFile => "audio"; protected override string TypeOfFile => "audio";
protected override string GetFilename(IBeatmap beatmap) => beatmap.Metadata?.AudioFile; protected override string? GetFilename(IBeatmap beatmap) => beatmap.Metadata?.AudioFile;
} }
} }

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic; using System.Collections.Generic;
using osu.Game.Rulesets.Edit.Checks.Components; using osu.Game.Rulesets.Edit.Checks.Components;
@ -29,7 +27,7 @@ namespace osu.Game.Rulesets.Edit.Checks
public IEnumerable<Issue> Run(BeatmapVerifierContext context) public IEnumerable<Issue> Run(BeatmapVerifierContext context)
{ {
string audioFile = context.Beatmap.Metadata?.AudioFile; string? audioFile = context.Beatmap.Metadata?.AudioFile;
if (string.IsNullOrEmpty(audioFile)) if (string.IsNullOrEmpty(audioFile))
yield break; yield break;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Edit.Checks.Components; 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 CheckCategory Category => CheckCategory.Resources;
protected override string TypeOfFile => "background"; protected override string TypeOfFile => "background";
protected override string GetFilename(IBeatmap beatmap) => beatmap.Metadata?.BackgroundFile; protected override string? GetFilename(IBeatmap beatmap) => beatmap.Metadata?.BackgroundFile;
} }
} }

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
@ -35,7 +33,7 @@ namespace osu.Game.Rulesets.Edit.Checks
public IEnumerable<Issue> Run(BeatmapVerifierContext context) public IEnumerable<Issue> Run(BeatmapVerifierContext context)
{ {
string backgroundFile = context.Beatmap.Metadata?.BackgroundFile; string? backgroundFile = context.Beatmap.Metadata?.BackgroundFile;
if (backgroundFile == null) if (backgroundFile == null)
yield break; yield break;
@ -51,7 +49,7 @@ namespace osu.Game.Rulesets.Edit.Checks
else if (texture.Width < low_width || texture.Height < low_height) else if (texture.Width < low_width || texture.Height < low_height)
yield return new IssueTemplateLowResolution(this).Create(texture.Width, texture.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)) using (Stream stream = context.WorkingBeatmap.GetStream(storagePath))
{ {

View File

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

View File

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

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic; using System.Collections.Generic;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Edit.Checks.Components; using osu.Game.Rulesets.Edit.Checks.Components;
@ -13,7 +11,7 @@ namespace osu.Game.Rulesets.Edit.Checks
{ {
protected abstract CheckCategory Category { get; } protected abstract CheckCategory Category { get; }
protected abstract string TypeOfFile { 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}"); public CheckMetadata Metadata => new CheckMetadata(Category, $"Missing {TypeOfFile}");
@ -25,7 +23,7 @@ namespace osu.Game.Rulesets.Edit.Checks
public IEnumerable<Issue> Run(BeatmapVerifierContext context) public IEnumerable<Issue> Run(BeatmapVerifierContext context)
{ {
string filename = GetFilename(context.Beatmap); string? filename = GetFilename(context.Beatmap);
if (string.IsNullOrEmpty(filename)) 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. // 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) if (storagePath != null)
yield break; yield break;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -59,7 +57,7 @@ namespace osu.Game.Rulesets.Edit.Checks
} }
} }
private IEnumerable<Issue> getVolumeIssues(HitObject hitObject, HitObject sampledHitObject = null) private IEnumerable<Issue> getVolumeIssues(HitObject hitObject, HitObject? sampledHitObject = null)
{ {
sampledHitObject ??= hitObject; sampledHitObject ??= hitObject;
if (!sampledHitObject.Samples.Any()) if (!sampledHitObject.Samples.Any())
@ -74,7 +72,7 @@ namespace osu.Game.Rulesets.Edit.Checks
if (edgeType == EdgeType.None) if (edgeType == EdgeType.None)
yield break; 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) if (maxVolume <= muted_threshold)
{ {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -95,14 +95,14 @@ namespace osu.Game.Screens.Backgrounds
nextTask = Scheduler.AddDelayed(() => nextTask = Scheduler.AddDelayed(() =>
{ {
LoadComponentAsync(nextBackground, displayNext, cancellationTokenSource.Token); LoadComponentAsync(nextBackground, displayNext, cancellationTokenSource.Token);
}, 100); }, 500);
return true; return true;
} }
private void displayNext(Background newBackground) private void displayNext(Background newBackground)
{ {
background?.FadeOut(800, Easing.InOutSine); background?.FadeOut(800, Easing.OutQuint);
background?.Expire(); background?.Expire();
AddInternal(background = newBackground); AddInternal(background = newBackground);

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.IO; using System.IO;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Audio.Track; using osu.Framework.Audio.Track;
@ -16,7 +14,7 @@ namespace osu.Game.Tests.Beatmaps
public class TestWorkingBeatmap : WorkingBeatmap public class TestWorkingBeatmap : WorkingBeatmap
{ {
private readonly IBeatmap beatmap; private readonly IBeatmap beatmap;
private readonly Storyboard storyboard; private readonly Storyboard? storyboard;
/// <summary> /// <summary>
/// Create an instance which provides the <see cref="IBeatmap"/> when requested. /// Create an instance which provides the <see cref="IBeatmap"/> when requested.
@ -24,7 +22,7 @@ namespace osu.Game.Tests.Beatmaps
/// <param name="beatmap">The beatmap.</param> /// <param name="beatmap">The beatmap.</param>
/// <param name="storyboard">An optional storyboard.</param> /// <param name="storyboard">An optional storyboard.</param>
/// <param name="audioManager">The <see cref="AudioManager"/>.</param> /// <param name="audioManager">The <see cref="AudioManager"/>.</param>
public TestWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null, AudioManager audioManager = null) public TestWorkingBeatmap(IBeatmap beatmap, Storyboard? storyboard = null, AudioManager? audioManager = null)
: base(beatmap.BeatmapInfo, audioManager) : base(beatmap.BeatmapInfo, audioManager)
{ {
this.beatmap = beatmap; this.beatmap = beatmap;
@ -37,12 +35,12 @@ namespace osu.Game.Tests.Beatmaps
protected override Storyboard GetStoryboard() => storyboard ?? base.GetStoryboard(); 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;
} }
} }

View File

@ -87,6 +87,6 @@
<PackageReference Include="NUnit" Version="3.13.3" /> <PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" /> <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="ppy.osu.Framework.NativeLibs" Version="2022.429.0" ExcludeAssets="all" /> <PackageReference Include="ppy.osu.Framework.NativeLibs" Version="2022.429.0" ExcludeAssets="all" />
<PackageReference Include="Realm" Version="10.17.0" /> <PackageReference Include="Realm" Version="10.18.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>