diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 9e9af23b27..814fc81f51 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -5,7 +5,7 @@ updates:
schedule:
interval: monthly
time: "17:00"
- open-pull-requests-limit: 99
+ open-pull-requests-limit: 0 # disabled until https://github.com/dependabot/dependabot-core/issues/369 is resolved.
ignore:
- dependency-name: Microsoft.EntityFrameworkCore.Design
versions:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 2a3b2fd978..68f8ef51ef 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -52,22 +52,29 @@ jobs:
build-only-android:
name: Build only (Android)
- runs-on: windows-latest
+ runs-on: macos-latest
timeout-minutes: 60
steps:
- name: Checkout
uses: actions/checkout@v2
+ # Pin Xamarin.Android version to 11.2 for now to avoid build failures caused by a Xamarin-side regression.
+ # See: https://github.com/xamarin/xamarin-android/issues/6284
+ # This can be removed/reverted when the fix makes it to upstream and is deployed on github runners.
+ - name: Set default Xamarin SDK version
+ run: |
+ $VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=11.2
+
- name: Install .NET 5.0.x
uses: actions/setup-dotnet@v1
with:
dotnet-version: "5.0.x"
- - name: Setup MSBuild
- uses: microsoft/setup-msbuild@v1
-
+ # Contrary to seemingly any other msbuild, msbuild running on macOS/Mono
+ # cannot accept .sln(f) files as arguments.
+ # Build just the main game for now.
- name: Build
- run: msbuild osu.Android.slnf /restore /p:Configuration=Debug
+ run: msbuild osu.Android/osu.Android.csproj /restore /p:Configuration=Debug
build-only-ios:
# While this workflow technically *can* run, it fails as iOS builds are blocked by multiple issues.
diff --git a/osu.Android.props b/osu.Android.props
index 752eb160ed..f7b7b6fb23 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -51,7 +51,7 @@
-
+
diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/Checks/TestCheckBananaShowerGap.cs b/osu.Game.Rulesets.Catch.Tests/Editor/Checks/TestCheckBananaShowerGap.cs
new file mode 100644
index 0000000000..055c8429d7
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests/Editor/Checks/TestCheckBananaShowerGap.cs
@@ -0,0 +1,118 @@
+// 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 System.Linq;
+using NUnit.Framework;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.Edit.Checks;
+using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Edit;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Tests.Beatmaps;
+
+namespace osu.Game.Rulesets.Catch.Tests.Editor.Checks
+{
+ [TestFixture]
+ public class TestCheckBananaShowerGap
+ {
+ private CheckBananaShowerGap check;
+
+ [SetUp]
+ public void Setup()
+ {
+ check = new CheckBananaShowerGap();
+ }
+
+ [Test]
+ public void TestAllowedSpinnerGaps()
+ {
+ assertOk(mockBeatmap(250, 1000, 1250), DifficultyRating.Easy);
+ assertOk(mockBeatmap(250, 1000, 1250), DifficultyRating.Normal);
+ assertOk(mockBeatmap(125, 1000, 1250), DifficultyRating.Hard);
+ assertOk(mockBeatmap(125, 1000, 1125), DifficultyRating.Insane);
+ assertOk(mockBeatmap(62, 1000, 1125), DifficultyRating.Expert);
+ assertOk(mockBeatmap(62, 1000, 1125), DifficultyRating.ExpertPlus);
+ }
+
+ [Test]
+ public void TestDisallowedSpinnerGapStart()
+ {
+ assertTooShortSpinnerStart(mockBeatmap(249, 1000, 1250), DifficultyRating.Easy);
+ assertTooShortSpinnerStart(mockBeatmap(249, 1000, 1250), DifficultyRating.Normal);
+ assertTooShortSpinnerStart(mockBeatmap(124, 1000, 1250), DifficultyRating.Hard);
+ assertTooShortSpinnerStart(mockBeatmap(124, 1000, 1250), DifficultyRating.Insane);
+ assertTooShortSpinnerStart(mockBeatmap(61, 1000, 1250), DifficultyRating.Expert);
+ assertTooShortSpinnerStart(mockBeatmap(61, 1000, 1250), DifficultyRating.ExpertPlus);
+ }
+
+ [Test]
+ public void TestDisallowedSpinnerGapEnd()
+ {
+ assertTooShortSpinnerEnd(mockBeatmap(250, 1000, 1249), DifficultyRating.Easy);
+ assertTooShortSpinnerEnd(mockBeatmap(250, 1000, 1249), DifficultyRating.Normal);
+ assertTooShortSpinnerEnd(mockBeatmap(125, 1000, 1249), DifficultyRating.Hard);
+ assertTooShortSpinnerEnd(mockBeatmap(125, 1000, 1124), DifficultyRating.Insane);
+ assertTooShortSpinnerEnd(mockBeatmap(62, 1000, 1124), DifficultyRating.Expert);
+ assertTooShortSpinnerEnd(mockBeatmap(62, 1000, 1124), DifficultyRating.ExpertPlus);
+ }
+
+ [Test]
+ public void TestConsecutiveSpinners()
+ {
+ var spinnerConsecutiveBeatmap = new Beatmap
+ {
+ HitObjects = new List
+ {
+ new BananaShower { StartTime = 0, EndTime = 100, X = 0 },
+ new BananaShower { StartTime = 101, EndTime = 200, X = 0 },
+ new BananaShower { StartTime = 201, EndTime = 300, X = 0 }
+ }
+ };
+
+ assertOk(spinnerConsecutiveBeatmap, DifficultyRating.Easy);
+ assertOk(spinnerConsecutiveBeatmap, DifficultyRating.Normal);
+ assertOk(spinnerConsecutiveBeatmap, DifficultyRating.Hard);
+ assertOk(spinnerConsecutiveBeatmap, DifficultyRating.Insane);
+ assertOk(spinnerConsecutiveBeatmap, DifficultyRating.Expert);
+ assertOk(spinnerConsecutiveBeatmap, DifficultyRating.ExpertPlus);
+ }
+
+ private Beatmap mockBeatmap(double bananaShowerStart, double bananaShowerEnd, double nextFruitStart)
+ {
+ return new Beatmap
+ {
+ HitObjects = new List
+ {
+ new Fruit { StartTime = 0, X = 0 },
+ new BananaShower { StartTime = bananaShowerStart, EndTime = bananaShowerEnd, X = 0 },
+ new Fruit { StartTime = nextFruitStart, X = 0 }
+ }
+ };
+ }
+
+ private void assertOk(IBeatmap beatmap, DifficultyRating difficultyRating)
+ {
+ var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap), difficultyRating);
+ Assert.That(check.Run(context), Is.Empty);
+ }
+
+ private void assertTooShortSpinnerStart(IBeatmap beatmap, DifficultyRating difficultyRating)
+ {
+ var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap), difficultyRating);
+ var issues = check.Run(context).ToList();
+
+ Assert.That(issues, Has.Count.EqualTo(1));
+ Assert.That(issues.All(issue => issue.Template is CheckBananaShowerGap.IssueTemplateBananaShowerStartGap));
+ }
+
+ private void assertTooShortSpinnerEnd(IBeatmap beatmap, DifficultyRating difficultyRating)
+ {
+ var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap), difficultyRating);
+ var issues = check.Run(context).ToList();
+
+ Assert.That(issues, Has.Count.EqualTo(1));
+ Assert.That(issues.All(issue => issue.Template is CheckBananaShowerGap.IssueTemplateBananaShowerEndGap));
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModNoScope.cs b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModNoScope.cs
new file mode 100644
index 0000000000..bbe543e73e
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModNoScope.cs
@@ -0,0 +1,110 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Collections.Generic;
+using NUnit.Framework;
+using osu.Framework.Utils;
+using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.Timing;
+using osu.Game.Rulesets.Catch.Mods;
+using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Tests.Visual;
+
+namespace osu.Game.Rulesets.Catch.Tests.Mods
+{
+ public class TestSceneCatchModNoScope : ModTestScene
+ {
+ protected override Ruleset CreatePlayerRuleset() => new CatchRuleset();
+
+ [Test]
+ public void TestVisibleDuringBreak()
+ {
+ CreateModTest(new ModTestData
+ {
+ Mod = new CatchModNoScope
+ {
+ HiddenComboCount = { Value = 0 },
+ },
+ Autoplay = true,
+ PassCondition = () => true,
+ Beatmap = new Beatmap
+ {
+ HitObjects = new List
+ {
+ new Fruit
+ {
+ X = CatchPlayfield.CENTER_X,
+ StartTime = 1000,
+ },
+ new Fruit
+ {
+ X = CatchPlayfield.CENTER_X,
+ StartTime = 5000,
+ }
+ },
+ Breaks = new List
+ {
+ new BreakPeriod(2000, 4000),
+ }
+ }
+ });
+
+ AddUntilStep("wait for catcher to hide", () => catcherAlphaAlmostEquals(0));
+ AddUntilStep("wait for start of break", isBreak);
+ AddUntilStep("wait for catcher to show", () => catcherAlphaAlmostEquals(1));
+ AddUntilStep("wait for end of break", () => !isBreak());
+ AddUntilStep("wait for catcher to hide", () => catcherAlphaAlmostEquals(0));
+ }
+
+ [Test]
+ public void TestVisibleAfterComboBreak()
+ {
+ CreateModTest(new ModTestData
+ {
+ Mod = new CatchModNoScope
+ {
+ HiddenComboCount = { Value = 2 },
+ },
+ Autoplay = true,
+ PassCondition = () => true,
+ Beatmap = new Beatmap
+ {
+ HitObjects = new List
+ {
+ new Fruit
+ {
+ X = 0,
+ StartTime = 1000,
+ },
+ new Fruit
+ {
+ X = CatchPlayfield.CENTER_X,
+ StartTime = 3000,
+ },
+ new Fruit
+ {
+ X = CatchPlayfield.WIDTH,
+ StartTime = 5000,
+ },
+ }
+ }
+ });
+
+ AddAssert("catcher must start visible", () => catcherAlphaAlmostEquals(1));
+ AddUntilStep("wait for combo", () => Player.ScoreProcessor.Combo.Value >= 2);
+ AddAssert("catcher must dim after combo", () => !catcherAlphaAlmostEquals(1));
+ AddStep("break combo", () => Player.ScoreProcessor.Combo.Value = 0);
+ AddUntilStep("wait for catcher to show", () => catcherAlphaAlmostEquals(1));
+ }
+
+ private bool isBreak() => Player.IsBreakTime.Value;
+
+ private bool catcherAlphaAlmostEquals(float alpha)
+ {
+ var playfield = (CatchPlayfield)Player.DrawableRuleset.Playfield;
+ return Precision.AlmostEquals(playfield.CatcherArea.Alpha, alpha);
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs
index 9fee6b2bc1..93240d312b 100644
--- a/osu.Game.Rulesets.Catch/CatchRuleset.cs
+++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs
@@ -133,6 +133,7 @@ namespace osu.Game.Rulesets.Catch
new MultiMod(new ModWindUp(), new ModWindDown()),
new CatchModFloatingFruits(),
new CatchModMuted(),
+ new CatchModNoScope(),
};
default:
@@ -188,5 +189,7 @@ namespace osu.Game.Rulesets.Catch
public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new CatchReplayFrame();
public override HitObjectComposer CreateHitObjectComposer() => new CatchHitObjectComposer(this);
+
+ public override IBeatmapVerifier CreateBeatmapVerifier() => new CatchBeatmapVerifier();
}
}
diff --git a/osu.Game.Rulesets.Catch/Edit/CatchBeatmapVerifier.cs b/osu.Game.Rulesets.Catch/Edit/CatchBeatmapVerifier.cs
new file mode 100644
index 0000000000..c7a41a4e22
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Edit/CatchBeatmapVerifier.cs
@@ -0,0 +1,24 @@
+// 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 System.Linq;
+using osu.Game.Rulesets.Catch.Edit.Checks;
+using osu.Game.Rulesets.Edit;
+using osu.Game.Rulesets.Edit.Checks.Components;
+
+namespace osu.Game.Rulesets.Catch.Edit
+{
+ public class CatchBeatmapVerifier : IBeatmapVerifier
+ {
+ private readonly List checks = new List
+ {
+ new CheckBananaShowerGap()
+ };
+
+ public IEnumerable Run(BeatmapVerifierContext context)
+ {
+ return checks.SelectMany(check => check.Run(context));
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Edit/Checks/CheckBananaShowerGap.cs b/osu.Game.Rulesets.Catch/Edit/Checks/CheckBananaShowerGap.cs
new file mode 100644
index 0000000000..4b2933c0e1
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Edit/Checks/CheckBananaShowerGap.cs
@@ -0,0 +1,102 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Edit;
+using osu.Game.Rulesets.Edit.Checks.Components;
+using osu.Game.Rulesets.Objects;
+
+namespace osu.Game.Rulesets.Catch.Edit.Checks
+{
+ ///
+ /// Check the spinner/banana shower gaps specified in the osu!catch difficulty specific ranking criteria.
+ ///
+ public class CheckBananaShowerGap : ICheck
+ {
+ private static readonly Dictionary spinner_delta_threshold = new Dictionary
+ {
+ [DifficultyRating.Easy] = (250, 250),
+ [DifficultyRating.Normal] = (250, 250),
+ [DifficultyRating.Hard] = (125, 250),
+ [DifficultyRating.Insane] = (125, 125),
+ [DifficultyRating.Expert] = (62, 125),
+ [DifficultyRating.ExpertPlus] = (62, 125)
+ };
+
+ public CheckMetadata Metadata { get; } = new CheckMetadata(CheckCategory.Compose, "Too short spinner gap");
+
+ public IEnumerable PossibleTemplates => new IssueTemplate[]
+ {
+ new IssueTemplateBananaShowerStartGap(this),
+ new IssueTemplateBananaShowerEndGap(this)
+ };
+
+ public IEnumerable Run(BeatmapVerifierContext context)
+ {
+ var hitObjects = context.Beatmap.HitObjects;
+ (int expectedStartDelta, int expectedEndDelta) = spinner_delta_threshold[context.InterpretedDifficulty];
+
+ for (int i = 0; i < hitObjects.Count - 1; ++i)
+ {
+ if (!(hitObjects[i] is BananaShower bananaShower))
+ continue;
+
+ // Skip if the previous hitobject is a banana shower, consecutive spinners are allowed
+ if (i != 0 && hitObjects[i - 1] is CatchHitObject previousHitObject && !(previousHitObject is BananaShower))
+ {
+ double spinnerStartDelta = bananaShower.StartTime - previousHitObject.GetEndTime();
+
+ if (spinnerStartDelta < expectedStartDelta)
+ {
+ yield return new IssueTemplateBananaShowerStartGap(this)
+ .Create(spinnerStartDelta, expectedStartDelta, bananaShower, previousHitObject);
+ }
+ }
+
+ // Skip if the next hitobject is a banana shower, consecutive spinners are allowed
+ if (hitObjects[i + 1] is CatchHitObject nextHitObject && !(nextHitObject is BananaShower))
+ {
+ double spinnerEndDelta = nextHitObject.StartTime - bananaShower.EndTime;
+
+ if (spinnerEndDelta < expectedEndDelta)
+ {
+ yield return new IssueTemplateBananaShowerEndGap(this)
+ .Create(spinnerEndDelta, expectedEndDelta, bananaShower, nextHitObject);
+ }
+ }
+ }
+ }
+
+ public abstract class IssueTemplateBananaShowerGap : IssueTemplate
+ {
+ protected IssueTemplateBananaShowerGap(ICheck check, IssueType issueType, string unformattedMessage)
+ : base(check, issueType, unformattedMessage)
+ {
+ }
+
+ public Issue Create(double deltaTime, int expectedDeltaTime, params HitObject[] hitObjects)
+ {
+ return new Issue(hitObjects, this, Math.Floor(deltaTime), expectedDeltaTime);
+ }
+ }
+
+ public class IssueTemplateBananaShowerStartGap : IssueTemplateBananaShowerGap
+ {
+ public IssueTemplateBananaShowerStartGap(ICheck check)
+ : base(check, IssueType.Problem, "There is only {0} ms between the start of the spinner and the last object, it should not be less than {1} ms.")
+ {
+ }
+ }
+
+ public class IssueTemplateBananaShowerEndGap : IssueTemplateBananaShowerGap
+ {
+ public IssueTemplateBananaShowerEndGap(ICheck check)
+ : base(check, IssueType.Problem, "There is only {0} ms between the end of the spinner and the next object, it should not be less than {1} ms.")
+ {
+ }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs b/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs
new file mode 100644
index 0000000000..a24a6227fe
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs
@@ -0,0 +1,40 @@
+// 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 osu.Framework.Bindables;
+using osu.Game.Rulesets.Mods;
+using osu.Framework.Utils;
+using osu.Game.Configuration;
+using osu.Game.Overlays.Settings;
+using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Rulesets.UI;
+
+namespace osu.Game.Rulesets.Catch.Mods
+{
+ public class CatchModNoScope : ModNoScope, IUpdatableByPlayfield
+ {
+ public override string Description => "Where's the catcher?";
+
+ [SettingSource(
+ "Hidden at combo",
+ "The combo count at which the catcher becomes completely hidden",
+ SettingControlType = typeof(SettingsSlider)
+ )]
+ public override BindableInt HiddenComboCount { get; } = new BindableInt
+ {
+ Default = 10,
+ Value = 10,
+ MinValue = 0,
+ MaxValue = 50,
+ };
+
+ public void Update(Playfield playfield)
+ {
+ var catchPlayfield = (CatchPlayfield)playfield;
+ bool shouldAlwaysShowCatcher = IsBreakTime.Value;
+ float targetAlpha = shouldAlwaysShowCatcher ? 1 : ComboBasedAlpha;
+ catchPlayfield.CatcherArea.Alpha = (float)Interpolation.Lerp(catchPlayfield.CatcherArea.Alpha, targetAlpha, Math.Clamp(catchPlayfield.Time.Elapsed / TRANSITION_DURATION, 0, 1));
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs
index 0f520215a1..24d2a786a0 100644
--- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs
@@ -22,6 +22,9 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
[Resolved]
private SkinManager skins { get; set; }
+ [Cached]
+ private EditorClipboard clipboard = new EditorClipboard();
+
[SetUpSteps]
public void SetUpSteps()
{
diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderStreamConversion.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderStreamConversion.cs
new file mode 100644
index 0000000000..559d612037
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderStreamConversion.cs
@@ -0,0 +1,185 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Linq;
+using NUnit.Framework;
+using osu.Framework.Utils;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Osu.Objects;
+using osu.Game.Screens.Edit;
+using osuTK;
+using osuTK.Input;
+
+namespace osu.Game.Rulesets.Osu.Tests.Editor
+{
+ public class TestSceneSliderStreamConversion : TestSceneOsuEditor
+ {
+ private BindableBeatDivisor beatDivisor => (BindableBeatDivisor)Editor.Dependencies.Get(typeof(BindableBeatDivisor));
+
+ [Test]
+ public void TestSimpleConversion()
+ {
+ Slider slider = null;
+
+ AddStep("select first slider", () =>
+ {
+ slider = (Slider)EditorBeatmap.HitObjects.First(h => h is Slider);
+ EditorClock.Seek(slider.StartTime);
+ EditorBeatmap.SelectedHitObjects.Add(slider);
+ });
+
+ convertToStream();
+
+ AddAssert("stream created", () => streamCreatedFor(slider,
+ (time: 0, pathPosition: 0),
+ (time: 0.25, pathPosition: 0.25),
+ (time: 0.5, pathPosition: 0.5),
+ (time: 0.75, pathPosition: 0.75),
+ (time: 1, pathPosition: 1)));
+
+ AddStep("undo", () => Editor.Undo());
+ AddAssert("slider restored", () => sliderRestored(slider));
+
+ AddStep("select first slider", () =>
+ {
+ slider = (Slider)EditorBeatmap.HitObjects.First(h => h is Slider);
+ EditorClock.Seek(slider.StartTime);
+ EditorBeatmap.SelectedHitObjects.Add(slider);
+ });
+ AddStep("change beat divisor", () => beatDivisor.Value = 8);
+
+ convertToStream();
+ AddAssert("stream created", () => streamCreatedFor(slider,
+ (time: 0, pathPosition: 0),
+ (time: 0.125, pathPosition: 0.125),
+ (time: 0.25, pathPosition: 0.25),
+ (time: 0.375, pathPosition: 0.375),
+ (time: 0.5, pathPosition: 0.5),
+ (time: 0.625, pathPosition: 0.625),
+ (time: 0.75, pathPosition: 0.75),
+ (time: 0.875, pathPosition: 0.875),
+ (time: 1, pathPosition: 1)));
+ }
+
+ [Test]
+ public void TestConversionWithNonMatchingDivisor()
+ {
+ Slider slider = null;
+
+ AddStep("select second slider", () =>
+ {
+ slider = (Slider)EditorBeatmap.HitObjects.Where(h => h is Slider).ElementAt(1);
+ EditorClock.Seek(slider.StartTime);
+ EditorBeatmap.SelectedHitObjects.Add(slider);
+ });
+ AddStep("change beat divisor", () => beatDivisor.Value = 3);
+
+ convertToStream();
+
+ AddAssert("stream created", () => streamCreatedFor(slider,
+ (time: 0, pathPosition: 0),
+ (time: 2 / 3d, pathPosition: 2 / 3d)));
+ }
+
+ [Test]
+ public void TestConversionWithRepeats()
+ {
+ Slider slider = null;
+
+ AddStep("select first slider with repeats", () =>
+ {
+ slider = (Slider)EditorBeatmap.HitObjects.First(h => h is Slider s && s.RepeatCount > 0);
+ EditorClock.Seek(slider.StartTime);
+ EditorBeatmap.SelectedHitObjects.Add(slider);
+ });
+ AddStep("change beat divisor", () => beatDivisor.Value = 2);
+
+ convertToStream();
+
+ AddAssert("stream created", () => streamCreatedFor(slider,
+ (time: 0, pathPosition: 0),
+ (time: 0.25, pathPosition: 0.5),
+ (time: 0.5, pathPosition: 1),
+ (time: 0.75, pathPosition: 0.5),
+ (time: 1, pathPosition: 0)));
+ }
+
+ [Test]
+ public void TestConversionPreservesSliderProperties()
+ {
+ Slider slider = null;
+
+ AddStep("select second new-combo-starting slider", () =>
+ {
+ slider = (Slider)EditorBeatmap.HitObjects.Where(h => h is Slider s && s.NewCombo).ElementAt(1);
+ EditorClock.Seek(slider.StartTime);
+ EditorBeatmap.SelectedHitObjects.Add(slider);
+ });
+
+ convertToStream();
+
+ AddAssert("stream created", () => streamCreatedFor(slider,
+ (time: 0, pathPosition: 0),
+ (time: 0.25, pathPosition: 0.25),
+ (time: 0.5, pathPosition: 0.5),
+ (time: 0.75, pathPosition: 0.75),
+ (time: 1, pathPosition: 1)));
+
+ AddStep("undo", () => Editor.Undo());
+ AddAssert("slider restored", () => sliderRestored(slider));
+ }
+
+ private void convertToStream()
+ {
+ AddStep("convert to stream", () =>
+ {
+ InputManager.PressKey(Key.LControl);
+ InputManager.PressKey(Key.LShift);
+ InputManager.Key(Key.F);
+ InputManager.ReleaseKey(Key.LShift);
+ InputManager.ReleaseKey(Key.LControl);
+ });
+ }
+
+ private bool streamCreatedFor(Slider slider, params (double time, double pathPosition)[] expectedCircles)
+ {
+ if (EditorBeatmap.HitObjects.Contains(slider))
+ return false;
+
+ foreach ((double expectedTime, double expectedPathPosition) in expectedCircles)
+ {
+ double time = slider.StartTime + slider.Duration * expectedTime;
+ Vector2 position = slider.Position + slider.Path.PositionAt(expectedPathPosition);
+
+ if (!EditorBeatmap.HitObjects.OfType().Any(h => matches(h, time, position, slider.NewCombo && expectedTime == 0)))
+ return false;
+ }
+
+ return true;
+
+ bool matches(HitCircle circle, double time, Vector2 position, bool startsNewCombo) =>
+ Precision.AlmostEquals(circle.StartTime, time, 1)
+ && Precision.AlmostEquals(circle.Position, position, 0.01f)
+ && circle.NewCombo == startsNewCombo
+ && circle.Samples.SequenceEqual(slider.HeadCircle.Samples)
+ && circle.SampleControlPoint.IsRedundant(slider.SampleControlPoint);
+ }
+
+ private bool sliderRestored(Slider slider)
+ {
+ var objects = EditorBeatmap.HitObjects.Where(h => h.StartTime >= slider.StartTime && h.GetEndTime() <= slider.EndTime).ToList();
+
+ if (objects.Count > 1)
+ return false;
+
+ var hitObject = objects.Single();
+ if (!(hitObject is Slider restoredSlider))
+ return false;
+
+ return Precision.AlmostEquals(slider.StartTime, restoredSlider.StartTime)
+ && Precision.AlmostEquals(slider.GetEndTime(), restoredSlider.GetEndTime())
+ && Precision.AlmostEquals(slider.Position, restoredSlider.Position, 0.01f)
+ && Precision.AlmostEquals(slider.EndPosition, restoredSlider.EndPosition, 0.01f);
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs
index 0d0fefe0ff..8e226c7ded 100644
--- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs
@@ -137,7 +137,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
AddAssert("cursor must start visible", () => cursorAlphaAlmostEquals(1));
AddUntilStep("wait for combo", () => Player.ScoreProcessor.Combo.Value >= 2);
AddAssert("cursor must dim after combo", () => !cursorAlphaAlmostEquals(1));
- AddStep("break combo", () => Player.ScoreProcessor.Combo.Set(0));
+ AddStep("break combo", () => Player.ScoreProcessor.Combo.Value = 0);
AddUntilStep("wait for cursor to show", () => cursorAlphaAlmostEquals(1));
}
diff --git a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs
index b0e173e752..9148f0715c 100644
--- a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs
+++ b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs
@@ -15,13 +15,13 @@ namespace osu.Game.Rulesets.Osu.Tests
{
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
- [TestCase(6.6975550434910005d, "diffcalc-test")]
- [TestCase(1.4670676815251105d, "zero-length-sliders")]
+ [TestCase(6.6972307565739273d, "diffcalc-test")]
+ [TestCase(1.4484754139145539d, "zero-length-sliders")]
public void Test(double expected, string name)
=> base.Test(expected, name);
- [TestCase(8.9389769779826267d, "diffcalc-test")]
- [TestCase(1.7786917985891204d, "zero-length-sliders")]
+ [TestCase(8.9382559208689809d, "diffcalc-test")]
+ [TestCase(1.7548875851757628d, "zero-length-sliders")]
public void TestClockRateAdjusted(double expected, string name)
=> Test(expected, name, new OsuModDoubleTime());
diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs
index a08fe3b7c5..e0a216c8e0 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs
@@ -10,6 +10,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
public double AimStrain { get; set; }
public double SpeedStrain { get; set; }
public double FlashlightRating { get; set; }
+ public double SliderFactor { get; set; }
public double ApproachRate { get; set; }
public double OverallDifficulty { get; set; }
public double DrainRate { get; set; }
diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
index b0a764dc4d..558ddc16ef 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
@@ -34,8 +34,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty
return new OsuDifficultyAttributes { Mods = mods, Skills = skills };
double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier;
- double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
- double flashlightRating = Math.Sqrt(skills[2].DifficultyValue()) * difficulty_multiplier;
+ double aimRatingNoSliders = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
+ double speedRating = Math.Sqrt(skills[2].DifficultyValue()) * difficulty_multiplier;
+ double flashlightRating = Math.Sqrt(skills[3].DifficultyValue()) * difficulty_multiplier;
+
+ double sliderFactor = aimRating > 0 ? aimRatingNoSliders / aimRating : 1;
if (mods.Any(h => h is OsuModRelax))
speedRating = 0.0;
@@ -74,6 +77,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
AimStrain = aimRating,
SpeedStrain = speedRating,
FlashlightRating = flashlightRating,
+ SliderFactor = sliderFactor,
ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
OverallDifficulty = (80 - hitWindowGreat) / 6,
DrainRate = drainRate,
@@ -108,7 +112,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty
return new Skill[]
{
- new Aim(mods),
+ new Aim(mods, true),
+ new Aim(mods, false),
new Speed(mods, hitWindowGreat),
new Flashlight(mods)
};
diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
index a9d9ff6985..8d45c7a8cc 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
@@ -125,6 +125,16 @@ namespace osu.Game.Rulesets.Osu.Difficulty
aimValue *= 1.0 + 0.04 * (12.0 - Attributes.ApproachRate);
}
+ // We assume 15% of sliders in a map are difficult since there's no way to tell from the performance calculator.
+ double estimateDifficultSliders = Attributes.SliderCount * 0.15;
+
+ if (Attributes.SliderCount > 0)
+ {
+ double estimateSliderEndsDropped = Math.Clamp(Math.Min(countOk + countMeh + countMiss, Attributes.MaxCombo - scoreMaxCombo), 0, estimateDifficultSliders);
+ double sliderNerfFactor = (1 - Attributes.SliderFactor) * Math.Pow(1 - estimateSliderEndsDropped / estimateDifficultSliders, 3) + Attributes.SliderFactor;
+ aimValue *= sliderNerfFactor;
+ }
+
aimValue *= accuracy;
// It is important to also consider accuracy difficulty when doing that.
aimValue *= 0.98 + Math.Pow(Attributes.OverallDifficulty, 2) / 2500;
diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs
index cbaad93bed..d073d751d0 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs
@@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
private const int normalized_radius = 50; // Change radius to 50 to make 100 the diameter. Easier for mental maths.
private const int min_delta_time = 25;
private const float maximum_slider_radius = normalized_radius * 2.4f;
- private const float assumed_slider_radius = normalized_radius * 1.65f;
+ private const float assumed_slider_radius = normalized_radius * 1.8f;
protected new OsuHitObject BaseObject => (OsuHitObject)base.BaseObject;
diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs
index 4c40a49396..2a8d2ce759 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs
@@ -14,11 +14,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
///
public class Aim : OsuStrainSkill
{
- public Aim(Mod[] mods)
+ public Aim(Mod[] mods, bool withSliders)
: base(mods)
{
+ this.withSliders = withSliders;
}
+ private readonly bool withSliders;
+
protected override int HistoryLength => 2;
private const double wide_angle_multiplier = 1.5;
@@ -44,7 +47,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
double currVelocity = osuCurrObj.JumpDistance / osuCurrObj.StrainTime;
// But if the last object is a slider, then we extend the travel velocity through the slider into the current object.
- if (osuLastObj.BaseObject is Slider)
+ if (osuLastObj.BaseObject is Slider && withSliders)
{
double movementVelocity = osuCurrObj.MovementDistance / osuCurrObj.MovementTime; // calculate the movement velocity from slider end to current object
double travelVelocity = osuCurrObj.TravelDistance / osuCurrObj.TravelTime; // calculate the slider velocity from slider head to slider end.
@@ -55,7 +58,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
// As above, do the same for the previous hitobject.
double prevVelocity = osuLastObj.JumpDistance / osuLastObj.StrainTime;
- if (osuLastLastObj.BaseObject is Slider)
+ if (osuLastLastObj.BaseObject is Slider && withSliders)
{
double movementVelocity = osuLastObj.MovementDistance / osuLastObj.MovementTime;
double travelVelocity = osuLastObj.TravelDistance / osuLastObj.TravelTime;
@@ -135,7 +138,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier + velocityChangeBonus * velocity_change_multiplier);
// Add in additional slider velocity bonus.
- aimStrain += sliderBonus * slider_multiplier;
+ if (withSliders)
+ aimStrain += sliderBonus * slider_multiplier;
return aimStrain;
}
diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs
index a7fadfb67f..17a62fc61c 100644
--- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs
@@ -11,9 +11,12 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
+using osu.Framework.Utils;
+using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
@@ -47,6 +50,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
[Resolved(CanBeNull = true)]
private IEditorChangeHandler changeHandler { get; set; }
+ [Resolved(CanBeNull = true)]
+ private BindableBeatDivisor beatDivisor { get; set; }
+
public override Quad SelectionQuad => BodyPiece.ScreenSpaceDrawQuad;
private readonly BindableList controlPoints = new BindableList();
@@ -173,6 +179,20 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
}
}
+ protected override bool OnKeyDown(KeyDownEvent e)
+ {
+ if (!IsSelected)
+ return false;
+
+ if (e.Key == Key.F && e.ControlPressed && e.ShiftPressed)
+ {
+ convertToStream();
+ return true;
+ }
+
+ return false;
+ }
+
private int addControlPoint(Vector2 position)
{
position -= HitObject.Position;
@@ -234,9 +254,56 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
editorBeatmap?.Update(HitObject);
}
+ private void convertToStream()
+ {
+ if (editorBeatmap == null || changeHandler == null || beatDivisor == null)
+ return;
+
+ var timingPoint = editorBeatmap.ControlPointInfo.TimingPointAt(HitObject.StartTime);
+ double streamSpacing = timingPoint.BeatLength / beatDivisor.Value;
+
+ changeHandler.BeginChange();
+
+ int i = 0;
+ double time = HitObject.StartTime;
+
+ while (!Precision.DefinitelyBigger(time, HitObject.GetEndTime(), 1))
+ {
+ // positionWithRepeats is a fractional number in the range of [0, HitObject.SpanCount()]
+ // and indicates how many fractional spans of a slider have passed up to time.
+ double positionWithRepeats = (time - HitObject.StartTime) / HitObject.Duration * HitObject.SpanCount();
+ double pathPosition = positionWithRepeats - (int)positionWithRepeats;
+ // every second span is in the reverse direction - need to reverse the path position.
+ if (Precision.AlmostBigger(positionWithRepeats % 2, 1))
+ pathPosition = 1 - pathPosition;
+
+ Vector2 position = HitObject.Position + HitObject.Path.PositionAt(pathPosition);
+
+ var samplePoint = (SampleControlPoint)HitObject.SampleControlPoint.DeepClone();
+ samplePoint.Time = time;
+
+ editorBeatmap.Add(new HitCircle
+ {
+ StartTime = time,
+ Position = position,
+ NewCombo = i == 0 && HitObject.NewCombo,
+ SampleControlPoint = samplePoint,
+ Samples = HitObject.HeadCircle.Samples.Select(s => s.With()).ToList()
+ });
+
+ i += 1;
+ time = HitObject.StartTime + i * streamSpacing;
+ }
+
+ editorBeatmap.Remove(HitObject);
+
+ changeHandler.EndChange();
+ }
+
public override MenuItem[] ContextMenuItems => new MenuItem[]
{
new OsuMenuItem("Add control point", MenuItemType.Standard, () => addControlPoint(rightClickPosition)),
+ new OsuMenuItem("Convert to stream", MenuItemType.Destructive, convertToStream),
};
// Always refer to the drawable object's slider body so subsequent movement deltas are calculated with updated positions.
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs b/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs
index 501c0a55bd..8e377ea632 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs
@@ -4,52 +4,29 @@
using System;
using System.Linq;
using osu.Framework.Bindables;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Sprites;
-using osu.Framework.Localisation;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
-using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.UI;
-using osu.Game.Rulesets.Scoring;
-using osu.Game.Scoring;
-using osu.Game.Screens.Play;
using osu.Game.Utils;
namespace osu.Game.Rulesets.Osu.Mods
{
- public class OsuModNoScope : Mod, IUpdatableByPlayfield, IApplicableToScoreProcessor, IApplicableToPlayer, IApplicableToBeatmap
+ public class OsuModNoScope : ModNoScope, IUpdatableByPlayfield, IApplicableToBeatmap
{
- ///
- /// Slightly higher than the cutoff for .
- ///
- private const float min_alpha = 0.0002f;
-
- private const float transition_duration = 100;
-
- public override string Name => "No Scope";
- public override string Acronym => "NS";
- public override ModType Type => ModType.Fun;
- public override IconUsage? Icon => FontAwesome.Solid.EyeSlash;
public override string Description => "Where's the cursor?";
- public override double ScoreMultiplier => 1;
- private BindableNumber currentCombo;
- private IBindable isBreakTime;
private PeriodTracker spinnerPeriods;
- private float comboBasedAlpha;
-
[SettingSource(
"Hidden at combo",
"The combo count at which the cursor becomes completely hidden",
SettingControlType = typeof(SettingsSlider)
)]
- public BindableInt HiddenComboCount { get; } = new BindableInt
+ public override BindableInt HiddenComboCount { get; } = new BindableInt
{
Default = 10,
Value = 10,
@@ -57,39 +34,16 @@ namespace osu.Game.Rulesets.Osu.Mods
MaxValue = 50,
};
- public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
-
- public void ApplyToPlayer(Player player)
- {
- isBreakTime = player.IsBreakTime.GetBoundCopy();
- }
-
public void ApplyToBeatmap(IBeatmap beatmap)
{
- spinnerPeriods = new PeriodTracker(beatmap.HitObjects.OfType().Select(b => new Period(b.StartTime - transition_duration, b.EndTime)));
+ spinnerPeriods = new PeriodTracker(beatmap.HitObjects.OfType().Select(b => new Period(b.StartTime - TRANSITION_DURATION, b.EndTime)));
}
- public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor)
+ public void Update(Playfield playfield)
{
- if (HiddenComboCount.Value == 0) return;
-
- currentCombo = scoreProcessor.Combo.GetBoundCopy();
- currentCombo.BindValueChanged(combo =>
- {
- comboBasedAlpha = Math.Max(min_alpha, 1 - (float)combo.NewValue / HiddenComboCount.Value);
- }, true);
+ bool shouldAlwaysShowCursor = IsBreakTime.Value || spinnerPeriods.IsInAny(playfield.Clock.CurrentTime);
+ float targetAlpha = shouldAlwaysShowCursor ? 1 : ComboBasedAlpha;
+ playfield.Cursor.Alpha = (float)Interpolation.Lerp(playfield.Cursor.Alpha, targetAlpha, Math.Clamp(playfield.Time.Elapsed / TRANSITION_DURATION, 0, 1));
}
-
- public virtual void Update(Playfield playfield)
- {
- bool shouldAlwaysShowCursor = isBreakTime.Value || spinnerPeriods.IsInAny(playfield.Clock.CurrentTime);
- float targetAlpha = shouldAlwaysShowCursor ? 1 : comboBasedAlpha;
- playfield.Cursor.Alpha = (float)Interpolation.Lerp(playfield.Cursor.Alpha, targetAlpha, Math.Clamp(playfield.Time.Elapsed / transition_duration, 0, 1));
- }
- }
-
- public class HiddenComboSlider : OsuSliderBar
- {
- public override LocalisableString TooltipText => Current.Value == 0 ? "always hidden" : base.TooltipText;
}
}
diff --git a/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneEditorSaving.cs b/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneEditorSaving.cs
index 159a64d1ac..42ab84714a 100644
--- a/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneEditorSaving.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneEditorSaving.cs
@@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Editor
editorBeatmap.BeatmapInfo.Metadata.Artist = "artist";
editorBeatmap.BeatmapInfo.Metadata.Title = "title";
});
- AddStep("Set difficulty name", () => editorBeatmap.BeatmapInfo.Version = "difficulty");
+ AddStep("Set difficulty name", () => editorBeatmap.BeatmapInfo.DifficultyName = "difficulty");
checkMutations();
@@ -85,7 +85,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Editor
return Precision.AlmostEquals(taikoDifficulty.SliderMultiplier, 2);
});
AddAssert("Beatmap has correct metadata", () => editorBeatmap.BeatmapInfo.Metadata.Artist == "artist" && editorBeatmap.BeatmapInfo.Metadata.Title == "title");
- AddAssert("Beatmap has correct difficulty name", () => editorBeatmap.BeatmapInfo.Version == "difficulty");
+ AddAssert("Beatmap has correct difficulty name", () => editorBeatmap.BeatmapInfo.DifficultyName == "difficulty");
}
}
}
diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
index 0bd7c19200..677aaf6f78 100644
--- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
+++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
@@ -113,11 +113,11 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.AreEqual("Soleily", metadata.Artist);
Assert.AreEqual("Soleily", metadata.ArtistUnicode);
Assert.AreEqual("Gamu", metadata.Author.Username);
- Assert.AreEqual("Insane", beatmapInfo.Version);
+ Assert.AreEqual("Insane", beatmapInfo.DifficultyName);
Assert.AreEqual(string.Empty, metadata.Source);
Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", metadata.Tags);
- Assert.AreEqual(557821, beatmapInfo.OnlineBeatmapID);
- Assert.AreEqual(241526, beatmapInfo.BeatmapSet.OnlineBeatmapSetID);
+ Assert.AreEqual(557821, beatmapInfo.OnlineID);
+ Assert.AreEqual(241526, beatmapInfo.BeatmapSet.OnlineID);
}
}
diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs
index 37c1dfc657..bfd6ff0314 100644
--- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs
+++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs
@@ -31,7 +31,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
{
var beatmap = decodeAsJson(normal);
var meta = beatmap.BeatmapInfo.Metadata;
- Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID);
+ Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet.OnlineID);
Assert.AreEqual("Soleily", meta.Artist);
Assert.AreEqual("Soleily", meta.ArtistUnicode);
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile);
diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
index a19e977c1a..e00d7a1115 100644
--- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
+++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
@@ -18,6 +18,7 @@ using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.IO;
using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Scoring;
@@ -387,6 +388,41 @@ namespace osu.Game.Tests.Beatmaps.IO
}
}
+ [Test]
+ public async Task TestModelCreationFailureDoesntReturn()
+ {
+ using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
+ {
+ try
+ {
+ var osu = LoadOsuIntoHost(host);
+ var importer = osu.Dependencies.Get();
+
+ var progressNotification = new ImportProgressNotification();
+
+ var zipStream = new MemoryStream();
+
+ using (var zip = ZipArchive.Create())
+ zip.SaveTo(zipStream, new ZipWriterOptions(CompressionType.Deflate));
+
+ var imported = await importer.Import(
+ progressNotification,
+ new ImportTask(zipStream, string.Empty)
+ );
+
+ checkBeatmapSetCount(osu, 0);
+ checkBeatmapCount(osu, 0);
+
+ Assert.IsEmpty(imported);
+ Assert.AreEqual(ProgressNotificationState.Cancelled, progressNotification.State);
+ }
+ finally
+ {
+ host.Exit();
+ }
+ }
+ }
+
[Test]
public async Task TestRollbackOnFailure()
{
@@ -506,7 +542,7 @@ namespace osu.Game.Tests.Beatmaps.IO
var imported = await LoadOszIntoOsu(osu);
foreach (var b in imported.Beatmaps)
- b.OnlineBeatmapID = null;
+ b.OnlineID = null;
osu.Dependencies.Get().Update(imported);
@@ -545,19 +581,19 @@ namespace osu.Game.Tests.Beatmaps.IO
var toImport = new BeatmapSetInfo
{
- OnlineBeatmapSetID = 1,
+ OnlineID = 1,
Metadata = metadata,
Beatmaps = new List
{
new BeatmapInfo
{
- OnlineBeatmapID = 2,
+ OnlineID = 2,
Metadata = metadata,
BaseDifficulty = difficulty
},
new BeatmapInfo
{
- OnlineBeatmapID = 2,
+ OnlineID = 2,
Metadata = metadata,
Status = BeatmapSetOnlineStatus.Loved,
BaseDifficulty = difficulty
@@ -570,8 +606,8 @@ namespace osu.Game.Tests.Beatmaps.IO
var imported = await manager.Import(toImport);
Assert.NotNull(imported);
- Assert.AreEqual(null, imported.Value.Beatmaps[0].OnlineBeatmapID);
- Assert.AreEqual(null, imported.Value.Beatmaps[1].OnlineBeatmapID);
+ Assert.AreEqual(null, imported.Value.Beatmaps[0].OnlineID);
+ Assert.AreEqual(null, imported.Value.Beatmaps[1].OnlineID);
}
finally
{
@@ -790,12 +826,12 @@ namespace osu.Game.Tests.Beatmaps.IO
// Update via the beatmap, not the beatmap info, to ensure correct linking
BeatmapSetInfo setToUpdate = manager.GetAllUsableBeatmapSets()[0];
Beatmap beatmapToUpdate = (Beatmap)manager.GetWorkingBeatmap(setToUpdate.Beatmaps.First(b => b.RulesetID == 0)).Beatmap;
- beatmapToUpdate.BeatmapInfo.Version = "updated";
+ beatmapToUpdate.BeatmapInfo.DifficultyName = "updated";
manager.Update(setToUpdate);
BeatmapInfo updatedInfo = manager.QueryBeatmap(b => b.ID == beatmapToUpdate.BeatmapInfo.ID);
- Assert.That(updatedInfo.Version, Is.EqualTo("updated"));
+ Assert.That(updatedInfo.DifficultyName, Is.EqualTo("updated"));
}
finally
{
@@ -863,7 +899,7 @@ namespace osu.Game.Tests.Beatmaps.IO
var beatmap = working.Beatmap;
- beatmap.BeatmapInfo.Version = "difficulty";
+ beatmap.BeatmapInfo.DifficultyName = "difficulty";
beatmap.BeatmapInfo.Metadata = new BeatmapMetadata
{
Artist = "Artist/With\\Slashes",
@@ -1020,13 +1056,13 @@ namespace osu.Game.Tests.Beatmaps.IO
{
IEnumerable resultSets = null;
var store = osu.Dependencies.Get();
- waitForOrAssert(() => (resultSets = store.QueryBeatmapSets(s => s.OnlineBeatmapSetID == 241526)).Any(),
+ waitForOrAssert(() => (resultSets = store.QueryBeatmapSets(s => s.OnlineID == 241526)).Any(),
@"BeatmapSet did not import to the database in allocated time.", timeout);
// ensure we were stored to beatmap database backing...
Assert.IsTrue(resultSets.Count() == 1, $@"Incorrect result count found ({resultSets.Count()} but should be 1).");
- IEnumerable queryBeatmaps() => store.QueryBeatmaps(s => s.BeatmapSet.OnlineBeatmapSetID == 241526 && s.BaseDifficultyID > 0);
- IEnumerable queryBeatmapSets() => store.QueryBeatmapSets(s => s.OnlineBeatmapSetID == 241526);
+ IEnumerable queryBeatmaps() => store.QueryBeatmaps(s => s.BeatmapSet.OnlineID == 241526 && s.BaseDifficultyID > 0);
+ IEnumerable queryBeatmapSets() => store.QueryBeatmapSets(s => s.OnlineID == 241526);
// if we don't re-check here, the set will be inserted but the beatmaps won't be present yet.
waitForOrAssert(() => queryBeatmaps().Count() == 12,
@@ -1042,7 +1078,7 @@ namespace osu.Game.Tests.Beatmaps.IO
var set = queryBeatmapSets().First();
foreach (BeatmapInfo b in set.Beatmaps)
- Assert.IsTrue(set.Beatmaps.Any(c => c.OnlineBeatmapID == b.OnlineBeatmapID));
+ Assert.IsTrue(set.Beatmaps.Any(c => c.OnlineID == b.OnlineID));
Assert.IsTrue(set.Beatmaps.Count > 0);
var beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 0))?.Beatmap;
Assert.IsTrue(beatmap?.HitObjects.Any() == true);
diff --git a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs
index eaf5d107ca..b2ab1eeaa6 100644
--- a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs
+++ b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs
@@ -56,7 +56,7 @@ namespace osu.Game.Tests.Beatmaps.IO
var meta = beatmap.Metadata;
- Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID);
+ Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet.OnlineID);
Assert.AreEqual("Soleily", meta.Artist);
Assert.AreEqual("Soleily", meta.ArtistUnicode);
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile);
diff --git a/osu.Game.Tests/Beatmaps/ToStringFormattingTest.cs b/osu.Game.Tests/Beatmaps/ToStringFormattingTest.cs
index da7f32a2d3..4a7d7505ad 100644
--- a/osu.Game.Tests/Beatmaps/ToStringFormattingTest.cs
+++ b/osu.Game.Tests/Beatmaps/ToStringFormattingTest.cs
@@ -52,7 +52,7 @@ namespace osu.Game.Tests.Beatmaps
Title = "title",
Author = new APIUser { Username = "creator" }
},
- Version = "difficulty"
+ DifficultyName = "difficulty"
};
Assert.That(beatmap.ToString(), Is.EqualTo("artist - title (creator) [difficulty]"));
diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs
index e1fe1e224e..88d16c8a36 100644
--- a/osu.Game.Tests/Database/BeatmapImporterTests.cs
+++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs
@@ -16,6 +16,7 @@ using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.IO.Archives;
using osu.Game.Models;
+using osu.Game.Overlays.Notifications;
using osu.Game.Stores;
using osu.Game.Tests.Resources;
using Realms;
@@ -367,6 +368,34 @@ namespace osu.Game.Tests.Database
});
}
+ [Test]
+ public void TestModelCreationFailureDoesntReturn()
+ {
+ RunTestWithRealmAsync(async (realmFactory, storage) =>
+ {
+ using var importer = new BeatmapImporter(realmFactory, storage);
+ using var store = new RealmRulesetStore(realmFactory, storage);
+
+ var progressNotification = new ImportProgressNotification();
+
+ var zipStream = new MemoryStream();
+
+ using (var zip = ZipArchive.Create())
+ zip.SaveTo(zipStream, new ZipWriterOptions(CompressionType.Deflate));
+
+ var imported = await importer.Import(
+ progressNotification,
+ new ImportTask(zipStream, string.Empty)
+ );
+
+ checkBeatmapSetCount(realmFactory.Context, 0);
+ checkBeatmapCount(realmFactory.Context, 0);
+
+ Assert.IsEmpty(imported);
+ Assert.AreEqual(ProgressNotificationState.Cancelled, progressNotification.State);
+ });
+ }
+
[Test]
public void TestRollbackOnFailure()
{
diff --git a/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs b/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs
index 2918dde2db..05bfae7e63 100644
--- a/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs
+++ b/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs
@@ -54,7 +54,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, System.Array.Empty());
+ var context = getContext(null, new MemoryStream(System.Array.Empty()));
Assert.That(check.Run(context), Is.Empty);
}
@@ -103,7 +103,7 @@ namespace osu.Game.Tests.Editing.Checks
[Test]
public void TestTooUncompressed()
{
- var context = getContext(new Texture(1920, 1080), new byte[1024 * 1024 * 3]);
+ var context = getContext(new Texture(1920, 1080), new MemoryStream(new byte[1024 * 1024 * 3]));
var issues = check.Run(context).ToList();
@@ -111,19 +111,32 @@ namespace osu.Game.Tests.Editing.Checks
Assert.That(issues.Single().Template is CheckBackgroundQuality.IssueTemplateTooUncompressed);
}
- private BeatmapVerifierContext getContext(Texture background, [CanBeNull] byte[] fileBytes = null)
+ [Test]
+ public void TestStreamClosed()
{
- return new BeatmapVerifierContext(beatmap, getMockWorkingBeatmap(background, fileBytes).Object);
+ var background = new Texture(1920, 1080);
+ var stream = new Mock(new byte[1024 * 1024]);
+
+ var context = getContext(background, stream.Object);
+
+ Assert.That(check.Run(context), Is.Empty);
+
+ stream.Verify(x => x.Close(), Times.Once());
+ }
+
+ private BeatmapVerifierContext getContext(Texture background, [CanBeNull] Stream stream = null)
+ {
+ return new BeatmapVerifierContext(beatmap, getMockWorkingBeatmap(background, stream).Object);
}
///
- /// Returns the mock of the working beatmap with the given background and filesize.
+ /// Returns the mock of the working beatmap with the given background and its file stream.
///
/// The texture of the background.
- /// The bytes that represent the background file.
- private Mock getMockWorkingBeatmap(Texture background, [CanBeNull] byte[] fileBytes = null)
+ /// The stream representing the background file.
+ private Mock getMockWorkingBeatmap(Texture background, [CanBeNull] Stream stream = null)
{
- var stream = new MemoryStream(fileBytes ?? new byte[1024 * 1024]);
+ stream ??= new MemoryStream(new byte[1024 * 1024]);
var mock = new Mock();
mock.SetupGet(w => w.Beatmap).Returns(beatmap);
diff --git a/osu.Game.Tests/Models/DisplayStringTest.cs b/osu.Game.Tests/Models/DisplayStringTest.cs
new file mode 100644
index 0000000000..95af21eb5f
--- /dev/null
+++ b/osu.Game.Tests/Models/DisplayStringTest.cs
@@ -0,0 +1,133 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using Moq;
+using NUnit.Framework;
+using osu.Game.Beatmaps;
+using osu.Game.Extensions;
+using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Rulesets;
+using osu.Game.Scoring;
+using osu.Game.Users;
+
+#nullable enable
+
+namespace osu.Game.Tests.Models
+{
+ [TestFixture]
+ public class DisplayStringTest
+ {
+ [Test]
+ public void TestNull()
+ {
+ IBeatmapSetInfo? beatmap = null;
+ Assert.That(beatmap.GetDisplayString(), Is.EqualTo("null"));
+ }
+
+ [Test]
+ public void TestBeatmapSet()
+ {
+ var mock = new Mock();
+
+ mock.Setup(m => m.Metadata!.Artist).Returns("artist");
+ mock.Setup(m => m.Metadata!.Title).Returns("title");
+ mock.Setup(m => m.Metadata!.Author.Username).Returns("author");
+
+ Assert.That(mock.Object.GetDisplayString(), Is.EqualTo("artist - title (author)"));
+ }
+
+ [Test]
+ public void TestBeatmapSetWithNoAuthor()
+ {
+ var mock = new Mock();
+
+ mock.Setup(m => m.Metadata!.Artist).Returns("artist");
+ mock.Setup(m => m.Metadata!.Title).Returns("title");
+ mock.Setup(m => m.Metadata!.Author.Username).Returns(string.Empty);
+
+ Assert.That(mock.Object.GetDisplayString(), Is.EqualTo("artist - title"));
+ }
+
+ [Test]
+ public void TestBeatmapSetWithNoMetadata()
+ {
+ var mock = new Mock();
+
+ mock.Setup(m => m.Metadata).Returns(new BeatmapMetadata());
+
+ Assert.That(mock.Object.GetDisplayString(), Is.EqualTo("unknown artist - unknown title"));
+ }
+
+ [Test]
+ public void TestBeatmap()
+ {
+ var mock = new Mock();
+
+ mock.Setup(m => m.Metadata.Artist).Returns("artist");
+ mock.Setup(m => m.Metadata.Title).Returns("title");
+ mock.Setup(m => m.Metadata.Author.Username).Returns("author");
+ mock.Setup(m => m.DifficultyName).Returns("difficulty");
+
+ Assert.That(mock.Object.GetDisplayString(), Is.EqualTo("artist - title (author) [difficulty]"));
+ }
+
+ [Test]
+ public void TestMetadata()
+ {
+ var mock = new Mock();
+
+ mock.Setup(m => m.Artist).Returns("artist");
+ mock.Setup(m => m.Title).Returns("title");
+ mock.Setup(m => m.Author.Username).Returns("author");
+
+ Assert.That(mock.Object.GetDisplayString(), Is.EqualTo("artist - title (author)"));
+ }
+
+ [Test]
+ public void TestScore()
+ {
+ var mock = new Mock();
+
+ mock.Setup(m => m.User).Returns(new APIUser { Username = "user" }); // TODO: temporary.
+ mock.Setup(m => m.Beatmap.Metadata.Artist).Returns("artist");
+ mock.Setup(m => m.Beatmap.Metadata.Title).Returns("title");
+ mock.Setup(m => m.Beatmap.Metadata.Author.Username).Returns("author");
+ mock.Setup(m => m.Beatmap.DifficultyName).Returns("difficulty");
+
+ Assert.That(mock.Object.GetDisplayString(), Is.EqualTo("user playing artist - title (author) [difficulty]"));
+ }
+
+ [Test]
+ public void TestRuleset()
+ {
+ var mock = new Mock();
+
+ mock.Setup(m => m.Name).Returns("ruleset");
+
+ Assert.That(mock.Object.GetDisplayString(), Is.EqualTo("ruleset"));
+ }
+
+ [Test]
+ public void TestUser()
+ {
+ var mock = new Mock();
+
+ mock.Setup(m => m.Username).Returns("user");
+
+ Assert.That(mock.Object.GetDisplayString(), Is.EqualTo("user"));
+ }
+
+ [Test]
+ public void TestFallback()
+ {
+ var fallback = new Fallback();
+
+ Assert.That(fallback.GetDisplayString(), Is.EqualTo("fallback"));
+ }
+
+ private class Fallback
+ {
+ public override string ToString() => "fallback";
+ }
+ }
+}
diff --git a/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs b/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs
index 9ce7e0a0e0..938edf07c6 100644
--- a/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs
+++ b/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs
@@ -12,8 +12,8 @@ namespace osu.Game.Tests.NonVisual
[Test]
public void TestOnlineWithOnline()
{
- var ourInfo = new BeatmapSetInfo { OnlineBeatmapSetID = 123 };
- var otherInfo = new BeatmapSetInfo { OnlineBeatmapSetID = 123 };
+ var ourInfo = new BeatmapSetInfo { OnlineID = 123 };
+ var otherInfo = new BeatmapSetInfo { OnlineID = 123 };
Assert.AreEqual(ourInfo, otherInfo);
}
@@ -30,8 +30,8 @@ namespace osu.Game.Tests.NonVisual
[Test]
public void TestDatabasedWithOnline()
{
- var ourInfo = new BeatmapSetInfo { ID = 123, OnlineBeatmapSetID = 12 };
- var otherInfo = new BeatmapSetInfo { OnlineBeatmapSetID = 12 };
+ var ourInfo = new BeatmapSetInfo { ID = 123, OnlineID = 12 };
+ var otherInfo = new BeatmapSetInfo { OnlineID = 12 };
Assert.AreEqual(ourInfo, otherInfo);
}
diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs
index 41939cec3f..ee1feeca8d 100644
--- a/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs
+++ b/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs
@@ -17,7 +17,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
private BeatmapInfo getExampleBeatmap() => new BeatmapInfo
{
Ruleset = new RulesetInfo { ID = 5 },
- StarDifficulty = 4.0d,
+ StarRating = 4.0d,
BaseDifficulty = new BeatmapDifficulty
{
ApproachRate = 5.0f,
@@ -34,7 +34,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
Source = "unit tests",
Tags = "look for tags too",
},
- Version = "version as well",
+ DifficultyName = "version as well",
Length = 2500,
BPM = 160,
BeatDivisor = 12,
@@ -207,8 +207,8 @@ namespace osu.Game.Tests.NonVisual.Filtering
public void TestCriteriaMatchingBeatmapIDs(string query, bool filtered)
{
var beatmap = getExampleBeatmap();
- beatmap.OnlineBeatmapID = 20201010;
- beatmap.BeatmapSet = new BeatmapSetInfo { OnlineBeatmapSetID = 1535 };
+ beatmap.OnlineID = 20201010;
+ beatmap.BeatmapSet = new BeatmapSetInfo { OnlineID = 1535 };
var criteria = new FilterCriteria { SearchText = query };
var carouselItem = new CarouselBeatmap(beatmap);
diff --git a/osu.Game.Tests/NonVisual/Ranking/UnstableRateTest.cs b/osu.Game.Tests/NonVisual/Ranking/UnstableRateTest.cs
index ad6f01881b..103831822c 100644
--- a/osu.Game.Tests/NonVisual/Ranking/UnstableRateTest.cs
+++ b/osu.Game.Tests/NonVisual/Ranking/UnstableRateTest.cs
@@ -22,7 +22,8 @@ namespace osu.Game.Tests.NonVisual.Ranking
var unstableRate = new UnstableRate(events);
- Assert.IsTrue(Precision.AlmostEquals(unstableRate.Value, 10 * Math.Sqrt(10)));
+ Assert.IsNotNull(unstableRate.Value);
+ Assert.IsTrue(Precision.AlmostEquals(unstableRate.Value.Value, 10 * Math.Sqrt(10)));
}
[Test]
diff --git a/osu.Game.Tests/Online/TestSceneBeatmapManager.cs b/osu.Game.Tests/Online/TestSceneBeatmapManager.cs
index 0ae0186770..fc1b4f224d 100644
--- a/osu.Game.Tests/Online/TestSceneBeatmapManager.cs
+++ b/osu.Game.Tests/Online/TestSceneBeatmapManager.cs
@@ -5,6 +5,7 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.Notifications;
using osu.Game.Tests.Visual;
@@ -16,7 +17,30 @@ namespace osu.Game.Tests.Online
private BeatmapManager beatmaps;
private ProgressNotification recentNotification;
- private static readonly BeatmapSetInfo test_model = new BeatmapSetInfo { OnlineBeatmapSetID = 1 };
+ private static readonly BeatmapSetInfo test_db_model = new BeatmapSetInfo
+ {
+ OnlineID = 1,
+ Metadata = new BeatmapMetadata
+ {
+ Artist = "test author",
+ Title = "test title",
+ Author = new APIUser
+ {
+ Username = "mapper"
+ }
+ }
+ };
+
+ private static readonly APIBeatmapSet test_online_model = new APIBeatmapSet
+ {
+ OnlineID = 2,
+ Artist = "test author",
+ Title = "test title",
+ Author = new APIUser
+ {
+ Username = "mapper"
+ }
+ };
[BackgroundDependencyLoader]
private void load(BeatmapManager beatmaps)
@@ -26,25 +50,41 @@ namespace osu.Game.Tests.Online
beatmaps.PostNotification = n => recentNotification = n as ProgressNotification;
}
+ private static readonly object[][] notification_test_cases =
+ {
+ new object[] { test_db_model },
+ new object[] { test_online_model }
+ };
+
+ [TestCaseSource(nameof(notification_test_cases))]
+ public void TestNotificationMessage(IBeatmapSetInfo model)
+ {
+ AddStep("clear recent notification", () => recentNotification = null);
+ AddStep("download beatmap", () => beatmaps.Download(model));
+
+ AddUntilStep("wait for notification", () => recentNotification != null);
+ AddUntilStep("notification text correct", () => recentNotification.Text.ToString() == "Downloading test author - test title (mapper)");
+ }
+
[Test]
public void TestCancelDownloadFromRequest()
{
- AddStep("download beatmap", () => beatmaps.Download(test_model));
+ AddStep("download beatmap", () => beatmaps.Download(test_db_model));
- AddStep("cancel download from request", () => beatmaps.GetExistingDownload(test_model).Cancel());
+ AddStep("cancel download from request", () => beatmaps.GetExistingDownload(test_db_model).Cancel());
- AddUntilStep("is removed from download list", () => beatmaps.GetExistingDownload(test_model) == null);
+ AddUntilStep("is removed from download list", () => beatmaps.GetExistingDownload(test_db_model) == null);
AddAssert("is notification cancelled", () => recentNotification.State == ProgressNotificationState.Cancelled);
}
[Test]
public void TestCancelDownloadFromNotification()
{
- AddStep("download beatmap", () => beatmaps.Download(test_model));
+ AddStep("download beatmap", () => beatmaps.Download(test_db_model));
AddStep("cancel download from notification", () => recentNotification.Close());
- AddUntilStep("is removed from download list", () => beatmaps.GetExistingDownload(test_model) == null);
+ AddUntilStep("is removed from download list", () => beatmaps.GetExistingDownload(test_db_model) == null);
AddAssert("is notification cancelled", () => recentNotification.State == ProgressNotificationState.Cancelled);
}
}
diff --git a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs
index e3e2304990..b66da028f1 100644
--- a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs
+++ b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs
@@ -58,7 +58,7 @@ namespace osu.Game.Tests.Online
testBeatmapInfo = getTestBeatmapInfo(testBeatmapFile);
testBeatmapSet = testBeatmapInfo.BeatmapSet;
- var existing = beatmaps.QueryBeatmapSet(s => s.OnlineBeatmapSetID == testBeatmapSet.OnlineBeatmapSetID);
+ var existing = beatmaps.QueryBeatmapSet(s => s.OnlineID == testBeatmapSet.OnlineID);
if (existing != null)
beatmaps.Delete(existing);
@@ -101,10 +101,10 @@ namespace osu.Game.Tests.Online
AddStep("import beatmap", () => beatmaps.Import(testBeatmapFile).Wait());
addAvailabilityCheckStep("state locally available", BeatmapAvailability.LocallyAvailable);
- AddStep("delete beatmap", () => beatmaps.Delete(beatmaps.QueryBeatmapSet(b => b.OnlineBeatmapSetID == testBeatmapSet.OnlineBeatmapSetID)));
+ AddStep("delete beatmap", () => beatmaps.Delete(beatmaps.QueryBeatmapSet(b => b.OnlineID == testBeatmapSet.OnlineID)));
addAvailabilityCheckStep("state not downloaded", BeatmapAvailability.NotDownloaded);
- AddStep("undelete beatmap", () => beatmaps.Undelete(beatmaps.QueryBeatmapSet(b => b.OnlineBeatmapSetID == testBeatmapSet.OnlineBeatmapSetID)));
+ AddStep("undelete beatmap", () => beatmaps.Undelete(beatmaps.QueryBeatmapSet(b => b.OnlineID == testBeatmapSet.OnlineID)));
addAvailabilityCheckStep("state locally available", BeatmapAvailability.LocallyAvailable);
}
diff --git a/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs b/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs
index 89e20043fb..82b6710a17 100644
--- a/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs
+++ b/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs
@@ -13,10 +13,17 @@ namespace osu.Game.Tests.Visual.Components
{
public class TestScenePreviewTrackManager : OsuTestScene, IPreviewTrackOwner
{
- private readonly TestPreviewTrackManager trackManager = new TestPreviewTrackManager();
+ private readonly IAdjustableAudioComponent gameTrackAudio = new AudioAdjustments();
+
+ private readonly TestPreviewTrackManager trackManager;
private AudioManager audio;
+ public TestScenePreviewTrackManager()
+ {
+ trackManager = new TestPreviewTrackManager(gameTrackAudio);
+ }
+
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
@@ -151,19 +158,19 @@ namespace osu.Game.Tests.Visual.Components
audio.VolumeTrack.Value = 1;
});
- AddAssert("game not muted", () => audio.Tracks.AggregateVolume.Value != 0);
+ AddAssert("game not muted", () => gameTrackAudio.AggregateVolume.Value != 0);
AddStep("get track", () => Add(owner = new TestTrackOwner(track = getTrack())));
AddUntilStep("wait loaded", () => track.IsLoaded);
AddStep("start track", () => track.Start());
- AddAssert("game is muted", () => audio.Tracks.AggregateVolume.Value == 0);
+ AddAssert("game is muted", () => gameTrackAudio.AggregateVolume.Value == 0);
if (stopAnyPlaying)
AddStep("stop any playing", () => trackManager.StopAnyPlaying(owner));
else
AddStep("stop track", () => track.Stop());
- AddAssert("game not muted", () => audio.Tracks.AggregateVolume.Value != 0);
+ AddAssert("game not muted", () => gameTrackAudio.AggregateVolume.Value != 0);
}
[Test]
@@ -224,6 +231,11 @@ namespace osu.Game.Tests.Visual.Components
public new PreviewTrack CurrentTrack => base.CurrentTrack;
+ public TestPreviewTrackManager(IAdjustableAudioComponent mainTrackAdjustments)
+ : base(mainTrackAdjustments)
+ {
+ }
+
protected override TrackManagerPreviewTrack CreatePreviewTrack(IBeatmapSetInfo beatmapSetInfo, ITrackStore trackStore) => new TestPreviewTrack(beatmapSetInfo, trackStore);
public override bool UpdateSubTree()
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneComposeScreen.cs b/osu.Game.Tests/Visual/Editing/TestSceneComposeScreen.cs
index 4813598c9d..9b8567e853 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneComposeScreen.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneComposeScreen.cs
@@ -26,6 +26,9 @@ namespace osu.Game.Tests.Visual.Editing
}
});
+ [Cached]
+ private EditorClipboard clipboard = new EditorClipboard();
+
[BackgroundDependencyLoader]
private void load()
{
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs
index af3d9beb69..e1e869cfbf 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs
@@ -46,7 +46,7 @@ namespace osu.Game.Tests.Visual.Editing
editorBeatmap.BeatmapInfo.Metadata.Artist = "artist";
editorBeatmap.BeatmapInfo.Metadata.Title = "title";
});
- AddStep("Set difficulty name", () => editorBeatmap.BeatmapInfo.Version = "difficulty");
+ AddStep("Set difficulty name", () => editorBeatmap.BeatmapInfo.DifficultyName = "difficulty");
AddStep("Add timing point", () => editorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint()));
@@ -85,7 +85,7 @@ namespace osu.Game.Tests.Visual.Editing
AddAssert("Beatmap contains single hitcircle", () => editorBeatmap.HitObjects.Count == 1);
AddAssert("Beatmap has correct overall difficulty", () => editorBeatmap.Difficulty.OverallDifficulty == 7);
AddAssert("Beatmap has correct metadata", () => editorBeatmap.BeatmapInfo.Metadata.Artist == "artist" && editorBeatmap.BeatmapInfo.Metadata.Title == "title");
- AddAssert("Beatmap has correct difficulty name", () => editorBeatmap.BeatmapInfo.Version == "difficulty");
+ AddAssert("Beatmap has correct difficulty name", () => editorBeatmap.BeatmapInfo.DifficultyName == "difficulty");
}
}
}
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs
new file mode 100644
index 0000000000..db42667033
--- /dev/null
+++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs
@@ -0,0 +1,123 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Linq;
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Framework.Screens;
+using osu.Framework.Testing;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets;
+using osu.Game.Rulesets.Osu;
+using osu.Game.Screens.Edit;
+using osu.Game.Screens.Edit.Components.Timelines.Summary;
+using osu.Game.Tests.Beatmaps.IO;
+using osuTK.Input;
+
+namespace osu.Game.Tests.Visual.Editing
+{
+ public class TestSceneEditorTestGameplay : EditorTestScene
+ {
+ protected override bool IsolateSavingFromDatabase => false;
+
+ protected override Ruleset CreateEditorRuleset() => new OsuRuleset();
+
+ [Resolved]
+ private OsuGameBase game { get; set; }
+
+ [Resolved]
+ private BeatmapManager beatmaps { get; set; }
+
+ private BeatmapSetInfo importedBeatmapSet;
+
+ public override void SetUpSteps()
+ {
+ AddStep("import test beatmap", () => importedBeatmapSet = ImportBeatmapTest.LoadOszIntoOsu(game).Result);
+ base.SetUpSteps();
+ }
+
+ protected override void LoadEditor()
+ {
+ Beatmap.Value = beatmaps.GetWorkingBeatmap(importedBeatmapSet.Beatmaps.First(b => b.RulesetID == 0));
+ base.LoadEditor();
+ }
+
+ [Test]
+ public void TestBasicGameplayTest()
+ {
+ AddStep("click test gameplay button", () =>
+ {
+ var button = Editor.ChildrenOfType().Single();
+
+ InputManager.MoveMouseTo(button);
+ InputManager.Click(MouseButton.Left);
+ });
+
+ EditorPlayer editorPlayer = null;
+ AddUntilStep("player pushed", () => (editorPlayer = Stack.CurrentScreen as EditorPlayer) != null);
+ AddStep("exit player", () => editorPlayer.Exit());
+ AddUntilStep("current screen is editor", () => Stack.CurrentScreen is Editor);
+ }
+
+ [Test]
+ public void TestCancelGameplayTestWithUnsavedChanges()
+ {
+ AddStep("delete all but first object", () => EditorBeatmap.RemoveRange(EditorBeatmap.HitObjects.Skip(1).ToList()));
+
+ AddStep("click test gameplay button", () =>
+ {
+ var button = Editor.ChildrenOfType().Single();
+
+ InputManager.MoveMouseTo(button);
+ InputManager.Click(MouseButton.Left);
+ });
+ AddUntilStep("save prompt shown", () => DialogOverlay.CurrentDialog is SaveBeforeGameplayTestDialog);
+
+ AddStep("dismiss prompt", () =>
+ {
+ var button = DialogOverlay.CurrentDialog.Buttons.Last();
+ InputManager.MoveMouseTo(button);
+ InputManager.Click(MouseButton.Left);
+ });
+
+ AddWaitStep("wait some", 3);
+ AddAssert("stayed in editor", () => Stack.CurrentScreen is Editor);
+ }
+
+ [Test]
+ public void TestSaveChangesBeforeGameplayTest()
+ {
+ AddStep("delete all but first object", () => EditorBeatmap.RemoveRange(EditorBeatmap.HitObjects.Skip(1).ToList()));
+ // bit of a hack to ensure this test can be ran multiple times without running into UNIQUE constraint failures
+ AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = Guid.NewGuid().ToString());
+
+ AddStep("click test gameplay button", () =>
+ {
+ var button = Editor.ChildrenOfType().Single();
+
+ InputManager.MoveMouseTo(button);
+ InputManager.Click(MouseButton.Left);
+ });
+ AddUntilStep("save prompt shown", () => DialogOverlay.CurrentDialog is SaveBeforeGameplayTestDialog);
+
+ AddStep("save changes", () => DialogOverlay.CurrentDialog.PerformOkAction());
+
+ EditorPlayer editorPlayer = null;
+ AddUntilStep("player pushed", () => (editorPlayer = Stack.CurrentScreen as EditorPlayer) != null);
+ AddAssert("beatmap has 1 object", () => editorPlayer.Beatmap.Value.Beatmap.HitObjects.Count == 1);
+
+ AddUntilStep("wait for return to editor", () => Stack.CurrentScreen is Editor);
+ AddAssert("track stopped", () => !Beatmap.Value.Track.IsRunning);
+ }
+
+ public override void TearDownSteps()
+ {
+ base.TearDownSteps();
+ AddStep("delete imported", () =>
+ {
+ beatmaps.Delete(importedBeatmapSet);
+ });
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs b/osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs
index c3c803ff23..03e78ce854 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs
@@ -4,6 +4,7 @@
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
+using osu.Game.Overlays;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Catch;
using osu.Game.Rulesets.Edit;
@@ -23,6 +24,9 @@ namespace osu.Game.Tests.Visual.Editing
[Cached(typeof(IBeatSnapProvider))]
private readonly EditorBeatmap editorBeatmap;
+ [Cached]
+ private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
+
public TestSceneSetupScreen()
{
editorBeatmap = new EditorBeatmap(new OsuBeatmap());
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs
index f961fff1e5..4bbffbdc7a 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs
@@ -4,6 +4,7 @@
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
+using osu.Game.Overlays;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Edit;
@@ -18,6 +19,9 @@ namespace osu.Game.Tests.Visual.Editing
[Cached(typeof(IBeatSnapProvider))]
private readonly EditorBeatmap editorBeatmap;
+ [Cached]
+ private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
+
protected override bool ScrollUsingMouseWheel => false;
public TestSceneTimingScreen()
diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePerformancePointsCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePerformancePointsCounter.cs
index 4c48d52acd..84c7f611af 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestScenePerformancePointsCounter.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestScenePerformancePointsCounter.cs
@@ -1,9 +1,10 @@
// 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.Diagnostics;
using NUnit.Framework;
-using osu.Framework.Allocation;
+using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Testing;
using osu.Game.Rulesets;
@@ -20,16 +21,17 @@ namespace osu.Game.Tests.Visual.Gameplay
{
public class TestScenePerformancePointsCounter : OsuTestScene
{
- [Cached]
- private GameplayState gameplayState;
+ private DependencyProvidingContainer dependencyContainer;
- [Cached]
+ private GameplayState gameplayState;
private ScoreProcessor scoreProcessor;
private int iteration;
+ private Bindable lastJudgementResult = new Bindable();
private PerformancePointsCounter counter;
- public TestScenePerformancePointsCounter()
+ [SetUpSteps]
+ public void SetUpSteps() => AddStep("create components", () =>
{
var ruleset = CreateRuleset();
@@ -38,32 +40,43 @@ namespace osu.Game.Tests.Visual.Gameplay
var beatmap = CreateWorkingBeatmap(ruleset.RulesetInfo)
.GetPlayableBeatmap(ruleset.RulesetInfo);
+ lastJudgementResult = new Bindable();
+
gameplayState = new GameplayState(beatmap, ruleset);
+ gameplayState.LastJudgementResult.BindTo(lastJudgementResult);
+
scoreProcessor = new ScoreProcessor();
- }
+
+ Child = dependencyContainer = new DependencyProvidingContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ CachedDependencies = new (Type, object)[]
+ {
+ (typeof(GameplayState), gameplayState),
+ (typeof(ScoreProcessor), scoreProcessor)
+ }
+ };
+
+ iteration = 0;
+ });
protected override Ruleset CreateRuleset() => new OsuRuleset();
- [SetUpSteps]
- public void SetUpSteps()
+ private void createCounter() => AddStep("Create counter", () =>
{
- AddStep("Create counter", () =>
+ dependencyContainer.Child = counter = new PerformancePointsCounter
{
- iteration = 0;
-
- Child = counter = new PerformancePointsCounter
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Scale = new Vector2(5),
- };
- });
- }
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Scale = new Vector2(5),
+ };
+ });
[Test]
public void TestBasicCounting()
{
int previousValue = 0;
+ createCounter();
AddAssert("counter displaying zero", () => counter.Current.Value == 0);
@@ -86,6 +99,17 @@ namespace osu.Game.Tests.Visual.Gameplay
AddUntilStep("counter non-zero", () => counter.Current.Value > 0);
}
+ [Test]
+ public void TestCounterUpdatesWithJudgementsBeforeCreation()
+ {
+ AddRepeatStep("Add judgement", applyOneJudgement, 10);
+
+ createCounter();
+
+ AddUntilStep("counter non-zero", () => counter.Current.Value > 0);
+ AddUntilStep("counter opaque", () => counter.Child.Alpha == 1);
+ }
+
private void applyOneJudgement()
{
var scoreInfo = gameplayState.Score.ScoreInfo;
@@ -94,13 +118,14 @@ namespace osu.Game.Tests.Visual.Gameplay
scoreInfo.Accuracy = 1;
scoreInfo.Statistics[HitResult.Great] = iteration * 1000;
- scoreProcessor.ApplyResult(new OsuJudgementResult(new HitObject
+ lastJudgementResult.Value = new OsuJudgementResult(new HitObject
{
StartTime = iteration * 10000,
}, new OsuJudgement())
{
Type = HitResult.Perfect,
- });
+ };
+ scoreProcessor.ApplyResult(lastJudgementResult.Value);
iteration++;
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerScoreSubmission.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerScoreSubmission.cs
index bf864f844c..cb5058779c 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerScoreSubmission.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerScoreSubmission.cs
@@ -215,7 +215,7 @@ namespace osu.Game.Tests.Visual.Gameplay
createPlayerTest(false, r =>
{
var beatmap = createTestBeatmap(r);
- beatmap.BeatmapInfo.OnlineBeatmapID = null;
+ beatmap.BeatmapInfo.OnlineID = null;
return beatmap;
});
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs
index d4036fefc0..f47fae33ca 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs
@@ -175,7 +175,7 @@ namespace osu.Game.Tests.Visual.Gameplay
Id = 39828,
Username = @"WubWoofWolf",
}
- }.CreateScoreInfo(rulesets);
+ }.CreateScoreInfo(rulesets, CreateBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo);
}
private class TestReplayDownloadButton : ReplayDownloadButton
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs
index 20e859dd2b..9fadbe02bd 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs
@@ -61,7 +61,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("import beatmap", () =>
{
importedBeatmap = ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).Result;
- importedBeatmapId = importedBeatmap.Beatmaps.First(b => b.RulesetID == 0).OnlineBeatmapID ?? -1;
+ importedBeatmapId = importedBeatmap.Beatmaps.First(b => b.RulesetID == 0).OnlineID ?? -1;
});
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneUnstableRateCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneUnstableRateCounter.cs
new file mode 100644
index 0000000000..be20799479
--- /dev/null
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneUnstableRateCounter.cs
@@ -0,0 +1,108 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Testing;
+using osu.Game.Rulesets.Judgements;
+using osu.Game.Rulesets.Osu.Objects;
+using osu.Game.Rulesets.Osu.Scoring;
+using osu.Game.Rulesets.Scoring;
+using osu.Game.Screens.Play.HUD;
+using osuTK;
+
+namespace osu.Game.Tests.Visual.Gameplay
+{
+ public class TestSceneUnstableRateCounter : OsuTestScene
+ {
+ [Cached(typeof(ScoreProcessor))]
+ private TestScoreProcessor scoreProcessor = new TestScoreProcessor();
+
+ private readonly OsuHitWindows hitWindows = new OsuHitWindows();
+
+ private UnstableRateCounter counter;
+
+ private double prev;
+
+ [SetUpSteps]
+ public void SetUp()
+ {
+ AddStep("Reset Score Processor", () => scoreProcessor.Reset());
+ }
+
+ [Test]
+ public void TestBasic()
+ {
+ AddStep("Create Display", recreateDisplay);
+
+ // Needs multiples 2 by the nature of UR, and went for 4 to be safe.
+ // Creates a 250 UR by placing a +25ms then a -25ms judgement, which then results in a 250 UR
+ AddRepeatStep("Set UR to 250", () => applyJudgement(25, true), 4);
+
+ AddUntilStep("UR = 250", () => counter.Current.Value == 250.0);
+
+ AddRepeatStep("Revert UR", () =>
+ {
+ scoreProcessor.RevertResult(
+ new JudgementResult(new HitCircle { HitWindows = hitWindows }, new Judgement())
+ {
+ TimeOffset = 25,
+ Type = HitResult.Perfect,
+ });
+ }, 4);
+
+ AddUntilStep("UR is 0", () => counter.Current.Value == 0.0);
+ AddUntilStep("Counter is invalid", () => counter.Child.Alpha == 0.3f);
+
+ //Sets a UR of 0 by creating 10 10ms offset judgements. Since average = offset, UR = 0
+ AddRepeatStep("Set UR to 0", () => applyJudgement(10, false), 10);
+ //Applies a UR of 100 by creating 10 -10ms offset judgements. At the 10th judgement, offset should be 100.
+ AddRepeatStep("Bring UR to 100", () => applyJudgement(-10, false), 10);
+ }
+
+ [Test]
+ public void TestCounterReceivesJudgementsBeforeCreation()
+ {
+ AddRepeatStep("Set UR to 250", () => applyJudgement(25, true), 4);
+
+ AddStep("Create Display", recreateDisplay);
+
+ AddUntilStep("UR = 250", () => counter.Current.Value == 250.0);
+ }
+
+ private void recreateDisplay()
+ {
+ Clear();
+
+ Add(counter = new UnstableRateCounter
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Scale = new Vector2(5),
+ });
+ }
+
+ private void applyJudgement(double offsetMs, bool alt)
+ {
+ double placement = offsetMs;
+
+ if (alt)
+ {
+ placement = prev > 0 ? -offsetMs : offsetMs;
+ prev = placement;
+ }
+
+ scoreProcessor.ApplyResult(new JudgementResult(new HitCircle { HitWindows = hitWindows }, new Judgement())
+ {
+ TimeOffset = placement,
+ Type = HitResult.Perfect,
+ });
+ }
+
+ private class TestScoreProcessor : ScoreProcessor
+ {
+ public void Reset() => base.Reset(false);
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs
index 721862c177..2c28a1752e 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs
@@ -59,7 +59,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
BeatmapInfo =
{
- StarDifficulty = 2.5
+ StarRating = 2.5
}
}.BeatmapInfo,
}
@@ -82,7 +82,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
BeatmapInfo =
{
- StarDifficulty = 2.5,
+ StarRating = 2.5,
Metadata =
{
Artist = "very very very very very very very very very long artist",
@@ -111,7 +111,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
BeatmapInfo =
{
- StarDifficulty = 2.5
+ StarRating = 2.5
}
}.BeatmapInfo,
}
@@ -124,7 +124,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
BeatmapInfo =
{
- StarDifficulty = 4.5
+ StarRating = 4.5
}
}.BeatmapInfo,
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs
index fdd01446b9..b10856b704 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs
@@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
importedSet = ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).Result;
importedBeatmap = importedSet.Beatmaps.First(b => b.RulesetID == 0);
- importedBeatmapId = importedBeatmap.OnlineBeatmapID ?? -1;
+ importedBeatmapId = importedBeatmap.OnlineID ?? -1;
}
[SetUp]
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs
index 902629765f..25200560e4 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs
@@ -57,7 +57,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
foreach (int user in users)
{
- SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0);
+ SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineID ?? 0);
multiplayerUsers.Add(OnlinePlayDependencies.Client.AddUser(new APIUser { Id = user }, true));
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs
index af4e696fce..16a342df8c 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs
@@ -61,7 +61,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
foreach (int user in users)
{
- SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0);
+ SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineID ?? 0);
var roomUser = OnlinePlayDependencies.Client.AddUser(new APIUser { Id = user }, true);
roomUser.MatchState = new TeamVersusUserState
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs
index 0d6b428cce..aef1fb31d6 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs
@@ -57,7 +57,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
beatmaps.Add(new BeatmapInfo
{
Ruleset = rulesets.GetRuleset(i % 4),
- OnlineBeatmapID = beatmapId,
+ OnlineID = beatmapId,
Length = length,
BPM = bpm,
BaseDifficulty = new BeatmapDifficulty()
@@ -66,7 +66,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
manager.Import(new BeatmapSetInfo
{
- OnlineBeatmapSetID = 10,
+ OnlineID = 10,
Hash = Guid.NewGuid().ToString().ComputeMD5Hash(),
Metadata = new BeatmapMetadata
{
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs
index ba30315663..05f9a94cf7 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs
@@ -54,8 +54,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
beatmaps.Add(new BeatmapInfo
{
Ruleset = new OsuRuleset().RulesetInfo,
- OnlineBeatmapID = beatmapId,
- Version = $"{beatmapId} (length {TimeSpan.FromMilliseconds(length):m\\:ss}, bpm {bpm:0.#})",
+ OnlineID = beatmapId,
+ DifficultyName = $"{beatmapId} (length {TimeSpan.FromMilliseconds(length):m\\:ss}, bpm {bpm:0.#})",
Length = length,
BPM = bpm,
BaseDifficulty = new BeatmapDifficulty
@@ -67,7 +67,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
manager.Import(new BeatmapSetInfo
{
- OnlineBeatmapSetID = 10,
+ OnlineID = 10,
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
Metadata = new BeatmapMetadata
{
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneStarRatingRangeDisplay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneStarRatingRangeDisplay.cs
index cdeafdc9a3..20db922122 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneStarRatingRangeDisplay.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneStarRatingRangeDisplay.cs
@@ -31,8 +31,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
SelectedRoom.Value.Playlist.AddRange(new[]
{
- new PlaylistItem { Beatmap = { Value = new BeatmapInfo { StarDifficulty = min } } },
- new PlaylistItem { Beatmap = { Value = new BeatmapInfo { StarDifficulty = max } } },
+ new PlaylistItem { Beatmap = { Value = new BeatmapInfo { StarRating = min } } },
+ new PlaylistItem { Beatmap = { Value = new BeatmapInfo { StarRating = max } } },
});
});
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs
index ad92886bab..99ff307235 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs
@@ -10,6 +10,7 @@ using osu.Framework.Platform;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Database;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets;
@@ -97,16 +98,24 @@ namespace osu.Game.Tests.Visual.Multiplayer
});
AddAssert("user on team 0", () => (client.Room?.Users.FirstOrDefault()?.MatchState as TeamVersusUserState)?.TeamID == 0);
+ AddStep("add another user", () => client.AddUser(new APIUser { Username = "otheruser", Id = 44 }));
- AddStep("press button", () =>
+ AddStep("press own button", () =>
{
InputManager.MoveMouseTo(multiplayerScreenStack.ChildrenOfType().First());
InputManager.Click(MouseButton.Left);
});
AddAssert("user on team 1", () => (client.Room?.Users.FirstOrDefault()?.MatchState as TeamVersusUserState)?.TeamID == 1);
- AddStep("press button", () => InputManager.Click(MouseButton.Left));
+ AddStep("press own button again", () => InputManager.Click(MouseButton.Left));
AddAssert("user on team 0", () => (client.Room?.Users.FirstOrDefault()?.MatchState as TeamVersusUserState)?.TeamID == 0);
+
+ AddStep("press other user's button", () =>
+ {
+ InputManager.MoveMouseTo(multiplayerScreenStack.ChildrenOfType().ElementAt(1));
+ InputManager.Click(MouseButton.Left);
+ });
+ AddAssert("user still on team 0", () => (client.Room?.Users.FirstOrDefault()?.MatchState as TeamVersusUserState)?.TeamID == 0);
}
[Test]
@@ -127,9 +136,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddAssert("room type is head to head", () => client.Room?.Settings.MatchType == MatchType.HeadToHead);
+ AddUntilStep("team displays are not displaying teams", () => multiplayerScreenStack.ChildrenOfType().All(d => d.DisplayedTeam == null));
+
AddStep("change to team vs", () => client.ChangeSettings(matchType: MatchType.TeamVersus));
AddAssert("room type is team vs", () => client.Room?.Settings.MatchType == MatchType.TeamVersus);
+
+ AddUntilStep("team displays are displaying teams", () => multiplayerScreenStack.ChildrenOfType().All(d => d.DisplayedTeam != null));
}
private void createRoom(Func room)
diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs b/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs
index 4ec76e1e4b..4e1b3bb9bf 100644
--- a/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs
+++ b/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs
@@ -174,7 +174,7 @@ namespace osu.Game.Tests.Visual.Navigation
{
AddStep("import beatmap", () => ImportBeatmapTest.LoadQuickOszIntoOsu(Game).Wait());
PushAndConfirm(() => new TestPlaySongSelect());
- AddUntilStep("beatmap updated", () => Game.Beatmap.Value.BeatmapSetInfo.OnlineBeatmapSetID == 241526);
+ AddUntilStep("beatmap updated", () => Game.Beatmap.Value.BeatmapSetInfo.OnlineID == 241526);
}
public class DialogBlockingScreen : OsuScreen
diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs b/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs
index 5f5ebfccfb..ff976c7bf6 100644
--- a/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs
+++ b/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs
@@ -107,20 +107,20 @@ namespace osu.Game.Tests.Visual.Navigation
imported = Game.BeatmapManager.Import(new BeatmapSetInfo
{
Hash = Guid.NewGuid().ToString(),
- OnlineBeatmapSetID = i,
+ OnlineID = i,
Metadata = metadata,
Beatmaps = new List
{
new BeatmapInfo
{
- OnlineBeatmapID = i * 1024,
+ OnlineID = i * 1024,
Metadata = metadata,
BaseDifficulty = difficulty,
Ruleset = ruleset ?? new OsuRuleset().RulesetInfo
},
new BeatmapInfo
{
- OnlineBeatmapID = i * 2048,
+ OnlineID = i * 2048,
Metadata = metadata,
BaseDifficulty = difficulty,
Ruleset = ruleset ?? new OsuRuleset().RulesetInfo
@@ -145,11 +145,11 @@ namespace osu.Game.Tests.Visual.Navigation
private void presentSecondDifficultyAndConfirm(Func getImport, int importedID)
{
- Predicate pred = b => b.OnlineBeatmapID == importedID * 2048;
+ Predicate pred = b => b.OnlineID == importedID * 2048;
AddStep("present difficulty", () => Game.PresentBeatmap(getImport(), pred));
AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect);
- AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapInfo.OnlineBeatmapID == importedID * 2048);
+ AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapInfo.OnlineID == importedID * 2048);
AddAssert("correct ruleset selected", () => Game.Ruleset.Value.ID == getImport().Beatmaps.First().Ruleset.ID);
}
}
diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs b/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs
index aca7ada535..72f160c9a9 100644
--- a/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs
+++ b/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs
@@ -39,20 +39,20 @@ namespace osu.Game.Tests.Visual.Navigation
beatmap = Game.BeatmapManager.Import(new BeatmapSetInfo
{
Hash = Guid.NewGuid().ToString(),
- OnlineBeatmapSetID = 1,
+ OnlineID = 1,
Metadata = metadata,
Beatmaps = new List
{
new BeatmapInfo
{
- OnlineBeatmapID = 1 * 1024,
+ OnlineID = 1 * 1024,
Metadata = metadata,
BaseDifficulty = difficulty,
Ruleset = new OsuRuleset().RulesetInfo
},
new BeatmapInfo
{
- OnlineBeatmapID = 1 * 2048,
+ OnlineID = 1 * 2048,
Metadata = metadata,
BaseDifficulty = difficulty,
Ruleset = new OsuRuleset().RulesetInfo
diff --git a/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs b/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs
index a865bbe950..22a91fa9a3 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs
@@ -44,7 +44,7 @@ namespace osu.Game.Tests.Visual.Online
AddAssert("button state not downloaded", () => downloadButton.DownloadState == DownloadState.NotDownloaded);
AddStep("import soleily", () => beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()));
- AddUntilStep("wait for beatmap import", () => beatmaps.GetAllUsableBeatmapSets().Any(b => b.OnlineBeatmapSetID == 241526));
+ AddUntilStep("wait for beatmap import", () => beatmaps.GetAllUsableBeatmapSets().Any(b => b.OnlineID == 241526));
AddUntilStep("button state downloaded", () => downloadButton.DownloadState == DownloadState.LocallyAvailable);
createButtonWithBeatmap(createSoleily());
@@ -57,7 +57,7 @@ namespace osu.Game.Tests.Visual.Online
{
AddStep("remove soleily", () =>
{
- var beatmap = beatmaps.QueryBeatmapSet(b => b.OnlineBeatmapSetID == 241526);
+ var beatmap = beatmaps.QueryBeatmapSet(b => b.OnlineID == 241526);
if (beatmap != null) beatmaps.Delete(beatmap);
});
diff --git a/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs b/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs
index 366fa8a4af..7a5ee84eb4 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs
@@ -64,7 +64,7 @@ namespace osu.Game.Tests.Visual.Online
AddStep("Set beatmap", () => Beatmap.Value = new DummyWorkingBeatmap(Audio, null)
{
- BeatmapInfo = { OnlineBeatmapID = hasOnlineId ? 1234 : (int?)null }
+ BeatmapInfo = { OnlineID = hasOnlineId ? 1234 : (int?)null }
});
AddStep("Run command", () => Add(new NowPlayingCommand()));
diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs
index cda7e95a46..c5287d4257 100644
--- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs
+++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs
@@ -121,8 +121,8 @@ namespace osu.Game.Tests.Visual.Playlists
beatmap.BeatmapInfo.BaseDifficulty.CircleSize = 1;
// intentionally increment online IDs to clash with import below.
- beatmap.BeatmapInfo.OnlineBeatmapID++;
- beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID++;
+ beatmap.BeatmapInfo.OnlineID++;
+ beatmap.BeatmapInfo.BeatmapSet.OnlineID++;
importedSet = manager.Import(beatmap.BeatmapInfo.BeatmapSet).Result.Value;
});
diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs b/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs
index 8d5d0ba8c7..423c0a048c 100644
--- a/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs
+++ b/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs
@@ -337,7 +337,7 @@ namespace osu.Game.Tests.Visual.Ranking
public UnrankedSoloResultsScreen(ScoreInfo score)
: base(score, true)
{
- Score.BeatmapInfo.OnlineBeatmapID = 0;
+ Score.BeatmapInfo.OnlineID = 0;
Score.BeatmapInfo.Status = BeatmapSetOnlineStatus.Pending;
}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs
index 07e68ef509..d57b3dec5d 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs
@@ -46,7 +46,7 @@ namespace osu.Game.Tests.Visual.SongSelect
OverallDifficulty = 5.7f,
ApproachRate = 3.5f
},
- StarDifficulty = 4.5f
+ StarRating = 4.5f
};
[Test]
@@ -76,7 +76,7 @@ namespace osu.Game.Tests.Visual.SongSelect
OverallDifficulty = 4.5f,
ApproachRate = 3.1f
},
- StarDifficulty = 8
+ StarRating = 8
});
AddAssert("first bar text is Key Count", () => advancedStats.ChildrenOfType().First().Text == "Key Count");
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
index 9a142f3ca8..534442c8b6 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
@@ -435,8 +435,8 @@ namespace osu.Game.Tests.Visual.SongSelect
for (int i = 0; i < 3; i++)
{
var set = createTestBeatmapSet(i);
- set.Beatmaps[0].StarDifficulty = 3 - i;
- set.Beatmaps[2].StarDifficulty = 6 + i;
+ set.Beatmaps[0].StarRating = 3 - i;
+ set.Beatmaps[2].StarRating = 6 + i;
sets.Add(set);
}
@@ -684,9 +684,9 @@ namespace osu.Game.Tests.Visual.SongSelect
{
set.Beatmaps.Add(new BeatmapInfo
{
- Version = $"Stars: {i}",
+ DifficultyName = $"Stars: {i}",
Ruleset = new OsuRuleset().RulesetInfo,
- StarDifficulty = i,
+ StarRating = i,
});
}
@@ -838,7 +838,7 @@ namespace osu.Game.Tests.Visual.SongSelect
return new BeatmapSetInfo
{
ID = id,
- OnlineBeatmapSetID = id,
+ OnlineID = id,
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
Metadata = new BeatmapMetadata
{
@@ -867,9 +867,9 @@ namespace osu.Game.Tests.Visual.SongSelect
yield return new BeatmapInfo
{
- OnlineBeatmapID = id++ * 10,
- Version = version,
- StarDifficulty = diff,
+ OnlineID = id++ * 10,
+ DifficultyName = version,
+ StarRating = diff,
Ruleset = new OsuRuleset().RulesetInfo,
BaseDifficulty = new BeatmapDifficulty
{
@@ -884,7 +884,7 @@ namespace osu.Game.Tests.Visual.SongSelect
var toReturn = new BeatmapSetInfo
{
ID = id,
- OnlineBeatmapSetID = id,
+ OnlineID = id,
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
Metadata = new BeatmapMetadata
{
@@ -900,11 +900,11 @@ namespace osu.Game.Tests.Visual.SongSelect
{
toReturn.Beatmaps.Add(new BeatmapInfo
{
- OnlineBeatmapID = b * 10,
+ OnlineID = b * 10,
Path = $"extra{b}.osu",
- Version = $"Extra {b}",
+ DifficultyName = $"Extra {b}",
Ruleset = rulesets.GetRuleset((b - 1) % 4),
- StarDifficulty = 2,
+ StarRating = 2,
BaseDifficulty = new BeatmapDifficulty
{
OverallDifficulty = 3.5f,
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs
index 9fa0eab548..1b070c00bf 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs
@@ -198,8 +198,8 @@ namespace osu.Game.Tests.Visual.SongSelect
Title = $"{ruleset.ShortName}Title"
},
Ruleset = ruleset,
- StarDifficulty = 6,
- Version = $"{ruleset.ShortName}Version",
+ StarRating = 6,
+ DifficultyName = $"{ruleset.ShortName}Version",
BaseDifficulty = new BeatmapDifficulty()
},
HitObjects = objects
@@ -219,7 +219,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Source = "Verrrrry long Source",
Title = "Verrrrry long Title"
},
- Version = "Verrrrrrrrrrrrrrrrrrrrrrrrrrrrry long Version",
+ DifficultyName = "Verrrrrrrrrrrrrrrrrrrrrrrrrrrrry long Version",
Status = BeatmapSetOnlineStatus.Graveyard,
},
};
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
index 855a59b5f5..a8a7a5d350 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
@@ -388,7 +388,7 @@ namespace osu.Game.Tests.Visual.SongSelect
{
leaderboard.BeatmapInfo = new BeatmapInfo
{
- OnlineBeatmapID = 1113057,
+ OnlineID = 1113057,
Status = status,
};
}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs
index 50ae673c06..9473b058cc 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs
@@ -45,8 +45,8 @@ namespace osu.Game.Tests.Visual.SongSelect
{
Title = title,
},
- Version = version,
- StarDifficulty = RNG.NextDouble(0, 10),
+ DifficultyName = version,
+ StarRating = RNG.NextDouble(0, 10),
}
}));
}
@@ -64,8 +64,8 @@ namespace osu.Game.Tests.Visual.SongSelect
{
Title = "Heavy beatmap",
},
- Version = "10k objects",
- StarDifficulty = 99.99f,
+ DifficultyName = "10k objects",
+ StarRating = 99.99f,
}
}));
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs
index 68d5836cac..a0742b862b 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs
@@ -180,16 +180,16 @@ namespace osu.Game.Tests.Visual.SongSelect
var beatmapSet = new BeatmapSetInfo
{
Hash = Guid.NewGuid().ToString(),
- OnlineBeatmapSetID = importID,
+ OnlineID = importID,
Metadata = metadata,
Beatmaps = difficultyRulesets.Select((ruleset, difficultyIndex) => new BeatmapInfo
{
- OnlineBeatmapID = importID * 1024 + difficultyIndex,
+ OnlineID = importID * 1024 + difficultyIndex,
Metadata = metadata,
BaseDifficulty = new BeatmapDifficulty(),
Ruleset = ruleset,
- StarDifficulty = difficultyIndex + 1,
- Version = $"SR{difficultyIndex + 1}"
+ StarRating = difficultyIndex + 1,
+ DifficultyName = $"SR{difficultyIndex + 1}"
}).ToList()
};
@@ -205,8 +205,8 @@ namespace osu.Game.Tests.Visual.SongSelect
AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect);
AddUntilStep("recommended beatmap displayed", () =>
{
- int? expectedID = getImport().Beatmaps[expectedDiff - 1].OnlineBeatmapID;
- return Game.Beatmap.Value.BeatmapInfo.OnlineBeatmapID == expectedID;
+ int? expectedID = getImport().Beatmaps[expectedDiff - 1].OnlineID;
+ return Game.Beatmap.Value.BeatmapInfo.OnlineID == expectedID;
});
}
}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
index 4861354921..ee5a61f21f 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
@@ -507,13 +507,13 @@ namespace osu.Game.Tests.Visual.SongSelect
i.IsFiltered || i.Item.BeatmapInfo.Ruleset.ID == targetRuleset || i.Item.BeatmapInfo.Ruleset.ID == 0);
});
- AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmapInfo?.OnlineBeatmapID == target.OnlineBeatmapID);
- AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.OnlineBeatmapID == target.OnlineBeatmapID);
+ AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmapInfo?.OnlineID == target.OnlineID);
+ AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.OnlineID == target.OnlineID);
AddStep("reset filter text", () => songSelect.FilterControl.ChildrenOfType().First().Text = string.Empty);
- AddAssert("game still correct", () => Beatmap.Value?.BeatmapInfo.OnlineBeatmapID == target.OnlineBeatmapID);
- AddAssert("carousel still correct", () => songSelect.Carousel.SelectedBeatmapInfo.OnlineBeatmapID == target.OnlineBeatmapID);
+ AddAssert("game still correct", () => Beatmap.Value?.BeatmapInfo.OnlineID == target.OnlineID);
+ AddAssert("carousel still correct", () => songSelect.Carousel.SelectedBeatmapInfo.OnlineID == target.OnlineID);
}
[Test]
@@ -544,8 +544,8 @@ namespace osu.Game.Tests.Visual.SongSelect
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo != null);
- AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmapInfo?.OnlineBeatmapID == target.OnlineBeatmapID);
- AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.OnlineBeatmapID == target.OnlineBeatmapID);
+ AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmapInfo?.OnlineID == target.OnlineID);
+ AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.OnlineID == target.OnlineID);
AddStep("set filter text", () => songSelect.FilterControl.ChildrenOfType().First().Text = "nononoo");
@@ -918,8 +918,8 @@ namespace osu.Game.Tests.Visual.SongSelect
beatmaps.Add(new BeatmapInfo
{
Ruleset = getRuleset(),
- OnlineBeatmapID = beatmapId,
- Version = $"{beatmapId} (length {TimeSpan.FromMilliseconds(length):m\\:ss}, bpm {bpm:0.#})",
+ OnlineID = beatmapId,
+ DifficultyName = $"{beatmapId} (length {TimeSpan.FromMilliseconds(length):m\\:ss}, bpm {bpm:0.#})",
Length = length,
BPM = bpm,
BaseDifficulty = new BeatmapDifficulty
@@ -931,7 +931,7 @@ namespace osu.Game.Tests.Visual.SongSelect
return new BeatmapSetInfo
{
- OnlineBeatmapSetID = setId,
+ OnlineID = setId,
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
Metadata = new BeatmapMetadata
{
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
index 07759d598e..7353e47229 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
@@ -69,7 +69,7 @@ namespace osu.Game.Tests.Visual.UserInterface
Username = "TestAuthor"
},
},
- Version = "Insane"
+ DifficultyName = "Insane"
},
}
},
diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs
index ca63add31d..fd9d5a97c6 100644
--- a/osu.Game/Audio/PreviewTrackManager.cs
+++ b/osu.Game/Audio/PreviewTrackManager.cs
@@ -1,13 +1,8 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Audio;
-using osu.Framework.Audio.Mixing;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@@ -19,27 +14,26 @@ namespace osu.Game.Audio
{
public class PreviewTrackManager : Component
{
+ private readonly IAdjustableAudioComponent mainTrackAdjustments;
+
private readonly BindableDouble muteBindable = new BindableDouble();
[Resolved]
private AudioManager audio { get; set; }
- private PreviewTrackStore trackStore;
+ private ITrackStore trackStore;
protected TrackManagerPreviewTrack CurrentTrack;
- private readonly BindableNumber globalTrackVolumeAdjust = new BindableNumber(OsuGameBase.GLOBAL_TRACK_VOLUME_ADJUST);
+ public PreviewTrackManager(IAdjustableAudioComponent mainTrackAdjustments)
+ {
+ this.mainTrackAdjustments = mainTrackAdjustments;
+ }
[BackgroundDependencyLoader]
private void load(AudioManager audioManager)
{
- // this is a temporary solution to get around muting ourselves.
- // todo: update this once we have a BackgroundTrackManager or similar.
- trackStore = new PreviewTrackStore(audioManager.TrackMixer, new OnlineStore());
-
- audio.AddItem(trackStore);
- trackStore.AddAdjustment(AdjustableProperty.Volume, globalTrackVolumeAdjust);
- trackStore.AddAdjustment(AdjustableProperty.Volume, audio.VolumeTrack);
+ trackStore = audioManager.GetTrackStore(new OnlineStore());
}
///
@@ -55,7 +49,7 @@ namespace osu.Game.Audio
{
CurrentTrack?.Stop();
CurrentTrack = track;
- audio.Tracks.AddAdjustment(AdjustableProperty.Volume, muteBindable);
+ mainTrackAdjustments.AddAdjustment(AdjustableProperty.Volume, muteBindable);
});
track.Stopped += () => Schedule(() =>
@@ -64,7 +58,7 @@ namespace osu.Game.Audio
return;
CurrentTrack = null;
- audio.Tracks.RemoveAdjustment(AdjustableProperty.Volume, muteBindable);
+ mainTrackAdjustments.RemoveAdjustment(AdjustableProperty.Volume, muteBindable);
});
return track;
@@ -116,52 +110,5 @@ namespace osu.Game.Audio
protected override Track GetTrack() => trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo.OnlineID}.mp3");
}
-
- private class PreviewTrackStore : AudioCollectionManager, ITrackStore
- {
- private readonly AudioMixer defaultMixer;
- private readonly IResourceStore store;
-
- internal PreviewTrackStore(AudioMixer defaultMixer, IResourceStore store)
- {
- this.defaultMixer = defaultMixer;
- this.store = store;
- }
-
- public Track GetVirtual(double length = double.PositiveInfinity)
- {
- if (IsDisposed) throw new ObjectDisposedException($"Cannot retrieve items for an already disposed {nameof(PreviewTrackStore)}");
-
- var track = new TrackVirtual(length);
- AddItem(track);
- return track;
- }
-
- public Track Get(string name)
- {
- if (IsDisposed) throw new ObjectDisposedException($"Cannot retrieve items for an already disposed {nameof(PreviewTrackStore)}");
-
- if (string.IsNullOrEmpty(name)) return null;
-
- var dataStream = store.GetStream(name);
-
- if (dataStream == null)
- return null;
-
- // Todo: This is quite unsafe. TrackBass shouldn't be exposed as public.
- Track track = new TrackBass(dataStream);
-
- defaultMixer.Add(track);
- AddItem(track);
-
- return track;
- }
-
- public Task
-
+