diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 1b06aa4d17..6444127594 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -14,8 +14,8 @@
"jb"
]
},
- "smoogipoo.nvika": {
- "version": "1.0.3",
+ "nvika": {
+ "version": "2.2.0",
"commands": [
"nvika"
]
diff --git a/Directory.Build.props b/Directory.Build.props
index 53ad973e47..894ea25c8b 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -16,7 +16,7 @@
-
+
diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj
index e28053d0ca..e9b92be0c3 100644
--- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj
+++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
index 027bd0b7e2..e145dd7b69 100644
--- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
+++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj
index e2c715d385..a301432a6c 100644
--- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj
+++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
index 027bd0b7e2..e145dd7b69 100644
--- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
+++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/osu.Android.props b/osu.Android.props
index dec994bcb2..6d2e8428a7 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,7 +52,7 @@
-
+
diff --git a/osu.Android/OsuGameActivity.cs b/osu.Android/OsuGameActivity.cs
index 0bcbfc4baf..fec96c9165 100644
--- a/osu.Android/OsuGameActivity.cs
+++ b/osu.Android/OsuGameActivity.cs
@@ -20,6 +20,7 @@ namespace osu.Android
[Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.FullUser, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, HardwareAccelerated = false, LaunchMode = LaunchMode.SingleInstance, Exported = true)]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osz", DataHost = "*", DataMimeType = "*/*")]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osk", DataHost = "*", DataMimeType = "*/*")]
+ [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osr", DataHost = "*", DataMimeType = "*/*")]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataMimeType = "application/x-osu-beatmap-archive")]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataMimeType = "application/x-osu-skin-archive")]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataMimeType = "application/x-osu-replay")]
diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
index 6457ec92da..4c8b9b2b08 100644
--- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
+++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
@@ -2,7 +2,7 @@
-
+
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs b/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs
index f1b51e51d0..6f3e6763bd 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs
@@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Catch.Mods
{
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList mods) => new Score
{
- ScoreInfo = new ScoreInfo { User = new User { Username = "osu!salad!" } },
+ ScoreInfo = new ScoreInfo { User = new User { Username = "osu!salad" } },
Replay = new CatchAutoGenerator(beatmap).Generate(),
};
}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModCinema.cs b/osu.Game.Rulesets.Catch/Mods/CatchModCinema.cs
index d53d019e90..1b7d254321 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModCinema.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModCinema.cs
@@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Catch.Mods
{
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList mods) => new Score
{
- ScoreInfo = new ScoreInfo { User = new User { Username = "osu!salad!" } },
+ ScoreInfo = new ScoreInfo { User = new User { Username = "osu!salad" } },
Replay = new CatchAutoGenerator(beatmap).Generate(),
};
}
diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
index 674a22df98..fad39ef9d6 100644
--- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
+++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
@@ -2,7 +2,7 @@
-
+
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModAutoplay.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModAutoplay.cs
index 6ae854e7f3..86f667466f 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModAutoplay.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModAutoplay.cs
@@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList mods) => new Score
{
- ScoreInfo = new ScoreInfo { User = new User { Username = "osu!topus!" } },
+ ScoreInfo = new ScoreInfo { User = new User { Username = "osu!topus" } },
Replay = new ManiaAutoGenerator((ManiaBeatmap)beatmap).Generate(),
};
}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModCinema.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModCinema.cs
index 064c55ed8d..1c06bb389b 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModCinema.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModCinema.cs
@@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList mods) => new Score
{
- ScoreInfo = new ScoreInfo { User = new User { Username = "osu!topus!" } },
+ ScoreInfo = new ScoreInfo { User = new User { Username = "osu!topus" } },
Replay = new ManiaAutoGenerator((ManiaBeatmap)beatmap).Generate(),
};
}
diff --git a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs
index 15675e74d1..7cd06c5225 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.5867229481955389d, "diffcalc-test")]
- [TestCase(1.0416315570967911d, "zero-length-sliders")]
+ [TestCase(6.5295339534769958d, "diffcalc-test")]
+ [TestCase(1.1514260533755143d, "zero-length-sliders")]
public void Test(double expected, string name)
=> base.Test(expected, name);
- [TestCase(8.2730989071947896d, "diffcalc-test")]
- [TestCase(1.2726413186221039d, "zero-length-sliders")]
+ [TestCase(9.047752485219954d, "diffcalc-test")]
+ [TestCase(1.3985711787077566d, "zero-length-sliders")]
public void TestClockRateAdjusted(double expected, string name)
=> Test(expected, name, new OsuModDoubleTime());
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneNoSpinnerStacking.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneNoSpinnerStacking.cs
new file mode 100644
index 0000000000..ef05bcd320
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneNoSpinnerStacking.cs
@@ -0,0 +1,34 @@
+// 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.Game.Beatmaps;
+using osu.Game.Rulesets.Osu.Objects;
+using osuTK;
+
+namespace osu.Game.Rulesets.Osu.Tests
+{
+ [TestFixture]
+ public class TestSceneNoSpinnerStacking : TestSceneOsuPlayer
+ {
+ protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
+ {
+ var beatmap = new Beatmap
+ {
+ BeatmapInfo = new BeatmapInfo
+ {
+ BaseDifficulty = new BeatmapDifficulty { OverallDifficulty = 10 },
+ Ruleset = ruleset
+ }
+ };
+
+ for (int i = 0; i < 512; i++)
+ {
+ if (i % 32 < 20)
+ beatmap.HitObjects.Add(new Spinner { Position = new Vector2(256, 192), StartTime = i * 200, EndTime = (i * 200) + 100 });
+ }
+
+ return beatmap;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
index f5f1159542..66f4ad3d3f 100644
--- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
+++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
@@ -2,7 +2,7 @@
-
+
diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs
index 49ac6a7af3..4b90285fd4 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs
@@ -12,20 +12,21 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
{
public class OsuDifficultyHitObject : DifficultyHitObject
{
- private const int normalized_radius = 52;
+ 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;
protected new OsuHitObject BaseObject => (OsuHitObject)base.BaseObject;
- ///
- /// Milliseconds elapsed since the start time of the previous , with a minimum of 25ms to account for simultaneous s.
- ///
- public double StrainTime { get; private set; }
-
///
/// Normalized distance from the end position of the previous to the start position of this .
///
public double JumpDistance { get; private set; }
+ ///
+ /// Minimum distance from the end position of the previous to the start position of this .
+ ///
+ public double MovementDistance { get; private set; }
+
///
/// Normalized distance between the start and end position of the previous .
///
@@ -37,6 +38,21 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
///
public double? Angle { get; private set; }
+ ///
+ /// Milliseconds elapsed since the end time of the previous , with a minimum of 25ms.
+ ///
+ public double MovementTime { get; private set; }
+
+ ///
+ /// Milliseconds elapsed since the start time of the previous to the end time of the same previous , with a minimum of 25ms.
+ ///
+ public double TravelTime { get; private set; }
+
+ ///
+ /// Milliseconds elapsed since the start time of the previous , with a minimum of 25ms.
+ ///
+ public readonly double StrainTime;
+
private readonly OsuHitObject lastLastObject;
private readonly OsuHitObject lastObject;
@@ -46,13 +62,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
this.lastLastObject = (OsuHitObject)lastLastObject;
this.lastObject = (OsuHitObject)lastObject;
- setDistances();
+ // Capped to 25ms to prevent difficulty calculation breaking from simultaneous objects.
+ StrainTime = Math.Max(DeltaTime, min_delta_time);
- // Capped to 25ms to prevent difficulty calculation breaking from simulatenous objects.
- StrainTime = Math.Max(DeltaTime, 25);
+ setDistances(clockRate);
}
- private void setDistances()
+ private void setDistances(double clockRate)
{
// We don't need to calculate either angle or distance when one of the last->curr objects is a spinner
if (BaseObject is Spinner || lastObject is Spinner)
@@ -67,15 +83,29 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
scalingFactor *= 1 + smallCircleBonus;
}
+ Vector2 lastCursorPosition = getEndCursorPosition(lastObject);
+ JumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length;
+
if (lastObject is Slider lastSlider)
{
computeSliderCursorPosition(lastSlider);
TravelDistance = lastSlider.LazyTravelDistance * scalingFactor;
+ TravelTime = Math.Max(lastSlider.LazyTravelTime / clockRate, min_delta_time);
+ MovementTime = Math.Max(StrainTime - TravelTime, min_delta_time);
+
+ // Jump distance from the slider tail to the next object, as opposed to the lazy position of JumpDistance.
+ float tailJumpDistance = Vector2.Subtract(lastSlider.TailCircle.StackedPosition, BaseObject.StackedPosition).Length * scalingFactor;
+
+ // For hitobjects which continue in the direction of the slider, the player will normally follow through the slider,
+ // such that they're not jumping from the lazy position but rather from very close to (or the end of) the slider.
+ // In such cases, a leniency is applied by also considering the jump distance from the tail of the slider, and taking the minimum jump distance.
+ MovementDistance = Math.Min(JumpDistance, tailJumpDistance);
+ }
+ else
+ {
+ MovementTime = StrainTime;
+ MovementDistance = JumpDistance;
}
-
- Vector2 lastCursorPosition = getEndCursorPosition(lastObject);
-
- JumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length;
if (lastLastObject != null && !(lastLastObject is Spinner))
{
@@ -98,7 +128,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
slider.LazyEndPosition = slider.StackedPosition;
- float approxFollowCircleRadius = (float)(slider.Radius * 3);
+ float followCircleRadius = (float)(slider.Radius * 2.4);
var computeVertex = new Action(t =>
{
double progress = (t - slider.StartTime) / slider.SpanDuration;
@@ -111,11 +141,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
var diff = slider.StackedPosition + slider.Path.PositionAt(progress) - slider.LazyEndPosition.Value;
float dist = diff.Length;
- if (dist > approxFollowCircleRadius)
+ slider.LazyTravelTime = t - slider.StartTime;
+
+ if (dist > followCircleRadius)
{
// The cursor would be outside the follow circle, we need to move it
diff.Normalize(); // Obtain direction of diff
- dist -= approxFollowCircleRadius;
+ dist -= followCircleRadius;
slider.LazyEndPosition += diff * dist;
slider.LazyTravelDistance += dist;
}
diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs
index 64ca567a15..a054b46366 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs
@@ -14,53 +14,96 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
///
public class Aim : OsuStrainSkill
{
- private const double angle_bonus_begin = Math.PI / 3;
- private const double timing_threshold = 107;
-
public Aim(Mod[] mods)
: base(mods)
{
}
+ protected override int HistoryLength => 2;
+
+ private const double wide_angle_multiplier = 1.5;
+ private const double acute_angle_multiplier = 2.0;
+
private double currentStrain = 1;
- private double skillMultiplier => 26.25;
+ private double skillMultiplier => 23.25;
private double strainDecayBase => 0.15;
private double strainValueOf(DifficultyHitObject current)
{
- if (current.BaseObject is Spinner)
+ if (current.BaseObject is Spinner || Previous.Count <= 1 || Previous[0].BaseObject is Spinner)
return 0;
- var osuCurrent = (OsuDifficultyHitObject)current;
+ var osuCurrObj = (OsuDifficultyHitObject)current;
+ var osuLastObj = (OsuDifficultyHitObject)Previous[0];
+ var osuLastLastObj = (OsuDifficultyHitObject)Previous[1];
- double aimStrain = 0;
+ // Calculate the velocity to the current hitobject, which starts with a base distance / time assuming the last object is a hitcircle.
+ double currVelocity = osuCurrObj.JumpDistance / osuCurrObj.StrainTime;
- if (Previous.Count > 0)
+ // 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)
{
- var osuPrevious = (OsuDifficultyHitObject)Previous[0];
+ 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.
- if (osuCurrent.Angle != null && osuCurrent.Angle.Value > angle_bonus_begin)
+ currVelocity = Math.Max(currVelocity, movementVelocity + travelVelocity); // take the larger total combined velocity.
+ }
+
+ // As above, do the same for the previous hitobject.
+ double prevVelocity = osuLastObj.JumpDistance / osuLastObj.StrainTime;
+
+ if (osuLastLastObj.BaseObject is Slider)
+ {
+ double movementVelocity = osuLastObj.MovementDistance / osuLastObj.MovementTime;
+ double travelVelocity = osuLastObj.TravelDistance / osuLastObj.TravelTime;
+
+ prevVelocity = Math.Max(prevVelocity, movementVelocity + travelVelocity);
+ }
+
+ double angleBonus = 0;
+ double aimStrain = currVelocity; // Start strain with regular velocity.
+
+ if (Math.Max(osuCurrObj.StrainTime, osuLastObj.StrainTime) < 1.25 * Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime)) // If rhythms are the same.
+ {
+ if (osuCurrObj.Angle != null && osuLastObj.Angle != null && osuLastLastObj.Angle != null)
{
- const double scale = 90;
+ double currAngle = osuCurrObj.Angle.Value;
+ double lastAngle = osuLastObj.Angle.Value;
+ double lastLastAngle = osuLastLastObj.Angle.Value;
- double angleBonus = Math.Sqrt(
- Math.Max(osuPrevious.JumpDistance - scale, 0)
- * Math.Pow(Math.Sin(osuCurrent.Angle.Value - angle_bonus_begin), 2)
- * Math.Max(osuCurrent.JumpDistance - scale, 0));
- aimStrain = 1.4 * applyDiminishingExp(Math.Max(0, angleBonus)) / Math.Max(timing_threshold, osuPrevious.StrainTime);
+ // Rewarding angles, take the smaller velocity as base.
+ angleBonus = Math.Min(currVelocity, prevVelocity);
+
+ double wideAngleBonus = calcWideAngleBonus(currAngle);
+ double acuteAngleBonus = calcAcuteAngleBonus(currAngle);
+
+ if (osuCurrObj.StrainTime > 100) // Only buff deltaTime exceeding 300 bpm 1/2.
+ acuteAngleBonus = 0;
+ else
+ {
+ acuteAngleBonus *= calcAcuteAngleBonus(lastAngle) // Multiply by previous angle, we don't want to buff unless this is a wiggle type pattern.
+ * Math.Min(angleBonus, 125 / osuCurrObj.StrainTime) // The maximum velocity we buff is equal to 125 / strainTime
+ * Math.Pow(Math.Sin(Math.PI / 2 * Math.Min(1, (100 - osuCurrObj.StrainTime) / 25)), 2) // scale buff from 150 bpm 1/4 to 200 bpm 1/4
+ * Math.Pow(Math.Sin(Math.PI / 2 * (Math.Clamp(osuCurrObj.JumpDistance, 50, 100) - 50) / 50), 2); // Buff distance exceeding 50 (radius) up to 100 (diameter).
+ }
+
+ wideAngleBonus *= angleBonus * (1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3))); // Penalize wide angles if they're repeated, reducing the penalty as the lastAngle gets more acute.
+ acuteAngleBonus *= 0.5 + 0.5 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastLastAngle), 3))); // Penalize acute angles if they're repeated, reducing the penalty as the lastLastAngle gets more obtuse.
+
+ angleBonus = acuteAngleBonus * acute_angle_multiplier + wideAngleBonus * wide_angle_multiplier; // add the angle buffs together.
}
}
- double jumpDistanceExp = applyDiminishingExp(osuCurrent.JumpDistance);
- double travelDistanceExp = applyDiminishingExp(osuCurrent.TravelDistance);
+ aimStrain += angleBonus; // Add in angle bonus.
- return Math.Max(
- aimStrain + (jumpDistanceExp + travelDistanceExp + Math.Sqrt(travelDistanceExp * jumpDistanceExp)) / Math.Max(osuCurrent.StrainTime, timing_threshold),
- (Math.Sqrt(travelDistanceExp * jumpDistanceExp) + jumpDistanceExp + travelDistanceExp) / osuCurrent.StrainTime
- );
+ return aimStrain;
}
+ private double calcWideAngleBonus(double angle) => Math.Pow(Math.Sin(3.0 / 4 * (Math.Min(5.0 / 6 * Math.PI, Math.Max(Math.PI / 6, angle)) - Math.PI / 6)), 2);
+
+ private double calcAcuteAngleBonus(double angle) => 1 - calcWideAngleBonus(angle);
+
private double applyDiminishingExp(double val) => Math.Pow(val, 0.99);
private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000);
diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs
index 7c45b2bc07..8b7de9e109 100644
--- a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs
+++ b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs
@@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Osu.Objects
set => StackHeightBindable.Value = value;
}
- public Vector2 StackOffset => new Vector2(StackHeight * Scale * -6.4f);
+ public virtual Vector2 StackOffset => new Vector2(StackHeight * Scale * -6.4f);
public double Radius => OBJECT_RADIUS * Scale;
diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs
index 9b2babb9ff..5c1c3fd253 100644
--- a/osu.Game.Rulesets.Osu/Objects/Slider.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs
@@ -79,6 +79,12 @@ namespace osu.Game.Rulesets.Osu.Objects
///
internal float LazyTravelDistance;
+ ///
+ /// The time taken by the cursor upon completion of this if it was hit
+ /// with as few movements as possible. This is set and used by difficulty calculation.
+ ///
+ internal double LazyTravelTime;
+
public IList> NodeSamples { get; set; } = new List>();
[JsonIgnore]
diff --git a/osu.Game.Rulesets.Osu/Objects/Spinner.cs b/osu.Game.Rulesets.Osu/Objects/Spinner.cs
index f85dc0d391..0ad8e4ea68 100644
--- a/osu.Game.Rulesets.Osu/Objects/Spinner.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Spinner.cs
@@ -8,6 +8,7 @@ using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Scoring;
+using osuTK;
namespace osu.Game.Rulesets.Osu.Objects
{
@@ -31,6 +32,8 @@ namespace osu.Game.Rulesets.Osu.Objects
///
public int MaximumBonusSpins { get; protected set; } = 1;
+ public override Vector2 StackOffset => Vector2.Zero;
+
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, IBeatmapDifficultyInfo difficulty)
{
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
index b9b295767e..568e35c221 100644
--- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
+++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
@@ -2,7 +2,7 @@
-
+
diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
index d37e09aa29..7a95856c36 100644
--- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
+++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
@@ -673,6 +673,8 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.That(first.ControlPoints[1].Position, Is.EqualTo(new Vector2(161, -244)));
Assert.That(first.ControlPoints[1].Type, Is.EqualTo(null));
+ // ReSharper disable once HeuristicUnreachableCode
+ // weird one, see https://youtrack.jetbrains.com/issue/RIDER-70159.
Assert.That(first.ControlPoints[2].Position, Is.EqualTo(new Vector2(376, -3)));
Assert.That(first.ControlPoints[2].Type, Is.EqualTo(PathType.Bezier));
Assert.That(first.ControlPoints[3].Position, Is.EqualTo(new Vector2(68, 15)));
diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
index 935194db58..d68d43c998 100644
--- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
+++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
@@ -846,6 +846,42 @@ namespace osu.Game.Tests.Beatmaps.IO
}
}
+ // TODO: needs to be pulled across to realm implementation when this file is nuked.
+ [Test]
+ public void TestSaveRemovesInvalidCharactersFromPath()
+ {
+ // unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
+ using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
+ {
+ try
+ {
+ var osu = LoadOsuIntoHost(host);
+
+ var manager = osu.Dependencies.Get();
+
+ var working = manager.CreateNew(new OsuRuleset().RulesetInfo, User.SYSTEM_USER);
+
+ var beatmap = working.Beatmap;
+
+ beatmap.BeatmapInfo.Version = "difficulty";
+ beatmap.BeatmapInfo.Metadata = new BeatmapMetadata
+ {
+ Artist = "Artist/With\\Slashes",
+ Title = "Title",
+ AuthorString = "mapper",
+ };
+
+ manager.Save(beatmap.BeatmapInfo, working.Beatmap);
+
+ Assert.AreEqual("Artist_With_Slashes - Title (mapper) [difficulty].osu", beatmap.BeatmapInfo.Path);
+ }
+ finally
+ {
+ host.Exit();
+ }
+ }
+ }
+
[Test]
public void TestCreateNewEmptyBeatmap()
{
diff --git a/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs b/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs
index 39fbf11d51..e22dfa5f8b 100644
--- a/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs
+++ b/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs
@@ -35,7 +35,7 @@ namespace osu.Game.Tests.Editing.Checks
public void TestMissing()
{
// While this is a problem, it is out of scope for this check and is caught by a different one.
- beatmap.Metadata.AudioFile = null;
+ beatmap.Metadata.AudioFile = string.Empty;
var mock = new Mock();
mock.SetupGet(w => w.Beatmap).Returns(beatmap);
diff --git a/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs b/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs
index 3424cfe732..2918dde2db 100644
--- a/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs
+++ b/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs
@@ -53,7 +53,7 @@ namespace osu.Game.Tests.Editing.Checks
public void TestMissing()
{
// While this is a problem, it is out of scope for this check and is caught by a different one.
- beatmap.Metadata.BackgroundFile = null;
+ beatmap.Metadata.BackgroundFile = string.Empty;
var context = getContext(null, System.Array.Empty());
Assert.That(check.Run(context), Is.Empty);
diff --git a/osu.Game.Tests/Editing/Checks/CheckFilePresenceTest.cs b/osu.Game.Tests/Editing/Checks/CheckFilePresenceTest.cs
index 39a1d76d83..70e4c76b19 100644
--- a/osu.Game.Tests/Editing/Checks/CheckFilePresenceTest.cs
+++ b/osu.Game.Tests/Editing/Checks/CheckFilePresenceTest.cs
@@ -65,7 +65,7 @@ namespace osu.Game.Tests.Editing.Checks
[Test]
public void TestBackgroundNotSet()
{
- beatmap.Metadata.BackgroundFile = null;
+ beatmap.Metadata.BackgroundFile = string.Empty;
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
var issues = check.Run(context).ToList();
diff --git a/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs b/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs
index 42a3b4cf43..9ce7e0a0e0 100644
--- a/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs
+++ b/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs
@@ -39,8 +39,8 @@ namespace osu.Game.Tests.NonVisual
[Test]
public void TestCheckNullID()
{
- var ourInfo = new BeatmapSetInfo { Status = BeatmapSetOnlineStatus.Loved };
- var otherInfo = new BeatmapSetInfo { Status = BeatmapSetOnlineStatus.Approved };
+ var ourInfo = new BeatmapSetInfo { Hash = "1" };
+ var otherInfo = new BeatmapSetInfo { Hash = "2" };
Assert.AreNotEqual(ourInfo, otherInfo);
}
diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs
index ed86daf8b6..41939cec3f 100644
--- a/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs
+++ b/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs
@@ -189,7 +189,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
public void TestCriteriaMatchingArtistWithNullUnicodeName(string artistName, bool filtered)
{
var exampleBeatmapInfo = getExampleBeatmap();
- exampleBeatmapInfo.Metadata.ArtistUnicode = null;
+ exampleBeatmapInfo.Metadata.ArtistUnicode = string.Empty;
var criteria = new FilterCriteria
{
diff --git a/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs b/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs
index c8848ab7d8..656e333073 100644
--- a/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs
+++ b/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs
@@ -1,6 +1,7 @@
// 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 Newtonsoft.Json;
using NUnit.Framework;
@@ -67,9 +68,11 @@ namespace osu.Game.Tests.Online
var deserialised = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(apiMod));
var converted = (TestModTimeRamp)deserialised?.ToMod(new TestRuleset());
- Assert.That(converted?.AdjustPitch.Value, Is.EqualTo(false));
- Assert.That(converted?.InitialRate.Value, Is.EqualTo(1.25));
- Assert.That(converted?.FinalRate.Value, Is.EqualTo(0.25));
+ Assert.That(converted, Is.Not.Null);
+
+ Assert.That(converted.AdjustPitch.Value, Is.EqualTo(false));
+ Assert.That(converted.InitialRate.Value, Is.EqualTo(1.25));
+ Assert.That(converted.FinalRate.Value, Is.EqualTo(0.25));
}
[Test]
@@ -121,11 +124,11 @@ namespace osu.Game.Tests.Online
new TestModDifficultyAdjust()
};
- public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => throw new System.NotImplementedException();
+ public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => throw new NotImplementedException();
- public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new System.NotImplementedException();
+ public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new NotImplementedException();
- public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => throw new System.NotImplementedException();
+ public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => throw new NotImplementedException();
public override string Description { get; } = string.Empty;
public override string ShortName { get; } = string.Empty;
diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
index c75714032e..ecc9c92025 100644
--- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
+++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
@@ -38,6 +38,15 @@ namespace osu.Game.Tests.Skins.IO
assertCorrectMetadata(import1, "test skin [skin]", "skinner", osu);
});
+ [Test]
+ public Task TestSingleImportMissingSectionHeader() => runSkinTest(async osu =>
+ {
+ var import1 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni("test skin", "skinner", includeSectionHeader: false), "skin.osk"));
+
+ // When the import filename doesn't match, it should be appended (and update the skin.ini).
+ assertCorrectMetadata(import1, "test skin [skin]", "skinner", osu);
+ });
+
[Test]
public Task TestSingleImportMatchingFilename() => runSkinTest(async osu =>
{
@@ -199,21 +208,23 @@ namespace osu.Game.Tests.Skins.IO
return zipStream;
}
- private MemoryStream createOskWithIni(string name, string author, bool makeUnique = false, string iniFilename = @"skin.ini")
+ private MemoryStream createOskWithIni(string name, string author, bool makeUnique = false, string iniFilename = @"skin.ini", bool includeSectionHeader = true)
{
var zipStream = new MemoryStream();
using var zip = ZipArchive.Create();
- zip.AddEntry(iniFilename, generateSkinIni(name, author, makeUnique));
+ zip.AddEntry(iniFilename, generateSkinIni(name, author, makeUnique, includeSectionHeader));
zip.SaveTo(zipStream);
return zipStream;
}
- private MemoryStream generateSkinIni(string name, string author, bool makeUnique = true)
+ private MemoryStream generateSkinIni(string name, string author, bool makeUnique = true, bool includeSectionHeader = true)
{
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
- writer.WriteLine("[General]");
+ if (includeSectionHeader)
+ writer.WriteLine("[General]");
+
writer.WriteLine($"Name: {name}");
writer.WriteLine($"Author: {author}");
diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs
new file mode 100644
index 0000000000..2aeb4ab4e2
--- /dev/null
+++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs
@@ -0,0 +1,181 @@
+// 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.Linq;
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.Drawables.Cards;
+using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Overlays;
+using osu.Game.Users;
+using osuTK;
+
+namespace osu.Game.Tests.Visual.Beatmaps
+{
+ public class TestSceneBeatmapCard : OsuTestScene
+ {
+ private APIBeatmapSet[] testCases;
+
+ #region Test case generation
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ var normal = CreateAPIBeatmapSet(Ruleset.Value);
+ normal.HasVideo = true;
+ normal.HasStoryboard = true;
+
+ var undownloadable = getUndownloadableBeatmapSet();
+
+ var someDifficulties = getManyDifficultiesBeatmapSet(11);
+ someDifficulties.Title = someDifficulties.TitleUnicode = "some difficulties";
+ someDifficulties.Status = BeatmapSetOnlineStatus.Qualified;
+
+ var manyDifficulties = getManyDifficultiesBeatmapSet(100);
+ manyDifficulties.Status = BeatmapSetOnlineStatus.Pending;
+
+ var explicitMap = CreateAPIBeatmapSet(Ruleset.Value);
+ explicitMap.HasExplicitContent = true;
+
+ var featuredMap = CreateAPIBeatmapSet(Ruleset.Value);
+ featuredMap.TrackId = 1;
+
+ var explicitFeaturedMap = CreateAPIBeatmapSet(Ruleset.Value);
+ explicitFeaturedMap.HasExplicitContent = true;
+ explicitFeaturedMap.TrackId = 2;
+
+ var longName = CreateAPIBeatmapSet(Ruleset.Value);
+ longName.Title = longName.TitleUnicode = "this track has an incredibly and implausibly long title";
+ longName.Artist = longName.ArtistUnicode = "and this artist! who would have thunk it. it's really such a long name.";
+ longName.HasExplicitContent = true;
+ longName.TrackId = 444;
+
+ testCases = new[]
+ {
+ normal,
+ undownloadable,
+ someDifficulties,
+ manyDifficulties,
+ explicitMap,
+ featuredMap,
+ explicitFeaturedMap,
+ longName
+ };
+ }
+
+ private APIBeatmapSet getUndownloadableBeatmapSet() => new APIBeatmapSet
+ {
+ OnlineID = 123,
+ Title = "undownloadable beatmap",
+ Artist = "test",
+ Source = "more tests",
+ Author = new User
+ {
+ Username = "BanchoBot",
+ Id = 3,
+ },
+ Availability = new BeatmapSetOnlineAvailability
+ {
+ DownloadDisabled = true,
+ },
+ Preview = @"https://b.ppy.sh/preview/12345.mp3",
+ PlayCount = 123,
+ FavouriteCount = 456,
+ BPM = 111,
+ HasVideo = true,
+ HasStoryboard = true,
+ Covers = new BeatmapSetOnlineCovers(),
+ Beatmaps = new[]
+ {
+ new APIBeatmap
+ {
+ RulesetID = Ruleset.Value.OnlineID,
+ DifficultyName = "Test",
+ StarRating = 6.42,
+ }
+ }
+ };
+
+ private static APIBeatmapSet getManyDifficultiesBeatmapSet(int count)
+ {
+ var beatmaps = new List();
+
+ for (int i = 0; i < count; i++)
+ {
+ beatmaps.Add(new APIBeatmap
+ {
+ RulesetID = i % 4,
+ StarRating = 2 + i % 4 * 2,
+ });
+ }
+
+ return new APIBeatmapSet
+ {
+ OnlineID = 1,
+ Title = "many difficulties beatmap",
+ Artist = "test",
+ Author = new User
+ {
+ Username = "BanchoBot",
+ Id = 3,
+ },
+ HasVideo = true,
+ HasStoryboard = true,
+ Covers = new BeatmapSetOnlineCovers(),
+ Beatmaps = beatmaps.ToArray(),
+ };
+ }
+
+ #endregion
+
+ private Drawable createContent(OverlayColourScheme colourScheme, Func creationFunc)
+ {
+ var colourProvider = new OverlayColourProvider(colourScheme);
+
+ return new DependencyProvidingContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ CachedDependencies = new (Type, object)[]
+ {
+ (typeof(OverlayColourProvider), colourProvider)
+ },
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = colourProvider.Background5
+ },
+ new BasicScrollContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Child = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Full,
+ Padding = new MarginPadding(10),
+ Spacing = new Vector2(10),
+ ChildrenEnumerable = testCases.Select(creationFunc)
+ }
+ }
+ }
+ };
+ }
+
+ private void createTestCase(Func creationFunc)
+ {
+ foreach (var scheme in Enum.GetValues(typeof(OverlayColourScheme)).Cast())
+ AddStep($"set {scheme} scheme", () => Child = createContent(scheme, creationFunc));
+ }
+
+ [Test]
+ public void TestNormal() => createTestCase(beatmapSetInfo => new BeatmapCard(beatmapSetInfo));
+ }
+}
diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultySpectrumDisplay.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultySpectrumDisplay.cs
index 1f38b05879..4063fa1252 100644
--- a/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultySpectrumDisplay.cs
+++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultySpectrumDisplay.cs
@@ -21,7 +21,7 @@ namespace osu.Game.Tests.Visual.Beatmaps
{
RulesetID = difficulty.rulesetId,
StarRating = difficulty.stars
- }).ToList()
+ }).ToArray()
};
[Test]
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneComposerSelection.cs b/osu.Game.Tests/Visual/Editing/TestSceneComposerSelection.cs
index a2a7b72283..dddd9f07ab 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneComposerSelection.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneComposerSelection.cs
@@ -5,7 +5,10 @@ using System;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Testing;
+using osu.Framework.Graphics.Cursor;
+using osu.Framework.Graphics.UserInterface;
using osu.Game.Beatmaps;
+using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu;
@@ -29,6 +32,9 @@ namespace osu.Game.Tests.Visual.Editing
private ComposeBlueprintContainer blueprintContainer
=> Editor.ChildrenOfType().First();
+ private ContextMenuContainer contextMenuContainer
+ => Editor.ChildrenOfType().First();
+
private void moveMouseToObject(Func targetFunc)
{
AddStep("move mouse to object", () =>
@@ -42,6 +48,19 @@ namespace osu.Game.Tests.Visual.Editing
});
}
+ [Test]
+ public void TestSelectAndShowContextMenu()
+ {
+ var addedObject = new HitCircle { StartTime = 100, Position = new Vector2(100, 100) };
+ AddStep("add hitobject", () => EditorBeatmap.Add(addedObject));
+
+ moveMouseToObject(() => addedObject);
+ AddStep("right click", () => InputManager.Click(MouseButton.Right));
+
+ AddUntilStep("hitobject selected", () => EditorBeatmap.SelectedHitObjects.Single() == addedObject);
+ AddUntilStep("context menu is visible", () => contextMenuContainer.ChildrenOfType().Single().State == MenuState.Open);
+ }
+
[Test]
public void TestNudgeSelection()
{
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneMetadataSection.cs b/osu.Game.Tests/Visual/Editing/TestSceneMetadataSection.cs
index 19081f3281..4621436cc6 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneMetadataSection.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneMetadataSection.cs
@@ -23,10 +23,10 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("set metadata", () =>
{
editorBeatmap.Metadata.Artist = "Example Artist";
- editorBeatmap.Metadata.ArtistUnicode = null;
+ editorBeatmap.Metadata.ArtistUnicode = string.Empty;
editorBeatmap.Metadata.Title = "Example Title";
- editorBeatmap.Metadata.TitleUnicode = null;
+ editorBeatmap.Metadata.TitleUnicode = string.Empty;
});
createSection();
@@ -44,10 +44,10 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("set metadata", () =>
{
editorBeatmap.Metadata.ArtistUnicode = "*なみりん";
- editorBeatmap.Metadata.Artist = null;
+ editorBeatmap.Metadata.Artist = string.Empty;
editorBeatmap.Metadata.TitleUnicode = "コイシテイク・プラネット";
- editorBeatmap.Metadata.Title = null;
+ editorBeatmap.Metadata.Title = string.Empty;
});
createSection();
@@ -86,10 +86,10 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("set metadata", () =>
{
editorBeatmap.Metadata.ArtistUnicode = "*なみりん";
- editorBeatmap.Metadata.Artist = null;
+ editorBeatmap.Metadata.Artist = string.Empty;
editorBeatmap.Metadata.TitleUnicode = "コイシテイク・プラネット";
- editorBeatmap.Metadata.Title = null;
+ editorBeatmap.Metadata.Title = string.Empty;
});
createSection();
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs
index 311c3ddc03..64d9addc77 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs
@@ -136,7 +136,7 @@ namespace osu.Game.Tests.Visual.Gameplay
return new APIScoreInfo
{
OnlineID = 2553163309,
- OnlineRulesetID = 0,
+ RulesetID = 0,
Beatmap = CreateAPIBeatmapSet(new OsuRuleset().RulesetInfo).Beatmaps.First(),
HasReplay = replayAvailable,
User = new User
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecording.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecording.cs
index 3545fc96e8..08578168d6 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecording.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecording.cs
@@ -54,7 +54,7 @@ namespace osu.Game.Tests.Visual.Gameplay
ScoreInfo = { BeatmapInfo = gameplayState.Beatmap.BeatmapInfo }
})
{
- ScreenSpaceToGamefield = pos => recordingManager.ToLocalSpace(pos)
+ ScreenSpaceToGamefield = pos => recordingManager?.ToLocalSpace(pos) ?? Vector2.Zero,
},
Child = new Container
{
@@ -84,7 +84,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{
ReplayInputHandler = new TestFramedReplayInputHandler(replay)
{
- GamefieldToScreenSpace = pos => playbackManager.ToScreenSpace(pos),
+ GamefieldToScreenSpace = pos => playbackManager?.ToScreenSpace(pos) ?? Vector2.Zero,
},
Child = new Container
{
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs
index 22ff2b98ce..84a6e95883 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs
@@ -67,6 +67,36 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
}),
createLoungeRoom(new Room
+ {
+ Name = { Value = "Multiplayer room" },
+ Status = { Value = new RoomStatusOpen() },
+ EndDate = { Value = DateTimeOffset.Now.AddDays(1) },
+ Type = { Value = MatchType.HeadToHead },
+ Playlist =
+ {
+ new PlaylistItem
+ {
+ Beatmap =
+ {
+ Value = new TestBeatmap(new OsuRuleset().RulesetInfo)
+ {
+ BeatmapInfo =
+ {
+ StarDifficulty = 2.5,
+ Metadata =
+ {
+ Artist = "very very very very very very very very very long artist",
+ ArtistUnicode = "very very very very very very very very very long artist",
+ Title = "very very very very very very very very very very very long title",
+ TitleUnicode = "very very very very very very very very very very very long title",
+ }
+ }
+ }.BeatmapInfo,
+ }
+ }
+ }
+ }),
+ createLoungeRoom(new Room
{
Name = { Value = "Playlist room with multiple beatmaps" },
Status = { Value = new RoomStatusPlaying() },
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs
index 69d68f163e..b587fd03bd 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
@@ -223,11 +224,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestDownloadButtonVisibleInitiallyWhenBeatmapDoesNotExist()
{
- var byOnlineId = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo;
- byOnlineId.BeatmapSet.OnlineBeatmapSetID = 1337; // Some random ID that does not exist locally.
+ var byOnlineId = CreateAPIBeatmap();
+ byOnlineId.OnlineID = 1337; // Some random ID that does not exist locally.
- var byChecksum = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo;
- byChecksum.MD5Hash = "1337"; // Some random checksum that does not exist locally.
+ var byChecksum = CreateAPIBeatmap();
+ byChecksum.Checksum = "1337"; // Some random checksum that does not exist locally.
createPlaylist(byOnlineId, byChecksum);
@@ -237,8 +238,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestExplicitBeatmapItem()
{
- var beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo;
- beatmap.BeatmapSet.OnlineInfo.HasExplicitContent = true;
+ var beatmap = CreateAPIBeatmap();
+
+ Debug.Assert(beatmap.BeatmapSet != null);
+
+ beatmap.BeatmapSet.HasExplicitContent = true;
createPlaylist(beatmap);
}
@@ -355,7 +359,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep("wait for items to load", () => playlist.ItemMap.Values.All(i => i.IsLoaded));
}
- private void createPlaylist(params BeatmapInfo[] beatmaps)
+ private void createPlaylist(params IBeatmapInfo[] beatmaps)
{
AddStep("create playlist", () =>
{
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs
index 11caf9f498..38cf9d662f 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs
@@ -231,6 +231,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
}
});
+
+ AddAssert("Check participant count correct", () => client.APIRoom?.ParticipantCount.Value == 1);
+ AddAssert("Check participant list contains user", () => client.APIRoom?.RecentParticipants.Count(u => u.Id == API.LocalUser.Value.Id) == 1);
}
[Test]
@@ -290,6 +293,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep("wait for room open", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true);
AddUntilStep("wait for join", () => client.Room != null);
+
+ AddAssert("Check participant count correct", () => client.APIRoom?.ParticipantCount.Value == 1);
+ AddAssert("Check participant list contains user", () => client.APIRoom?.RecentParticipants.Count(u => u.Id == API.LocalUser.Value.Id) == 1);
}
[Test]
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs
index e50b150f94..2549681519 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs
@@ -45,11 +45,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
[Test]
- public void TestAddNullUser()
+ public void TestAddUnresolvedUser()
{
AddAssert("one unique panel", () => this.ChildrenOfType().Select(p => p.User).Distinct().Count() == 1);
- AddStep("add non-resolvable user", () => Client.AddNullUser());
+ AddStep("add non-resolvable user", () => Client.TestAddUnresolvedUser());
AddAssert("null user added", () => Client.Room.AsNonNull().Users.Count(u => u.User == null) == 1);
AddUntilStep("two unique panels", () => this.ChildrenOfType().Select(p => p.User).Distinct().Count() == 2);
diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapAvailability.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapAvailability.cs
index 6f9744ca73..176e0592ef 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapAvailability.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapAvailability.cs
@@ -21,15 +21,12 @@ namespace osu.Game.Tests.Visual.Online
[Test]
public void TestUndownloadableWithLink()
{
- AddStep("set undownloadable beatmapset with link", () => container.BeatmapSet = new BeatmapSetInfo
+ AddStep("set undownloadable beatmapset with link", () => container.BeatmapSet = new APIBeatmapSet
{
- OnlineInfo = new APIBeatmapSet
+ Availability = new BeatmapSetOnlineAvailability
{
- Availability = new BeatmapSetOnlineAvailability
- {
- DownloadDisabled = true,
- ExternalLink = @"https://osu.ppy.sh",
- },
+ DownloadDisabled = true,
+ ExternalLink = @"https://osu.ppy.sh",
},
});
@@ -39,14 +36,11 @@ namespace osu.Game.Tests.Visual.Online
[Test]
public void TestUndownloadableNoLink()
{
- AddStep("set undownloadable beatmapset without link", () => container.BeatmapSet = new BeatmapSetInfo
+ AddStep("set undownloadable beatmapset without link", () => container.BeatmapSet = new APIBeatmapSet
{
- OnlineInfo = new APIBeatmapSet
+ Availability = new BeatmapSetOnlineAvailability
{
- Availability = new BeatmapSetOnlineAvailability
- {
- DownloadDisabled = true,
- },
+ DownloadDisabled = true,
},
});
@@ -56,15 +50,12 @@ namespace osu.Game.Tests.Visual.Online
[Test]
public void TestPartsRemovedWithLink()
{
- AddStep("set parts-removed beatmapset with link", () => container.BeatmapSet = new BeatmapSetInfo
+ AddStep("set parts-removed beatmapset with link", () => container.BeatmapSet = new APIBeatmapSet
{
- OnlineInfo = new APIBeatmapSet
+ Availability = new BeatmapSetOnlineAvailability
{
- Availability = new BeatmapSetOnlineAvailability
- {
- DownloadDisabled = false,
- ExternalLink = @"https://osu.ppy.sh",
- },
+ DownloadDisabled = false,
+ ExternalLink = @"https://osu.ppy.sh",
},
});
@@ -74,14 +65,11 @@ namespace osu.Game.Tests.Visual.Online
[Test]
public void TestNormal()
{
- AddStep("set normal beatmapset", () => container.BeatmapSet = new BeatmapSetInfo
+ AddStep("set normal beatmapset", () => container.BeatmapSet = new APIBeatmapSet
{
- OnlineInfo = new APIBeatmapSet
+ Availability = new BeatmapSetOnlineAvailability
{
- Availability = new BeatmapSetOnlineAvailability
- {
- DownloadDisabled = false,
- },
+ DownloadDisabled = false,
},
});
diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs
index eb34187cd6..90f3eb64e4 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs
@@ -1,15 +1,14 @@
// 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.Allocation;
using osu.Framework.Graphics.UserInterface;
-using osu.Game.Beatmaps;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
using osu.Game.Overlays.BeatmapSet;
using osu.Game.Rulesets;
-using System.Collections.Generic;
-using System.Linq;
namespace osu.Game.Tests.Visual.Online
{
@@ -35,9 +34,9 @@ namespace osu.Game.Tests.Visual.Online
AddStep("load multiple rulesets beatmapset", () =>
{
- selector.BeatmapSet = new BeatmapSetInfo
+ selector.BeatmapSet = new APIBeatmapSet
{
- Beatmaps = enabledRulesets.Select(r => new BeatmapInfo { Ruleset = r }).ToList()
+ Beatmaps = enabledRulesets.Select(r => new APIBeatmap { RulesetID = r.OnlineID }).ToArray()
};
});
@@ -53,13 +52,13 @@ namespace osu.Game.Tests.Visual.Online
AddStep("load single ruleset beatmapset", () =>
{
- selector.BeatmapSet = new BeatmapSetInfo
+ selector.BeatmapSet = new APIBeatmapSet
{
- Beatmaps = new List
+ Beatmaps = new[]
{
- new BeatmapInfo
+ new APIBeatmap
{
- Ruleset = enabledRuleset
+ RulesetID = enabledRuleset.OnlineID
}
}
};
@@ -71,10 +70,7 @@ namespace osu.Game.Tests.Visual.Online
[Test]
public void TestEmptyBeatmapSet()
{
- AddStep("load empty beatmapset", () => selector.BeatmapSet = new BeatmapSetInfo
- {
- Beatmaps = new List()
- });
+ AddStep("load empty beatmapset", () => selector.BeatmapSet = new APIBeatmapSet());
AddAssert("no ruleset selected", () => selector.SelectedTab == null);
AddAssert("all rulesets disabled", () => selector.TabContainer.TabItems.All(t => !t.Enabled.Value));
diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs
index 7f9b56e873..63ce057667 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs
@@ -49,60 +49,48 @@ namespace osu.Game.Tests.Visual.Online
{
AddStep(@"show first", () =>
{
- overlay.ShowBeatmapSet(new BeatmapSetInfo
+ overlay.ShowBeatmapSet(new APIBeatmapSet
{
- OnlineBeatmapSetID = 1235,
- Metadata = new BeatmapMetadata
+ OnlineID = 1235,
+ Title = @"an awesome beatmap",
+ Artist = @"naru narusegawa",
+ Source = @"hinata sou",
+ Tags = @"test tag tag more tag",
+ Author = new User
{
- Title = @"an awesome beatmap",
- Artist = @"naru narusegawa",
- Source = @"hinata sou",
- Tags = @"test tag tag more tag",
- Author = new User
- {
- Username = @"BanchoBot",
- Id = 3,
- },
+ Username = @"BanchoBot",
+ Id = 3,
},
- OnlineInfo = new APIBeatmapSet
+ Preview = @"https://b.ppy.sh/preview/12345.mp3",
+ PlayCount = 123,
+ FavouriteCount = 456,
+ Submitted = DateTime.Now,
+ Ranked = DateTime.Now,
+ BPM = 111,
+ HasVideo = true,
+ Ratings = Enumerable.Range(0, 11).ToArray(),
+ HasStoryboard = true,
+ Covers = new BeatmapSetOnlineCovers(),
+ Beatmaps = new[]
{
- Preview = @"https://b.ppy.sh/preview/12345.mp3",
- PlayCount = 123,
- FavouriteCount = 456,
- Submitted = DateTime.Now,
- Ranked = DateTime.Now,
- BPM = 111,
- HasVideo = true,
- Ratings = Enumerable.Range(0, 11).ToArray(),
- HasStoryboard = true,
- Covers = new BeatmapSetOnlineCovers(),
- },
- Beatmaps = new List
- {
- new BeatmapInfo
+ new APIBeatmap
{
- StarDifficulty = 9.99,
- Version = @"TEST",
+ StarRating = 9.99,
+ DifficultyName = @"TEST",
Length = 456000,
- Ruleset = rulesets.GetRuleset(3),
- BaseDifficulty = new BeatmapDifficulty
+ RulesetID = 3,
+ CircleSize = 1,
+ DrainRate = 2.3f,
+ OverallDifficulty = 4.5f,
+ ApproachRate = 6,
+ CircleCount = 111,
+ SliderCount = 12,
+ PlayCount = 222,
+ PassCount = 21,
+ FailTimes = new APIFailTimes
{
- CircleSize = 1,
- DrainRate = 2.3f,
- OverallDifficulty = 4.5f,
- ApproachRate = 6,
- },
- OnlineInfo = new APIBeatmap
- {
- CircleCount = 111,
- SliderCount = 12,
- PlayCount = 222,
- PassCount = 21,
- FailTimes = new APIFailTimes
- {
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
- },
+ Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
+ Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
},
},
},
@@ -120,71 +108,15 @@ namespace osu.Game.Tests.Visual.Online
{
AddStep(@"show undownloadable", () =>
{
- overlay.ShowBeatmapSet(new BeatmapSetInfo
+ var set = getBeatmapSet();
+
+ set.Availability = new BeatmapSetOnlineAvailability
{
- OnlineBeatmapSetID = 1234,
- Metadata = new BeatmapMetadata
- {
- Title = @"undownloadable beatmap",
- Artist = @"no one",
- Source = @"some source",
- Tags = @"another test tag tag more test tags",
- Author = new User
- {
- Username = @"BanchoBot",
- Id = 3,
- },
- },
- OnlineInfo = new APIBeatmapSet
- {
- Availability = new BeatmapSetOnlineAvailability
- {
- DownloadDisabled = true,
- ExternalLink = "https://osu.ppy.sh",
- },
- Preview = @"https://b.ppy.sh/preview/1234.mp3",
- PlayCount = 123,
- FavouriteCount = 456,
- Submitted = DateTime.Now,
- Ranked = DateTime.Now,
- BPM = 111,
- HasVideo = true,
- HasStoryboard = true,
- Covers = new BeatmapSetOnlineCovers(),
- Language = new BeatmapSetOnlineLanguage { Id = 3, Name = "English" },
- Genre = new BeatmapSetOnlineGenre { Id = 4, Name = "Rock" },
- Ratings = Enumerable.Range(0, 11).ToArray(),
- },
- Beatmaps = new List
- {
- new BeatmapInfo
- {
- StarDifficulty = 5.67,
- Version = @"ANOTHER TEST",
- Length = 123000,
- Ruleset = rulesets.GetRuleset(1),
- BaseDifficulty = new BeatmapDifficulty
- {
- CircleSize = 9,
- DrainRate = 8,
- OverallDifficulty = 7,
- ApproachRate = 6,
- },
- OnlineInfo = new APIBeatmap
- {
- CircleCount = 123,
- SliderCount = 45,
- PlayCount = 567,
- PassCount = 89,
- FailTimes = new APIFailTimes
- {
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
- },
- },
- },
- },
- });
+ DownloadDisabled = true,
+ ExternalLink = "https://osu.ppy.sh",
+ };
+
+ overlay.ShowBeatmapSet(set);
});
downloadAssert(false);
@@ -195,48 +127,30 @@ namespace osu.Game.Tests.Visual.Online
{
AddStep("show multiple rulesets beatmap", () =>
{
- var beatmaps = new List();
+ var beatmaps = new List();
foreach (var ruleset in rulesets.AvailableRulesets.Skip(1))
{
- beatmaps.Add(new BeatmapInfo
+ beatmaps.Add(new APIBeatmap
{
- Version = ruleset.Name,
- Ruleset = ruleset,
- BaseDifficulty = new BeatmapDifficulty(),
- OnlineInfo = new APIBeatmap
+ DifficultyName = ruleset.Name,
+ RulesetID = ruleset.OnlineID,
+ FailTimes = new APIFailTimes
{
- FailTimes = new APIFailTimes
- {
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
- },
- }
+ Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
+ Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
+ },
});
}
- overlay.ShowBeatmapSet(new BeatmapSetInfo
- {
- Metadata = new BeatmapMetadata
- {
- Title = @"multiple rulesets beatmap",
- Artist = @"none",
- Author = new User
- {
- Username = "BanchoBot",
- Id = 3,
- }
- },
- OnlineInfo = new APIBeatmapSet
- {
- Covers = new BeatmapSetOnlineCovers(),
- Ratings = Enumerable.Range(0, 11).ToArray(),
- },
- Beatmaps = beatmaps
- });
+ var set = getBeatmapSet();
+
+ set.Beatmaps = beatmaps.ToArray();
+
+ overlay.ShowBeatmapSet(set);
});
- AddAssert("shown beatmaps of current ruleset", () => overlay.Header.HeaderContent.Picker.Difficulties.All(b => b.BeatmapInfo.Ruleset.Equals(overlay.Header.RulesetSelector.Current.Value)));
+ AddAssert("shown beatmaps of current ruleset", () => overlay.Header.HeaderContent.Picker.Difficulties.All(b => b.Beatmap.Ruleset.OnlineID == overlay.Header.RulesetSelector.Current.Value.OnlineID));
AddAssert("left-most beatmap selected", () => overlay.Header.HeaderContent.Picker.Difficulties.First().State == BeatmapPicker.DifficultySelectorState.Selected);
}
@@ -246,7 +160,7 @@ namespace osu.Game.Tests.Visual.Online
AddStep("show explicit map", () =>
{
var beatmapSet = getBeatmapSet();
- beatmapSet.OnlineInfo.HasExplicitContent = true;
+ beatmapSet.HasExplicitContent = true;
overlay.ShowBeatmapSet(beatmapSet);
});
}
@@ -257,7 +171,7 @@ namespace osu.Game.Tests.Visual.Online
AddStep("show featured map", () =>
{
var beatmapSet = getBeatmapSet();
- beatmapSet.OnlineInfo.TrackId = 1;
+ beatmapSet.TrackId = 1;
overlay.ShowBeatmapSet(beatmapSet);
});
}
@@ -274,63 +188,41 @@ namespace osu.Game.Tests.Visual.Online
AddStep(@"show without reload", overlay.Show);
}
- private BeatmapSetInfo createManyDifficultiesBeatmapSet()
+ private APIBeatmapSet createManyDifficultiesBeatmapSet()
{
- var beatmaps = new List();
+ var set = getBeatmapSet();
+
+ var beatmaps = new List();
for (int i = 1; i < 41; i++)
{
- beatmaps.Add(new BeatmapInfo
+ beatmaps.Add(new APIBeatmap
{
- OnlineBeatmapID = i * 10,
- Version = $"Test #{i}",
- Ruleset = Ruleset.Value,
- StarDifficulty = 2 + i * 0.1,
- BaseDifficulty = new BeatmapDifficulty
+ OnlineID = i * 10,
+ DifficultyName = $"Test #{i}",
+ RulesetID = Ruleset.Value.ID ?? -1,
+ StarRating = 2 + i * 0.1,
+ OverallDifficulty = 3.5f,
+ FailTimes = new APIFailTimes
{
- OverallDifficulty = 3.5f,
+ Fails = Enumerable.Range(1, 100).Select(j => j % 12 - 6).ToArray(),
+ Retries = Enumerable.Range(-2, 100).Select(j => j % 12 - 6).ToArray(),
},
- OnlineInfo = new APIBeatmap
- {
- FailTimes = new APIFailTimes
- {
- Fails = Enumerable.Range(1, 100).Select(j => j % 12 - 6).ToArray(),
- Retries = Enumerable.Range(-2, 100).Select(j => j % 12 - 6).ToArray(),
- },
- }
});
}
- return new BeatmapSetInfo
- {
- OnlineBeatmapSetID = 123,
- Metadata = new BeatmapMetadata
- {
- Title = @"many difficulties beatmap",
- Artist = @"none",
- Author = new User
- {
- Username = @"BanchoBot",
- Id = 3,
- },
- },
- OnlineInfo = new APIBeatmapSet
- {
- Preview = @"https://b.ppy.sh/preview/123.mp3",
- HasVideo = true,
- HasStoryboard = true,
- Covers = new BeatmapSetOnlineCovers(),
- Ratings = Enumerable.Range(0, 11).ToArray(),
- },
- Beatmaps = beatmaps,
- };
+ set.Beatmaps = beatmaps.ToArray();
+
+ return set;
}
- private BeatmapSetInfo getBeatmapSet()
+ private APIBeatmapSet getBeatmapSet()
{
- var beatmapSet = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet;
+ var beatmapSet = CreateAPIBeatmapSet(Ruleset.Value);
+
// Make sure the overlay is reloaded (see `BeatmapSetInfo.Equals`).
- beatmapSet.OnlineBeatmapSetID = nextBeatmapSetId++;
+ beatmapSet.OnlineID = nextBeatmapSetId++;
+
return beatmapSet;
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs
index d14f9f47d1..9c0c67b1d8 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs
@@ -1,7 +1,6 @@
// 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.Framework.Allocation;
@@ -44,27 +43,21 @@ namespace osu.Game.Tests.Visual.Online
AddStep("set second set", () => details.BeatmapSet = secondSet);
AddAssert("ratings set", () => details.Ratings.Ratings == secondSet.Ratings);
- static BeatmapSetInfo createSet() => new BeatmapSetInfo
+ static APIBeatmapSet createSet() => new APIBeatmapSet
{
- Beatmaps = new List
+ Beatmaps = new[]
{
- new BeatmapInfo
+ new APIBeatmap
{
- OnlineInfo = new APIBeatmap
+ FailTimes = new APIFailTimes
{
- FailTimes = new APIFailTimes
- {
- Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(),
- Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(),
- },
- }
+ Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(),
+ Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(),
+ },
}
},
- OnlineInfo = new APIBeatmapSet
- {
- Ratings = Enumerable.Range(0, 11).Select(_ => RNG.Next(10)).ToArray(),
- Status = BeatmapSetOnlineStatus.Ranked
- }
+ Ratings = Enumerable.Range(0, 11).Select(_ => RNG.Next(10)).ToArray(),
+ Status = BeatmapSetOnlineStatus.Ranked
};
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs
index b3b67fcbca..be3fc7aff9 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs
@@ -59,21 +59,18 @@ namespace osu.Game.Tests.Visual.Online
var firstBeatmap = createBeatmap();
var secondBeatmap = createBeatmap();
- AddStep("set first set", () => successRate.BeatmapInfo = firstBeatmap);
+ AddStep("set first set", () => successRate.Beatmap = firstBeatmap);
AddAssert("ratings set", () => successRate.Graph.FailTimes == firstBeatmap.FailTimes);
- AddStep("set second set", () => successRate.BeatmapInfo = secondBeatmap);
+ AddStep("set second set", () => successRate.Beatmap = secondBeatmap);
AddAssert("ratings set", () => successRate.Graph.FailTimes == secondBeatmap.FailTimes);
- static BeatmapInfo createBeatmap() => new BeatmapInfo
+ static APIBeatmap createBeatmap() => new APIBeatmap
{
- OnlineInfo = new APIBeatmap
+ FailTimes = new APIFailTimes
{
- FailTimes = new APIFailTimes
- {
- Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(),
- Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(),
- }
+ Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(),
+ Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(),
}
};
}
@@ -81,14 +78,11 @@ namespace osu.Game.Tests.Visual.Online
[Test]
public void TestOnlyFailMetrics()
{
- AddStep("set beatmap", () => successRate.BeatmapInfo = new BeatmapInfo
+ AddStep("set beatmap", () => successRate.Beatmap = new APIBeatmap
{
- OnlineInfo = new APIBeatmap
+ FailTimes = new APIFailTimes
{
- FailTimes = new APIFailTimes
- {
- Fails = Enumerable.Range(1, 100).ToArray(),
- }
+ Fails = Enumerable.Range(1, 100).ToArray(),
}
});
@@ -98,12 +92,9 @@ namespace osu.Game.Tests.Visual.Online
[Test]
public void TestEmptyMetrics()
{
- AddStep("set beatmap", () => successRate.BeatmapInfo = new BeatmapInfo
+ AddStep("set beatmap", () => successRate.Beatmap = new APIBeatmap
{
- OnlineInfo = new APIBeatmap
- {
- FailTimes = new APIFailTimes(),
- }
+ FailTimes = new APIFailTimes()
});
AddAssert("graph max values correct", () => successRate.ChildrenOfType().All(graph => graph.MaxValue == 0));
diff --git a/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs b/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs
index bb7fcc2fce..3d828077c8 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs
@@ -9,7 +9,6 @@ using osu.Game.Beatmaps;
using osu.Game.Online;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.BeatmapListing.Panels;
-using osu.Game.Rulesets.Osu;
using osu.Game.Tests.Resources;
using osuTK;
@@ -69,24 +68,7 @@ namespace osu.Game.Tests.Visual.Online
AddAssert($"button {(enabled ? "enabled" : "disabled")}", () => downloadButton.DownloadEnabled == enabled);
}
- private BeatmapSetInfo createSoleily()
- {
- return new BeatmapSetInfo
- {
- ID = 1,
- OnlineBeatmapSetID = 241526,
- OnlineInfo = new APIBeatmapSet
- {
- Availability = new BeatmapSetOnlineAvailability
- {
- DownloadDisabled = false,
- ExternalLink = string.Empty,
- },
- },
- };
- }
-
- private void createButtonWithBeatmap(BeatmapSetInfo beatmap)
+ private void createButtonWithBeatmap(IBeatmapSetInfo beatmap)
{
AddStep("create button", () =>
{
@@ -112,32 +94,47 @@ namespace osu.Game.Tests.Visual.Online
});
}
- private BeatmapSetInfo getDownloadableBeatmapSet()
+ private IBeatmapSetInfo createSoleily()
{
- var normal = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo).BeatmapSetInfo;
- normal.OnlineInfo.HasVideo = true;
- normal.OnlineInfo.HasStoryboard = true;
-
- return normal;
+ return new APIBeatmapSet
+ {
+ OnlineID = 241526,
+ Availability = new BeatmapSetOnlineAvailability
+ {
+ DownloadDisabled = false,
+ ExternalLink = string.Empty,
+ },
+ };
}
- private BeatmapSetInfo getUndownloadableBeatmapSet()
+ private IBeatmapSetInfo getDownloadableBeatmapSet()
{
- var beatmap = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo).BeatmapSetInfo;
- beatmap.Metadata.Artist = "test";
- beatmap.Metadata.Title = "undownloadable";
- beatmap.Metadata.AuthorString = "test";
+ var apiBeatmapSet = CreateAPIBeatmapSet();
- beatmap.OnlineInfo.HasVideo = true;
- beatmap.OnlineInfo.HasStoryboard = true;
+ apiBeatmapSet.HasVideo = true;
+ apiBeatmapSet.HasStoryboard = true;
- beatmap.OnlineInfo.Availability = new BeatmapSetOnlineAvailability
+ return apiBeatmapSet;
+ }
+
+ private IBeatmapSetInfo getUndownloadableBeatmapSet()
+ {
+ var apiBeatmapSet = CreateAPIBeatmapSet();
+
+ apiBeatmapSet.Artist = "test";
+ apiBeatmapSet.Title = "undownloadable";
+ apiBeatmapSet.AuthorString = "test";
+
+ apiBeatmapSet.HasVideo = true;
+ apiBeatmapSet.HasStoryboard = true;
+
+ apiBeatmapSet.Availability = new BeatmapSetOnlineAvailability
{
DownloadDisabled = true,
ExternalLink = "http://osu.ppy.sh",
};
- return beatmap;
+ return apiBeatmapSet;
}
private class TestDownloadButton : BeatmapPanelDownloadButton
@@ -146,7 +143,7 @@ namespace osu.Game.Tests.Visual.Online
public DownloadState DownloadState => State.Value;
- public TestDownloadButton(BeatmapSetInfo beatmapSet)
+ public TestDownloadButton(IBeatmapSetInfo beatmapSet)
: base(beatmapSet)
{
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs
index 6caca2a67c..a3c8935fa8 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs
@@ -18,104 +18,25 @@ namespace osu.Game.Tests.Visual.Online
[Cached(typeof(IPreviewTrackOwner))]
public class TestSceneDirectPanel : OsuTestScene, IPreviewTrackOwner
{
- private BeatmapSetInfo getUndownloadableBeatmapSet() => new BeatmapSetInfo
- {
- OnlineBeatmapSetID = 123,
- Metadata = new BeatmapMetadata
- {
- Title = "undownloadable beatmap",
- Artist = "test",
- Source = "more tests",
- Author = new User
- {
- Username = "BanchoBot",
- Id = 3,
- },
- },
- OnlineInfo = new APIBeatmapSet
- {
- Availability = new BeatmapSetOnlineAvailability
- {
- DownloadDisabled = true,
- },
- Preview = @"https://b.ppy.sh/preview/12345.mp3",
- PlayCount = 123,
- FavouriteCount = 456,
- BPM = 111,
- HasVideo = true,
- HasStoryboard = true,
- Covers = new BeatmapSetOnlineCovers(),
- },
- Beatmaps = new List
- {
- new BeatmapInfo
- {
- Ruleset = Ruleset.Value,
- Version = "Test",
- StarDifficulty = 6.42,
- }
- }
- };
-
- private BeatmapSetInfo getManyDifficultiesBeatmapSet(RulesetStore rulesets)
- {
- var beatmaps = new List();
-
- for (int i = 0; i < 100; i++)
- {
- beatmaps.Add(new BeatmapInfo
- {
- Ruleset = rulesets.GetRuleset(i % 4),
- StarDifficulty = 2 + i % 4 * 2,
- BaseDifficulty = new BeatmapDifficulty
- {
- OverallDifficulty = 3.5f,
- }
- });
- }
-
- return new BeatmapSetInfo
- {
- OnlineBeatmapSetID = 1,
- Metadata = new BeatmapMetadata
- {
- Title = "many difficulties beatmap",
- Artist = "test",
- Author = new User
- {
- Username = "BanchoBot",
- Id = 3,
- }
- },
- OnlineInfo = new APIBeatmapSet
- {
- HasVideo = true,
- HasStoryboard = true,
- Covers = new BeatmapSetOnlineCovers(),
- },
- Beatmaps = beatmaps,
- };
- }
-
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
{
var normal = getBeatmapSet();
- normal.OnlineInfo.HasVideo = true;
- normal.OnlineInfo.HasStoryboard = true;
+ normal.HasVideo = true;
+ normal.HasStoryboard = true;
var undownloadable = getUndownloadableBeatmapSet();
- var manyDifficulties = getManyDifficultiesBeatmapSet(rulesets);
+ var manyDifficulties = getManyDifficultiesBeatmapSet();
var explicitMap = getBeatmapSet();
- explicitMap.OnlineInfo.HasExplicitContent = true;
+ explicitMap.HasExplicitContent = true;
var featuredMap = getBeatmapSet();
- featuredMap.OnlineInfo.TrackId = 1;
+ featuredMap.TrackId = 1;
var explicitFeaturedMap = getBeatmapSet();
- explicitFeaturedMap.OnlineInfo.HasExplicitContent = true;
- explicitFeaturedMap.OnlineInfo.TrackId = 2;
+ explicitFeaturedMap.HasExplicitContent = true;
+ explicitFeaturedMap.TrackId = 2;
Child = new BasicScrollContainer
{
@@ -145,7 +66,72 @@ namespace osu.Game.Tests.Visual.Online
},
};
- BeatmapSetInfo getBeatmapSet() => CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet;
+ APIBeatmapSet getBeatmapSet() => CreateAPIBeatmapSet(Ruleset.Value);
+
+ APIBeatmapSet getUndownloadableBeatmapSet() => new APIBeatmapSet
+ {
+ OnlineID = 123,
+ Title = "undownloadable beatmap",
+ Artist = "test",
+ Source = "more tests",
+ Author = new User
+ {
+ Username = "BanchoBot",
+ Id = 3,
+ },
+ Availability = new BeatmapSetOnlineAvailability
+ {
+ DownloadDisabled = true,
+ },
+ Preview = @"https://b.ppy.sh/preview/12345.mp3",
+ PlayCount = 123,
+ FavouriteCount = 456,
+ BPM = 111,
+ HasVideo = true,
+ HasStoryboard = true,
+ Covers = new BeatmapSetOnlineCovers(),
+ Beatmaps = new[]
+ {
+ new APIBeatmap
+ {
+ RulesetID = Ruleset.Value.ID ?? 0,
+ DifficultyName = "Test",
+ StarRating = 6.42,
+ }
+ }
+ };
+
+ APIBeatmapSet getManyDifficultiesBeatmapSet()
+ {
+ var beatmaps = new List();
+
+ for (int i = 0; i < 100; i++)
+ {
+ beatmaps.Add(new APIBeatmap
+ {
+ RulesetID = i % 4,
+ StarRating = 2 + i % 4 * 2,
+ OverallDifficulty = 3.5f,
+ });
+ }
+
+ return new APIBeatmapSet
+ {
+ OnlineID = 1,
+ Title = "undownloadable beatmap",
+ Artist = "test",
+ Source = "more tests",
+ Author = new User
+ {
+ Username = "BanchoBot",
+ Id = 3,
+ },
+ HasVideo = true,
+ HasStoryboard = true,
+ Covers = new BeatmapSetOnlineCovers(),
+ Beatmaps = beatmaps.ToArray(),
+ };
+ }
}
}
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneFavouriteButton.cs b/osu.Game.Tests/Visual/Online/TestSceneFavouriteButton.cs
index 8e2ee4e28d..87458da578 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneFavouriteButton.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneFavouriteButton.cs
@@ -4,7 +4,7 @@
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Testing;
-using osu.Game.Beatmaps;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.BeatmapSet.Buttons;
using osuTK;
@@ -29,7 +29,7 @@ namespace osu.Game.Tests.Visual.Online
[Test]
public void TestLoggedOutIn()
{
- AddStep("set valid beatmap", () => favourite.BeatmapSet.Value = new BeatmapSetInfo { OnlineBeatmapSetID = 88 });
+ AddStep("set valid beatmap", () => favourite.BeatmapSet.Value = new APIBeatmapSet { OnlineID = 88 });
AddStep("log out", () => API.Logout());
checkEnabled(false);
AddStep("log in", () => API.Login("test", "test"));
@@ -40,9 +40,9 @@ namespace osu.Game.Tests.Visual.Online
public void TestBeatmapChange()
{
AddStep("log in", () => API.Login("test", "test"));
- AddStep("set valid beatmap", () => favourite.BeatmapSet.Value = new BeatmapSetInfo { OnlineBeatmapSetID = 88 });
+ AddStep("set valid beatmap", () => favourite.BeatmapSet.Value = new APIBeatmapSet { OnlineID = 88 });
checkEnabled(true);
- AddStep("set invalid beatmap", () => favourite.BeatmapSet.Value = new BeatmapSetInfo());
+ AddStep("set invalid beatmap", () => favourite.BeatmapSet.Value = new APIBeatmapSet());
checkEnabled(false);
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneLeaderboardModSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneLeaderboardModSelector.cs
index fc438ce6dd..aa442ded02 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneLeaderboardModSelector.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneLeaderboardModSelector.cs
@@ -26,7 +26,8 @@ namespace osu.Game.Tests.Visual.Online
{
LeaderboardModSelector modSelector;
FillFlowContainer selectedMods;
- var ruleset = new Bindable();
+
+ var ruleset = new Bindable();
Add(selectedMods = new FillFlowContainer
{
diff --git a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs
index 991be33917..23899154c4 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs
@@ -7,6 +7,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Utils;
+using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
using osu.Game.Overlays.BeatmapSet.Scores;
@@ -61,10 +62,10 @@ namespace osu.Game.Tests.Visual.Online
},
Mods = new[]
{
- new OsuModDoubleTime().Acronym,
- new OsuModHidden().Acronym,
- new OsuModFlashlight().Acronym,
- new OsuModHardRock().Acronym,
+ new APIMod { Acronym = new OsuModDoubleTime().Acronym },
+ new APIMod { Acronym = new OsuModHidden().Acronym },
+ new APIMod { Acronym = new OsuModFlashlight().Acronym },
+ new APIMod { Acronym = new OsuModHardRock().Acronym },
},
Rank = ScoreRank.XH,
PP = 200,
@@ -86,9 +87,9 @@ namespace osu.Game.Tests.Visual.Online
},
Mods = new[]
{
- new OsuModDoubleTime().Acronym,
- new OsuModHidden().Acronym,
- new OsuModFlashlight().Acronym,
+ new APIMod { Acronym = new OsuModDoubleTime().Acronym },
+ new APIMod { Acronym = new OsuModHidden().Acronym },
+ new APIMod { Acronym = new OsuModFlashlight().Acronym },
},
Rank = ScoreRank.S,
PP = 190,
@@ -110,8 +111,8 @@ namespace osu.Game.Tests.Visual.Online
},
Mods = new[]
{
- new OsuModDoubleTime().Acronym,
- new OsuModHidden().Acronym,
+ new APIMod { Acronym = new OsuModDoubleTime().Acronym },
+ new APIMod { Acronym = new OsuModHidden().Acronym },
},
Rank = ScoreRank.B,
PP = 180,
@@ -133,7 +134,7 @@ namespace osu.Game.Tests.Visual.Online
},
Mods = new[]
{
- new OsuModDoubleTime().Acronym,
+ new APIMod { Acronym = new OsuModDoubleTime().Acronym },
},
Rank = ScoreRank.C,
PP = 170,
@@ -226,10 +227,10 @@ namespace osu.Game.Tests.Visual.Online
},
Mods = new[]
{
- new OsuModDoubleTime().Acronym,
- new OsuModHidden().Acronym,
- new OsuModFlashlight().Acronym,
- new OsuModHardRock().Acronym,
+ new APIMod { Acronym = new OsuModDoubleTime().Acronym },
+ new APIMod { Acronym = new OsuModHidden().Acronym },
+ new APIMod { Acronym = new OsuModFlashlight().Acronym },
+ new APIMod { Acronym = new OsuModHardRock().Acronym },
},
Rank = ScoreRank.XH,
PP = 200,
diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs
index 513631a221..9c2cc13416 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs
@@ -2,16 +2,16 @@
// See the LICENCE file in the repository root for full licence text.
using System;
-using osu.Game.Overlays.Profile.Sections.Ranks;
-using osu.Framework.Graphics;
-using osu.Game.Scoring;
-using osu.Framework.Graphics.Containers;
-using osuTK;
-using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Mods;
-using osu.Game.Rulesets.Osu.Mods;
-using osu.Game.Overlays;
using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Online.API;
+using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Overlays;
+using osu.Game.Overlays.Profile.Sections.Ranks;
+using osu.Game.Rulesets.Osu.Mods;
+using osu.Game.Scoring;
+using osuTK;
namespace osu.Game.Tests.Visual.Online
{
@@ -19,79 +19,79 @@ namespace osu.Game.Tests.Visual.Online
{
public TestSceneUserProfileScores()
{
- var firstScore = new ScoreInfo
+ var firstScore = new APIScoreInfo
{
PP = 1047.21,
Rank = ScoreRank.SH,
- BeatmapInfo = new BeatmapInfo
+ Beatmap = new APIBeatmap
{
- Metadata = new BeatmapMetadata
+ BeatmapSet = new APIBeatmapSet
{
Title = "JUSTadICE (TV Size)",
- Artist = "Oomori Seiko"
+ Artist = "Oomori Seiko",
},
- Version = "Extreme"
+ DifficultyName = "Extreme"
},
Date = DateTimeOffset.Now,
- Mods = new Mod[]
+ Mods = new[]
{
- new OsuModHidden(),
- new OsuModHardRock(),
- new OsuModDoubleTime()
+ new APIMod { Acronym = new OsuModHidden().Acronym },
+ new APIMod { Acronym = new OsuModHardRock().Acronym },
+ new APIMod { Acronym = new OsuModDoubleTime().Acronym },
},
Accuracy = 0.9813
};
- var secondScore = new ScoreInfo
+ var secondScore = new APIScoreInfo
{
PP = 134.32,
Rank = ScoreRank.A,
- BeatmapInfo = new BeatmapInfo
+ Beatmap = new APIBeatmap
{
- Metadata = new BeatmapMetadata
+ BeatmapSet = new APIBeatmapSet
{
Title = "Triumph & Regret",
- Artist = "typeMARS"
+ Artist = "typeMARS",
},
- Version = "[4K] Regret"
+ DifficultyName = "[4K] Regret"
},
Date = DateTimeOffset.Now,
- Mods = new Mod[]
+ Mods = new[]
{
- new OsuModHardRock(),
- new OsuModDoubleTime(),
+ new APIMod { Acronym = new OsuModHardRock().Acronym },
+ new APIMod { Acronym = new OsuModDoubleTime().Acronym },
},
Accuracy = 0.998546
};
- var thirdScore = new ScoreInfo
+ var thirdScore = new APIScoreInfo
{
PP = 96.83,
Rank = ScoreRank.S,
- BeatmapInfo = new BeatmapInfo
+ Beatmap = new APIBeatmap
{
- Metadata = new BeatmapMetadata
+ BeatmapSet = new APIBeatmapSet
{
Title = "Idolize",
- Artist = "Creo"
+ Artist = "Creo",
},
- Version = "Insane"
+ DifficultyName = "Insane"
},
Date = DateTimeOffset.Now,
Accuracy = 0.9726
};
- var noPPScore = new ScoreInfo
+ var noPPScore = new APIScoreInfo
{
Rank = ScoreRank.B,
- BeatmapInfo = new BeatmapInfo
+ Beatmap = new APIBeatmap
{
- Metadata = new BeatmapMetadata
+ BeatmapSet = new APIBeatmapSet
{
Title = "C18H27NO3(extend)",
- Artist = "Team Grimoire"
+ Artist = "Team Grimoire",
},
- Version = "[4K] Cataclysmic Hypernova"
+ DifficultyName = "[4K] Cataclysmic Hypernova"
},
Date = DateTimeOffset.Now,
Accuracy = 0.55879
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs
index 4538e36c5e..07e68ef509 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs
@@ -5,6 +5,7 @@ using System;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
+using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
@@ -88,7 +89,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("select EZ mod", () =>
{
- var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance();
+ var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance().AsNonNull();
SelectedMods.Value = new[] { ruleset.CreateMod() };
});
@@ -105,7 +106,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("select HR mod", () =>
{
- var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance();
+ var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance().AsNonNull();
SelectedMods.Value = new[] { ruleset.CreateMod() };
});
@@ -122,9 +123,9 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("select unchanged Difficulty Adjust mod", () =>
{
- var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance();
+ var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance().AsNonNull();
var difficultyAdjustMod = ruleset.CreateMod();
- difficultyAdjustMod.ReadFromDifficulty(advancedStats.BeatmapInfo.BaseDifficulty);
+ difficultyAdjustMod.ReadFromDifficulty(advancedStats.BeatmapInfo.Difficulty);
SelectedMods.Value = new[] { difficultyAdjustMod };
});
@@ -141,9 +142,9 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("select changed Difficulty Adjust mod", () =>
{
- var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance();
+ var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance().AsNonNull();
var difficultyAdjustMod = ruleset.CreateMod();
- var originalDifficulty = advancedStats.BeatmapInfo.BaseDifficulty;
+ var originalDifficulty = advancedStats.BeatmapInfo.Difficulty;
difficultyAdjustMod.ReadFromDifficulty(originalDifficulty);
difficultyAdjustMod.DrainRate.Value = originalDifficulty.DrainRate - 0.5f;
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs
index 1125e16d91..bd15c40271 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs
@@ -31,154 +31,112 @@ namespace osu.Game.Tests.Visual.SongSelect
[Test]
public void TestAllMetrics()
{
- AddStep("all metrics", () => details.BeatmapInfo = new BeatmapInfo
+ AddStep("all metrics", () => details.BeatmapInfo = new APIBeatmap
{
- BeatmapSet = new BeatmapSetInfo
- {
- OnlineInfo = new APIBeatmapSet
- {
- Ratings = Enumerable.Range(0, 11).ToArray(),
- }
- },
- Version = "All Metrics",
- Metadata = new BeatmapMetadata
+ BeatmapSet = new APIBeatmapSet
{
Source = "osu!",
Tags = "this beatmap has all the metrics",
+ Ratings = Enumerable.Range(0, 11).ToArray(),
},
- BaseDifficulty = new BeatmapDifficulty
+ DifficultyName = "All Metrics",
+ CircleSize = 7,
+ DrainRate = 1,
+ OverallDifficulty = 5.7f,
+ ApproachRate = 3.5f,
+ StarRating = 5.3f,
+ FailTimes = new APIFailTimes
{
- CircleSize = 7,
- DrainRate = 1,
- OverallDifficulty = 5.7f,
- ApproachRate = 3.5f,
+ Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
+ Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
},
- StarDifficulty = 5.3f,
- OnlineInfo = new APIBeatmap
- {
- FailTimes = new APIFailTimes
- {
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
- },
- }
});
}
[Test]
public void TestAllMetricsExceptSource()
{
- AddStep("all except source", () => details.BeatmapInfo = new BeatmapInfo
+ AddStep("all except source", () => details.BeatmapInfo = new APIBeatmap
{
- BeatmapSet = new BeatmapSetInfo
- {
- OnlineInfo = new APIBeatmapSet
- {
- Ratings = Enumerable.Range(0, 11).ToArray(),
- }
- },
- Version = "All Metrics",
- Metadata = new BeatmapMetadata
+ BeatmapSet = new APIBeatmapSet
{
Tags = "this beatmap has all the metrics",
+ Ratings = Enumerable.Range(0, 11).ToArray(),
},
- BaseDifficulty = new BeatmapDifficulty
+ DifficultyName = "All Metrics",
+ CircleSize = 7,
+ DrainRate = 1,
+ OverallDifficulty = 5.7f,
+ ApproachRate = 3.5f,
+ StarRating = 5.3f,
+ FailTimes = new APIFailTimes
{
- CircleSize = 7,
- DrainRate = 1,
- OverallDifficulty = 5.7f,
- ApproachRate = 3.5f,
+ Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
+ Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
},
- StarDifficulty = 5.3f,
- OnlineInfo = new APIBeatmap
- {
- FailTimes = new APIFailTimes
- {
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
- },
- }
});
}
[Test]
public void TestOnlyRatings()
{
- AddStep("ratings", () => details.BeatmapInfo = new BeatmapInfo
+ AddStep("ratings", () => details.BeatmapInfo = new APIBeatmap
{
- BeatmapSet = new BeatmapSetInfo
- {
- OnlineInfo = new APIBeatmapSet
- {
- Ratings = Enumerable.Range(0, 11).ToArray(),
- }
- },
- Version = "Only Ratings",
- Metadata = new BeatmapMetadata
+ BeatmapSet = new APIBeatmapSet
{
+ Ratings = Enumerable.Range(0, 11).ToArray(),
Source = "osu!",
Tags = "this beatmap has ratings metrics but not retries or fails",
},
- BaseDifficulty = new BeatmapDifficulty
- {
- CircleSize = 6,
- DrainRate = 9,
- OverallDifficulty = 6,
- ApproachRate = 6,
- },
- StarDifficulty = 4.8f,
+ DifficultyName = "Only Ratings",
+ CircleSize = 6,
+ DrainRate = 9,
+ OverallDifficulty = 6,
+ ApproachRate = 6,
+ StarRating = 4.8f,
});
}
[Test]
public void TestOnlyFailsAndRetries()
{
- AddStep("fails retries", () => details.BeatmapInfo = new BeatmapInfo
+ AddStep("fails retries", () => details.BeatmapInfo = new APIBeatmap
{
- Version = "Only Retries and Fails",
- Metadata = new BeatmapMetadata
+ DifficultyName = "Only Retries and Fails",
+ BeatmapSet = new APIBeatmapSet
{
Source = "osu!",
Tags = "this beatmap has retries and fails but no ratings",
},
- BaseDifficulty = new BeatmapDifficulty
+ CircleSize = 3.7f,
+ DrainRate = 6,
+ OverallDifficulty = 6,
+ ApproachRate = 7,
+ StarRating = 2.91f,
+ FailTimes = new APIFailTimes
{
- CircleSize = 3.7f,
- DrainRate = 6,
- OverallDifficulty = 6,
- ApproachRate = 7,
+ Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
+ Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
},
- StarDifficulty = 2.91f,
- OnlineInfo = new APIBeatmap
- {
- FailTimes = new APIFailTimes
- {
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
- },
- }
});
}
[Test]
public void TestNoMetrics()
{
- AddStep("no metrics", () => details.BeatmapInfo = new BeatmapInfo
+ AddStep("no metrics", () => details.BeatmapInfo = new APIBeatmap
{
- Version = "No Metrics",
- Metadata = new BeatmapMetadata
+ DifficultyName = "No Metrics",
+ BeatmapSet = new APIBeatmapSet
{
Source = "osu!",
Tags = "this beatmap has no metrics",
},
- BaseDifficulty = new BeatmapDifficulty
- {
- CircleSize = 5,
- DrainRate = 5,
- OverallDifficulty = 5.5f,
- ApproachRate = 6.5f,
- },
- StarDifficulty = 1.97f,
+ CircleSize = 5,
+ DrainRate = 5,
+ OverallDifficulty = 5.5f,
+ ApproachRate = 6.5f,
+ StarRating = 1.97f,
});
}
@@ -191,9 +149,9 @@ namespace osu.Game.Tests.Visual.SongSelect
[Test]
public void TestOnlineMetrics()
{
- AddStep("online ratings/retries/fails", () => details.BeatmapInfo = new BeatmapInfo
+ AddStep("online ratings/retries/fails", () => details.BeatmapInfo = new APIBeatmap
{
- OnlineBeatmapID = 162,
+ OnlineID = 162,
});
AddStep("set online", () => api.SetState(APIState.Online));
AddStep("set offline", () => api.SetState(APIState.Offline));
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs
index a9fe7ed7d8..f17de75f5c 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs
@@ -110,25 +110,19 @@ namespace osu.Game.Tests.Visual.UserInterface
base.Dispose(isDisposing);
}
- private static readonly BeatmapSetInfo beatmap_set = new BeatmapSetInfo
+ private static readonly APIBeatmapSet beatmap_set = new APIBeatmapSet
{
- OnlineInfo = new APIBeatmapSet
+ Covers = new BeatmapSetOnlineCovers
{
- Covers = new BeatmapSetOnlineCovers
- {
- Cover = "https://assets.ppy.sh/beatmaps/1094296/covers/cover@2x.jpg?1581416305"
- }
+ Cover = "https://assets.ppy.sh/beatmaps/1094296/covers/cover@2x.jpg?1581416305"
}
};
- private static readonly BeatmapSetInfo no_cover_beatmap_set = new BeatmapSetInfo
+ private static readonly APIBeatmapSet no_cover_beatmap_set = new APIBeatmapSet
{
- OnlineInfo = new APIBeatmapSet
+ Covers = new BeatmapSetOnlineCovers
{
- Covers = new BeatmapSetOnlineCovers
- {
- Cover = string.Empty
- }
+ Cover = string.Empty
}
};
}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDrawable.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDrawable.cs
index fe312ccc8f..d5dda6f6cd 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDrawable.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDrawable.cs
@@ -1,6 +1,7 @@
// 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.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
@@ -65,10 +66,10 @@ namespace osu.Game.Tests.Visual.UserInterface
private void createPaddedComponent(bool hasDescription = false, bool padded = true)
{
+ LabelledDrawable component = null;
+
AddStep("create component", () =>
{
- LabelledDrawable component;
-
Child = new Container
{
Anchor = Anchor.Centre,
@@ -81,6 +82,8 @@ namespace osu.Game.Tests.Visual.UserInterface
component.Label = "a sample component";
component.Description = hasDescription ? "this text describes the component" : string.Empty;
});
+
+ AddAssert($"description {(hasDescription ? "visible" : "hidden")}", () => component.ChildrenOfType().ElementAt(1).IsPresent == hasDescription);
}
private class PaddedLabelledDrawable : LabelledDrawable
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs
index 74cd675a05..d30f1e8889 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs
@@ -12,6 +12,7 @@ using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets;
using osu.Game.Tests.Beatmaps.IO;
using osuTK;
@@ -24,7 +25,6 @@ namespace osu.Game.Tests.Visual.UserInterface
private BeatmapSetInfo testBeatmap;
private IAPIProvider api;
- private RulesetStore rulesets;
[Resolved]
private BeatmapManager beatmaps { get; set; }
@@ -33,7 +33,6 @@ namespace osu.Game.Tests.Visual.UserInterface
private void load(OsuGameBase osu, IAPIProvider api, RulesetStore rulesets)
{
this.api = api;
- this.rulesets = rulesets;
testBeatmap = ImportBeatmapTest.LoadOszIntoOsu(osu).Result;
}
@@ -81,7 +80,7 @@ namespace osu.Game.Tests.Visual.UserInterface
Child = background = new TestUpdateableBeatmapBackgroundSprite
{
RelativeSizeAxes = Axes.Both,
- Beatmap = { Value = new BeatmapInfo { BeatmapSet = req.Response?.ToBeatmapSet(rulesets) } }
+ Beatmap = { Value = new APIBeatmap { BeatmapSet = req.Response } }
};
});
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapSetCover.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapSetCover.cs
index f67f6258cc..7b6774a6b2 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapSetCover.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapSetCover.cs
@@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.UserInterface
{
AddStep("setup cover", () => Child = new UpdateableOnlineBeatmapSetCover(coverType)
{
- OnlineInfo = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet.OnlineInfo,
+ OnlineInfo = CreateAPIBeatmapSet(),
RelativeSizeAxes = Axes.Both,
Masking = true,
});
@@ -41,7 +41,7 @@ namespace osu.Game.Tests.Visual.UserInterface
AddStep("setup covers", () =>
{
- BeatmapSetInfo setInfo = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet;
+ var beatmapSet = CreateAPIBeatmapSet();
FillFlowContainer fillFlow;
@@ -68,7 +68,7 @@ namespace osu.Game.Tests.Visual.UserInterface
var cover = new UpdateableOnlineBeatmapSetCover(coverType)
{
- OnlineInfo = setInfo.OnlineInfo,
+ OnlineInfo = beatmapSet,
Height = 100,
Masking = true,
};
@@ -99,7 +99,7 @@ namespace osu.Game.Tests.Visual.UserInterface
AddStep("setup cover", () => Child = updateableCover = new TestUpdateableOnlineBeatmapSetCover
{
- OnlineInfo = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet.OnlineInfo,
+ OnlineInfo = CreateAPIBeatmapSet(),
RelativeSizeAxes = Axes.Both,
Masking = true,
});
@@ -117,7 +117,7 @@ namespace osu.Game.Tests.Visual.UserInterface
AddStep("setup cover", () => Child = updateableCover = new TestUpdateableOnlineBeatmapSetCover(0)
{
- OnlineInfo = createBeatmapWithCover("https://assets.ppy.sh/beatmaps/1189904/covers/cover.jpg").OnlineInfo,
+ OnlineInfo = createBeatmapWithCover("https://assets.ppy.sh/beatmaps/1189904/covers/cover.jpg"),
RelativeSizeAxes = Axes.Both,
Masking = true,
Alpha = 0.4f
@@ -128,16 +128,13 @@ namespace osu.Game.Tests.Visual.UserInterface
AddUntilStep("wait for fade complete", () => initialCover.Alpha == 1);
AddStep("switch beatmap",
- () => updateableCover.OnlineInfo = createBeatmapWithCover("https://assets.ppy.sh/beatmaps/1079428/covers/cover.jpg").OnlineInfo);
+ () => updateableCover.OnlineInfo = createBeatmapWithCover("https://assets.ppy.sh/beatmaps/1079428/covers/cover.jpg"));
AddUntilStep("new cover loaded", () => updateableCover.ChildrenOfType().Except(new[] { initialCover }).Any());
}
- private static BeatmapSetInfo createBeatmapWithCover(string coverUrl) => new BeatmapSetInfo
+ private static APIBeatmapSet createBeatmapWithCover(string coverUrl) => new APIBeatmapSet
{
- OnlineInfo = new APIBeatmapSet
- {
- Covers = new BeatmapSetOnlineCovers { Cover = coverUrl }
- }
+ Covers = new BeatmapSetOnlineCovers { Cover = coverUrl }
};
private class TestUpdateableOnlineBeatmapSetCover : UpdateableOnlineBeatmapSetCover
diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj
index cd56cb51ae..57815d9273 100644
--- a/osu.Game.Tests/osu.Game.Tests.csproj
+++ b/osu.Game.Tests/osu.Game.Tests.csproj
@@ -3,7 +3,7 @@
-
+
diff --git a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj
index 2673c9ec9f..c0f94d49c7 100644
--- a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj
+++ b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj
@@ -5,7 +5,7 @@
-
+
diff --git a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs
index 9a0cdb387d..035f438b89 100644
--- a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs
+++ b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs
@@ -131,7 +131,7 @@ namespace osu.Game.Beatmaps
var localRulesetInfo = rulesetInfo as RulesetInfo;
// Difficulty can only be computed if the beatmap and ruleset are locally available.
- if (localBeatmapInfo == null || localRulesetInfo == null)
+ if (localBeatmapInfo == null || localBeatmapInfo.ID == 0 || localRulesetInfo == null)
{
// If not, fall back to the existing star difficulty (e.g. from an online source).
return Task.FromResult(new StarDifficulty(beatmapInfo.StarRating, (beatmapInfo as IBeatmapOnlineInfo)?.MaxCombo ?? 0));
diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs
index 9069ea4404..01a819dead 100644
--- a/osu.Game/Beatmaps/BeatmapInfo.cs
+++ b/osu.Game/Beatmaps/BeatmapInfo.cs
@@ -17,7 +17,7 @@ namespace osu.Game.Beatmaps
{
[ExcludeFromDynamicCompile]
[Serializable]
- public class BeatmapInfo : IEquatable, IHasPrimaryKey, IBeatmapInfo, IBeatmapOnlineInfo
+ public class BeatmapInfo : IEquatable, IHasPrimaryKey, IBeatmapInfo
{
public int ID { get; set; }
@@ -186,7 +186,7 @@ namespace osu.Game.Beatmaps
string IBeatmapInfo.DifficultyName => Version;
[JsonIgnore]
- IBeatmapMetadataInfo IBeatmapInfo.Metadata => Metadata;
+ IBeatmapMetadataInfo IBeatmapInfo.Metadata => Metadata ?? BeatmapSet?.Metadata ?? new BeatmapMetadata();
[JsonIgnore]
IBeatmapDifficultyInfo IBeatmapInfo.Difficulty => BaseDifficulty;
@@ -201,24 +201,5 @@ namespace osu.Game.Beatmaps
double IBeatmapInfo.StarRating => StarDifficulty;
#endregion
-
- #region Implementation of IBeatmapOnlineInfo
-
- [JsonIgnore]
- public int CircleCount => OnlineInfo.CircleCount;
-
- [JsonIgnore]
- public int SliderCount => OnlineInfo.SliderCount;
-
- [JsonIgnore]
- public int PlayCount => OnlineInfo.PlayCount;
-
- [JsonIgnore]
- public int PassCount => OnlineInfo.PassCount;
-
- [JsonIgnore]
- public APIFailTimes FailTimes => OnlineInfo.FailTimes;
-
- #endregion
}
}
diff --git a/osu.Game/Beatmaps/BeatmapInfoExtensions.cs b/osu.Game/Beatmaps/BeatmapInfoExtensions.cs
index 2d69015933..707b588063 100644
--- a/osu.Game/Beatmaps/BeatmapInfoExtensions.cs
+++ b/osu.Game/Beatmaps/BeatmapInfoExtensions.cs
@@ -11,14 +11,14 @@ namespace osu.Game.Beatmaps
///
/// A user-presentable display title representing this beatmap.
///
- public static string GetDisplayTitle(this IBeatmapInfo beatmapInfo) => $"{getClosestMetadata(beatmapInfo)} {getVersionString(beatmapInfo)}".Trim();
+ public static string GetDisplayTitle(this IBeatmapInfo beatmapInfo) => $"{beatmapInfo.Metadata} {getVersionString(beatmapInfo)}".Trim();
///
/// A user-presentable display title representing this beatmap, with localisation handling for potentially romanisable fields.
///
public static RomanisableString GetDisplayTitleRomanisable(this IBeatmapInfo beatmapInfo, bool includeDifficultyName = true, bool includeCreator = true)
{
- var metadata = getClosestMetadata(beatmapInfo).GetDisplayTitleRomanisable(includeCreator);
+ var metadata = beatmapInfo.Metadata.GetDisplayTitleRomanisable(includeCreator);
if (includeDifficultyName)
{
@@ -32,12 +32,8 @@ namespace osu.Game.Beatmaps
public static string[] GetSearchableTerms(this IBeatmapInfo beatmapInfo) => new[]
{
beatmapInfo.DifficultyName
- }.Concat(getClosestMetadata(beatmapInfo).GetSearchableTerms()).Where(s => !string.IsNullOrEmpty(s)).ToArray();
+ }.Concat(beatmapInfo.Metadata.GetSearchableTerms()).Where(s => !string.IsNullOrEmpty(s)).ToArray();
private static string getVersionString(IBeatmapInfo beatmapInfo) => string.IsNullOrEmpty(beatmapInfo.DifficultyName) ? string.Empty : $"[{beatmapInfo.DifficultyName}]";
-
- // temporary helper methods until we figure which metadata should be where.
- private static IBeatmapMetadataInfo getClosestMetadata(IBeatmapInfo beatmapInfo) =>
- beatmapInfo.Metadata ?? beatmapInfo.BeatmapSet?.Metadata ?? new BeatmapMetadata();
}
}
diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs
index 0509a9db47..7a9f3e0a45 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -114,7 +114,8 @@ namespace osu.Game.Beatmaps
/// The to save the content against. The file referenced by will be replaced.
/// The content to write.
/// The beatmap content to write, null if to be omitted.
- public virtual void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) => beatmapModelManager.Save(info, beatmapContent, beatmapSkin);
+ public virtual void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) =>
+ beatmapModelManager.Save(info, beatmapContent, beatmapSkin);
///
/// Returns a list of all usable s.
@@ -249,6 +250,23 @@ namespace osu.Game.Beatmaps
public IBindable>> DownloadFailed => beatmapModelDownloader.DownloadFailed;
+ // Temporary method until this class supports IBeatmapSetInfo or otherwise.
+ public bool Download(IBeatmapSetInfo model, bool minimiseDownloadSize = false)
+ {
+ return beatmapModelDownloader.Download(new BeatmapSetInfo
+ {
+ OnlineBeatmapSetID = model.OnlineID,
+ Metadata = new BeatmapMetadata
+ {
+ Title = model.Metadata?.Title ?? string.Empty,
+ Artist = model.Metadata?.Artist ?? string.Empty,
+ TitleUnicode = model.Metadata?.TitleUnicode ?? string.Empty,
+ ArtistUnicode = model.Metadata?.ArtistUnicode ?? string.Empty,
+ Author = new User { Username = model.Metadata?.Author },
+ }
+ }, minimiseDownloadSize);
+ }
+
public bool Download(BeatmapSetInfo model, bool minimiseDownloadSize = false)
{
return beatmapModelDownloader.Download(model, minimiseDownloadSize);
diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs
index 711533e118..5d3b4007ae 100644
--- a/osu.Game/Beatmaps/BeatmapMetadata.cs
+++ b/osu.Game/Beatmaps/BeatmapMetadata.cs
@@ -9,6 +9,8 @@ using osu.Framework.Testing;
using osu.Game.Database;
using osu.Game.Users;
+#nullable enable
+
namespace osu.Game.Beatmaps
{
[ExcludeFromDynamicCompile]
@@ -17,21 +19,21 @@ namespace osu.Game.Beatmaps
{
public int ID { get; set; }
- public string Title { get; set; }
+ public string Title { get; set; } = string.Empty;
[JsonProperty("title_unicode")]
- public string TitleUnicode { get; set; }
+ public string TitleUnicode { get; set; } = string.Empty;
- public string Artist { get; set; }
+ public string Artist { get; set; } = string.Empty;
[JsonProperty("artist_unicode")]
- public string ArtistUnicode { get; set; }
+ public string ArtistUnicode { get; set; } = string.Empty;
[JsonIgnore]
- public List Beatmaps { get; set; }
+ public List Beatmaps { get; set; } = new List();
[JsonIgnore]
- public List BeatmapSets { get; set; }
+ public List BeatmapSets { get; set; } = new List();
///
/// Helper property to deserialize a username to .
@@ -55,7 +57,7 @@ namespace osu.Game.Beatmaps
[Column("Author")]
public string AuthorString
{
- get => Author?.Username;
+ get => Author?.Username ?? string.Empty;
set
{
Author ??= new User();
@@ -67,22 +69,22 @@ namespace osu.Game.Beatmaps
/// The author of the beatmaps in this set.
///
[JsonIgnore]
- public User Author;
+ public User? Author;
- public string Source { get; set; }
+ public string Source { get; set; } = string.Empty;
[JsonProperty(@"tags")]
- public string Tags { get; set; }
+ public string Tags { get; set; } = string.Empty;
///
/// The time in milliseconds to begin playing the track for preview purposes.
/// If -1, the track should begin playing at 40% of its length.
///
- public int PreviewTime { get; set; }
+ public int PreviewTime { get; set; } = -1;
- public string AudioFile { get; set; }
+ public string AudioFile { get; set; } = string.Empty;
- public string BackgroundFile { get; set; }
+ public string BackgroundFile { get; set; } = string.Empty;
public bool Equals(BeatmapMetadata other) => ((IBeatmapMetadataInfo)this).Equals(other);
diff --git a/osu.Game/Beatmaps/BeatmapModelManager.cs b/osu.Game/Beatmaps/BeatmapModelManager.cs
index 16cf6193f9..f148d05aca 100644
--- a/osu.Game/Beatmaps/BeatmapModelManager.cs
+++ b/osu.Game/Beatmaps/BeatmapModelManager.cs
@@ -216,7 +216,8 @@ namespace osu.Game.Beatmaps
var fileInfo = setInfo.Files.SingleOrDefault(f => string.Equals(f.Filename, beatmapInfo.Path, StringComparison.OrdinalIgnoreCase)) ?? new BeatmapSetFileInfo();
// metadata may have changed; update the path with the standard format.
- beatmapInfo.Path = $"{metadata.Artist} - {metadata.Title} ({metadata.Author}) [{beatmapInfo.Version}].osu";
+ beatmapInfo.Path = GetValidFilename($"{metadata.Artist} - {metadata.Title} ({metadata.Author}) [{beatmapInfo.Version}].osu");
+
beatmapInfo.MD5Hash = stream.ComputeMD5Hash();
// update existing or populate new file's filename.
diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs
index 79cc8b70fb..638366c580 100644
--- a/osu.Game/Beatmaps/BeatmapSetInfo.cs
+++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs
@@ -6,10 +6,8 @@ using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using JetBrains.Annotations;
-using Newtonsoft.Json;
using osu.Framework.Testing;
using osu.Game.Database;
-using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Beatmaps
{
@@ -32,13 +30,11 @@ namespace osu.Game.Beatmaps
public List Beatmaps { get; set; }
+ public BeatmapSetOnlineStatus Status { get; set; } = BeatmapSetOnlineStatus.None;
+
[NotNull]
public List Files { get; set; } = new List();
- // This field is temporary and only used by `APIBeatmapSet.ToBeatmapSet` (soon to be removed) and tests (to be updated to provide APIBeatmapSet instead).
- [NotMapped]
- public APIBeatmapSet OnlineInfo { get; set; }
-
///
/// The maximum star difficulty of all beatmaps in this set.
///
@@ -100,80 +96,5 @@ namespace osu.Game.Beatmaps
IEnumerable IBeatmapSetInfo.Files => Files;
#endregion
-
- #region Delegation for IBeatmapSetOnlineInfo
-
- [NotMapped]
- [JsonIgnore]
- public DateTimeOffset Submitted => OnlineInfo.Submitted;
-
- [NotMapped]
- [JsonIgnore]
- public DateTimeOffset? Ranked => OnlineInfo.Ranked;
-
- [NotMapped]
- [JsonIgnore]
- public DateTimeOffset? LastUpdated => OnlineInfo.LastUpdated;
-
- [JsonIgnore]
- public BeatmapSetOnlineStatus Status { get; set; } = BeatmapSetOnlineStatus.None;
-
- [NotMapped]
- [JsonIgnore]
- public bool HasExplicitContent => OnlineInfo.HasExplicitContent;
-
- [NotMapped]
- [JsonIgnore]
- public bool HasVideo => OnlineInfo.HasVideo;
-
- [NotMapped]
- [JsonIgnore]
- public bool HasStoryboard => OnlineInfo.HasStoryboard;
-
- [NotMapped]
- [JsonIgnore]
- public BeatmapSetOnlineCovers Covers => OnlineInfo.Covers;
-
- [NotMapped]
- [JsonIgnore]
- public string Preview => OnlineInfo.Preview;
-
- [NotMapped]
- [JsonIgnore]
- public double BPM => OnlineInfo.BPM;
-
- [NotMapped]
- [JsonIgnore]
- public int PlayCount => OnlineInfo.PlayCount;
-
- [NotMapped]
- [JsonIgnore]
- public int FavouriteCount => OnlineInfo.FavouriteCount;
-
- [NotMapped]
- [JsonIgnore]
- public bool HasFavourited => OnlineInfo.HasFavourited;
-
- [NotMapped]
- [JsonIgnore]
- public BeatmapSetOnlineAvailability Availability => OnlineInfo.Availability;
-
- [NotMapped]
- [JsonIgnore]
- public BeatmapSetOnlineGenre Genre => OnlineInfo.Genre;
-
- [NotMapped]
- [JsonIgnore]
- public BeatmapSetOnlineLanguage Language => OnlineInfo.Language;
-
- [NotMapped]
- [JsonIgnore]
- public int? TrackId => OnlineInfo?.TrackId;
-
- [NotMapped]
- [JsonIgnore]
- public int[] Ratings => OnlineInfo?.Ratings;
-
- #endregion
}
}
diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs
new file mode 100644
index 0000000000..8136ebbd70
--- /dev/null
+++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs
@@ -0,0 +1,280 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Graphics.Sprites;
+using osu.Framework.Input.Events;
+using osu.Framework.Localisation;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Containers;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Graphics.UserInterface;
+using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Overlays;
+using osu.Game.Overlays.BeatmapSet;
+using osuTK;
+using osu.Game.Overlays.BeatmapListing.Panels;
+using osu.Game.Resources.Localisation.Web;
+using osuTK.Graphics;
+
+namespace osu.Game.Beatmaps.Drawables.Cards
+{
+ public class BeatmapCard : OsuClickableContainer
+ {
+ public const float TRANSITION_DURATION = 400;
+
+ private const float width = 408;
+ private const float height = 100;
+ private const float corner_radius = 10;
+
+ private readonly APIBeatmapSet beatmapSet;
+
+ private UpdateableOnlineBeatmapSetCover leftCover;
+ private FillFlowContainer iconArea;
+
+ private Container mainContent;
+ private BeatmapCardContentBackground mainContentBackground;
+
+ private GridContainer titleContainer;
+ private GridContainer artistContainer;
+
+ [Resolved]
+ private OverlayColourProvider colourProvider { get; set; }
+
+ public BeatmapCard(APIBeatmapSet beatmapSet)
+ : base(HoverSampleSet.Submit)
+ {
+ this.beatmapSet = beatmapSet;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Width = width;
+ Height = height;
+ CornerRadius = corner_radius;
+ Masking = true;
+
+ InternalChildren = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = colourProvider.Background3
+ },
+ new Container
+ {
+ Name = @"Left (icon) area",
+ Size = new Vector2(height),
+ Children = new Drawable[]
+ {
+ leftCover = new UpdateableOnlineBeatmapSetCover(BeatmapSetCoverType.List)
+ {
+ RelativeSizeAxes = Axes.Both,
+ OnlineInfo = beatmapSet
+ },
+ iconArea = new FillFlowContainer
+ {
+ Margin = new MarginPadding(5),
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Horizontal,
+ Spacing = new Vector2(1)
+ }
+ }
+ },
+ mainContent = new Container
+ {
+ Name = @"Main content",
+ X = height - corner_radius,
+ Height = height,
+ CornerRadius = corner_radius,
+ Masking = true,
+ Children = new Drawable[]
+ {
+ mainContentBackground = new BeatmapCardContentBackground(beatmapSet)
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Padding = new MarginPadding
+ {
+ Horizontal = 10,
+ Vertical = 4
+ },
+ Direction = FillDirection.Vertical,
+ Children = new Drawable[]
+ {
+ titleContainer = new GridContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ ColumnDimensions = new[]
+ {
+ new Dimension(),
+ new Dimension(GridSizeMode.AutoSize)
+ },
+ RowDimensions = new[]
+ {
+ new Dimension(GridSizeMode.AutoSize)
+ },
+ Content = new[]
+ {
+ new[]
+ {
+ new OsuSpriteText
+ {
+ Text = new RomanisableString(beatmapSet.TitleUnicode, beatmapSet.Title),
+ Font = OsuFont.Default.With(size: 22.5f, weight: FontWeight.SemiBold),
+ RelativeSizeAxes = Axes.X,
+ Truncate = true
+ },
+ Empty()
+ }
+ }
+ },
+ artistContainer = new GridContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ ColumnDimensions = new[]
+ {
+ new Dimension(),
+ new Dimension(GridSizeMode.AutoSize)
+ },
+ RowDimensions = new[]
+ {
+ new Dimension(GridSizeMode.AutoSize)
+ },
+ Content = new[]
+ {
+ new[]
+ {
+ new OsuSpriteText
+ {
+ Text = createArtistText(),
+ Font = OsuFont.Default.With(size: 17.5f, weight: FontWeight.SemiBold),
+ RelativeSizeAxes = Axes.X,
+ Truncate = true
+ },
+ Empty()
+ },
+ }
+ },
+ new LinkFlowContainer(s =>
+ {
+ s.Shadow = false;
+ s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold);
+ }).With(d =>
+ {
+ d.AutoSizeAxes = Axes.Both;
+ d.Margin = new MarginPadding { Top = 2 };
+ d.AddText("mapped by ", t => t.Colour = colourProvider.Content2);
+ d.AddUserLink(beatmapSet.Author);
+ }),
+ }
+ },
+ new FillFlowContainer
+ {
+ Name = @"Bottom content",
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Horizontal,
+ Padding = new MarginPadding
+ {
+ Horizontal = 10,
+ Vertical = 4
+ },
+ Spacing = new Vector2(4, 0),
+ Anchor = Anchor.BottomLeft,
+ Origin = Anchor.BottomLeft,
+ Children = new Drawable[]
+ {
+ new BeatmapSetOnlineStatusPill
+ {
+ AutoSizeAxes = Axes.Both,
+ Status = beatmapSet.Status,
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft
+ },
+ new DifficultySpectrumDisplay(beatmapSet)
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ DotSize = new Vector2(6, 12)
+ }
+ }
+ }
+ }
+ }
+ };
+
+ if (beatmapSet.HasVideo)
+ iconArea.Add(new IconPill(FontAwesome.Solid.Film));
+
+ if (beatmapSet.HasStoryboard)
+ iconArea.Add(new IconPill(FontAwesome.Solid.Image));
+
+ if (beatmapSet.HasExplicitContent)
+ {
+ titleContainer.Content[0][1] = new ExplicitContentBeatmapPill
+ {
+ Anchor = Anchor.BottomRight,
+ Origin = Anchor.BottomRight,
+ Margin = new MarginPadding { Left = 5 }
+ };
+ }
+
+ if (beatmapSet.TrackId != null)
+ {
+ artistContainer.Content[0][1] = new FeaturedArtistBeatmapPill
+ {
+ Anchor = Anchor.BottomRight,
+ Origin = Anchor.BottomRight,
+ Margin = new MarginPadding { Left = 5 }
+ };
+ }
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+ updateState();
+ FinishTransforms(true);
+ }
+
+ protected override bool OnHover(HoverEvent e)
+ {
+ updateState();
+ return base.OnHover(e);
+ }
+
+ protected override void OnHoverLost(HoverLostEvent e)
+ {
+ updateState();
+ base.OnHoverLost(e);
+ }
+
+ private LocalisableString createArtistText()
+ {
+ var romanisableArtist = new RomanisableString(beatmapSet.ArtistUnicode, beatmapSet.Artist);
+ return BeatmapsetsStrings.ShowDetailsByArtist(romanisableArtist);
+ }
+
+ private void updateState()
+ {
+ float targetWidth = width - height;
+ if (IsHovered)
+ targetWidth -= 20;
+
+ mainContent.ResizeWidthTo(targetWidth, TRANSITION_DURATION, Easing.OutQuint);
+ mainContentBackground.Dimmed.Value = IsHovered;
+
+ leftCover.FadeColour(IsHovered ? OsuColour.Gray(0.2f) : Color4.White, TRANSITION_DURATION, Easing.OutQuint);
+ }
+ }
+}
diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardContentBackground.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardContentBackground.cs
new file mode 100644
index 0000000000..392f5d1bfa
--- /dev/null
+++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardContentBackground.cs
@@ -0,0 +1,71 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+#nullable enable
+
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Colour;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Overlays;
+
+namespace osu.Game.Beatmaps.Drawables.Cards
+{
+ public class BeatmapCardContentBackground : CompositeDrawable
+ {
+ public BindableBool Dimmed { get; } = new BindableBool();
+
+ private readonly Box background;
+ private readonly DelayedLoadUnloadWrapper cover;
+
+ [Resolved]
+ private OverlayColourProvider colourProvider { get; set; } = null!;
+
+ public BeatmapCardContentBackground(IBeatmapSetOnlineInfo onlineInfo)
+ {
+ InternalChildren = new Drawable[]
+ {
+ background = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ cover = new DelayedLoadUnloadWrapper(() => createCover(onlineInfo), 500, 500)
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Colour4.Transparent
+ }
+ };
+ }
+
+ private static Drawable createCover(IBeatmapSetOnlineInfo onlineInfo) => new OnlineBeatmapSetCover(onlineInfo)
+ {
+ RelativeSizeAxes = Axes.Both,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ FillMode = FillMode.Fill
+ };
+
+ [BackgroundDependencyLoader]
+ private void load(OverlayColourProvider colourProvider)
+ {
+ background.Colour = colourProvider.Background2;
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+ Dimmed.BindValueChanged(_ => updateState(), true);
+ FinishTransforms(true);
+ }
+
+ private void updateState() => Schedule(() =>
+ {
+ background.FadeColour(Dimmed.Value ? colourProvider.Background4 : colourProvider.Background2, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
+
+ var gradient = ColourInfo.GradientHorizontal(Colour4.White.Opacity(0), Colour4.White.Opacity(0.2f));
+ cover.FadeColour(gradient, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
+ });
+ }
+}
diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs
index 64412675bb..6e573cc2a0 100644
--- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs
+++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs
@@ -60,8 +60,9 @@ namespace osu.Game.Beatmaps.Drawables
/// The ruleset to show the difficulty with.
/// The mods to show the difficulty with.
/// Whether to display a tooltip when hovered.
- public DifficultyIcon([NotNull] IBeatmapInfo beatmapInfo, [CanBeNull] IRulesetInfo ruleset, [CanBeNull] IReadOnlyList mods, bool shouldShowTooltip = true)
- : this(beatmapInfo, shouldShowTooltip)
+ /// Whether to perform difficulty lookup (including calculation if necessary).
+ public DifficultyIcon([NotNull] IBeatmapInfo beatmapInfo, [CanBeNull] IRulesetInfo ruleset, [CanBeNull] IReadOnlyList mods, bool shouldShowTooltip = true, bool performBackgroundDifficultyLookup = true)
+ : this(beatmapInfo, shouldShowTooltip, performBackgroundDifficultyLookup)
{
this.ruleset = ruleset ?? beatmapInfo.Ruleset;
this.mods = mods ?? Array.Empty();
diff --git a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs
index 4100fe9586..636c568bd0 100644
--- a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs
+++ b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs
@@ -57,12 +57,7 @@ namespace osu.Game.Beatmaps.Drawables
return new OnlineBeatmapSetCover(online, beatmapSetCoverType);
if (model is BeatmapInfo localModel)
- {
- if (localModel.BeatmapSet?.OnlineInfo != null)
- return new OnlineBeatmapSetCover(localModel.BeatmapSet.OnlineInfo, beatmapSetCoverType);
-
return new BeatmapBackgroundSprite(beatmaps.GetWorkingBeatmap(localModel));
- }
return new BeatmapBackgroundSprite(beatmaps.DefaultBeatmap);
}
diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs
index 89541a0845..3ed5055b7f 100644
--- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs
@@ -82,7 +82,7 @@ namespace osu.Game.Beatmaps.Formats
{
writer.WriteLine("[General]");
- if (beatmap.Metadata.AudioFile != null) writer.WriteLine(FormattableString.Invariant($"AudioFilename: {Path.GetFileName(beatmap.Metadata.AudioFile)}"));
+ if (!string.IsNullOrEmpty(beatmap.Metadata.AudioFile)) writer.WriteLine(FormattableString.Invariant($"AudioFilename: {Path.GetFileName(beatmap.Metadata.AudioFile)}"));
writer.WriteLine(FormattableString.Invariant($"AudioLeadIn: {beatmap.BeatmapInfo.AudioLeadIn}"));
writer.WriteLine(FormattableString.Invariant($"PreviewTime: {beatmap.Metadata.PreviewTime}"));
writer.WriteLine(FormattableString.Invariant($"Countdown: {(int)beatmap.BeatmapInfo.Countdown}"));
@@ -126,13 +126,13 @@ namespace osu.Game.Beatmaps.Formats
writer.WriteLine("[Metadata]");
writer.WriteLine(FormattableString.Invariant($"Title: {beatmap.Metadata.Title}"));
- if (beatmap.Metadata.TitleUnicode != null) writer.WriteLine(FormattableString.Invariant($"TitleUnicode: {beatmap.Metadata.TitleUnicode}"));
+ if (!string.IsNullOrEmpty(beatmap.Metadata.TitleUnicode)) writer.WriteLine(FormattableString.Invariant($"TitleUnicode: {beatmap.Metadata.TitleUnicode}"));
writer.WriteLine(FormattableString.Invariant($"Artist: {beatmap.Metadata.Artist}"));
- if (beatmap.Metadata.ArtistUnicode != null) writer.WriteLine(FormattableString.Invariant($"ArtistUnicode: {beatmap.Metadata.ArtistUnicode}"));
+ if (!string.IsNullOrEmpty(beatmap.Metadata.ArtistUnicode)) writer.WriteLine(FormattableString.Invariant($"ArtistUnicode: {beatmap.Metadata.ArtistUnicode}"));
writer.WriteLine(FormattableString.Invariant($"Creator: {beatmap.Metadata.AuthorString}"));
writer.WriteLine(FormattableString.Invariant($"Version: {beatmap.BeatmapInfo.Version}"));
- if (beatmap.Metadata.Source != null) writer.WriteLine(FormattableString.Invariant($"Source: {beatmap.Metadata.Source}"));
- if (beatmap.Metadata.Tags != null) writer.WriteLine(FormattableString.Invariant($"Tags: {beatmap.Metadata.Tags}"));
+ if (!string.IsNullOrEmpty(beatmap.Metadata.Source)) writer.WriteLine(FormattableString.Invariant($"Source: {beatmap.Metadata.Source}"));
+ if (!string.IsNullOrEmpty(beatmap.Metadata.Tags)) writer.WriteLine(FormattableString.Invariant($"Tags: {beatmap.Metadata.Tags}"));
if (beatmap.BeatmapInfo.OnlineBeatmapID != null) writer.WriteLine(FormattableString.Invariant($"BeatmapID: {beatmap.BeatmapInfo.OnlineBeatmapID}"));
if (beatmap.BeatmapInfo.BeatmapSet?.OnlineBeatmapSetID != null) writer.WriteLine(FormattableString.Invariant($"BeatmapSetID: {beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID}"));
}
diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs
index 56525ddb14..0276abc3ff 100644
--- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs
@@ -27,7 +27,7 @@ namespace osu.Game.Beatmaps.Formats
protected override void ParseStreamInto(LineBufferedReader stream, T output)
{
- Section section = Section.None;
+ Section section = Section.General;
string line;
@@ -47,10 +47,7 @@ namespace osu.Game.Beatmaps.Formats
if (line.StartsWith('[') && line.EndsWith(']'))
{
if (!Enum.TryParse(line[1..^1], out section))
- {
Logger.Log($"Unknown section \"{line}\" in \"{output}\"");
- section = Section.None;
- }
OnBeginNewSection(section);
continue;
@@ -148,7 +145,6 @@ namespace osu.Game.Beatmaps.Formats
protected enum Section
{
- None,
General,
Editor,
Metadata,
diff --git a/osu.Game/Beatmaps/IBeatmapInfo.cs b/osu.Game/Beatmaps/IBeatmapInfo.cs
index d206cfaaed..84ea6d3019 100644
--- a/osu.Game/Beatmaps/IBeatmapInfo.cs
+++ b/osu.Game/Beatmaps/IBeatmapInfo.cs
@@ -21,7 +21,7 @@ namespace osu.Game.Beatmaps
///
/// The metadata representing this beatmap. May be shared between multiple beatmaps.
///
- IBeatmapMetadataInfo? Metadata { get; }
+ IBeatmapMetadataInfo Metadata { get; }
///
/// The difficulty settings for this beatmap.
diff --git a/osu.Game/Beatmaps/WorkingBeatmapCache.cs b/osu.Game/Beatmaps/WorkingBeatmapCache.cs
index 65f84984c2..11257e3abc 100644
--- a/osu.Game/Beatmaps/WorkingBeatmapCache.cs
+++ b/osu.Game/Beatmaps/WorkingBeatmapCache.cs
@@ -149,7 +149,7 @@ namespace osu.Game.Beatmaps
protected override Texture GetBackground()
{
- if (Metadata?.BackgroundFile == null)
+ if (string.IsNullOrEmpty(Metadata?.BackgroundFile))
return null;
try
@@ -165,7 +165,7 @@ namespace osu.Game.Beatmaps
protected override Track GetBeatmapTrack()
{
- if (Metadata?.AudioFile == null)
+ if (string.IsNullOrEmpty(Metadata?.AudioFile))
return null;
try
@@ -181,7 +181,7 @@ namespace osu.Game.Beatmaps
protected override Waveform GetWaveform()
{
- if (Metadata?.AudioFile == null)
+ if (string.IsNullOrEmpty(Metadata?.AudioFile))
return null;
try
diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs
index 49c9ac5c65..4e40e52051 100644
--- a/osu.Game/Database/ArchiveModelManager.cs
+++ b/osu.Game/Database/ArchiveModelManager.cs
@@ -466,7 +466,7 @@ namespace osu.Game.Database
if (retrievedItem == null)
throw new ArgumentException(@"Specified model could not be found", nameof(item));
- string filename = $"{getValidFilename(item.ToString())}{HandledExtensions.First()}";
+ string filename = $"{GetValidFilename(item.ToString())}{HandledExtensions.First()}";
using (var stream = exportStorage.GetStream(filename, FileAccess.Write, FileMode.Create))
ExportModelTo(retrievedItem, stream);
@@ -913,9 +913,15 @@ namespace osu.Game.Database
return Guid.NewGuid().ToString();
}
- private string getValidFilename(string filename)
+ private readonly char[] invalidFilenameCharacters = Path.GetInvalidFileNameChars()
+ // Backslash is added to avoid issues when exporting to zip.
+ // See SharpCompress filename normalisation https://github.com/adamhathcock/sharpcompress/blob/a1e7c0068db814c9aa78d86a94ccd1c761af74bd/src/SharpCompress/Writers/Zip/ZipWriter.cs#L143.
+ .Append('\\')
+ .ToArray();
+
+ protected string GetValidFilename(string filename)
{
- foreach (char c in Path.GetInvalidFileNameChars())
+ foreach (char c in invalidFilenameCharacters)
filename = filename.Replace(c, '_');
return filename;
}
diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs
index 0b43c16ebe..7d1210d0e3 100644
--- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs
+++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs
@@ -7,12 +7,10 @@ using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Sprites;
using System.Collections.Generic;
-using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Localisation;
using osu.Framework.Platform;
-using osu.Game.Graphics.Sprites;
using osu.Game.Users;
namespace osu.Game.Graphics.Containers
@@ -58,23 +56,14 @@ namespace osu.Game.Graphics.Containers
AddText(text.Substring(previousLinkEnd));
}
- public void AddLink(string text, string url, Action creationParameters = null) =>
+ public void AddLink(LocalisableString text, string url, Action creationParameters = null) =>
createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(LinkAction.External, url), url);
- public void AddLink(string text, Action action, string tooltipText = null, Action creationParameters = null)
+ public void AddLink(LocalisableString text, Action action, string tooltipText = null, Action creationParameters = null)
=> createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(LinkAction.Custom, string.Empty), tooltipText, action);
- public void AddLink(string text, LinkAction action, string argument, string tooltipText = null, Action creationParameters = null)
- => createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(action, argument), tooltipText);
-
public void AddLink(LocalisableString text, LinkAction action, string argument, string tooltipText = null, Action creationParameters = null)
- {
- var spriteText = new OsuSpriteText { Text = text };
-
- AddText(spriteText, creationParameters);
- RemoveInternal(spriteText); // TODO: temporary, will go away when TextParts support localisation properly.
- createLink(new TextPartManual(spriteText.Yield()), new LinkDetails(action, argument), tooltipText);
- }
+ => createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(action, argument), tooltipText);
public void AddLink(IEnumerable text, LinkAction action, string linkArgument, string tooltipText = null)
{
diff --git a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs
index e8f80dec57..da511d8212 100644
--- a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs
+++ b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs
@@ -8,6 +8,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
+using osu.Framework.Localisation;
using osu.Game.Graphics.Containers;
namespace osu.Game.Graphics.UserInterface
@@ -19,7 +20,7 @@ namespace osu.Game.Graphics.UserInterface
///
protected virtual bool PlaySoundsOnUserChange => true;
- public string LabelText
+ public LocalisableString LabelText
{
set
{
diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs
index d5f76733cf..1e6032c1d0 100644
--- a/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs
+++ b/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs
@@ -8,6 +8,7 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
+using osu.Framework.Localisation;
using osu.Game.Graphics.Containers;
using osu.Game.Overlays;
using osuTK;
@@ -156,18 +157,18 @@ namespace osu.Game.Graphics.UserInterfaceV2
descriptionText.Colour = osuColour.Yellow;
}
- public string Label
+ public LocalisableString Label
{
set => labelText.Text = value;
}
- public string Description
+ public LocalisableString Description
{
set
{
descriptionText.Text = value;
- if (!string.IsNullOrEmpty(value))
+ if (!string.IsNullOrEmpty(value.ToString()))
descriptionText.Show();
else
descriptionText.Hide();
diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs
index d60c9cfe65..69d72226ba 100644
--- a/osu.Game/Online/API/APIRequest.cs
+++ b/osu.Game/Online/API/APIRequest.cs
@@ -107,7 +107,8 @@ namespace osu.Game.Online.API
WebRequest = CreateWebRequest();
WebRequest.Failed += Fail;
WebRequest.AllowRetryOnTimeout = false;
- WebRequest.AddHeader("Authorization", $"Bearer {API.AccessToken}");
+ if (!string.IsNullOrEmpty(API.AccessToken))
+ WebRequest.AddHeader("Authorization", $"Bearer {API.AccessToken}");
if (isFailing) return;
diff --git a/osu.Game/Online/API/Requests/GetScoresRequest.cs b/osu.Game/Online/API/Requests/GetScoresRequest.cs
index 790a247ccb..8e447390e6 100644
--- a/osu.Game/Online/API/Requests/GetScoresRequest.cs
+++ b/osu.Game/Online/API/Requests/GetScoresRequest.cs
@@ -14,15 +14,15 @@ namespace osu.Game.Online.API.Requests
{
public class GetScoresRequest : APIRequest
{
- private readonly BeatmapInfo beatmapInfo;
+ private readonly IBeatmapInfo beatmapInfo;
private readonly BeatmapLeaderboardScope scope;
- private readonly RulesetInfo ruleset;
+ private readonly IRulesetInfo ruleset;
private readonly IEnumerable mods;
- public GetScoresRequest(BeatmapInfo beatmapInfo, RulesetInfo ruleset, BeatmapLeaderboardScope scope = BeatmapLeaderboardScope.Global, IEnumerable mods = null)
+ public GetScoresRequest(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset, BeatmapLeaderboardScope scope = BeatmapLeaderboardScope.Global, IEnumerable mods = null)
{
- if (!beatmapInfo.OnlineBeatmapID.HasValue)
- throw new InvalidOperationException($"Cannot lookup a beatmap's scores without having a populated {nameof(BeatmapInfo.OnlineBeatmapID)}.");
+ if (beatmapInfo.OnlineID <= 0)
+ throw new InvalidOperationException($"Cannot lookup a beatmap's scores without having a populated {nameof(IBeatmapInfo.OnlineID)}.");
if (scope == BeatmapLeaderboardScope.Local)
throw new InvalidOperationException("Should not attempt to request online scores for a local scoped leaderboard");
@@ -33,7 +33,7 @@ namespace osu.Game.Online.API.Requests
this.mods = mods ?? Array.Empty();
}
- protected override string Target => $@"beatmaps/{beatmapInfo.OnlineBeatmapID}/scores{createQueryParameters()}";
+ protected override string Target => $@"beatmaps/{beatmapInfo.OnlineID}/scores{createQueryParameters()}";
private string createQueryParameters()
{
diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs
index e65dca752b..653b011f73 100644
--- a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs
+++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs
@@ -43,16 +43,16 @@ namespace osu.Game.Online.API.Requests.Responses
public double StarRating { get; set; }
[JsonProperty(@"drain")]
- private float drainRate { get; set; }
+ public float DrainRate { get; set; }
[JsonProperty(@"cs")]
- private float circleSize { get; set; }
+ public float CircleSize { get; set; }
[JsonProperty(@"ar")]
- private float approachRate { get; set; }
+ public float ApproachRate { get; set; }
[JsonProperty(@"accuracy")]
- private float overallDifficulty { get; set; }
+ public float OverallDifficulty { get; set; }
[JsonIgnore]
public double Length { get; set; }
@@ -100,10 +100,10 @@ namespace osu.Game.Online.API.Requests.Responses
MaxCombo = MaxCombo,
BaseDifficulty = new BeatmapDifficulty
{
- DrainRate = drainRate,
- CircleSize = circleSize,
- ApproachRate = approachRate,
- OverallDifficulty = overallDifficulty,
+ DrainRate = DrainRate,
+ CircleSize = CircleSize,
+ ApproachRate = ApproachRate,
+ OverallDifficulty = OverallDifficulty,
},
OnlineInfo = this,
};
@@ -115,10 +115,10 @@ namespace osu.Game.Online.API.Requests.Responses
public IBeatmapDifficultyInfo Difficulty => new BeatmapDifficulty
{
- DrainRate = drainRate,
- CircleSize = circleSize,
- ApproachRate = approachRate,
- OverallDifficulty = overallDifficulty,
+ DrainRate = DrainRate,
+ CircleSize = CircleSize,
+ ApproachRate = ApproachRate,
+ OverallDifficulty = OverallDifficulty,
};
IBeatmapSetInfo? IBeatmapInfo.BeatmapSet => BeatmapSet;
diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs
index d8efa20b39..c41271ad5c 100644
--- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs
+++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs
@@ -119,7 +119,7 @@ namespace osu.Game.Online.API.Requests.Responses
public string Tags { get; set; } = string.Empty;
[JsonProperty(@"beatmaps")]
- public IEnumerable Beatmaps { get; set; } = Array.Empty();
+ public APIBeatmap[] Beatmaps { get; set; } = Array.Empty();
public virtual BeatmapSetInfo ToBeatmapSet(RulesetStore rulesets)
{
@@ -128,7 +128,6 @@ namespace osu.Game.Online.API.Requests.Responses
OnlineBeatmapSetID = OnlineID,
Metadata = metadata,
Status = Status,
- OnlineInfo = this
};
beatmapSet.Beatmaps = Beatmaps.Select(b =>
diff --git a/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs
index 1b66a1dcc3..5395fe0429 100644
--- a/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs
+++ b/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using JetBrains.Annotations;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using osu.Game.Beatmaps;
@@ -36,6 +37,7 @@ namespace osu.Game.Online.API.Requests.Responses
public DateTimeOffset Date { get; set; }
[JsonProperty(@"beatmap")]
+ [CanBeNull]
public APIBeatmap Beatmap { get; set; }
[JsonProperty("accuracy")]
@@ -45,6 +47,7 @@ namespace osu.Game.Online.API.Requests.Responses
public double? PP { get; set; }
[JsonProperty(@"beatmapset")]
+ [CanBeNull]
public APIBeatmapSet BeatmapSet
{
set
@@ -62,10 +65,13 @@ namespace osu.Game.Online.API.Requests.Responses
public Dictionary Statistics { get; set; }
[JsonProperty(@"mode_int")]
- public int OnlineRulesetID { get; set; }
+ public int RulesetID { get; set; }
[JsonProperty(@"mods")]
- public string[] Mods { get; set; }
+ private string[] mods { set => Mods = value.Select(acronym => new APIMod { Acronym = acronym }); }
+
+ [NotNull]
+ public IEnumerable Mods { get; set; } = Array.Empty();
[JsonProperty("rank")]
[JsonConverter(typeof(StringEnumConverter))]
@@ -79,30 +85,30 @@ namespace osu.Game.Online.API.Requests.Responses
///
public ScoreInfo CreateScoreInfo(RulesetStore rulesets, BeatmapInfo beatmap = null)
{
- var ruleset = rulesets.GetRuleset(OnlineRulesetID);
+ var ruleset = rulesets.GetRuleset(RulesetID);
var rulesetInstance = ruleset.CreateInstance();
- var mods = Mods != null ? Mods.Select(acronym => rulesetInstance.CreateModFromAcronym(acronym)).Where(m => m != null).ToArray() : Array.Empty();
+ var modInstances = Mods.Select(apiMod => rulesetInstance.CreateModFromAcronym(apiMod.Acronym)).Where(m => m != null).ToArray();
// all API scores provided by this class are considered to be legacy.
- mods = mods.Append(rulesetInstance.CreateMod()).ToArray();
+ modInstances = modInstances.Append(rulesetInstance.CreateMod()).ToArray();
var scoreInfo = new ScoreInfo
{
TotalScore = TotalScore,
MaxCombo = MaxCombo,
- BeatmapInfo = Beatmap.ToBeatmapInfo(rulesets),
+ BeatmapInfo = Beatmap?.ToBeatmapInfo(rulesets),
User = User,
Accuracy = Accuracy,
OnlineScoreID = OnlineID,
Date = Date,
PP = PP,
- RulesetID = OnlineRulesetID,
+ RulesetID = RulesetID,
Hash = HasReplay ? "online" : string.Empty, // todo: temporary?
Rank = Rank,
Ruleset = ruleset,
- Mods = mods,
+ Mods = modInstances,
};
if (beatmap != null)
@@ -144,7 +150,7 @@ namespace osu.Game.Online.API.Requests.Responses
return scoreInfo;
}
- public IRulesetInfo Ruleset => new RulesetInfo { ID = OnlineRulesetID };
+ public IRulesetInfo Ruleset => new RulesetInfo { ID = RulesetID };
IBeatmapInfo IScoreInfo.Beatmap => Beatmap;
}
diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs
index d3e1a7c91a..a058420f78 100644
--- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs
+++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs
@@ -17,6 +17,7 @@ using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Online.API;
using osu.Game.Online.Multiplayer.Queueing;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Rooms;
using osu.Game.Online.Rooms.RoomStatuses;
using osu.Game.Rulesets;
@@ -148,6 +149,10 @@ namespace osu.Game.Online.Multiplayer
{
Room = joinedRoom;
APIRoom = room;
+
+ Debug.Assert(LocalUser != null);
+ addUserToAPIRoom(LocalUser);
+
foreach (var user in joinedRoom.Users)
updateUserPlayingState(user.UserID, user.State);
@@ -358,6 +363,8 @@ namespace osu.Game.Online.Multiplayer
Room.Users.Add(user);
+ addUserToAPIRoom(user);
+
UserJoined?.Invoke(user);
RoomUpdated?.Invoke();
});
@@ -377,6 +384,18 @@ namespace osu.Game.Online.Multiplayer
return handleUserLeft(user, UserKicked);
}
+ private void addUserToAPIRoom(MultiplayerRoomUser user)
+ {
+ Debug.Assert(APIRoom != null);
+
+ APIRoom.RecentParticipants.Add(user.User ?? new User
+ {
+ Id = user.UserID,
+ Username = "[Unresolved]"
+ });
+ APIRoom.ParticipantCount.Value++;
+ }
+
private Task handleUserLeft(MultiplayerRoomUser user, Action? callback)
{
if (Room == null)
@@ -390,6 +409,10 @@ namespace osu.Game.Online.Multiplayer
Room.Users.Remove(user);
PlayingUserIds.Remove(user.UserID);
+ Debug.Assert(APIRoom != null);
+ APIRoom.RecentParticipants.RemoveAll(u => u.Id == user.UserID);
+ APIRoom.ParticipantCount.Value--;
+
callback?.Invoke(user);
RoomUpdated?.Invoke();
}, false);
@@ -667,20 +690,17 @@ namespace osu.Game.Online.Multiplayer
CurrentMatchPlayingItem.Value = APIRoom.Playlist.SingleOrDefault(p => p.ID == settings.PlaylistItemId);
}, cancellationToken);
- ///
- /// Retrieves a from an online source.
- ///
- /// The beatmap set ID.
- /// A token to cancel the request.
- /// The retrieval task.
- protected abstract Task GetOnlineBeatmapSet(int beatmapId, CancellationToken cancellationToken = default);
-
private async Task createPlaylistItem(APIPlaylistItem item)
{
var set = await GetOnlineBeatmapSet(item.BeatmapID).ConfigureAwait(false);
- var beatmap = set.Beatmaps.Single(b => b.OnlineBeatmapID == item.BeatmapID);
- beatmap.MD5Hash = item.BeatmapChecksum;
+ // The incoming response is deserialised without circular reference handling currently.
+ // Because we require using metadata from this instance, populate the nested beatmaps' sets manually here.
+ foreach (var b in set.Beatmaps)
+ b.BeatmapSet = set;
+
+ var beatmap = set.Beatmaps.Single(b => b.OnlineID == item.BeatmapID);
+ beatmap.Checksum = item.BeatmapChecksum;
var ruleset = Rulesets.GetRuleset(item.RulesetID);
var rulesetInstance = ruleset.CreateInstance();
@@ -699,6 +719,14 @@ namespace osu.Game.Online.Multiplayer
return playlistItem;
}
+ ///
+ /// Retrieves a from an online source.
+ ///
+ /// The beatmap set ID.
+ /// A token to cancel the request.
+ /// The retrieval task.
+ protected abstract Task GetOnlineBeatmapSet(int beatmapId, CancellationToken cancellationToken = default);
+
///
/// For the provided user ID, update whether the user is included in .
///
diff --git a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs
index f69464e37e..94225b6de9 100644
--- a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs
+++ b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs
@@ -9,9 +9,9 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR.Client;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
-using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Rooms;
namespace osu.Game.Online.Multiplayer
@@ -167,9 +167,9 @@ namespace osu.Game.Online.Multiplayer
return connection.InvokeAsync(nameof(IMultiplayerServer.RemovePlaylistItem), item);
}
- protected override Task GetOnlineBeatmapSet(int beatmapId, CancellationToken cancellationToken = default)
+ protected override Task GetOnlineBeatmapSet(int beatmapId, CancellationToken cancellationToken = default)
{
- var tcs = new TaskCompletionSource();
+ var tcs = new TaskCompletionSource();
var req = new GetBeatmapSetRequest(beatmapId, BeatmapSetLookupType.BeatmapId);
req.Success += res =>
@@ -180,7 +180,7 @@ namespace osu.Game.Online.Multiplayer
return;
}
- tcs.SetResult(res.ToBeatmapSet(Rulesets));
+ tcs.SetResult(res);
};
req.Failure += e => tcs.SetException(e);
diff --git a/osu.Game/Online/Placeholders/ClickablePlaceholder.cs b/osu.Game/Online/Placeholders/ClickablePlaceholder.cs
index 936ad79c64..054a4a3c39 100644
--- a/osu.Game/Online/Placeholders/ClickablePlaceholder.cs
+++ b/osu.Game/Online/Placeholders/ClickablePlaceholder.cs
@@ -3,6 +3,7 @@
using System;
using osu.Framework.Graphics.Sprites;
+using osu.Framework.Localisation;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
@@ -12,7 +13,7 @@ namespace osu.Game.Online.Placeholders
{
public Action Action;
- public ClickablePlaceholder(string actionMessage, IconUsage icon)
+ public ClickablePlaceholder(LocalisableString actionMessage, IconUsage icon)
{
OsuTextFlowContainer textFlow;
diff --git a/osu.Game/Online/Placeholders/MessagePlaceholder.cs b/osu.Game/Online/Placeholders/MessagePlaceholder.cs
index 7342765ca4..1676ba6cf2 100644
--- a/osu.Game/Online/Placeholders/MessagePlaceholder.cs
+++ b/osu.Game/Online/Placeholders/MessagePlaceholder.cs
@@ -3,14 +3,15 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
+using osu.Framework.Localisation;
namespace osu.Game.Online.Placeholders
{
public class MessagePlaceholder : Placeholder
{
- private readonly string message;
+ private readonly LocalisableString message;
- public MessagePlaceholder(string message)
+ public MessagePlaceholder(LocalisableString message)
{
AddIcon(FontAwesome.Solid.ExclamationCircle, cp =>
{
diff --git a/osu.Game/Online/Rooms/MultiplayerScore.cs b/osu.Game/Online/Rooms/MultiplayerScore.cs
index 7ec34e70d5..375e0b6b9f 100644
--- a/osu.Game/Online/Rooms/MultiplayerScore.cs
+++ b/osu.Game/Online/Rooms/MultiplayerScore.cs
@@ -7,6 +7,7 @@ using System.Linq;
using JetBrains.Annotations;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
+using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
@@ -61,7 +62,7 @@ namespace osu.Game.Online.Rooms
[CanBeNull]
public MultiplayerScoresAround ScoresAround { get; set; }
- public ScoreInfo CreateScoreInfo(PlaylistItem playlistItem)
+ public ScoreInfo CreateScoreInfo(PlaylistItem playlistItem, [NotNull] BeatmapInfo beatmap)
{
var rulesetInstance = playlistItem.Ruleset.Value.CreateInstance();
@@ -70,7 +71,7 @@ namespace osu.Game.Online.Rooms
OnlineScoreID = ID,
TotalScore = TotalScore,
MaxCombo = MaxCombo,
- BeatmapInfo = playlistItem.Beatmap.Value,
+ BeatmapInfo = beatmap,
BeatmapInfoID = playlistItem.BeatmapID,
Ruleset = playlistItem.Ruleset.Value,
RulesetID = playlistItem.RulesetID,
diff --git a/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs
index 6cd735af23..eb9ea608f7 100644
--- a/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs
+++ b/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
+using System.Diagnostics;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@@ -52,8 +53,13 @@ namespace osu.Game.Online.Rooms
downloadTracker?.RemoveAndDisposeImmediately();
+ Debug.Assert(item.NewValue.Beatmap.Value.BeatmapSet != null);
+
downloadTracker = new BeatmapDownloadTracker(item.NewValue.Beatmap.Value.BeatmapSet);
- downloadTracker.State.BindValueChanged(_ => updateAvailability());
+
+ AddInternal(downloadTracker);
+
+ downloadTracker.State.BindValueChanged(_ => updateAvailability(), true);
downloadTracker.Progress.BindValueChanged(_ =>
{
if (downloadTracker.State.Value != DownloadState.Downloading)
@@ -63,9 +69,7 @@ namespace osu.Game.Online.Rooms
// we don't want to flood the network with this, so rate limit how often we send progress updates.
if (progressUpdate?.Completed != false)
progressUpdate = Scheduler.AddDelayed(updateAvailability, progressUpdate == null ? 0 : 500);
- });
-
- AddInternal(downloadTracker);
+ }, true);
}, true);
}
diff --git a/osu.Game/Online/Rooms/PlaylistItem.cs b/osu.Game/Online/Rooms/PlaylistItem.cs
index e2a47ed744..e6eae4ae2a 100644
--- a/osu.Game/Online/Rooms/PlaylistItem.cs
+++ b/osu.Game/Online/Rooms/PlaylistItem.cs
@@ -31,7 +31,7 @@ namespace osu.Game.Online.Rooms
public bool Expired { get; set; }
[JsonIgnore]
- public readonly Bindable Beatmap = new Bindable();
+ public readonly Bindable Beatmap = new Bindable();
[JsonIgnore]
public readonly Bindable Ruleset = new Bindable();
@@ -65,13 +65,13 @@ namespace osu.Game.Online.Rooms
public PlaylistItem()
{
- Beatmap.BindValueChanged(beatmap => BeatmapID = beatmap.NewValue?.OnlineBeatmapID ?? 0);
+ Beatmap.BindValueChanged(beatmap => BeatmapID = beatmap.NewValue?.OnlineID ?? -1);
Ruleset.BindValueChanged(ruleset => RulesetID = ruleset.NewValue?.ID ?? 0);
}
- public void MapObjects(BeatmapManager beatmaps, RulesetStore rulesets)
+ public void MapObjects(RulesetStore rulesets)
{
- Beatmap.Value ??= apiBeatmap.ToBeatmapInfo(rulesets);
+ Beatmap.Value ??= apiBeatmap;
Ruleset.Value ??= rulesets.GetRuleset(RulesetID);
Ruleset rulesetInstance = Ruleset.Value.CreateInstance();
diff --git a/osu.Game/Online/Rooms/SubmitRoomScoreRequest.cs b/osu.Game/Online/Rooms/SubmitRoomScoreRequest.cs
index 9e432fa99e..d5da6c401c 100644
--- a/osu.Game/Online/Rooms/SubmitRoomScoreRequest.cs
+++ b/osu.Game/Online/Rooms/SubmitRoomScoreRequest.cs
@@ -5,6 +5,7 @@ using System.Net.Http;
using Newtonsoft.Json;
using osu.Framework.IO.Network;
using osu.Game.Online.API;
+using osu.Game.Online.Solo;
using osu.Game.Scoring;
namespace osu.Game.Online.Rooms
@@ -14,14 +15,14 @@ namespace osu.Game.Online.Rooms
private readonly long scoreId;
private readonly long roomId;
private readonly long playlistItemId;
- private readonly ScoreInfo scoreInfo;
+ private readonly SubmittableScore score;
public SubmitRoomScoreRequest(long scoreId, long roomId, long playlistItemId, ScoreInfo scoreInfo)
{
this.scoreId = scoreId;
this.roomId = roomId;
this.playlistItemId = playlistItemId;
- this.scoreInfo = scoreInfo;
+ score = new SubmittableScore(scoreInfo);
}
protected override WebRequest CreateWebRequest()
@@ -31,7 +32,7 @@ namespace osu.Game.Online.Rooms
req.ContentType = "application/json";
req.Method = HttpMethod.Put;
- req.AddRaw(JsonConvert.SerializeObject(scoreInfo, new JsonSerializerSettings
+ req.AddRaw(JsonConvert.SerializeObject(score, new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
}));
diff --git a/osu.Game/Online/ScoreDownloadTracker.cs b/osu.Game/Online/ScoreDownloadTracker.cs
index 675dbf608c..e679071ac1 100644
--- a/osu.Game/Online/ScoreDownloadTracker.cs
+++ b/osu.Game/Online/ScoreDownloadTracker.cs
@@ -35,7 +35,11 @@ namespace osu.Game.Online
return;
// Used to interact with manager classes that don't support interface types. Will eventually be replaced.
- var scoreInfo = new ScoreInfo { OnlineScoreID = TrackedItem.OnlineScoreID };
+ var scoreInfo = new ScoreInfo
+ {
+ ID = TrackedItem.ID,
+ OnlineScoreID = TrackedItem.OnlineScoreID
+ };
if (Manager.IsAvailableLocally(scoreInfo))
UpdateState(DownloadState.LocallyAvailable);
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index f9e080a93c..a7ed7fedf5 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -436,11 +436,15 @@ namespace osu.Game
/// - first beatmap from any ruleset.
///
///
- public void PresentBeatmap(BeatmapSetInfo beatmap, Predicate difficultyCriteria = null)
+ public void PresentBeatmap(IBeatmapSetInfo beatmap, Predicate difficultyCriteria = null)
{
- var databasedSet = beatmap.OnlineBeatmapSetID != null
- ? BeatmapManager.QueryBeatmapSet(s => s.OnlineBeatmapSetID == beatmap.OnlineBeatmapSetID)
- : BeatmapManager.QueryBeatmapSet(s => s.Hash == beatmap.Hash);
+ BeatmapSetInfo databasedSet = null;
+
+ if (beatmap.OnlineID > 0)
+ databasedSet = BeatmapManager.QueryBeatmapSet(s => s.OnlineBeatmapSetID == beatmap.OnlineID);
+
+ if (beatmap is BeatmapSetInfo localBeatmap)
+ databasedSet ??= BeatmapManager.QueryBeatmapSet(s => s.Hash == localBeatmap.Hash);
if (databasedSet == null)
{
diff --git a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
index 8ee3b1cb2e..2ba8fc3ae2 100644
--- a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
+++ b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
@@ -5,7 +5,6 @@ using System;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Allocation;
-using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Utils;
@@ -135,7 +134,16 @@ namespace osu.Game.Overlays.AccountCreation
characterCheckText = passwordDescription.AddText("8 characters long");
passwordDescription.AddText(". Choose something long but also something you will remember, like a line from your favourite song.");
- passwordTextBox.Current.ValueChanged += password => { characterCheckText.Drawables.ForEach(s => s.Colour = password.NewValue.Length == 0 ? Color4.White : Interpolation.ValueAt(password.NewValue.Length, Color4.OrangeRed, Color4.YellowGreen, 0, 8, Easing.In)); };
+ passwordTextBox.Current.BindValueChanged(_ => updateCharacterCheckTextColour(), true);
+ characterCheckText.DrawablePartsRecreated += _ => updateCharacterCheckTextColour();
+ }
+
+ private void updateCharacterCheckTextColour()
+ {
+ string password = passwordTextBox.Text;
+
+ foreach (var d in characterCheckText.Drawables)
+ d.Colour = password.Length == 0 ? Color4.White : Interpolation.ValueAt(password.Length, Color4.OrangeRed, Color4.YellowGreen, 0, 8, Easing.In);
}
public override void OnEntering(IScreen last)
diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs
index 03d36ff5df..fa57191ef3 100644
--- a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs
+++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs
@@ -12,9 +12,9 @@ using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Localisation;
using osu.Framework.Threading;
-using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets;
using osu.Game.Resources.Localisation.Web;
using osuTK;
@@ -206,7 +206,7 @@ namespace osu.Game.Overlays.BeatmapListing
getSetsRequest.Success += response =>
{
- var sets = response.BeatmapSets.Select(responseJson => responseJson.ToBeatmapSet(rulesets)).ToList();
+ var sets = response.BeatmapSets.ToList();
// If the previous request returned a null cursor, the API is indicating we can't paginate further (maybe there are no more beatmaps left).
if (sets.Count == 0 || response.Cursor == null)
@@ -289,7 +289,7 @@ namespace osu.Game.Overlays.BeatmapListing
/// Contains the beatmap sets returned from API.
/// Valid for read if and only if is .
///
- public List Results { get; private set; }
+ public List Results { get; private set; }
///
/// Contains the names of supporter-only filters requested by the user.
@@ -297,7 +297,7 @@ namespace osu.Game.Overlays.BeatmapListing
///
public List SupporterOnlyFiltersUsed { get; private set; }
- public static SearchResult ResultsReturned(List results) => new SearchResult
+ public static SearchResult ResultsReturned(List results) => new SearchResult
{
Type = SearchResultType.ResultsReturned,
Results = results
diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs
index 776a8e73b0..2474515802 100644
--- a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs
+++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs
@@ -8,12 +8,12 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
-using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Configuration;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Input.Bindings;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Resources.Localisation.Web;
using osu.Game.Rulesets;
using osu.Game.Scoring;
@@ -49,17 +49,17 @@ namespace osu.Game.Overlays.BeatmapListing
public Bindable ExplicitContent => explicitContentFilter.Current;
- public BeatmapSetInfo BeatmapSet
+ public APIBeatmapSet BeatmapSet
{
set
{
- if (value == null || string.IsNullOrEmpty(value.OnlineInfo.Covers.Cover))
+ if (value == null || string.IsNullOrEmpty(value.Covers.Cover))
{
beatmapCover.FadeOut(600, Easing.OutQuint);
return;
}
- beatmapCover.OnlineInfo = value.OnlineInfo;
+ beatmapCover.OnlineInfo = value;
beatmapCover.FadeTo(0.1f, 200, Easing.OutQuint);
}
}
diff --git a/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanel.cs b/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanel.cs
index c7fa98f159..34086c214f 100644
--- a/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanel.cs
+++ b/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanel.cs
@@ -23,6 +23,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
+using osu.Game.Online.API.Requests.Responses;
using osuTK;
using osuTK.Graphics;
@@ -30,7 +31,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
{
public abstract class BeatmapPanel : OsuClickableContainer, IHasContextMenu
{
- public readonly BeatmapSetInfo SetInfo;
+ public readonly APIBeatmapSet SetInfo;
private const double hover_transition_time = 400;
private const int maximum_difficulty_icons = 10;
@@ -49,10 +50,10 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
protected Action ViewBeatmap;
- protected BeatmapPanel(BeatmapSetInfo setInfo)
+ protected BeatmapPanel(APIBeatmapSet setInfo)
: base(HoverSampleSet.Submit)
{
- Debug.Assert(setInfo.OnlineBeatmapSetID != null);
+ Debug.Assert(setInfo.OnlineID > 0);
SetInfo = setInfo;
}
@@ -95,8 +96,8 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
Action = ViewBeatmap = () =>
{
- Debug.Assert(SetInfo.OnlineBeatmapSetID != null);
- beatmapSetOverlay?.FetchAndShowBeatmapSet(SetInfo.OnlineBeatmapSetID.Value);
+ Debug.Assert(SetInfo.OnlineID > 0);
+ beatmapSetOverlay?.FetchAndShowBeatmapSet(SetInfo.OnlineID);
};
}
@@ -146,14 +147,14 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
{
var icons = new List();
- if (SetInfo.Beatmaps.Count > maximum_difficulty_icons)
+ if (SetInfo.Beatmaps.Length > maximum_difficulty_icons)
{
foreach (var ruleset in SetInfo.Beatmaps.Select(b => b.Ruleset).Distinct())
- icons.Add(new GroupedDifficultyIcon(SetInfo.Beatmaps.FindAll(b => b.Ruleset.Equals(ruleset)), ruleset, this is ListBeatmapPanel ? Color4.White : colours.Gray5));
+ icons.Add(new GroupedDifficultyIcon(SetInfo.Beatmaps.Where(b => b.RulesetID == ruleset.OnlineID).ToList(), ruleset, this is ListBeatmapPanel ? Color4.White : colours.Gray5));
}
else
{
- foreach (var b in SetInfo.Beatmaps.OrderBy(beatmap => beatmap.Ruleset.ID).ThenBy(beatmap => beatmap.StarDifficulty))
+ foreach (var b in SetInfo.Beatmaps.OrderBy(beatmap => beatmap.RulesetID).ThenBy(beatmap => beatmap.StarRating))
icons.Add(new DifficultyIcon(b));
}
@@ -163,7 +164,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
protected Drawable CreateBackground() => new UpdateableOnlineBeatmapSetCover
{
RelativeSizeAxes = Axes.Both,
- OnlineInfo = SetInfo.OnlineInfo,
+ OnlineInfo = SetInfo,
};
public class Statistic : FillFlowContainer
diff --git a/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanelDownloadButton.cs b/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanelDownloadButton.cs
index dd12e8e467..5ed49cf384 100644
--- a/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanelDownloadButton.cs
+++ b/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanelDownloadButton.cs
@@ -11,6 +11,7 @@ using osu.Game.Configuration;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online;
+using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Overlays.BeatmapListing.Panels
{
@@ -21,7 +22,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
///
/// Currently selected beatmap. Used to present the correct difficulty after completing a download.
///
- public readonly IBindable SelectedBeatmap = new Bindable();
+ public readonly IBindable SelectedBeatmap = new Bindable();
private readonly ShakeContainer shakeContainer;
private readonly DownloadButton button;
@@ -31,9 +32,9 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
protected readonly Bindable State = new Bindable();
- private readonly BeatmapSetInfo beatmapSet;
+ private readonly IBeatmapSetInfo beatmapSet;
- public BeatmapPanelDownloadButton(BeatmapSetInfo beatmapSet)
+ public BeatmapPanelDownloadButton(IBeatmapSetInfo beatmapSet)
{
this.beatmapSet = beatmapSet;
@@ -79,7 +80,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
case DownloadState.LocallyAvailable:
Predicate findPredicate = null;
if (SelectedBeatmap.Value != null)
- findPredicate = b => b.OnlineBeatmapID == SelectedBeatmap.Value.OnlineBeatmapID;
+ findPredicate = b => b.OnlineBeatmapID == SelectedBeatmap.Value.OnlineID;
game?.PresentBeatmap(beatmapSet, findPredicate);
break;
@@ -100,7 +101,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
break;
default:
- if (beatmapSet.OnlineInfo?.Availability.DownloadDisabled ?? false)
+ if ((beatmapSet as IBeatmapSetOnlineInfo)?.Availability.DownloadDisabled == true)
{
button.Enabled.Value = false;
button.TooltipText = "this beatmap is currently not available for download.";
diff --git a/osu.Game/Overlays/BeatmapListing/Panels/DownloadProgressBar.cs b/osu.Game/Overlays/BeatmapListing/Panels/DownloadProgressBar.cs
index 24f929f55e..93eaf775e0 100644
--- a/osu.Game/Overlays/BeatmapListing/Panels/DownloadProgressBar.cs
+++ b/osu.Game/Overlays/BeatmapListing/Panels/DownloadProgressBar.cs
@@ -18,7 +18,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
private readonly ProgressBar progressBar;
private readonly BeatmapDownloadTracker downloadTracker;
- public DownloadProgressBar(BeatmapSetInfo beatmapSet)
+ public DownloadProgressBar(IBeatmapSetInfo beatmapSet)
{
InternalChildren = new Drawable[]
{
diff --git a/osu.Game/Overlays/BeatmapListing/Panels/GridBeatmapPanel.cs b/osu.Game/Overlays/BeatmapListing/Panels/GridBeatmapPanel.cs
index 4a0fa59c31..770e5af7bd 100644
--- a/osu.Game/Overlays/BeatmapListing/Panels/GridBeatmapPanel.cs
+++ b/osu.Game/Overlays/BeatmapListing/Panels/GridBeatmapPanel.cs
@@ -9,11 +9,11 @@ using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osu.Framework.Localisation;
-using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.BeatmapSet;
using osuTK;
using osuTK.Graphics;
@@ -32,7 +32,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
protected override PlayButton PlayButton => playButton;
protected override Box PreviewBar => progressBar;
- public GridBeatmapPanel(BeatmapSetInfo beatmap)
+ public GridBeatmapPanel(APIBeatmapSet beatmap)
: base(beatmap)
{
Width = 380;
@@ -84,7 +84,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
{
new OsuSpriteText
{
- Text = new RomanisableString(SetInfo.Metadata.TitleUnicode, SetInfo.Metadata.Title),
+ Text = new RomanisableString(SetInfo.TitleUnicode, SetInfo.Title),
Font = OsuFont.GetFont(size: 18, weight: FontWeight.Bold, italics: true)
},
}
@@ -97,7 +97,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
{
new OsuSpriteText
{
- Text = new RomanisableString(SetInfo.Metadata.ArtistUnicode, SetInfo.Metadata.Artist),
+ Text = new RomanisableString(SetInfo.ArtistUnicode, SetInfo.Artist),
Font = OsuFont.GetFont(weight: FontWeight.Bold, italics: true)
}
}
@@ -145,7 +145,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
{
d.AutoSizeAxes = Axes.Both;
d.AddText("mapped by ", t => t.Colour = colours.Gray5);
- d.AddUserLink(SetInfo.Metadata.Author);
+ d.AddUserLink(SetInfo.Author);
}),
new Container
{
@@ -155,11 +155,11 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
{
new OsuSpriteText
{
- Text = SetInfo.Metadata.Source,
+ Text = SetInfo.Source,
Font = OsuFont.GetFont(size: 14),
Shadow = false,
Colour = colours.Gray5,
- Alpha = string.IsNullOrEmpty(SetInfo.Metadata.Source) ? 0f : 1f,
+ Alpha = string.IsNullOrEmpty(SetInfo.Source) ? 0f : 1f,
},
},
},
@@ -193,8 +193,8 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
Margin = new MarginPadding { Top = vertical_padding, Right = vertical_padding },
Children = new[]
{
- new Statistic(FontAwesome.Solid.PlayCircle, SetInfo.OnlineInfo?.PlayCount ?? 0),
- new Statistic(FontAwesome.Solid.Heart, SetInfo.OnlineInfo?.FavouriteCount ?? 0),
+ new Statistic(FontAwesome.Solid.PlayCircle, SetInfo.PlayCount),
+ new Statistic(FontAwesome.Solid.Heart, SetInfo.FavouriteCount),
},
},
statusContainer = new FillFlowContainer
@@ -211,7 +211,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
},
});
- if (SetInfo.OnlineInfo?.HasExplicitContent ?? false)
+ if (SetInfo.HasExplicitContent)
{
titleContainer.Add(new ExplicitContentBeatmapPill
{
@@ -221,7 +221,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
});
}
- if (SetInfo.OnlineInfo?.TrackId != null)
+ if (SetInfo.TrackId != null)
{
artistContainer.Add(new FeaturedArtistBeatmapPill
{
@@ -231,12 +231,12 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
});
}
- if (SetInfo.OnlineInfo?.HasVideo ?? false)
+ if (SetInfo.HasVideo)
{
statusContainer.Add(new IconPill(FontAwesome.Solid.Film));
}
- if (SetInfo.OnlineInfo?.HasStoryboard ?? false)
+ if (SetInfo.HasStoryboard)
{
statusContainer.Add(new IconPill(FontAwesome.Solid.Image));
}
@@ -246,7 +246,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
AutoSizeAxes = Axes.Both,
TextSize = 12,
TextPadding = new MarginPadding { Horizontal = 10, Vertical = 5 },
- Status = SetInfo.OnlineInfo?.Status ?? BeatmapSetOnlineStatus.None,
+ Status = SetInfo.Status,
});
PreviewPlaying.ValueChanged += _ => updateStatusContainer();
diff --git a/osu.Game/Overlays/BeatmapListing/Panels/ListBeatmapPanel.cs b/osu.Game/Overlays/BeatmapListing/Panels/ListBeatmapPanel.cs
index 63d651f9de..dcd676724a 100644
--- a/osu.Game/Overlays/BeatmapListing/Panels/ListBeatmapPanel.cs
+++ b/osu.Game/Overlays/BeatmapListing/Panels/ListBeatmapPanel.cs
@@ -9,11 +9,11 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
-using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.BeatmapSet;
using osuTK;
using osuTK.Graphics;
@@ -37,7 +37,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
protected override PlayButton PlayButton => playButton;
protected override Box PreviewBar => progressBar;
- public ListBeatmapPanel(BeatmapSetInfo beatmap)
+ public ListBeatmapPanel(APIBeatmapSet beatmap)
: base(beatmap)
{
RelativeSizeAxes = Axes.X;
@@ -107,7 +107,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
{
new OsuSpriteText
{
- Text = new RomanisableString(SetInfo.Metadata.TitleUnicode, SetInfo.Metadata.Title),
+ Text = new RomanisableString(SetInfo.TitleUnicode, SetInfo.Title),
Font = OsuFont.GetFont(size: 18, weight: FontWeight.Bold, italics: true)
},
}
@@ -120,7 +120,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
{
new OsuSpriteText
{
- Text = new RomanisableString(SetInfo.Metadata.ArtistUnicode, SetInfo.Metadata.Artist),
+ Text = new RomanisableString(SetInfo.ArtistUnicode, SetInfo.Artist),
Font = OsuFont.GetFont(weight: FontWeight.Bold, italics: true)
},
},
@@ -182,8 +182,8 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
- new Statistic(FontAwesome.Solid.PlayCircle, SetInfo.OnlineInfo?.PlayCount ?? 0),
- new Statistic(FontAwesome.Solid.Heart, SetInfo.OnlineInfo?.FavouriteCount ?? 0),
+ new Statistic(FontAwesome.Solid.PlayCircle, SetInfo.PlayCount),
+ new Statistic(FontAwesome.Solid.Heart, SetInfo.FavouriteCount),
new LinkFlowContainer(s =>
{
s.Shadow = false;
@@ -197,15 +197,15 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
{
d.AutoSizeAxes = Axes.Both;
d.AddText("mapped by ");
- d.AddUserLink(SetInfo.Metadata.Author);
+ d.AddUserLink(SetInfo.Author);
}),
new OsuSpriteText
{
- Text = SetInfo.Metadata.Source,
+ Text = SetInfo.Source,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Font = OsuFont.GetFont(size: 14),
- Alpha = string.IsNullOrEmpty(SetInfo.Metadata.Source) ? 0f : 1f,
+ Alpha = string.IsNullOrEmpty(SetInfo.Source) ? 0f : 1f,
},
},
},
@@ -225,7 +225,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
},
});
- if (SetInfo.OnlineInfo?.HasExplicitContent ?? false)
+ if (SetInfo.HasExplicitContent)
{
titleContainer.Add(new ExplicitContentBeatmapPill
{
@@ -235,7 +235,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
});
}
- if (SetInfo.OnlineInfo?.TrackId != null)
+ if (SetInfo.TrackId != null)
{
artistContainer.Add(new FeaturedArtistBeatmapPill
{
@@ -245,12 +245,12 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
});
}
- if (SetInfo.OnlineInfo?.HasVideo ?? false)
+ if (SetInfo.HasVideo)
{
statusContainer.Add(new IconPill(FontAwesome.Solid.Film) { IconSize = new Vector2(20) });
}
- if (SetInfo.OnlineInfo?.HasStoryboard ?? false)
+ if (SetInfo.HasStoryboard)
{
statusContainer.Add(new IconPill(FontAwesome.Solid.Image) { IconSize = new Vector2(20) });
}
@@ -260,7 +260,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
AutoSizeAxes = Axes.Both,
TextSize = 12,
TextPadding = new MarginPadding { Horizontal = 10, Vertical = 4 },
- Status = SetInfo.OnlineInfo?.Status ?? BeatmapSetOnlineStatus.None,
+ Status = SetInfo.Status,
});
}
}
diff --git a/osu.Game/Overlays/BeatmapListing/Panels/PlayButton.cs b/osu.Game/Overlays/BeatmapListing/Panels/PlayButton.cs
index 3aa9aa5ca5..c352fe0223 100644
--- a/osu.Game/Overlays/BeatmapListing/Panels/PlayButton.cs
+++ b/osu.Game/Overlays/BeatmapListing/Panels/PlayButton.cs
@@ -8,9 +8,9 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osu.Game.Audio;
-using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
+using osu.Game.Online.API.Requests.Responses;
using osuTK;
using osuTK.Graphics;
@@ -24,9 +24,9 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
public PreviewTrack Preview { get; private set; }
- private BeatmapSetInfo beatmapSet;
+ private APIBeatmapSet beatmapSet;
- public BeatmapSetInfo BeatmapSet
+ public APIBeatmapSet BeatmapSet
{
get => beatmapSet;
set
@@ -66,7 +66,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
}
}
- public PlayButton(BeatmapSetInfo setInfo = null)
+ public PlayButton(APIBeatmapSet setInfo = null)
{
BeatmapSet = setInfo;
AddRange(new Drawable[]
diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs
index 935a89b99b..e08af52a72 100644
--- a/osu.Game/Overlays/BeatmapListingOverlay.cs
+++ b/osu.Game/Overlays/BeatmapListingOverlay.cs
@@ -15,10 +15,10 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Events;
using osu.Game.Audio;
-using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.Containers;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.BeatmapListing;
using osu.Game.Overlays.BeatmapListing.Panels;
using osu.Game.Resources.Localisation.Web;
@@ -136,7 +136,7 @@ namespace osu.Game.Overlays
return;
}
- var newPanels = searchResult.Results.Select(b => new GridBeatmapPanel(b)
+ var newPanels = searchResult.Results.Select(b => new GridBeatmapPanel(b)
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
diff --git a/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs b/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs
index 265d9bf125..c90e2e2085 100644
--- a/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs
+++ b/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs
@@ -6,7 +6,6 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Game.Beatmaps;
using osu.Game.Graphics.Sprites;
using osu.Game.Users.Drawables;
using osuTK;
@@ -16,6 +15,7 @@ using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Users;
using osu.Game.Graphics.Containers;
+using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Overlays.BeatmapSet
{
@@ -26,9 +26,9 @@ namespace osu.Game.Overlays.BeatmapSet
private UpdateableAvatar avatar;
private FillFlowContainer fields;
- private BeatmapSetInfo beatmapSet;
+ private APIBeatmapSet beatmapSet;
- public BeatmapSetInfo BeatmapSet
+ public APIBeatmapSet BeatmapSet
{
get => beatmapSet;
set
@@ -78,30 +78,28 @@ namespace osu.Game.Overlays.BeatmapSet
private void updateDisplay()
{
- avatar.User = BeatmapSet?.Metadata.Author;
+ avatar.User = BeatmapSet?.Author;
fields.Clear();
if (BeatmapSet == null)
return;
- var online = BeatmapSet.OnlineInfo;
-
fields.Children = new Drawable[]
{
- new Field("mapped by", BeatmapSet.Metadata.Author, OsuFont.GetFont(weight: FontWeight.Regular, italics: true)),
- new Field("submitted", online.Submitted, OsuFont.GetFont(weight: FontWeight.Bold))
+ new Field("mapped by", BeatmapSet.Author, OsuFont.GetFont(weight: FontWeight.Regular, italics: true)),
+ new Field("submitted", BeatmapSet.Submitted, OsuFont.GetFont(weight: FontWeight.Bold))
{
Margin = new MarginPadding { Top = 5 },
},
};
- if (online.Ranked.HasValue)
+ if (BeatmapSet.Ranked.HasValue)
{
- fields.Add(new Field(online.Status.ToString().ToLowerInvariant(), online.Ranked.Value, OsuFont.GetFont(weight: FontWeight.Bold)));
+ fields.Add(new Field(BeatmapSet.Status.ToString().ToLowerInvariant(), BeatmapSet.Ranked.Value, OsuFont.GetFont(weight: FontWeight.Bold)));
}
- else if (online.LastUpdated.HasValue)
+ else if (BeatmapSet.LastUpdated.HasValue)
{
- fields.Add(new Field("last updated", online.LastUpdated.Value, OsuFont.GetFont(weight: FontWeight.Bold)));
+ fields.Add(new Field("last updated", BeatmapSet.LastUpdated.Value, OsuFont.GetFont(weight: FontWeight.Bold)));
}
}
diff --git a/osu.Game/Overlays/BeatmapSet/BasicStats.cs b/osu.Game/Overlays/BeatmapSet/BasicStats.cs
index 683f4f0c49..8f848edf24 100644
--- a/osu.Game/Overlays/BeatmapSet/BasicStats.cs
+++ b/osu.Game/Overlays/BeatmapSet/BasicStats.cs
@@ -14,6 +14,7 @@ using osu.Game.Beatmaps;
using osu.Game.Extensions;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Resources.Localisation.Web;
using osuTK;
@@ -23,9 +24,9 @@ namespace osu.Game.Overlays.BeatmapSet
{
private readonly Statistic length, bpm, circleCount, sliderCount;
- private BeatmapSetInfo beatmapSet;
+ private APIBeatmapSet beatmapSet;
- public BeatmapSetInfo BeatmapSet
+ public APIBeatmapSet BeatmapSet
{
get => beatmapSet;
set
@@ -38,9 +39,9 @@ namespace osu.Game.Overlays.BeatmapSet
}
}
- private BeatmapInfo beatmapInfo;
+ private IBeatmapInfo beatmapInfo;
- public BeatmapInfo BeatmapInfo
+ public IBeatmapInfo BeatmapInfo
{
get => beatmapInfo;
set
@@ -55,7 +56,7 @@ namespace osu.Game.Overlays.BeatmapSet
private void updateDisplay()
{
- bpm.Value = BeatmapSet?.OnlineInfo?.BPM.ToLocalisableString(@"0.##") ?? (LocalisableString)"-";
+ bpm.Value = BeatmapSet?.BPM.ToLocalisableString(@"0.##") ?? (LocalisableString)"-";
if (beatmapInfo == null)
{
@@ -68,8 +69,10 @@ namespace osu.Game.Overlays.BeatmapSet
length.TooltipText = BeatmapsetsStrings.ShowStatsTotalLength(TimeSpan.FromMilliseconds(beatmapInfo.Length).ToFormattedDuration());
length.Value = TimeSpan.FromMilliseconds(beatmapInfo.Length).ToFormattedDuration();
- circleCount.Value = beatmapInfo.OnlineInfo.CircleCount.ToLocalisableString(@"N0");
- sliderCount.Value = beatmapInfo.OnlineInfo.SliderCount.ToLocalisableString(@"N0");
+ var onlineInfo = beatmapInfo as IBeatmapOnlineInfo;
+
+ circleCount.Value = (onlineInfo?.CircleCount ?? 0).ToLocalisableString(@"N0");
+ sliderCount.Value = (onlineInfo?.SliderCount ?? 0).ToLocalisableString(@"N0");
}
}
diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapAvailability.cs b/osu.Game/Overlays/BeatmapSet/BeatmapAvailability.cs
index f005a37eaa..dc46452dcb 100644
--- a/osu.Game/Overlays/BeatmapSet/BeatmapAvailability.cs
+++ b/osu.Game/Overlays/BeatmapSet/BeatmapAvailability.cs
@@ -5,19 +5,19 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
-using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
+using osu.Game.Online.API.Requests.Responses;
using osuTK.Graphics;
namespace osu.Game.Overlays.BeatmapSet
{
public class BeatmapAvailability : Container
{
- private BeatmapSetInfo beatmapSet;
+ private APIBeatmapSet beatmapSet;
- private bool downloadDisabled => BeatmapSet?.OnlineInfo.Availability.DownloadDisabled ?? false;
- private bool hasExternalLink => !string.IsNullOrEmpty(BeatmapSet?.OnlineInfo.Availability.ExternalLink);
+ private bool downloadDisabled => BeatmapSet?.Availability.DownloadDisabled ?? false;
+ private bool hasExternalLink => !string.IsNullOrEmpty(BeatmapSet?.Availability.ExternalLink);
private readonly LinkFlowContainer textContainer;
@@ -44,7 +44,7 @@ namespace osu.Game.Overlays.BeatmapSet
};
}
- public BeatmapSetInfo BeatmapSet
+ public APIBeatmapSet BeatmapSet
{
get => beatmapSet;
@@ -76,7 +76,7 @@ namespace osu.Game.Overlays.BeatmapSet
{
textContainer.NewParagraph();
textContainer.NewParagraph();
- textContainer.AddLink("Check here for more information.", BeatmapSet.OnlineInfo.Availability.ExternalLink, creationParameters: t => t.Font = OsuFont.GetFont(size: 10));
+ textContainer.AddLink("Check here for more information.", BeatmapSet.Availability.ExternalLink, creationParameters: t => t.Font = OsuFont.GetFont(size: 10));
}
}
}
diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs
index 3df275c6d3..b152375062 100644
--- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs
+++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs
@@ -17,6 +17,7 @@ using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Resources.Localisation.Web;
using osu.Game.Rulesets;
using osuTK;
@@ -34,10 +35,10 @@ namespace osu.Game.Overlays.BeatmapSet
public readonly DifficultiesContainer Difficulties;
- public readonly Bindable Beatmap = new Bindable();
- private BeatmapSetInfo beatmapSet;
+ public readonly Bindable Beatmap = new Bindable();
+ private APIBeatmapSet beatmapSet;
- public BeatmapSetInfo BeatmapSet
+ public APIBeatmapSet BeatmapSet
{
get => beatmapSet;
set
@@ -164,35 +165,38 @@ namespace osu.Game.Overlays.BeatmapSet
if (BeatmapSet != null)
{
- Difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps.Where(b => b.Ruleset.Equals(ruleset.Value)).OrderBy(b => b.StarDifficulty).Select(b => new DifficultySelectorButton(b)
- {
- State = DifficultySelectorState.NotSelected,
- OnHovered = beatmap =>
- {
- showBeatmap(beatmap);
- starRating.Text = beatmap.StarDifficulty.ToLocalisableString(@"0.##");
- starRatingContainer.FadeIn(100);
- },
- OnClicked = beatmap => { Beatmap.Value = beatmap; },
- });
+ Difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps
+ .Where(b => b.Ruleset.OnlineID == ruleset.Value?.OnlineID)
+ .OrderBy(b => b.StarRating)
+ .Select(b => new DifficultySelectorButton(b)
+ {
+ State = DifficultySelectorState.NotSelected,
+ OnHovered = beatmap =>
+ {
+ showBeatmap(beatmap);
+ starRating.Text = beatmap.StarRating.ToLocalisableString(@"0.##");
+ starRatingContainer.FadeIn(100);
+ },
+ OnClicked = beatmap => { Beatmap.Value = beatmap; },
+ });
}
starRatingContainer.FadeOut(100);
- Beatmap.Value = Difficulties.FirstOrDefault()?.BeatmapInfo;
- plays.Value = BeatmapSet?.OnlineInfo.PlayCount ?? 0;
- favourites.Value = BeatmapSet?.OnlineInfo.FavouriteCount ?? 0;
+ Beatmap.Value = Difficulties.FirstOrDefault()?.Beatmap;
+ plays.Value = BeatmapSet?.PlayCount ?? 0;
+ favourites.Value = BeatmapSet?.FavouriteCount ?? 0;
updateDifficultyButtons();
}
- private void showBeatmap(BeatmapInfo beatmapInfo)
+ private void showBeatmap(IBeatmapInfo beatmapInfo)
{
- version.Text = beatmapInfo?.Version;
+ version.Text = beatmapInfo?.DifficultyName;
}
private void updateDifficultyButtons()
{
- Difficulties.Children.ToList().ForEach(diff => diff.State = diff.BeatmapInfo == Beatmap.Value ? DifficultySelectorState.Selected : DifficultySelectorState.NotSelected);
+ Difficulties.Children.ToList().ForEach(diff => diff.State = diff.Beatmap == Beatmap.Value ? DifficultySelectorState.Selected : DifficultySelectorState.NotSelected);
}
public class DifficultiesContainer : FillFlowContainer
@@ -216,10 +220,10 @@ namespace osu.Game.Overlays.BeatmapSet
private readonly Box backgroundBox;
private readonly DifficultyIcon icon;
- public readonly BeatmapInfo BeatmapInfo;
+ public readonly APIBeatmap Beatmap;
- public Action OnHovered;
- public Action OnClicked;
+ public Action OnHovered;
+ public Action OnClicked;
public event Action StateChanged;
private DifficultySelectorState state;
@@ -241,9 +245,9 @@ namespace osu.Game.Overlays.BeatmapSet
}
}
- public DifficultySelectorButton(BeatmapInfo beatmapInfo)
+ public DifficultySelectorButton(APIBeatmap beatmapInfo)
{
- BeatmapInfo = beatmapInfo;
+ Beatmap = beatmapInfo;
Size = new Vector2(size);
Margin = new MarginPadding { Horizontal = tile_spacing / 2 };
@@ -273,7 +277,7 @@ namespace osu.Game.Overlays.BeatmapSet
protected override bool OnHover(HoverEvent e)
{
fadeIn();
- OnHovered?.Invoke(BeatmapInfo);
+ OnHovered?.Invoke(Beatmap);
return base.OnHover(e);
}
@@ -286,7 +290,7 @@ namespace osu.Game.Overlays.BeatmapSet
protected override bool OnClick(ClickEvent e)
{
- OnClicked?.Invoke(BeatmapInfo);
+ OnClicked?.Invoke(Beatmap);
return base.OnClick(e);
}
diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs
index 005d21726b..6564ca3d41 100644
--- a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs
+++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs
@@ -3,17 +3,17 @@
using osu.Framework.Bindables;
using osu.Framework.Graphics.UserInterface;
-using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using System.Linq;
+using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Overlays.BeatmapSet
{
public class BeatmapRulesetSelector : OverlayRulesetSelector
{
- private readonly Bindable beatmapSet = new Bindable();
+ private readonly Bindable beatmapSet = new Bindable();
- public BeatmapSetInfo BeatmapSet
+ public APIBeatmapSet BeatmapSet
{
get => beatmapSet.Value;
set
diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs
index 79c95d6646..b3b3d1980b 100644
--- a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs
+++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs
@@ -1,22 +1,22 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
-using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets;
-using System.Linq;
namespace osu.Game.Overlays.BeatmapSet
{
public class BeatmapRulesetTabItem : OverlayRulesetTabItem
{
- public readonly Bindable BeatmapSet = new Bindable();
+ public readonly Bindable BeatmapSet = new Bindable();
[Resolved]
private OverlayColourProvider colourProvider { get; set; }
@@ -64,7 +64,7 @@ namespace osu.Game.Overlays.BeatmapSet
BeatmapSet.BindValueChanged(setInfo =>
{
- int beatmapsCount = setInfo.NewValue?.Beatmaps.Count(b => b.Ruleset.Equals(Value)) ?? 0;
+ int beatmapsCount = setInfo.NewValue?.Beatmaps.Count(b => b.Ruleset.OnlineID == Value.OnlineID) ?? 0;
count.Text = beatmapsCount.ToString();
countContainer.FadeTo(beatmapsCount > 0 ? 1 : 0);
diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs
index 4a0c0e9f75..102cddfa92 100644
--- a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs
+++ b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs
@@ -6,7 +6,7 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Effects;
-using osu.Game.Beatmaps;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Resources.Localisation.Web;
using osu.Game.Rulesets;
using osuTK;
@@ -16,7 +16,7 @@ namespace osu.Game.Overlays.BeatmapSet
{
public class BeatmapSetHeader : OverlayHeader
{
- public readonly Bindable BeatmapSet = new Bindable();
+ public readonly Bindable BeatmapSet = new Bindable();
public BeatmapSetHeaderContent HeaderContent { get; private set; }
diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs
index 1bfa7d1c47..547b8a6ec3 100644
--- a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs
+++ b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs
@@ -10,13 +10,13 @@ using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Localisation;
-using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online;
using osu.Game.Online.API;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.BeatmapListing.Panels;
using osu.Game.Overlays.BeatmapSet.Buttons;
using osuTK;
@@ -25,7 +25,7 @@ namespace osu.Game.Overlays.BeatmapSet
{
public class BeatmapSetHeaderContent : CompositeDrawable
{
- public readonly Bindable BeatmapSet = new Bindable();
+ public readonly Bindable BeatmapSet = new Bindable();
private const float transition_duration = 200;
private const float buttons_height = 45;
@@ -219,7 +219,7 @@ namespace osu.Game.Overlays.BeatmapSet
Picker.Beatmap.ValueChanged += b =>
{
Details.BeatmapInfo = b.NewValue;
- externalLink.Link = $@"{api.WebsiteRootUrl}/beatmapsets/{BeatmapSet.Value?.OnlineBeatmapSetID}#{b.NewValue?.Ruleset.ShortName}/{b.NewValue?.OnlineBeatmapID}";
+ externalLink.Link = $@"{api.WebsiteRootUrl}/beatmapsets/{BeatmapSet.Value?.OnlineID}#{b.NewValue?.Ruleset.ShortName}/{b.NewValue?.OnlineID}";
};
}
@@ -231,7 +231,7 @@ namespace osu.Game.Overlays.BeatmapSet
BeatmapSet.BindValueChanged(setInfo =>
{
Picker.BeatmapSet = rulesetSelector.BeatmapSet = author.BeatmapSet = beatmapAvailability.BeatmapSet = Details.BeatmapSet = setInfo.NewValue;
- cover.OnlineInfo = setInfo.NewValue?.OnlineInfo;
+ cover.OnlineInfo = setInfo.NewValue;
downloadTracker?.RemoveAndDisposeImmediately();
@@ -255,14 +255,14 @@ namespace osu.Game.Overlays.BeatmapSet
loading.Hide();
- title.Text = new RomanisableString(setInfo.NewValue.Metadata.TitleUnicode, setInfo.NewValue.Metadata.Title);
- artist.Text = new RomanisableString(setInfo.NewValue.Metadata.ArtistUnicode, setInfo.NewValue.Metadata.Artist);
+ title.Text = new RomanisableString(setInfo.NewValue.TitleUnicode, setInfo.NewValue.Title);
+ artist.Text = new RomanisableString(setInfo.NewValue.ArtistUnicode, setInfo.NewValue.Artist);
- explicitContentPill.Alpha = setInfo.NewValue.OnlineInfo.HasExplicitContent ? 1 : 0;
- featuredArtistPill.Alpha = setInfo.NewValue.OnlineInfo.TrackId != null ? 1 : 0;
+ explicitContentPill.Alpha = setInfo.NewValue.HasExplicitContent ? 1 : 0;
+ featuredArtistPill.Alpha = setInfo.NewValue.TrackId != null ? 1 : 0;
onlineStatusPill.FadeIn(500, Easing.OutQuint);
- onlineStatusPill.Status = setInfo.NewValue.OnlineInfo.Status;
+ onlineStatusPill.Status = setInfo.NewValue.Status;
downloadButtonsContainer.FadeIn(transition_duration);
favouriteButton.FadeIn(transition_duration);
@@ -276,7 +276,7 @@ namespace osu.Game.Overlays.BeatmapSet
{
if (BeatmapSet.Value == null) return;
- if (BeatmapSet.Value.OnlineInfo.Availability.DownloadDisabled && downloadTracker.State.Value != DownloadState.LocallyAvailable)
+ if (BeatmapSet.Value.Availability.DownloadDisabled && downloadTracker.State.Value != DownloadState.LocallyAvailable)
{
downloadButtonsContainer.Clear();
return;
@@ -302,7 +302,7 @@ namespace osu.Game.Overlays.BeatmapSet
default:
downloadButtonsContainer.Child = new HeaderDownloadButton(BeatmapSet.Value);
- if (BeatmapSet.Value.OnlineInfo.HasVideo)
+ if (BeatmapSet.Value.HasVideo)
downloadButtonsContainer.Add(new HeaderDownloadButton(BeatmapSet.Value, true));
break;
}
diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs
index 43dd1438f1..d4873f241c 100644
--- a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs
+++ b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs
@@ -8,10 +8,10 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
-using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.Notifications;
using osu.Game.Resources.Localisation.Web;
using osu.Game.Users;
@@ -21,7 +21,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
{
public class FavouriteButton : HeaderButton, IHasTooltip
{
- public readonly Bindable BeatmapSet = new Bindable();
+ public readonly Bindable BeatmapSet = new Bindable();
private readonly BindableBool favourited = new BindableBool();
@@ -61,13 +61,13 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
Action = () =>
{
// guaranteed by disabled state above.
- Debug.Assert(BeatmapSet.Value.OnlineBeatmapSetID != null);
+ Debug.Assert(BeatmapSet.Value.OnlineID > 0);
loading.Show();
request?.Cancel();
- request = new PostBeatmapFavouriteRequest(BeatmapSet.Value.OnlineBeatmapSetID.Value, favourited.Value ? BeatmapFavouriteAction.UnFavourite : BeatmapFavouriteAction.Favourite);
+ request = new PostBeatmapFavouriteRequest(BeatmapSet.Value.OnlineID, favourited.Value ? BeatmapFavouriteAction.UnFavourite : BeatmapFavouriteAction.Favourite);
request.Success += () =>
{
@@ -98,11 +98,11 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
BeatmapSet.BindValueChanged(setInfo =>
{
updateEnabled();
- favourited.Value = setInfo.NewValue?.OnlineInfo?.HasFavourited ?? false;
+ favourited.Value = setInfo.NewValue?.HasFavourited ?? false;
}, true);
}
- private void updateEnabled() => Enabled.Value = !(localUser.Value is GuestUser) && BeatmapSet.Value?.OnlineBeatmapSetID > 0;
+ private void updateEnabled() => Enabled.Value = !(localUser.Value is GuestUser) && BeatmapSet.Value?.OnlineID > 0;
protected override void UpdateAfterChildren()
{
diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs
index 88d0778ae4..bd7723d3c0 100644
--- a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs
+++ b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs
@@ -14,11 +14,13 @@ using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Online;
using osu.Game.Online.API;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.BeatmapListing.Panels;
using osu.Game.Resources.Localisation.Web;
using osu.Game.Users;
using osuTK;
using osuTK.Graphics;
+using CommonStrings = osu.Game.Localisation.CommonStrings;
namespace osu.Game.Overlays.BeatmapSet.Buttons
{
@@ -36,9 +38,10 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
private HeaderButton button;
private BeatmapDownloadTracker downloadTracker;
- private readonly BeatmapSetInfo beatmapSet;
- public HeaderDownloadButton(BeatmapSetInfo beatmapSet, bool noVideo = false)
+ private readonly APIBeatmapSet beatmapSet;
+
+ public HeaderDownloadButton(APIBeatmapSet beatmapSet, bool noVideo = false)
{
this.beatmapSet = beatmapSet;
this.noVideo = noVideo;
@@ -121,7 +124,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
{
new OsuSpriteText
{
- Text = Localisation.CommonStrings.Downloading,
+ Text = CommonStrings.Downloading,
Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold)
},
};
@@ -132,7 +135,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
{
new OsuSpriteText
{
- Text = Localisation.CommonStrings.Importing,
+ Text = CommonStrings.Importing,
Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold)
},
};
@@ -168,7 +171,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
private LocalisableString getVideoSuffixText()
{
- if (!beatmapSet.OnlineInfo.HasVideo)
+ if (!beatmapSet.HasVideo)
return string.Empty;
return noVideo ? BeatmapsetsStrings.ShowDetailsDownloadNoVideo : BeatmapsetsStrings.ShowDetailsDownloadVideo;
diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs
index 5b3c142a66..6bcdb7bdc5 100644
--- a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs
+++ b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs
@@ -8,9 +8,9 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osu.Game.Audio;
-using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.BeatmapListing.Panels;
using osuTK;
@@ -25,7 +25,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
public IBindable Playing => playButton.Playing;
- public BeatmapSetInfo BeatmapSet
+ public APIBeatmapSet BeatmapSet
{
get => playButton.BeatmapSet;
set => playButton.BeatmapSet = value;
diff --git a/osu.Game/Overlays/BeatmapSet/Details.cs b/osu.Game/Overlays/BeatmapSet/Details.cs
index d6720e5f35..dfc8d5e680 100644
--- a/osu.Game/Overlays/BeatmapSet/Details.cs
+++ b/osu.Game/Overlays/BeatmapSet/Details.cs
@@ -6,6 +6,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.BeatmapSet.Buttons;
using osu.Game.Screens.Select.Details;
using osuTK;
@@ -21,9 +22,9 @@ namespace osu.Game.Overlays.BeatmapSet
private readonly AdvancedStats advanced;
private readonly DetailBox ratingBox;
- private BeatmapSetInfo beatmapSet;
+ private APIBeatmapSet beatmapSet;
- public BeatmapSetInfo BeatmapSet
+ public APIBeatmapSet BeatmapSet
{
get => beatmapSet;
set
@@ -37,9 +38,9 @@ namespace osu.Game.Overlays.BeatmapSet
}
}
- private BeatmapInfo beatmapInfo;
+ private IBeatmapInfo beatmapInfo;
- public BeatmapInfo BeatmapInfo
+ public IBeatmapInfo BeatmapInfo
{
get => beatmapInfo;
set
@@ -53,7 +54,7 @@ namespace osu.Game.Overlays.BeatmapSet
private void updateDisplay()
{
Ratings.Ratings = BeatmapSet?.Ratings;
- ratingBox.Alpha = BeatmapSet?.OnlineInfo?.Status > 0 ? 1 : 0;
+ ratingBox.Alpha = BeatmapSet?.Status > 0 ? 1 : 0;
}
public Details()
diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs
index 970e9bbf42..3ef52d718d 100644
--- a/osu.Game/Overlays/BeatmapSet/Info.cs
+++ b/osu.Game/Overlays/BeatmapSet/Info.cs
@@ -6,9 +6,9 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
-using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
+using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Overlays.BeatmapSet
{
@@ -22,12 +22,12 @@ namespace osu.Game.Overlays.BeatmapSet
private readonly Box background;
private readonly SuccessRate successRate;
- public readonly Bindable BeatmapSet = new Bindable();
+ public readonly Bindable BeatmapSet = new Bindable();
- public BeatmapInfo BeatmapInfo
+ public APIBeatmap BeatmapInfo
{
- get => successRate.BeatmapInfo;
- set => successRate.BeatmapInfo = value;
+ get => successRate.Beatmap;
+ set => successRate.Beatmap = value;
}
public Info()
@@ -115,11 +115,11 @@ namespace osu.Game.Overlays.BeatmapSet
BeatmapSet.ValueChanged += b =>
{
- source.Text = b.NewValue?.Metadata.Source ?? string.Empty;
- tags.Text = b.NewValue?.Metadata.Tags ?? string.Empty;
- genre.Text = b.NewValue?.OnlineInfo?.Genre.Name ?? string.Empty;
- language.Text = b.NewValue?.OnlineInfo?.Language.Name ?? string.Empty;
- bool setHasLeaderboard = b.NewValue?.OnlineInfo?.Status > 0;
+ source.Text = b.NewValue?.Source ?? string.Empty;
+ tags.Text = b.NewValue?.Tags ?? string.Empty;
+ genre.Text = b.NewValue?.Genre.Name ?? string.Empty;
+ language.Text = b.NewValue?.Language.Name ?? string.Empty;
+ bool setHasLeaderboard = b.NewValue?.Status > 0;
successRate.Alpha = setHasLeaderboard ? 1 : 0;
notRankedPlaceholder.Alpha = setHasLeaderboard ? 0 : 1;
Height = setHasLeaderboard ? 270 : base_height;
diff --git a/osu.Game/Overlays/BeatmapSet/LeaderboardModSelector.cs b/osu.Game/Overlays/BeatmapSet/LeaderboardModSelector.cs
index 6349f115cb..a9723c9c62 100644
--- a/osu.Game/Overlays/BeatmapSet/LeaderboardModSelector.cs
+++ b/osu.Game/Overlays/BeatmapSet/LeaderboardModSelector.cs
@@ -13,6 +13,7 @@ using osu.Game.Graphics.UserInterface;
using osuTK.Graphics;
using System;
using System.Linq;
+using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions;
namespace osu.Game.Overlays.BeatmapSet
@@ -20,7 +21,7 @@ namespace osu.Game.Overlays.BeatmapSet
public class LeaderboardModSelector : CompositeDrawable
{
public readonly BindableList SelectedMods = new BindableList();
- public readonly Bindable Ruleset = new Bindable();
+ public readonly Bindable Ruleset = new Bindable();
private readonly FillFlowContainer modsContainer;
@@ -45,7 +46,10 @@ namespace osu.Game.Overlays.BeatmapSet
Ruleset.BindValueChanged(onRulesetChanged, true);
}
- private void onRulesetChanged(ValueChangedEvent ruleset)
+ [Resolved]
+ private RulesetStore rulesets { get; set; }
+
+ private void onRulesetChanged(ValueChangedEvent ruleset)
{
SelectedMods.Clear();
modsContainer.Clear();
@@ -54,7 +58,7 @@ namespace osu.Game.Overlays.BeatmapSet
return;
modsContainer.Add(new ModButton(new ModNoMod()));
- modsContainer.AddRange(ruleset.NewValue.CreateInstance().AllMods.Where(m => m.UserPlayable).Select(m => new ModButton(m)));
+ modsContainer.AddRange(rulesets.GetRuleset(ruleset.NewValue.OnlineID).CreateInstance().AllMods.Where(m => m.UserPlayable).Select(m => new ModButton(m)));
modsContainer.ForEach(button =>
{
diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs
index c6eb516c7c..4a00c8b4a0 100644
--- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs
+++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs
@@ -1,24 +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 osu.Framework.Allocation;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Shapes;
-using osuTK;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using osu.Game.Online.API.Requests.Responses;
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
+using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
-using osu.Framework.Bindables;
-using osu.Game.Graphics.UserInterface;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets;
using osu.Game.Scoring;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Users;
+using osuTK;
namespace osu.Game.Overlays.BeatmapSet.Scores
{
@@ -26,8 +26,8 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
{
private const int spacing = 15;
- public readonly Bindable Beatmap = new Bindable();
- private readonly Bindable ruleset = new Bindable();
+ public readonly Bindable Beatmap = new Bindable();
+ private readonly Bindable ruleset = new Bindable();
private readonly Bindable scope = new Bindable(BeatmapLeaderboardScope.Global);
private readonly IBindable user = new Bindable();
@@ -66,7 +66,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
if (value?.Scores.Any() != true)
return;
- scoreManager.OrderByTotalScoreAsync(value.Scores.Select(s => s.CreateScoreInfo(rulesets, Beatmap.Value)).ToArray(), loadCancellationSource.Token)
+ scoreManager.OrderByTotalScoreAsync(value.Scores.Select(s => s.CreateScoreInfo(rulesets, Beatmap.Value.ToBeatmapInfo(rulesets))).ToArray(), loadCancellationSource.Token)
.ContinueWith(ordered => Schedule(() =>
{
if (loadCancellationSource.IsCancellationRequested)
@@ -78,7 +78,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
scoreTable.Show();
var userScore = value.UserScore;
- var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets, Beatmap.Value);
+ var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets, Beatmap.Value.ToBeatmapInfo(rulesets));
topScoresContainer.Add(new DrawableTopScore(topScore));
@@ -200,11 +200,11 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
user.BindValueChanged(onUserChanged, true);
}
- private void onBeatmapChanged(ValueChangedEvent beatmap)
+ private void onBeatmapChanged(ValueChangedEvent beatmap)
{
var beatmapRuleset = beatmap.NewValue?.Ruleset;
- if (ruleset.Value?.Equals(beatmapRuleset) ?? false)
+ if (ruleset.Value?.OnlineID == beatmapRuleset?.OnlineID)
{
modSelector.DeselectAll();
ruleset.TriggerChange();
@@ -232,7 +232,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
noScoresPlaceholder.Hide();
- if (Beatmap.Value?.OnlineBeatmapID.HasValue != true || Beatmap.Value.Status <= BeatmapSetOnlineStatus.Pending)
+ if (Beatmap.Value == null || Beatmap.Value.OnlineID <= 0 || (Beatmap.Value?.BeatmapSet as IBeatmapSetOnlineInfo)?.Status <= BeatmapSetOnlineStatus.Pending)
{
Scores = null;
Hide();
diff --git a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs
index 40a3c9fe8b..e08f099226 100644
--- a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs
+++ b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs
@@ -5,10 +5,10 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Resources.Localisation.Web;
using osu.Game.Screens.Select.Details;
@@ -23,16 +23,16 @@ namespace osu.Game.Overlays.BeatmapSet
private readonly Bar successRate;
private readonly Container percentContainer;
- private BeatmapInfo beatmapInfo;
+ private APIBeatmap beatmap;
- public BeatmapInfo BeatmapInfo
+ public APIBeatmap Beatmap
{
- get => beatmapInfo;
+ get => beatmap;
set
{
- if (value == beatmapInfo) return;
+ if (value == beatmap) return;
- beatmapInfo = value;
+ beatmap = value;
updateDisplay();
}
@@ -40,15 +40,15 @@ namespace osu.Game.Overlays.BeatmapSet
private void updateDisplay()
{
- int passCount = beatmapInfo?.OnlineInfo?.PassCount ?? 0;
- int playCount = beatmapInfo?.OnlineInfo?.PlayCount ?? 0;
+ int passCount = beatmap?.PassCount ?? 0;
+ int playCount = beatmap?.PlayCount ?? 0;
float rate = playCount != 0 ? (float)passCount / playCount : 0;
successPercent.Text = rate.ToLocalisableString(@"0.#%");
successRate.Length = rate;
percentContainer.ResizeWidthTo(successRate.Length, 250, Easing.InOutCubic);
- Graph.FailTimes = beatmapInfo?.FailTimes;
+ Graph.FailTimes = beatmap?.FailTimes;
}
public SuccessRate()
diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs
index f987b57d6e..fa5a7c66d0 100644
--- a/osu.Game/Overlays/BeatmapSetOverlay.cs
+++ b/osu.Game/Overlays/BeatmapSetOverlay.cs
@@ -7,8 +7,8 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events;
-using osu.Game.Beatmaps;
using osu.Game.Online.API.Requests;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.BeatmapSet;
using osu.Game.Overlays.BeatmapSet.Scores;
using osu.Game.Overlays.Comments;
@@ -27,7 +27,7 @@ namespace osu.Game.Overlays
[Resolved]
private RulesetStore rulesets { get; set; }
- private readonly Bindable beatmapSet = new Bindable();
+ private readonly Bindable beatmapSet = new Bindable();
// receive input outside our bounds so we can trigger a close event on ourselves.
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
@@ -89,8 +89,8 @@ namespace osu.Game.Overlays
var req = new GetBeatmapSetRequest(beatmapId, BeatmapSetLookupType.BeatmapId);
req.Success += res =>
{
- beatmapSet.Value = res.ToBeatmapSet(rulesets);
- Header.HeaderContent.Picker.Beatmap.Value = Header.BeatmapSet.Value.Beatmaps.First(b => b.OnlineBeatmapID == beatmapId);
+ beatmapSet.Value = res;
+ Header.HeaderContent.Picker.Beatmap.Value = Header.BeatmapSet.Value.Beatmaps.First(b => b.OnlineID == beatmapId);
};
API.Queue(req);
@@ -102,7 +102,7 @@ namespace osu.Game.Overlays
beatmapSet.Value = null;
var req = new GetBeatmapSetRequest(beatmapSetId);
- req.Success += res => beatmapSet.Value = res.ToBeatmapSet(rulesets);
+ req.Success += res => beatmapSet.Value = res;
API.Queue(req);
Show();
@@ -112,7 +112,7 @@ namespace osu.Game.Overlays
/// Show an already fully-populated beatmap set.
///
/// The set to show.
- public void ShowBeatmapSet(BeatmapSetInfo set)
+ public void ShowBeatmapSet(APIBeatmapSet set)
{
beatmapSet.Value = set;
Show();
@@ -120,7 +120,7 @@ namespace osu.Game.Overlays
private class CommentsSection : BeatmapSetLayoutSection
{
- public readonly Bindable BeatmapSet = new Bindable();
+ public readonly Bindable BeatmapSet = new Bindable();
public CommentsSection()
{
@@ -130,10 +130,10 @@ namespace osu.Game.Overlays
BeatmapSet.BindValueChanged(beatmapSet =>
{
- if (beatmapSet.NewValue?.OnlineBeatmapSetID is int onlineBeatmapSetID)
+ if (beatmapSet.NewValue?.OnlineID > 0)
{
Show();
- comments.ShowComments(CommentableType.Beatmapset, onlineBeatmapSetID);
+ comments.ShowComments(CommentableType.Beatmapset, beatmapSet.NewValue.OnlineID);
}
else
{
diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs
index 5cc598ae70..e84eee15be 100644
--- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs
+++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs
@@ -101,7 +101,7 @@ namespace osu.Game.Overlays.Changelog
t.Colour = colour.PinkLighter;
})
{
- Text = ChangelogStrings.SupportText2.ToString(),
+ Text = ChangelogStrings.SupportText2,
Margin = new MarginPadding { Top = 10 },
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs
index 78ef2ec795..0f953f92bb 100644
--- a/osu.Game/Overlays/Dialog/PopupDialog.cs
+++ b/osu.Game/Overlays/Dialog/PopupDialog.cs
@@ -10,6 +10,7 @@ using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
+using osu.Framework.Localisation;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers;
using osuTK;
@@ -42,9 +43,9 @@ namespace osu.Game.Overlays.Dialog
set => icon.Icon = value;
}
- private string headerText;
+ private LocalisableString headerText;
- public string HeaderText
+ public LocalisableString HeaderText
{
get => headerText;
set
@@ -57,9 +58,9 @@ namespace osu.Game.Overlays.Dialog
}
}
- private string bodyText;
+ private LocalisableString bodyText;
- public string BodyText
+ public LocalisableString BodyText
{
get => bodyText;
set
diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs
index eea2a9dc7e..04c12b8cd7 100644
--- a/osu.Game/Overlays/Music/PlaylistItem.cs
+++ b/osu.Game/Overlays/Music/PlaylistItem.cs
@@ -25,11 +25,8 @@ namespace osu.Game.Overlays.Music
private TextFlowContainer text;
private ITextPart titlePart;
- private ILocalisedBindableString title;
- private ILocalisedBindableString artist;
-
- private Color4 selectedColour;
- private Color4 artistColour;
+ [Resolved]
+ private OsuColour colours { get; set; }
public PlaylistItem(BeatmapSetInfo item)
: base(item)
@@ -40,22 +37,15 @@ namespace osu.Game.Overlays.Music
}
[BackgroundDependencyLoader]
- private void load(OsuColour colours, LocalisationManager localisation)
+ private void load()
{
- selectedColour = colours.Yellow;
- artistColour = colours.Gray9;
HandleColour = colours.Gray5;
-
- title = localisation.GetLocalisedString(new RomanisableString(Model.Metadata.TitleUnicode, Model.Metadata.Title));
- artist = localisation.GetLocalisedString(new RomanisableString(Model.Metadata.ArtistUnicode, Model.Metadata.Artist));
}
protected override void LoadComplete()
{
base.LoadComplete();
- artist.BindValueChanged(_ => recreateText(), true);
-
SelectedSet.BindValueChanged(set =>
{
if (set.OldValue?.Equals(Model) != true && set.NewValue?.Equals(Model) != true)
@@ -68,7 +58,7 @@ namespace osu.Game.Overlays.Music
private void updateSelectionState(bool instant)
{
foreach (Drawable s in titlePart.Drawables)
- s.FadeColour(SelectedSet.Value?.Equals(Model) == true ? selectedColour : Color4.White, instant ? 0 : FADE_DURATION);
+ s.FadeColour(SelectedSet.Value?.Equals(Model) == true ? colours.Yellow : Color4.White, instant ? 0 : FADE_DURATION);
}
protected override Drawable CreateContent() => text = new OsuTextFlowContainer
@@ -77,18 +67,23 @@ namespace osu.Game.Overlays.Music
AutoSizeAxes = Axes.Y,
};
- private void recreateText()
+ protected override void LoadAsyncComplete()
{
- text.Clear();
+ base.LoadAsyncComplete();
- // space after the title to put a space between the title and artist
- titlePart = text.AddText(title.Value + @" ", sprite => sprite.Font = OsuFont.GetFont(weight: FontWeight.Regular));
+ var title = new RomanisableString(Model.Metadata.TitleUnicode, Model.Metadata.Title);
+ var artist = new RomanisableString(Model.Metadata.ArtistUnicode, Model.Metadata.Artist);
+
+ titlePart = text.AddText(title, sprite => sprite.Font = OsuFont.GetFont(weight: FontWeight.Regular));
updateSelectionState(true);
+ titlePart.DrawablePartsRecreated += _ => updateSelectionState(true);
- text.AddText(artist.Value, sprite =>
+ text.AddText(@" "); // to separate the title from the artist.
+
+ text.AddText(artist, sprite =>
{
sprite.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold);
- sprite.Colour = artistColour;
+ sprite.Colour = colours.Gray9;
sprite.Padding = new MarginPadding { Top = 1 };
});
}
diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs
index b27e15dd2c..c44b88ad29 100644
--- a/osu.Game/Overlays/Notifications/ProgressNotification.cs
+++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs
@@ -10,6 +10,7 @@ using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
+using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
@@ -22,7 +23,7 @@ namespace osu.Game.Overlays.Notifications
{
private const float loading_spinner_size = 22;
- public string Text
+ public LocalisableString Text
{
set => Schedule(() => textDrawable.Text = value);
}
diff --git a/osu.Game/Overlays/Notifications/SimpleNotification.cs b/osu.Game/Overlays/Notifications/SimpleNotification.cs
index 3a3136b1ea..17ec12a4ca 100644
--- a/osu.Game/Overlays/Notifications/SimpleNotification.cs
+++ b/osu.Game/Overlays/Notifications/SimpleNotification.cs
@@ -7,6 +7,7 @@ using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
+using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osuTK;
@@ -15,9 +16,9 @@ namespace osu.Game.Overlays.Notifications
{
public class SimpleNotification : Notification
{
- private string text = string.Empty;
+ private LocalisableString text;
- public string Text
+ public LocalisableString Text
{
get => text;
set
diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs
index c1e56facd9..fffa20dc11 100644
--- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs
@@ -61,7 +61,7 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps
new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
protected override Drawable CreateDrawableItem(APIBeatmapSet model) => model.OnlineID > 0
- ? new GridBeatmapPanel(model.ToBeatmapSet(Rulesets))
+ ? new GridBeatmapPanel(model)
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
diff --git a/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.cs b/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.cs
index ac4299ae49..3ed4bd9e50 100644
--- a/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.cs
+++ b/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.cs
@@ -5,15 +5,15 @@ using System.Diagnostics;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Sprites;
+using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osuTK;
-using osu.Framework.Graphics.Cursor;
-using osu.Framework.Localisation;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Resources.Localisation.Web;
diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs
index 7bfa2ee51e..fb464e1b41 100644
--- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs
+++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs
@@ -12,9 +12,11 @@ using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Leaderboards;
+using osu.Game.Rulesets;
using osu.Game.Rulesets.UI;
-using osu.Game.Scoring;
+using osu.Game.Utils;
using osuTK;
namespace osu.Game.Overlays.Profile.Sections.Ranks
@@ -26,7 +28,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
private const float performance_background_shear = 0.45f;
- protected readonly ScoreInfo Score;
+ protected readonly APIScoreInfo Score;
[Resolved]
private OsuColour colours { get; set; }
@@ -34,7 +36,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
[Resolved]
private OverlayColourProvider colourProvider { get; set; }
- public DrawableProfileScore(ScoreInfo score)
+ public DrawableProfileScore(APIScoreInfo score)
{
Score = score;
@@ -43,7 +45,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
}
[BackgroundDependencyLoader]
- private void load()
+ private void load(RulesetStore rulesets)
{
AddInternal(new ProfileItemContainer
{
@@ -79,7 +81,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
Spacing = new Vector2(0, 2),
Children = new Drawable[]
{
- new ScoreBeatmapMetadataContainer(Score.BeatmapInfo),
+ new ScoreBeatmapMetadataContainer(Score.Beatmap),
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
@@ -89,7 +91,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
{
new OsuSpriteText
{
- Text = $"{Score.BeatmapInfo.Version}",
+ Text = $"{Score.Beatmap?.DifficultyName}",
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular),
Colour = colours.Yellow
},
@@ -129,7 +131,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
Origin = Anchor.CentreRight,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(2),
- Children = Score.Mods.Select(mod => new ModIcon(mod)
+ Children = Score.Mods.Select(mod => new ModIcon(rulesets.GetRuleset(Score.RulesetID).CreateInstance().CreateModFromAcronym(mod.Acronym))
{
Scale = new Vector2(0.35f)
}).ToList(),
@@ -198,7 +200,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
RelativeSizeAxes = Axes.Y,
Child = new OsuSpriteText
{
- Text = Score.DisplayAccuracy,
+ Text = Score.Accuracy.FormatAccuracy(),
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true),
Colour = colours.Yellow,
Anchor = Anchor.CentreLeft,
diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileWeightedScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileWeightedScore.cs
index f77464ecb9..e653be5cfa 100644
--- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileWeightedScore.cs
+++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileWeightedScore.cs
@@ -6,8 +6,8 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Resources.Localisation.Web;
-using osu.Game.Scoring;
using osuTK;
namespace osu.Game.Overlays.Profile.Sections.Ranks
@@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
{
private readonly double weight;
- public DrawableProfileWeightedScore(ScoreInfo score, double weight)
+ public DrawableProfileWeightedScore(APIScoreInfo score, double weight)
: base(score)
{
this.weight = weight;
diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs
index 1fb6100a28..cde386bc7b 100644
--- a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs
@@ -69,10 +69,10 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
switch (type)
{
default:
- return new DrawableProfileScore(model.CreateScoreInfo(Rulesets));
+ return new DrawableProfileScore(model);
case ScoreType.Best:
- return new DrawableProfileWeightedScore(model.CreateScoreInfo(Rulesets), Math.Pow(0.95, drawableItemIndex++));
+ return new DrawableProfileWeightedScore(model, Math.Pow(0.95, drawableItemIndex++));
}
}
}
diff --git a/osu.Game/Overlays/Rankings/SpotlightsLayout.cs b/osu.Game/Overlays/Rankings/SpotlightsLayout.cs
index b16e0a4908..b95b0a1afc 100644
--- a/osu.Game/Overlays/Rankings/SpotlightsLayout.cs
+++ b/osu.Game/Overlays/Rankings/SpotlightsLayout.cs
@@ -143,7 +143,7 @@ namespace osu.Game.Overlays.Rankings
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Spacing = new Vector2(10),
- Children = response.BeatmapSets.Select(b => new GridBeatmapPanel(b.ToBeatmapSet(rulesets))
+ Children = response.BeatmapSets.Select(b => new GridBeatmapPanel(b)
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs
index e509cac2f1..0814e3c824 100644
--- a/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs
+++ b/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs
@@ -83,7 +83,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
cp.Font = OsuFont.Default.With(size: 24);
})
{
- Text = HeaderText.ToString(),
+ Text = HeaderText,
TextAnchor = Anchor.TopCentre,
Margin = new MarginPadding(10),
RelativeSizeAxes = Axes.X,
diff --git a/osu.Game/Overlays/Settings/SettingsCheckbox.cs b/osu.Game/Overlays/Settings/SettingsCheckbox.cs
index 8b7ac80a5b..8a8fed4d30 100644
--- a/osu.Game/Overlays/Settings/SettingsCheckbox.cs
+++ b/osu.Game/Overlays/Settings/SettingsCheckbox.cs
@@ -16,8 +16,7 @@ namespace osu.Game.Overlays.Settings
public override LocalisableString LabelText
{
get => labelText;
- // checkbox doesn't properly support localisation yet.
- set => ((OsuCheckbox)Control).LabelText = (labelText = value).ToString();
+ set => ((OsuCheckbox)Control).LabelText = labelText = value;
}
}
}
diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs
index b593dea576..e709be1343 100644
--- a/osu.Game/Overlays/Settings/SettingsItem.cs
+++ b/osu.Game/Overlays/Settings/SettingsItem.cs
@@ -68,7 +68,7 @@ namespace osu.Game.Overlays.Settings
{
set
{
- bool hasValue = !string.IsNullOrWhiteSpace(value.ToString());
+ bool hasValue = value != default;
if (warningText == null)
{
@@ -80,7 +80,7 @@ namespace osu.Game.Overlays.Settings
}
warningText.Alpha = hasValue ? 1 : 0;
- warningText.Text = value.ToString(); // TODO: Remove ToString() call after TextFlowContainer supports localisation (see https://github.com/ppy/osu-framework/issues/4636).
+ warningText.Text = value ?? default;
}
}
diff --git a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs
index eab81186d5..5b4284dc2f 100644
--- a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs
+++ b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs
@@ -58,6 +58,11 @@ namespace osu.Game.Rulesets.Difficulty
return CreateDifficultyAttributes(Beatmap, playableMods, skills, clockRate);
}
+ ///
+ /// Calculates the difficulty of the beatmap and returns a set of representing the difficulty at every relevant time value in the beatmap.
+ ///
+ /// The mods that should be applied to the beatmap.
+ /// The set of .
public List CalculateTimed(params Mod[] mods)
{
preProcess(mods);
@@ -77,7 +82,7 @@ namespace osu.Game.Rulesets.Difficulty
foreach (var skill in skills)
skill.ProcessInternal(hitObject);
- attribs.Add(new TimedDifficultyAttributes(hitObject.EndTime, CreateDifficultyAttributes(progressiveBeatmap, playableMods, skills, clockRate)));
+ attribs.Add(new TimedDifficultyAttributes(hitObject.EndTime * clockRate, CreateDifficultyAttributes(progressiveBeatmap, playableMods, skills, clockRate)));
}
return attribs;
diff --git a/osu.Game/Rulesets/Difficulty/TimedDifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/TimedDifficultyAttributes.cs
index 973b2dacb2..2509971389 100644
--- a/osu.Game/Rulesets/Difficulty/TimedDifficultyAttributes.cs
+++ b/osu.Game/Rulesets/Difficulty/TimedDifficultyAttributes.cs
@@ -11,9 +11,21 @@ namespace osu.Game.Rulesets.Difficulty
///
public class TimedDifficultyAttributes : IComparable
{
+ ///
+ /// The non-clock-adjusted time value at which the attributes take effect.
+ ///
public readonly double Time;
+
+ ///
+ /// The attributes.
+ ///
public readonly DifficultyAttributes Attributes;
+ ///
+ /// Creates new .
+ ///
+ /// The non-clock-adjusted time value at which the attributes take effect.
+ /// The attributes.
public TimedDifficultyAttributes(double time, DifficultyAttributes attributes)
{
Time = time;
diff --git a/osu.Game/Rulesets/Edit/Checks/CheckAudioQuality.cs b/osu.Game/Rulesets/Edit/Checks/CheckAudioQuality.cs
index 08e0312b64..ec2ff68aad 100644
--- a/osu.Game/Rulesets/Edit/Checks/CheckAudioQuality.cs
+++ b/osu.Game/Rulesets/Edit/Checks/CheckAudioQuality.cs
@@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Edit.Checks
public IEnumerable Run(BeatmapVerifierContext context)
{
string audioFile = context.Beatmap.Metadata?.AudioFile;
- if (audioFile == null)
+ if (string.IsNullOrEmpty(audioFile))
yield break;
var track = context.WorkingBeatmap.Track;
diff --git a/osu.Game/Rulesets/Edit/Checks/CheckFilePresence.cs b/osu.Game/Rulesets/Edit/Checks/CheckFilePresence.cs
index abedee143a..33bcac1e75 100644
--- a/osu.Game/Rulesets/Edit/Checks/CheckFilePresence.cs
+++ b/osu.Game/Rulesets/Edit/Checks/CheckFilePresence.cs
@@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Edit.Checks
{
string filename = GetFilename(context.Beatmap);
- if (filename == null)
+ if (string.IsNullOrEmpty(filename))
{
yield return new IssueTemplateNoneSet(this).Create(TypeOfFile);
diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs
index d7d4642a39..29e3f12d03 100644
--- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs
@@ -108,11 +108,20 @@ namespace osu.Game.Screens.Edit.Compose.Components
protected override bool OnMouseDown(MouseDownEvent e)
{
bool selectionPerformed = performMouseDownActions(e);
-
- // even if a selection didn't occur, a drag event may still move the selection.
bool movementPossible = prepareSelectionMovement();
- return selectionPerformed || (e.Button == MouseButton.Left && movementPossible);
+ // check if selection has occurred
+ if (selectionPerformed)
+ {
+ // only unmodified right click should show context menu
+ bool shouldShowContextMenu = e.Button == MouseButton.Right && !e.ShiftPressed && !e.AltPressed && !e.SuperPressed;
+
+ // stop propagation if not showing context menu
+ return !shouldShowContextMenu;
+ }
+
+ // even if a selection didn't occur, a drag event may still move the selection.
+ return e.Button == MouseButton.Left && movementPossible;
}
protected SelectionBlueprint ClickedBlueprint { get; private set; }
diff --git a/osu.Game/Screens/Edit/Timing/SliderWithTextBoxInput.cs b/osu.Game/Screens/Edit/Timing/SliderWithTextBoxInput.cs
index 10a5771520..6c004a7c8b 100644
--- a/osu.Game/Screens/Edit/Timing/SliderWithTextBoxInput.cs
+++ b/osu.Game/Screens/Edit/Timing/SliderWithTextBoxInput.cs
@@ -6,6 +6,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.UserInterface;
+using osu.Framework.Localisation;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Overlays.Settings;
@@ -16,7 +17,7 @@ namespace osu.Game.Screens.Edit.Timing
{
private readonly SettingsSlider slider;
- public SliderWithTextBoxInput(string labelText)
+ public SliderWithTextBoxInput(LocalisableString labelText)
{
LabelledTextBox textbox;
diff --git a/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs b/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs
index 2901758332..e948c1adae 100644
--- a/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs
+++ b/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs
@@ -7,7 +7,6 @@ using osu.Framework.Graphics;
using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
-using osu.Game.Graphics.Sprites;
using osu.Game.Online.Chat;
namespace osu.Game.Screens.OnlinePlay.Components
@@ -69,24 +68,14 @@ namespace osu.Game.Screens.OnlinePlay.Components
}
else
{
- textFlow.AddLink(new[]
- {
- new OsuSpriteText
- {
- Text = new RomanisableString(beatmap.Value.Metadata.ArtistUnicode, beatmap.Value.Metadata.Artist),
- Font = OsuFont.GetFont(size: TextSize),
- },
- new OsuSpriteText
- {
- Text = " - ",
- Font = OsuFont.GetFont(size: TextSize),
- },
- new OsuSpriteText
- {
- Text = new RomanisableString(beatmap.Value.Metadata.TitleUnicode, beatmap.Value.Metadata.Title),
- Font = OsuFont.GetFont(size: TextSize),
- }
- }, LinkAction.OpenBeatmap, beatmap.Value.OnlineID.ToString(), "Open beatmap");
+ var metadataInfo = beatmap.Value.Metadata;
+
+ string artistUnicode = string.IsNullOrEmpty(metadataInfo.ArtistUnicode) ? metadataInfo.Artist : metadataInfo.ArtistUnicode;
+ string titleUnicode = string.IsNullOrEmpty(metadataInfo.TitleUnicode) ? metadataInfo.Title : metadataInfo.TitleUnicode;
+
+ var title = new RomanisableString($"{artistUnicode} - {titleUnicode}".Trim(), $"{metadataInfo.Artist} - {metadataInfo.Title}".Trim());
+
+ textFlow.AddLink(title, LinkAction.OpenBeatmap, beatmap.Value.OnlineID.ToString(), "Open beatmap");
}
}
}
diff --git a/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundScreen.cs b/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundScreen.cs
index e2088c77d5..ffc5c07d4e 100644
--- a/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundScreen.cs
@@ -8,6 +8,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Screens;
+using osu.Game.Beatmaps;
using osu.Game.Online.Rooms;
using osuTK;
using osuTK.Graphics;
@@ -61,7 +62,10 @@ namespace osu.Game.Screens.OnlinePlay.Components
{
var beatmap = playlistItem?.Beatmap.Value;
- if (background?.BeatmapInfo?.BeatmapSet?.OnlineInfo?.Covers.Cover == beatmap?.BeatmapSet?.OnlineInfo?.Covers.Cover)
+ string? lastCover = (background?.Beatmap?.BeatmapSet as IBeatmapSetOnlineInfo)?.Covers.Cover;
+ string? newCover = (beatmap?.BeatmapSet as IBeatmapSetOnlineInfo)?.Covers.Cover;
+
+ if (lastCover == newCover)
return;
cancellationSource?.Cancel();
diff --git a/osu.Game/Screens/OnlinePlay/Components/PlaylistItemBackground.cs b/osu.Game/Screens/OnlinePlay/Components/PlaylistItemBackground.cs
index 90ad6e0f6e..f3e90aa396 100644
--- a/osu.Game/Screens/OnlinePlay/Components/PlaylistItemBackground.cs
+++ b/osu.Game/Screens/OnlinePlay/Components/PlaylistItemBackground.cs
@@ -13,11 +13,11 @@ namespace osu.Game.Screens.OnlinePlay.Components
{
public class PlaylistItemBackground : Background
{
- public readonly BeatmapInfo? BeatmapInfo;
+ public readonly IBeatmapInfo? Beatmap;
public PlaylistItemBackground(PlaylistItem? playlistItem)
{
- BeatmapInfo = playlistItem?.Beatmap.Value;
+ Beatmap = playlistItem?.Beatmap.Value;
}
[BackgroundDependencyLoader]
@@ -26,8 +26,8 @@ namespace osu.Game.Screens.OnlinePlay.Components
Texture? texture = null;
// prefer online cover where available.
- if (BeatmapInfo?.BeatmapSet?.OnlineInfo?.Covers.Cover != null)
- texture = textures.Get(BeatmapInfo.BeatmapSet.OnlineInfo.Covers.Cover);
+ if (Beatmap?.BeatmapSet is IBeatmapSetOnlineInfo online)
+ texture = textures.Get(online.Covers.Cover);
Sprite.Texture = texture ?? beatmaps.DefaultBeatmap.Background;
}
@@ -38,7 +38,7 @@ namespace osu.Game.Screens.OnlinePlay.Components
if (ReferenceEquals(this, other)) return true;
return other.GetType() == GetType()
- && ((PlaylistItemBackground)other).BeatmapInfo == BeatmapInfo;
+ && ((PlaylistItemBackground)other).Beatmap == Beatmap;
}
}
}
diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs b/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs
index abda9e897b..ddfdab18f7 100644
--- a/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs
+++ b/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs
@@ -119,7 +119,7 @@ namespace osu.Game.Screens.OnlinePlay.Components
try
{
foreach (var pi in room.Playlist)
- pi.MapObjects(beatmaps, rulesets);
+ pi.MapObjects(rulesets);
var existing = rooms.FirstOrDefault(e => e.RoomID.Value == room.RoomID.Value);
if (existing == null)
diff --git a/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs b/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs
index 7b14acf924..fc029543bb 100644
--- a/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs
+++ b/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs
@@ -80,10 +80,10 @@ namespace osu.Game.Screens.OnlinePlay.Components
private void updateRange(object sender, NotifyCollectionChangedEventArgs e)
{
- var orderedDifficulties = Playlist.Select(p => p.Beatmap.Value).OrderBy(b => b.StarDifficulty).ToArray();
+ var orderedDifficulties = Playlist.Select(p => p.Beatmap.Value).OrderBy(b => b.StarRating).ToArray();
- StarDifficulty minDifficulty = new StarDifficulty(orderedDifficulties.Length > 0 ? orderedDifficulties[0].StarDifficulty : 0, 0);
- StarDifficulty maxDifficulty = new StarDifficulty(orderedDifficulties.Length > 0 ? orderedDifficulties[^1].StarDifficulty : 0, 0);
+ StarDifficulty minDifficulty = new StarDifficulty(orderedDifficulties.Length > 0 ? orderedDifficulties[0].StarRating : 0, 0);
+ StarDifficulty maxDifficulty = new StarDifficulty(orderedDifficulties.Length > 0 ? orderedDifficulties[^1].StarRating : 0, 0);
minDisplay.Current.Value = minDifficulty;
maxDisplay.Current.Value = maxDifficulty;
diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs
index fa2d0dd165..f4f0e5ce0b 100644
--- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs
+++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs
@@ -27,6 +27,7 @@ using osu.Game.Overlays.BeatmapSet;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Play.HUD;
+using osu.Game.Users;
using osuTK;
using osuTK.Graphics;
@@ -47,7 +48,7 @@ namespace osu.Game.Screens.OnlinePlay
private ExplicitContentBeatmapPill explicitContentPill;
private ModDisplay modDisplay;
- private readonly Bindable beatmap = new Bindable();
+ private readonly Bindable beatmap = new Bindable();
private readonly Bindable ruleset = new Bindable();
private readonly BindableList requiredMods = new BindableList();
@@ -101,6 +102,7 @@ namespace osu.Game.Screens.OnlinePlay
}
private ScheduledDelegate scheduledRefresh;
+ private PanelBackground panelBackground;
private void scheduleRefresh()
{
@@ -110,24 +112,25 @@ namespace osu.Game.Screens.OnlinePlay
private void refresh()
{
- difficultyIconContainer.Child = new DifficultyIcon(beatmap.Value, ruleset.Value, requiredMods) { Size = new Vector2(32) };
+ difficultyIconContainer.Child = new DifficultyIcon(Item.Beatmap.Value, ruleset.Value, requiredMods, performBackgroundDifficultyLookup: false) { Size = new Vector2(32) };
+
+ panelBackground.Beatmap.Value = Item.Beatmap.Value;
beatmapText.Clear();
- beatmapText.AddLink(Item.Beatmap.Value.GetDisplayTitleRomanisable(), LinkAction.OpenBeatmap, Item.Beatmap.Value.OnlineBeatmapID.ToString(), null, text =>
+ beatmapText.AddLink(Item.Beatmap.Value.GetDisplayTitleRomanisable(), LinkAction.OpenBeatmap, Item.Beatmap.Value.OnlineID.ToString(), null, text =>
{
text.Truncate = true;
- text.RelativeSizeAxes = Axes.X;
});
authorText.Clear();
- if (Item.Beatmap?.Value?.Metadata?.Author != null)
+ if (!string.IsNullOrEmpty(Item.Beatmap.Value?.Metadata.Author))
{
authorText.AddText("mapped by ");
- authorText.AddUserLink(Item.Beatmap.Value?.Metadata.Author);
+ authorText.AddUserLink(new User { Username = Item.Beatmap.Value.Metadata.Author });
}
- bool hasExplicitContent = Item.Beatmap.Value.BeatmapSet.OnlineInfo?.HasExplicitContent == true;
+ bool hasExplicitContent = (Item.Beatmap.Value.BeatmapSet as IBeatmapSetOnlineInfo)?.HasExplicitContent == true;
explicitContentPill.Alpha = hasExplicitContent ? 1 : 0;
modDisplay.Current.Value = requiredMods.ToArray();
@@ -151,10 +154,9 @@ namespace osu.Game.Screens.OnlinePlay
Alpha = 0,
AlwaysPresent = true
},
- new PanelBackground
+ panelBackground = new PanelBackground
{
RelativeSizeAxes = Axes.Both,
- Beatmap = { BindTarget = beatmap }
},
new GridContainer
{
@@ -187,8 +189,11 @@ namespace osu.Game.Screens.OnlinePlay
{
beatmapText = new LinkFlowContainer(fontParameters)
{
- AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
+ // workaround to ensure only the first line of text shows, emulating truncation (but without ellipsis at the end).
+ // TODO: remove when text/link flow can support truncation with ellipsis natively.
+ Height = OsuFont.DEFAULT_FONT_SIZE,
+ Masking = true
},
new FillFlowContainer
{
@@ -340,7 +345,7 @@ namespace osu.Game.Screens.OnlinePlay
// For now, this is the same implementation as in PanelBackground, but supports a beatmap info rather than a working beatmap
private class PanelBackground : Container // todo: should be a buffered container (https://github.com/ppy/osu-framework/issues/3222)
{
- public readonly Bindable Beatmap = new Bindable();
+ public readonly Bindable Beatmap = new Bindable();
public PanelBackground()
{
diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs
index acd87ed864..9920883078 100644
--- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs
+++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs
@@ -353,7 +353,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
})
{
RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y
+ // workaround to ensure only the first line of text shows, emulating truncation (but without ellipsis at the end).
+ // TODO: remove when text/link flow can support truncation with ellipsis natively.
+ Height = 16,
+ Masking = true
}
}
}
@@ -381,11 +384,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
statusText.Text = "Currently playing ";
beatmapText.AddLink(item.NewValue.Beatmap.Value.GetDisplayTitleRomanisable(),
LinkAction.OpenBeatmap,
- item.NewValue.Beatmap.Value.OnlineBeatmapID.ToString(),
+ item.NewValue.Beatmap.Value.OnlineID.ToString(),
creationParameters: s =>
{
s.Truncate = true;
- s.RelativeSizeAxes = Axes.X;
});
}
}
diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs
index 2fe3c7b668..ef2c2df4a6 100644
--- a/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs
+++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs
@@ -4,6 +4,7 @@
using System.Collections.Specialized;
using Humanizer;
using osu.Framework.Allocation;
+using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
@@ -46,7 +47,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
private void updateCount(object sender, NotifyCollectionChangedEventArgs e)
{
count.Clear();
- count.AddText(Playlist.Count.ToString(), s => s.Font = s.Font.With(weight: FontWeight.Bold));
+ count.AddText(Playlist.Count.ToLocalisableString(), s => s.Font = s.Font.With(weight: FontWeight.Bold));
count.AddText(" ");
count.AddText("Beatmap".ToQuantity(Playlist.Count, ShowQuantityAs.None));
}
diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs
index 2015a050bb..2cb29262e2 100644
--- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs
@@ -369,7 +369,7 @@ namespace osu.Game.Screens.OnlinePlay.Match
var beatmap = SelectedItem.Value?.Beatmap.Value;
// Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info
- var localBeatmap = beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == beatmap.OnlineBeatmapID);
+ var localBeatmap = beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == beatmap.OnlineID);
Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap);
}
diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs
index fa4a4d5112..bdb5ff9bb2 100644
--- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs
+++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs
@@ -32,7 +32,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
private void load(IBindable ruleset)
{
// Sanity checks to ensure that PlaylistsPlayer matches the settings for the current PlaylistItem
- if (Beatmap.Value.BeatmapInfo.OnlineBeatmapID != PlaylistItem.Beatmap.Value.OnlineBeatmapID)
+ if (Beatmap.Value.BeatmapInfo.OnlineBeatmapID != PlaylistItem.Beatmap.Value.OnlineID)
throw new InvalidOperationException("Current Beatmap does not match PlaylistItem's Beatmap");
if (ruleset.Value.ID != PlaylistItem.Ruleset.Value.ID)
diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs
index 89bc659f63..34698fccab 100644
--- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs
@@ -169,7 +169,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
/// An optional pivot around which the scores were retrieved.
private void performSuccessCallback([NotNull] Action> callback, [NotNull] List scores, [CanBeNull] MultiplayerScores pivot = null)
{
- var scoreInfos = scores.Select(s => s.CreateScoreInfo(playlistItem)).ToArray();
+ var scoreInfos = scores.Select(s => s.CreateScoreInfo(playlistItem, Beatmap.Value.BeatmapInfo)).ToArray();
// Score panels calculate total score before displaying, which can take some time. In order to count that calculation as part of the loading spinner display duration,
// calculate the total scores locally before invoking the success callback.
diff --git a/osu.Game/Screens/Play/SoloSpectator.cs b/osu.Game/Screens/Play/SoloSpectator.cs
index 9d4dad8bdc..250738df39 100644
--- a/osu.Game/Screens/Play/SoloSpectator.cs
+++ b/osu.Game/Screens/Play/SoloSpectator.cs
@@ -18,6 +18,7 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Spectator;
using osu.Game.Overlays.BeatmapListing.Panels;
using osu.Game.Overlays.Settings;
@@ -50,7 +51,6 @@ namespace osu.Game.Screens.Play
private Container beatmapPanelContainer;
private TriangleButton watchButton;
private SettingsCheckbox automaticDownload;
- private BeatmapSetInfo onlineBeatmap;
///
/// The player's immediate online gameplay state.
@@ -60,6 +60,8 @@ namespace osu.Game.Screens.Play
private GetBeatmapSetRequest onlineBeatmapRequest;
+ private APIBeatmapSet beatmapSet;
+
public SoloSpectator([NotNull] User targetUser)
: base(targetUser.Id)
{
@@ -220,10 +222,10 @@ namespace osu.Game.Screens.Play
Debug.Assert(state.BeatmapID != null);
onlineBeatmapRequest = new GetBeatmapSetRequest(state.BeatmapID.Value, BeatmapSetLookupType.BeatmapId);
- onlineBeatmapRequest.Success += res => Schedule(() =>
+ onlineBeatmapRequest.Success += beatmapSet => Schedule(() =>
{
- onlineBeatmap = res.ToBeatmapSet(rulesets);
- beatmapPanelContainer.Child = new GridBeatmapPanel(onlineBeatmap);
+ this.beatmapSet = beatmapSet;
+ beatmapPanelContainer.Child = new GridBeatmapPanel(this.beatmapSet);
checkForAutomaticDownload();
});
@@ -232,16 +234,16 @@ namespace osu.Game.Screens.Play
private void checkForAutomaticDownload()
{
- if (onlineBeatmap == null)
+ if (beatmapSet == null)
return;
if (!automaticDownload.Current.Value)
return;
- if (beatmaps.IsAvailableLocally(onlineBeatmap))
+ if (beatmaps.IsAvailableLocally(new BeatmapSetInfo { OnlineBeatmapSetID = beatmapSet.OnlineID }))
return;
- beatmaps.Download(onlineBeatmap);
+ beatmaps.Download(beatmapSet);
}
public override bool OnExiting(IScreen next)
diff --git a/osu.Game/Screens/Select/BeatmapDeleteDialog.cs b/osu.Game/Screens/Select/BeatmapDeleteDialog.cs
index 5fb72e4151..307c2352e3 100644
--- a/osu.Game/Screens/Select/BeatmapDeleteDialog.cs
+++ b/osu.Game/Screens/Select/BeatmapDeleteDialog.cs
@@ -29,7 +29,7 @@ namespace osu.Game.Screens.Select
new PopupDialogOkButton
{
Text = @"Yes. Totally. Delete it.",
- Action = () => manager.Delete(beatmap),
+ Action = () => manager?.Delete(beatmap),
},
new PopupDialogCancelButton
{
diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs
index dfbaa9c6a5..6f215b9287 100644
--- a/osu.Game/Screens/Select/BeatmapDetails.cs
+++ b/osu.Game/Screens/Select/BeatmapDetails.cs
@@ -41,13 +41,13 @@ namespace osu.Game.Screens.Select
[Resolved]
private RulesetStore rulesets { get; set; }
- private BeatmapInfo beatmapInfo;
+ private IBeatmapInfo beatmapInfo;
private APIFailTimes failTimes;
private int[] ratings;
- public BeatmapInfo BeatmapInfo
+ public IBeatmapInfo BeatmapInfo
{
get => beatmapInfo;
set
@@ -56,8 +56,11 @@ namespace osu.Game.Screens.Select
beatmapInfo = value;
- failTimes = beatmapInfo?.OnlineInfo?.FailTimes;
- ratings = beatmapInfo?.BeatmapSet?.Ratings;
+ var onlineInfo = beatmapInfo as IBeatmapOnlineInfo;
+ var onlineSetInfo = beatmapInfo.BeatmapSet as IBeatmapSetOnlineInfo;
+
+ failTimes = onlineInfo?.FailTimes;
+ ratings = onlineSetInfo?.Ratings;
Scheduler.AddOnce(updateStatistics);
}
@@ -178,11 +181,11 @@ namespace osu.Game.Screens.Select
private void updateStatistics()
{
advanced.BeatmapInfo = BeatmapInfo;
- description.Text = BeatmapInfo?.Version;
- source.Text = BeatmapInfo?.Metadata?.Source;
- tags.Text = BeatmapInfo?.Metadata?.Tags;
+ description.Text = BeatmapInfo?.DifficultyName;
+ source.Text = BeatmapInfo?.Metadata.Source;
+ tags.Text = BeatmapInfo?.Metadata.Tags;
- // metrics may have been previously fetched
+ // failTimes may have been previously fetched
if (ratings != null && failTimes != null)
{
updateMetrics();
@@ -190,7 +193,7 @@ namespace osu.Game.Screens.Select
}
// for now, let's early abort if an OnlineBeatmapID is not present (should have been populated at import time).
- if (BeatmapInfo?.OnlineBeatmapID == null || api.State.Value == APIState.Offline)
+ if (BeatmapInfo == null || BeatmapInfo.OnlineID <= 0 || api.State.Value == APIState.Offline)
{
updateMetrics();
return;
diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs
index 2de72beaad..89eed14e6d 100644
--- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs
+++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs
@@ -188,8 +188,8 @@ namespace osu.Game.Screens.Select
RelativeSizeAxes = Axes.Both;
- titleBinding = localisation.GetLocalisedString(new RomanisableString(metadata.TitleUnicode, metadata.Title));
- artistBinding = localisation.GetLocalisedString(new RomanisableString(metadata.ArtistUnicode, metadata.Artist));
+ titleBinding = localisation.GetLocalisedBindableString(new RomanisableString(metadata.TitleUnicode, metadata.Title));
+ artistBinding = localisation.GetLocalisedBindableString(new RomanisableString(metadata.ArtistUnicode, metadata.Artist));
const float top_height = 0.7f;
diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs
index e465f423bc..d41cb73a29 100644
--- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs
+++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs
@@ -69,7 +69,7 @@ namespace osu.Game.Screens.Select.Carousel
return string.Compare(BeatmapSet.Metadata.Title, otherSet.BeatmapSet.Metadata.Title, StringComparison.OrdinalIgnoreCase);
case SortMode.Author:
- return string.Compare(BeatmapSet.Metadata.Author.Username, otherSet.BeatmapSet.Metadata.Author.Username, StringComparison.OrdinalIgnoreCase);
+ return string.Compare(BeatmapSet.Metadata.Author?.Username, otherSet.BeatmapSet.Metadata.Author?.Username, StringComparison.OrdinalIgnoreCase);
case SortMode.Source:
return string.Compare(BeatmapSet.Metadata.Source, otherSet.BeatmapSet.Metadata.Source, StringComparison.OrdinalIgnoreCase);
diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs
index 5940911d4a..8a5dde961f 100644
--- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs
+++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs
@@ -142,7 +142,7 @@ namespace osu.Game.Screens.Select.Carousel
},
new OsuSpriteText
{
- Text = $"{(beatmapInfo.Metadata ?? beatmapInfo.BeatmapSet.Metadata).Author.Username}",
+ Text = $"{(beatmapInfo.Metadata ?? beatmapInfo.BeatmapSet.Metadata).Author?.Username ?? string.Empty}",
Font = OsuFont.GetFont(italics: true),
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft
diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs
index 25ca6ee264..91c8ce441e 100644
--- a/osu.Game/Screens/Select/Details/AdvancedStats.cs
+++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs
@@ -38,9 +38,9 @@ namespace osu.Game.Screens.Select.Details
protected readonly StatisticRow FirstValue, HpDrain, Accuracy, ApproachRate;
private readonly StatisticRow starDifficulty;
- private BeatmapInfo beatmapInfo;
+ private IBeatmapInfo beatmapInfo;
- public BeatmapInfo BeatmapInfo
+ public IBeatmapInfo BeatmapInfo
{
get => beatmapInfo;
set
@@ -103,7 +103,7 @@ namespace osu.Game.Screens.Select.Details
private void updateStatistics()
{
- IBeatmapDifficultyInfo baseDifficulty = BeatmapInfo?.BaseDifficulty;
+ IBeatmapDifficultyInfo baseDifficulty = BeatmapInfo?.Difficulty;
BeatmapDifficulty adjustedDifficulty = null;
if (baseDifficulty != null && mods.Value.Any(m => m is IApplicableToDifficulty))
@@ -114,7 +114,7 @@ namespace osu.Game.Screens.Select.Details
mod.ApplyToDifficulty(adjustedDifficulty);
}
- switch (BeatmapInfo?.Ruleset?.ID ?? 0)
+ switch (BeatmapInfo?.Ruleset.OnlineID)
{
case 3:
// Account for mania differences locally for now
diff --git a/osu.Game/Skinning/Editor/SkinSelectionHandler.cs b/osu.Game/Skinning/Editor/SkinSelectionHandler.cs
index 0790faad34..01bd5e8196 100644
--- a/osu.Game/Skinning/Editor/SkinSelectionHandler.cs
+++ b/osu.Game/Skinning/Editor/SkinSelectionHandler.cs
@@ -70,14 +70,16 @@ namespace osu.Game.Skinning.Editor
if (anchor.HasFlagFast(Anchor.x1)) scale.X = 0;
if (anchor.HasFlagFast(Anchor.y1)) scale.Y = 0;
- bool shouldAspectLock =
- // for now aspect lock scale adjustments that occur at corners..
- (!anchor.HasFlagFast(Anchor.x1) && !anchor.HasFlagFast(Anchor.y1))
- // ..or if any of the selection have been rotated.
- // this is to avoid requiring skew logic (which would likely not be the user's expected transform anyway).
- || SelectedBlueprints.Any(b => !Precision.AlmostEquals(((Drawable)b.Item).Rotation, 0));
-
- if (shouldAspectLock)
+ // for now aspect lock scale adjustments that occur at corners..
+ if (!anchor.HasFlagFast(Anchor.x1) && !anchor.HasFlagFast(Anchor.y1))
+ {
+ // project scale vector along diagonal
+ Vector2 diag = (selectionRect.TopLeft - selectionRect.BottomRight).Normalized();
+ scale = Vector2.Dot(scale, diag) * diag;
+ }
+ // ..or if any of the selection have been rotated.
+ // this is to avoid requiring skew logic (which would likely not be the user's expected transform anyway).
+ else if (SelectedBlueprints.Any(b => !Precision.AlmostEquals(((Drawable)b.Item).Rotation, 0)))
{
if (anchor.HasFlagFast(Anchor.x1))
// if dragging from the horizontal centre, only a vertical component is available.
diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs
index 76d36ae7d9..0739026544 100644
--- a/osu.Game/Skinning/SkinManager.cs
+++ b/osu.Game/Skinning/SkinManager.cs
@@ -194,68 +194,61 @@ namespace osu.Game.Skinning
string nameLine = @$"Name: {item.Name}";
string authorLine = @$"Author: {item.Creator}";
+ string[] newLines =
+ {
+ @"// The following content was automatically added by osu! during import, based on filename / folder metadata.",
+ @"[General]",
+ nameLine,
+ authorLine,
+ };
+
var existingFile = item.Files.SingleOrDefault(f => f.Filename.Equals(@"skin.ini", StringComparison.OrdinalIgnoreCase));
- if (existingFile != null)
+ if (existingFile == null)
{
- List outputLines = new List();
+ // In the case a skin doesn't have a skin.ini yet, let's create one.
+ writeNewSkinIni();
+ return;
+ }
- bool addedName = false;
- bool addedAuthor = false;
-
- using (var stream = Files.Storage.GetStream(existingFile.FileInfo.StoragePath))
- using (var sr = new StreamReader(stream))
+ using (Stream stream = new MemoryStream())
+ {
+ using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true))
{
- string line;
-
- while ((line = sr.ReadLine()) != null)
+ using (var existingStream = Files.Storage.GetStream(existingFile.FileInfo.StoragePath))
+ using (var sr = new StreamReader(existingStream))
{
- if (line.StartsWith(@"Name:", StringComparison.Ordinal))
- {
- outputLines.Add(nameLine);
- addedName = true;
- }
- else if (line.StartsWith(@"Author:", StringComparison.Ordinal))
- {
- outputLines.Add(authorLine);
- addedAuthor = true;
- }
- else
- outputLines.Add(line);
- }
- }
-
- if (!addedName || !addedAuthor)
- {
- outputLines.AddRange(new[]
- {
- @"[General]",
- nameLine,
- authorLine,
- });
- }
-
- using (Stream stream = new MemoryStream())
- {
- using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true))
- {
- foreach (string line in outputLines)
+ string line;
+ while ((line = sr.ReadLine()) != null)
sw.WriteLine(line);
}
- ReplaceFile(item, existingFile, stream);
+ sw.WriteLine();
+
+ foreach (string line in newLines)
+ sw.WriteLine(line);
+ }
+
+ ReplaceFile(item, existingFile, stream);
+
+ // can be removed 20220502.
+ if (!ensureIniWasUpdated(item))
+ {
+ Logger.Log($"Skin {item}'s skin.ini had issues and has been removed. Please report this and provide the problematic skin.", LoggingTarget.Database, LogLevel.Important);
+
+ DeleteFile(item, item.Files.SingleOrDefault(f => f.Filename.Equals(@"skin.ini", StringComparison.OrdinalIgnoreCase)));
+ writeNewSkinIni();
}
}
- else
+
+ void writeNewSkinIni()
{
using (Stream stream = new MemoryStream())
{
using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true))
{
- sw.WriteLine(@"[General]");
- sw.WriteLine(nameLine);
- sw.WriteLine(authorLine);
- sw.WriteLine(@"Version: latest");
+ foreach (string line in newLines)
+ sw.WriteLine(line);
}
AddFile(item, stream, @"skin.ini");
@@ -263,6 +256,17 @@ namespace osu.Game.Skinning
}
}
+ private bool ensureIniWasUpdated(SkinInfo item)
+ {
+ // This is a final consistency check to ensure that hash computation doesn't enter an infinite loop.
+ // With other changes to the surrounding code this should never be hit, but until we are 101% sure that there
+ // are no other cases let's avoid a hard startup crash by bailing and alerting.
+
+ var instance = GetSkin(item);
+
+ return instance.Configuration.SkinInfo.Name == item.Name;
+ }
+
protected override Task Populate(SkinInfo model, ArchiveReader archive, CancellationToken cancellationToken = default)
{
var instance = GetSkin(model);
diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs
index a25bf24491..9e3d3df915 100644
--- a/osu.Game/Storyboards/Storyboard.cs
+++ b/osu.Game/Storyboards/Storyboard.cs
@@ -77,10 +77,14 @@ namespace osu.Game.Storyboards
{
get
{
- string backgroundPath = BeatmapInfo.BeatmapSet?.Metadata?.BackgroundFile?.ToLowerInvariant();
- if (backgroundPath == null)
+ string backgroundPath = BeatmapInfo.BeatmapSet?.Metadata?.BackgroundFile;
+
+ if (string.IsNullOrEmpty(backgroundPath))
return false;
+ // Importantly, do this after the NullOrEmpty because EF may have stored the non-nullable value as null to the database, bypassing compile-time constraints.
+ backgroundPath = backgroundPath.ToLowerInvariant();
+
return GetLayer("Background").Elements.Any(e => e.Path.ToLowerInvariant() == backgroundPath);
}
}
@@ -93,7 +97,7 @@ namespace osu.Game.Storyboards
Drawable drawable = null;
string storyboardPath = BeatmapInfo.BeatmapSet?.Files.Find(f => f.Filename.Equals(path, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath;
- if (storyboardPath != null)
+ if (!string.IsNullOrEmpty(storyboardPath))
drawable = new Sprite { Texture = textureStore.Get(storyboardPath) };
// if the texture isn't available locally in the beatmap, some storyboards choose to source from the underlying skin lookup hierarchy.
else if (UseSkinSprites)
diff --git a/osu.Game/Tests/Beatmaps/TestBeatmap.cs b/osu.Game/Tests/Beatmaps/TestBeatmap.cs
index caf83973c4..b9eda5c06e 100644
--- a/osu.Game/Tests/Beatmaps/TestBeatmap.cs
+++ b/osu.Game/Tests/Beatmaps/TestBeatmap.cs
@@ -39,16 +39,6 @@ namespace osu.Game.Tests.Beatmaps
BeatmapInfo.Length = 75000;
BeatmapInfo.OnlineInfo = new APIBeatmap();
BeatmapInfo.OnlineBeatmapID = Interlocked.Increment(ref onlineBeatmapID);
- BeatmapInfo.BeatmapSet.OnlineInfo = new APIBeatmapSet
- {
- Status = BeatmapSetOnlineStatus.Ranked,
- Covers = new BeatmapSetOnlineCovers
- {
- Cover = "https://assets.ppy.sh/beatmaps/163112/covers/cover.jpg",
- Card = "https://assets.ppy.sh/beatmaps/163112/covers/card.jpg",
- List = "https://assets.ppy.sh/beatmaps/163112/covers/list.jpg"
- }
- };
}
protected virtual Beatmap CreateBeatmap() => createTestBeatmap();
diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs
index 01481e68e6..d14303a7ab 100644
--- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs
+++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs
@@ -13,6 +13,7 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Game.Beatmaps;
using osu.Game.Online.API;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
using osu.Game.Online.Multiplayer.Queueing;
@@ -63,7 +64,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
return roomUser;
}
- public void AddNullUser() => addUser(new MultiplayerRoomUser(TestUserLookupCache.NULL_USER_ID));
+ public void TestAddUnresolvedUser() => addUser(new MultiplayerRoomUser(TestUserLookupCache.UNRESOLVED_USER_ID));
private void addUser(MultiplayerRoomUser user)
{
@@ -308,18 +309,24 @@ namespace osu.Game.Tests.Visual.Multiplayer
return ((IMultiplayerClient)this).PlaylistItemRemoved(item);
}
- protected override Task GetOnlineBeatmapSet(int beatmapId, CancellationToken cancellationToken = default)
+ protected override Task GetOnlineBeatmapSet(int beatmapId, CancellationToken cancellationToken = default)
{
Debug.Assert(Room != null);
var apiRoom = roomManager.ServerSideRooms.Single(r => r.RoomID.Value == Room.RoomID);
- var set = apiRoom.Playlist.FirstOrDefault(p => p.BeatmapID == beatmapId)?.Beatmap.Value.BeatmapSet
- ?? beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == beatmapId)?.BeatmapSet;
+ IBeatmapSetInfo? set = apiRoom.Playlist.FirstOrDefault(p => p.BeatmapID == beatmapId)?.Beatmap.Value.BeatmapSet
+ ?? beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == beatmapId)?.BeatmapSet;
if (set == null)
throw new InvalidOperationException("Beatmap not found.");
- return Task.FromResult(set);
+ var apiSet = new APIBeatmapSet
+ {
+ OnlineID = set.OnlineID,
+ Beatmaps = set.Beatmaps.Select(b => new APIBeatmap { OnlineID = b.OnlineID }).ToArray(),
+ };
+
+ return Task.FromResult(apiSet);
}
private async Task changeMatchType(MatchType type)
diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs
index 90e85f7716..153e2c487c 100644
--- a/osu.Game/Tests/Visual/OsuTestScene.cs
+++ b/osu.Game/Tests/Visual/OsuTestScene.cs
@@ -175,27 +175,42 @@ namespace osu.Game.Tests.Visual
protected virtual IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset);
- protected APIBeatmapSet CreateAPIBeatmapSet(RulesetInfo ruleset)
+ ///
+ /// Returns a sample API Beatmap with BeatmapSet populated.
+ ///
+ /// The ruleset to create the sample model using. osu! ruleset will be used if not specified.
+ protected APIBeatmap CreateAPIBeatmap(RulesetInfo ruleset = null)
{
- var beatmap = CreateBeatmap(ruleset).BeatmapInfo;
+ var beatmapSet = CreateAPIBeatmapSet(ruleset ?? Ruleset.Value);
+
+ // Avoid circular reference.
+ var beatmap = beatmapSet.Beatmaps.First();
+ beatmapSet.Beatmaps = Array.Empty();
+
+ // Populate the set as that's generally what we expect from the API.
+ beatmap.BeatmapSet = beatmapSet;
+
+ return beatmap;
+ }
+
+ ///
+ /// Returns a sample API BeatmapSet with beatmaps populated.
+ ///
+ /// The ruleset to create the sample model using. osu! ruleset will be used if not specified.
+ protected APIBeatmapSet CreateAPIBeatmapSet(RulesetInfo ruleset = null)
+ {
+ var beatmap = CreateBeatmap(ruleset ?? Ruleset.Value).BeatmapInfo;
return new APIBeatmapSet
{
- Covers = beatmap.BeatmapSet.Covers,
OnlineID = beatmap.BeatmapSet.OnlineID,
- Status = beatmap.BeatmapSet.Status,
- Preview = beatmap.BeatmapSet.Preview,
- HasFavourited = beatmap.BeatmapSet.HasFavourited,
- PlayCount = beatmap.BeatmapSet.PlayCount,
- FavouriteCount = beatmap.BeatmapSet.FavouriteCount,
- BPM = beatmap.BeatmapSet.BPM,
- HasExplicitContent = beatmap.BeatmapSet.HasExplicitContent,
- HasVideo = beatmap.BeatmapSet.HasVideo,
- HasStoryboard = beatmap.BeatmapSet.HasStoryboard,
- Submitted = beatmap.BeatmapSet.Submitted,
- Ranked = beatmap.BeatmapSet.Ranked,
- LastUpdated = beatmap.BeatmapSet.LastUpdated,
- TrackId = beatmap.BeatmapSet.TrackId,
+ Status = BeatmapSetOnlineStatus.Ranked,
+ Covers = new BeatmapSetOnlineCovers
+ {
+ Cover = "https://assets.ppy.sh/beatmaps/163112/covers/cover.jpg",
+ Card = "https://assets.ppy.sh/beatmaps/163112/covers/card.jpg",
+ List = "https://assets.ppy.sh/beatmaps/163112/covers/list.jpg"
+ },
Title = beatmap.BeatmapSet.Metadata.Title,
TitleUnicode = beatmap.BeatmapSet.Metadata.TitleUnicode,
Artist = beatmap.BeatmapSet.Metadata.Artist,
@@ -203,9 +218,6 @@ namespace osu.Game.Tests.Visual
Author = beatmap.BeatmapSet.Metadata.Author,
AuthorID = beatmap.BeatmapSet.Metadata.AuthorID,
AuthorString = beatmap.BeatmapSet.Metadata.AuthorString,
- Availability = beatmap.BeatmapSet.Availability,
- Genre = beatmap.BeatmapSet.Genre,
- Language = beatmap.BeatmapSet.Language,
Source = beatmap.BeatmapSet.Metadata.Source,
Tags = beatmap.BeatmapSet.Metadata.Tags,
Beatmaps = new[]
diff --git a/osu.Game/Tests/Visual/TestUserLookupCache.cs b/osu.Game/Tests/Visual/TestUserLookupCache.cs
index b73e81d0dd..fcb9c070ff 100644
--- a/osu.Game/Tests/Visual/TestUserLookupCache.cs
+++ b/osu.Game/Tests/Visual/TestUserLookupCache.cs
@@ -14,11 +14,11 @@ namespace osu.Game.Tests.Visual
/// A special user ID which would return a for.
/// As a simulation to what a regular would return in the case of failing to fetch the user.
///
- public const int NULL_USER_ID = -1;
+ public const int UNRESOLVED_USER_ID = -1;
protected override Task ComputeValueAsync(int lookup, CancellationToken token = default)
{
- if (lookup == NULL_USER_ID)
+ if (lookup == UNRESOLVED_USER_ID)
return Task.FromResult((User)null);
return Task.FromResult(new User
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 8052ab5254..6dda1f77c6 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -23,9 +23,9 @@
-
-
-
+
+
+
@@ -36,10 +36,10 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
-
-
+
+
diff --git a/osu.iOS.props b/osu.iOS.props
index d152cb7066..df24a57e90 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -70,7 +70,7 @@
-
+
@@ -93,8 +93,8 @@
-
-
+
+