diff --git a/osu.Android.props b/osu.Android.props
index a168d351fc..f1cbe1c9eb 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -51,7 +51,7 @@
-
+
diff --git a/osu.Game.Rulesets.Catch.Tests/CatchDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchDifficultyCalculatorTest.cs
index 7e8d567fbe..48d46636df 100644
--- a/osu.Game.Rulesets.Catch.Tests/CatchDifficultyCalculatorTest.cs
+++ b/osu.Game.Rulesets.Catch.Tests/CatchDifficultyCalculatorTest.cs
@@ -14,13 +14,13 @@ namespace osu.Game.Rulesets.Catch.Tests
{
protected override string ResourceAssembly => "osu.Game.Rulesets.Catch";
- [TestCase(4.0505463516206195d, "diffcalc-test")]
- public void Test(double expected, string name)
- => base.Test(expected, name);
+ [TestCase(4.0505463516206195d, 127, "diffcalc-test")]
+ public void Test(double expectedStarRating, int expectedMaxCombo, string name)
+ => base.Test(expectedStarRating, expectedMaxCombo, name);
- [TestCase(5.1696411260785498d, "diffcalc-test")]
- public void TestClockRateAdjusted(double expected, string name)
- => Test(expected, name, new CatchModDoubleTime());
+ [TestCase(5.1696411260785498d, 127, "diffcalc-test")]
+ public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name)
+ => Test(expectedStarRating, expectedMaxCombo, name, new CatchModDoubleTime());
protected override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new CatchDifficultyCalculator(new CatchRuleset().RulesetInfo, beatmap);
diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Mania.Tests/ManiaDifficultyCalculatorTest.cs
index 6ec49d7634..715614a201 100644
--- a/osu.Game.Rulesets.Mania.Tests/ManiaDifficultyCalculatorTest.cs
+++ b/osu.Game.Rulesets.Mania.Tests/ManiaDifficultyCalculatorTest.cs
@@ -14,13 +14,13 @@ namespace osu.Game.Rulesets.Mania.Tests
{
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
- [TestCase(2.3449735700206298d, "diffcalc-test")]
- public void Test(double expected, string name)
- => base.Test(expected, name);
+ [TestCase(2.3449735700206298d, 151, "diffcalc-test")]
+ public void Test(double expectedStarRating, int expectedMaxCombo, string name)
+ => base.Test(expectedStarRating, expectedMaxCombo, name);
- [TestCase(2.7879104989252959d, "diffcalc-test")]
- public void TestClockRateAdjusted(double expected, string name)
- => Test(expected, name, new ManiaModDoubleTime());
+ [TestCase(2.7879104989252959d, 151, "diffcalc-test")]
+ public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name)
+ => Test(expectedStarRating, expectedMaxCombo, name, new ManiaModDoubleTime());
protected override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new ManiaDifficultyCalculator(new ManiaRuleset().RulesetInfo, beatmap);
diff --git a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs
index b7984e6995..df577ea8d3 100644
--- a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs
+++ b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs
@@ -15,15 +15,20 @@ namespace osu.Game.Rulesets.Osu.Tests
{
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
- [TestCase(6.6972307565739273d, "diffcalc-test")]
- [TestCase(1.4484754139145539d, "zero-length-sliders")]
- public void Test(double expected, string name)
- => base.Test(expected, name);
+ [TestCase(6.6972307565739273d, 206, "diffcalc-test")]
+ [TestCase(1.4484754139145539d, 45, "zero-length-sliders")]
+ public void Test(double expectedStarRating, int expectedMaxCombo, string name)
+ => base.Test(expectedStarRating, expectedMaxCombo, name);
- [TestCase(8.9382559208689809d, "diffcalc-test")]
- [TestCase(1.7548875851757628d, "zero-length-sliders")]
- public void TestClockRateAdjusted(double expected, string name)
- => Test(expected, name, new OsuModDoubleTime());
+ [TestCase(8.9382559208689809d, 206, "diffcalc-test")]
+ [TestCase(1.7548875851757628d, 45, "zero-length-sliders")]
+ public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name)
+ => Test(expectedStarRating, expectedMaxCombo, name, new OsuModDoubleTime());
+
+ [TestCase(6.6972307218715166d, 239, "diffcalc-test")]
+ [TestCase(1.4484754139145537d, 54, "zero-length-sliders")]
+ public void TestClassicMod(double expectedStarRating, int expectedMaxCombo, string name)
+ => Test(expectedStarRating, expectedMaxCombo, name, new OsuModClassic());
protected override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new OsuDifficultyCalculator(new OsuRuleset().RulesetInfo, beatmap);
diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
index c5b1baaad1..df6fd19d36 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
@@ -61,10 +61,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
double preempt = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.ApproachRate, 1800, 1200, 450) / clockRate;
double drainRate = beatmap.Difficulty.DrainRate;
-
- int maxCombo = beatmap.HitObjects.Count;
- // Add the ticks + tail of the slider. 1 is subtracted because the head circle would be counted twice (once for the slider itself in the line above)
- maxCombo += beatmap.HitObjects.OfType().Sum(s => s.NestedHitObjects.Count - 1);
+ int maxCombo = beatmap.GetMaxCombo();
int hitCirclesCount = beatmap.HitObjects.Count(h => h is HitCircle);
int sliderCount = beatmap.HitObjects.Count(h => h is Slider);
diff --git a/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs
index 2b1cbc580e..226da7df09 100644
--- a/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs
@@ -14,15 +14,15 @@ namespace osu.Game.Rulesets.Taiko.Tests
{
protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko";
- [TestCase(2.2420075288523802d, "diffcalc-test")]
- [TestCase(2.2420075288523802d, "diffcalc-test-strong")]
- public void Test(double expected, string name)
- => base.Test(expected, name);
+ [TestCase(2.2420075288523802d, 200, "diffcalc-test")]
+ [TestCase(2.2420075288523802d, 200, "diffcalc-test-strong")]
+ public void Test(double expectedStarRating, int expectedMaxCombo, string name)
+ => base.Test(expectedStarRating, expectedMaxCombo, name);
- [TestCase(3.134084469440479d, "diffcalc-test")]
- [TestCase(3.134084469440479d, "diffcalc-test-strong")]
- public void TestClockRateAdjusted(double expected, string name)
- => Test(expected, name, new TaikoModDoubleTime());
+ [TestCase(3.134084469440479d, 200, "diffcalc-test")]
+ [TestCase(3.134084469440479d, 200, "diffcalc-test-strong")]
+ public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name)
+ => Test(expectedStarRating, expectedMaxCombo, name, new TaikoModDoubleTime());
protected override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new TaikoDifficultyCalculator(new TaikoRuleset().RulesetInfo, beatmap);
diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs
index f047c03f4b..1a1fde1990 100644
--- a/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs
@@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Objects
///
/// Default size of a drawable taiko hit object.
///
- public const float DEFAULT_SIZE = 0.45f;
+ public const float DEFAULT_SIZE = 0.475f;
public override Judgement CreateJudgement() => new TaikoJudgement();
diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs
index 6c17573b50..6e0f6a3109 100644
--- a/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs
@@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Objects
///
/// Scale multiplier for a strong drawable taiko hit object.
///
- public const float STRONG_SCALE = 1.4f;
+ public const float STRONG_SCALE = 1 / 0.65f;
///
/// Default size of a strong drawable taiko hit object.
diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs
index a106c4f629..f2452ad88c 100644
--- a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs
+++ b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs
@@ -11,6 +11,7 @@ using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers;
+using osu.Game.Rulesets.Taiko.Objects;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Taiko.Skinning.Default
@@ -24,8 +25,9 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default
///
public abstract class CirclePiece : BeatSyncedContainer, IHasAccentColour
{
- public const float SYMBOL_SIZE = 0.45f;
+ public const float SYMBOL_SIZE = TaikoHitObject.DEFAULT_SIZE;
public const float SYMBOL_BORDER = 8;
+
private const double pre_beat_transition_time = 80;
private Color4 accentColour;
diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyHitTarget.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyHitTarget.cs
index 9feb2054da..c4657fcc49 100644
--- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyHitTarget.cs
+++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyHitTarget.cs
@@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
new Sprite
{
Texture = skin.GetTexture("approachcircle"),
- Scale = new Vector2(0.73f),
+ Scale = new Vector2(0.83f),
Alpha = 0.47f, // eyeballed to match stable
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
new Sprite
{
Texture = skin.GetTexture("taikobigcircle"),
- Scale = new Vector2(0.7f),
+ Scale = new Vector2(0.8f),
Alpha = 0.22f, // eyeballed to match stable
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs
index cbd8b472b8..1231866b36 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs
@@ -13,6 +13,7 @@ using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets;
@@ -183,14 +184,41 @@ namespace osu.Game.Tests.Visual.Multiplayer
assertItemInHistoryListStep(2, 0);
}
+ [Test]
+ public void TestInsertedItemDoesNotRefreshAllOthers()
+ {
+ AddStep("change to round robin queue mode", () => MultiplayerClient.ChangeSettings(new MultiplayerRoomSettings { QueueMode = QueueMode.AllPlayersRoundRobin }).WaitSafely());
+
+ // Add a few items for the local user.
+ addItemStep();
+ addItemStep();
+ addItemStep();
+ addItemStep();
+ addItemStep();
+
+ DrawableRoomPlaylistItem[] drawableItems = null;
+ AddStep("get drawable items", () => drawableItems = this.ChildrenOfType().ToArray());
+
+ // Add 1 item for another user.
+ AddStep("join second user", () => MultiplayerClient.AddUser(new APIUser { Id = 10 }));
+ addItemStep(userId: 10);
+
+ // New item inserted towards the top of the list.
+ assertItemInQueueListStep(7, 1);
+ AddAssert("all previous playlist items remained", () => drawableItems.All(this.ChildrenOfType().Contains));
+ }
+
///
/// Adds a step to create a new playlist item.
///
- private void addItemStep(bool expired = false) => AddStep("add item", () => MultiplayerClient.AddPlaylistItem(new MultiplayerPlaylistItem(new PlaylistItem(importedBeatmap)
+ private void addItemStep(bool expired = false, int? userId = null) => AddStep("add item", () =>
{
- Expired = expired,
- PlayedAt = DateTimeOffset.Now
- })));
+ MultiplayerClient.AddUserPlaylistItem(userId ?? API.LocalUser.Value.OnlineID, new MultiplayerPlaylistItem(new PlaylistItem(importedBeatmap)
+ {
+ Expired = expired,
+ PlayedAt = DateTimeOffset.Now
+ })).WaitSafely();
+ });
///
/// Asserts the position of a given playlist item in the queue list.
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
index a0a1feff36..13404a9810 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
@@ -44,9 +44,6 @@ namespace osu.Game.Tests.Visual.UserInterface
private BeatmapInfo beatmapInfo;
- [Resolved]
- private RealmAccess realm { get; set; }
-
[Cached]
private readonly DialogOverlay dialogOverlay;
@@ -92,6 +89,12 @@ namespace osu.Game.Tests.Visual.UserInterface
dependencies.Cache(scoreManager = new ScoreManager(dependencies.Get(), () => beatmapManager, LocalStorage, Realm, Scheduler));
Dependencies.Cache(Realm);
+ return dependencies;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load() => Schedule(() =>
+ {
var imported = beatmapManager.Import(new ImportTask(TestResources.GetQuickTestBeatmapForImport())).GetResultSafely();
imported?.PerformRead(s =>
@@ -115,26 +118,26 @@ namespace osu.Game.Tests.Visual.UserInterface
importedScores.Add(scoreManager.Import(score).Value);
}
});
-
- return dependencies;
- }
-
- [SetUp]
- public void Setup() => Schedule(() =>
- {
- realm.Run(r =>
- {
- // Due to soft deletions, we can re-use deleted scores between test runs
- scoreManager.Undelete(r.All().Where(s => s.DeletePending).ToList());
- });
-
- leaderboard.BeatmapInfo = beatmapInfo;
- leaderboard.RefetchScores(); // Required in the case that the beatmap hasn't changed
});
[SetUpSteps]
public void SetupSteps()
{
+ AddUntilStep("ensure scores imported", () => importedScores.Count == 50);
+ AddStep("undelete scores", () =>
+ {
+ Realm.Run(r =>
+ {
+ // Due to soft deletions, we can re-use deleted scores between test runs
+ scoreManager.Undelete(r.All().Where(s => s.DeletePending).ToList());
+ });
+ });
+ AddStep("set up leaderboard", () =>
+ {
+ leaderboard.BeatmapInfo = beatmapInfo;
+ leaderboard.RefetchScores(); // Required in the case that the beatmap hasn't changed
+ });
+
// Ensure the leaderboard items have finished showing up
AddStep("finish transforms", () => leaderboard.FinishTransforms(true));
AddUntilStep("wait for drawables", () => leaderboard.ChildrenOfType().Any());
@@ -169,11 +172,14 @@ namespace osu.Game.Tests.Visual.UserInterface
AddStep("click delete button", () =>
{
InputManager.MoveMouseTo(dialogOverlay.ChildrenOfType().First());
- InputManager.Click(MouseButton.Left);
+ InputManager.PressButton(MouseButton.Left);
});
AddUntilStep("wait for fetch", () => leaderboard.Scores != null);
AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineID != scoreBeingDeleted.OnlineID));
+
+ // "Clean up"
+ AddStep("release left mouse button", () => InputManager.ReleaseButton(MouseButton.Left));
}
[Test]
diff --git a/osu.Game/Beatmaps/IBeatmap.cs b/osu.Game/Beatmaps/IBeatmap.cs
index 3f598cd1e5..dec1ef4294 100644
--- a/osu.Game/Beatmaps/IBeatmap.cs
+++ b/osu.Game/Beatmaps/IBeatmap.cs
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Beatmaps.Timing;
using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Scoring;
namespace osu.Game.Beatmaps
{
@@ -70,4 +71,27 @@ namespace osu.Game.Beatmaps
///
new IReadOnlyList HitObjects { get; }
}
+
+ public static class BeatmapExtensions
+ {
+ ///
+ /// Finds the maximum achievable combo by hitting all s in a beatmap.
+ ///
+ public static int GetMaxCombo(this IBeatmap beatmap)
+ {
+ int combo = 0;
+ foreach (var h in beatmap.HitObjects)
+ addCombo(h, ref combo);
+ return combo;
+
+ static void addCombo(HitObject hitObject, ref int combo)
+ {
+ if (hitObject.CreateJudgement().MaxResult.AffectsCombo())
+ combo++;
+
+ foreach (var nested in hitObject.NestedHitObjects)
+ addCombo(nested, ref combo);
+ }
+ }
+ }
}
diff --git a/osu.Game/Configuration/SettingSourceAttribute.cs b/osu.Game/Configuration/SettingSourceAttribute.cs
index 4111a67b24..89f0e73f4f 100644
--- a/osu.Game/Configuration/SettingSourceAttribute.cs
+++ b/osu.Game/Configuration/SettingSourceAttribute.cs
@@ -88,6 +88,7 @@ namespace osu.Game.Configuration
throw new InvalidOperationException($"{nameof(SettingSourceAttribute)} had an unsupported custom control type ({controlType.ReadableName()})");
var control = (Drawable)Activator.CreateInstance(controlType);
+ controlType.GetProperty(nameof(SettingsItem
-
+