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/osu.Android.props b/osu.Android.props
index 4887e3a95f..4f9f83f199 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,7 +52,7 @@
-
+
diff --git a/osu.Game.Rulesets.Mania/Skinning/Default/DefaultBodyPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Default/DefaultBodyPiece.cs
index db1ac6da88..7138421b91 100644
--- a/osu.Game.Rulesets.Mania/Skinning/Default/DefaultBodyPiece.cs
+++ b/osu.Game.Rulesets.Mania/Skinning/Default/DefaultBodyPiece.cs
@@ -86,20 +86,18 @@ namespace osu.Game.Rulesets.Mania.Skinning.Default
[BackgroundDependencyLoader]
private void load()
{
- InternalChild = foregroundBuffer = new BufferedContainer
+ InternalChild = foregroundBuffer = new BufferedContainer(cachedFrameBuffer: true)
{
Blending = BlendingParameters.Additive,
RelativeSizeAxes = Axes.Both,
- CacheDrawnFrameBuffer = true,
Children = new Drawable[]
{
new Box { RelativeSizeAxes = Axes.Both },
- subtractionBuffer = new BufferedContainer
+ subtractionBuffer = new BufferedContainer(cachedFrameBuffer: true)
{
RelativeSizeAxes = Axes.Both,
// This is needed because we're blending with another object
BackgroundColour = Color4.White.Opacity(0),
- CacheDrawnFrameBuffer = true,
// The 'hole' is achieved by subtracting the result of this container with the parent
Blending = new BlendingParameters { AlphaEquation = BlendingEquation.ReverseSubtract },
Child = subtractionLayer = new CircularContainer
diff --git a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs
index 79d575ab3f..c88f70021b 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.531832890435525d, "diffcalc-test")]
- [TestCase(1.4644923495008817d, "zero-length-sliders")]
+ [TestCase(6.6975550434910005d, "diffcalc-test")]
+ [TestCase(1.4673500058356748d, "zero-length-sliders")]
public void Test(double expected, string name)
=> base.Test(expected, name);
- [TestCase(8.8067616302940852d, "diffcalc-test")]
- [TestCase(1.7763214959309293d, "zero-length-sliders")]
+ [TestCase(8.938989502378238d, "diffcalc-test")]
+ [TestCase(1.779323508403831d, "zero-length-sliders")]
public void TestClockRateAdjusted(double expected, string name)
=> Test(expected, name, new OsuModDoubleTime());
diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
index 4aeb038847..a9d9ff6985 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
@@ -54,7 +54,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty
if (mods.Any(h => h is OsuModRelax))
{
- effectiveMissCount += countOk + countMeh;
+ // As we're adding Oks and Mehs to an approximated number of combo breaks the result can be higher than total hits in specific scenarios (which breaks some calculations) so we need to clamp it.
+ effectiveMissCount = Math.Min(effectiveMissCount + countOk + countMeh, totalHits);
+
multiplier *= 0.6;
}
@@ -248,7 +250,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
private int calculateEffectiveMissCount()
{
- // guess the number of misses + slider breaks from combo
+ // Guess the number of misses + slider breaks from combo
double comboBasedMissCount = 0.0;
if (Attributes.SliderCount > 0)
@@ -258,7 +260,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
comboBasedMissCount = fullComboThreshold / Math.Max(1.0, scoreMaxCombo);
}
- // we're clamping misscount because since its derived from combo it can be higher than total hits and that breaks some calculations
+ // Clamp misscount since it's derived from combo and can be higher than total hits and that breaks some calculations
comboBasedMissCount = Math.Min(comboBasedMissCount, totalHits);
return Math.Max(countMiss, (int)Math.Floor(comboBasedMissCount));
diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs
index cf983a5fc2..aebc73f108 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs
@@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
private const double wide_angle_multiplier = 1.5;
private const double acute_angle_multiplier = 2.0;
private const double slider_multiplier = 1.5;
- private const double vel_change_multiplier = 0.75;
+ private const double velocity_change_multiplier = 0.75;
private double currentStrain = 1;
@@ -66,7 +66,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
double wideAngleBonus = 0;
double acuteAngleBonus = 0;
double sliderBonus = 0;
- double velChangeBonus = 0;
+ double velocityChangeBonus = 0;
double aimStrain = currVelocity; // Start strain with regular velocity.
@@ -107,26 +107,35 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
prevVelocity = (osuLastObj.JumpDistance + osuLastObj.TravelDistance) / osuLastObj.StrainTime;
currVelocity = (osuCurrObj.JumpDistance + osuCurrObj.TravelDistance) / osuCurrObj.StrainTime;
- // scale with ratio of difference compared to 0.5 * max dist.
+ // Scale with ratio of difference compared to 0.5 * max dist.
double distRatio = Math.Pow(Math.Sin(Math.PI / 2 * Math.Abs(prevVelocity - currVelocity) / Math.Max(prevVelocity, currVelocity)), 2);
- // reward for % distance up to 125 / strainTime for overlaps where velocity is still changing.
+
+ // Reward for % distance up to 125 / strainTime for overlaps where velocity is still changing.
double overlapVelocityBuff = Math.Min(125 / Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime), Math.Abs(prevVelocity - currVelocity));
- double nonOverlapVelocityBuff = Math.Abs(prevVelocity - currVelocity) // reward for % distance slowed down compared to previous, paying attention to not award overlap
- * Math.Pow(Math.Sin(Math.PI / 2 * Math.Min(1, Math.Min(osuCurrObj.JumpDistance, osuLastObj.JumpDistance) / 100)), 2); // do not award overlap
- velChangeBonus = Math.Max(overlapVelocityBuff, nonOverlapVelocityBuff) * distRatio; // choose larger distance, multiplied by ratio.
+ // Reward for % distance slowed down compared to previous, paying attention to not award overlap
+ double nonOverlapVelocityBuff = Math.Abs(prevVelocity - currVelocity)
+ // do not award overlap
+ * Math.Pow(Math.Sin(Math.PI / 2 * Math.Min(1, Math.Min(osuCurrObj.JumpDistance, osuLastObj.JumpDistance) / 100)), 2);
- velChangeBonus *= Math.Pow(Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime) / Math.Max(osuCurrObj.StrainTime, osuLastObj.StrainTime), 2); // penalize for rhythm changes.
+ // Choose the largest bonus, multiplied by ratio.
+ velocityChangeBonus = Math.Max(overlapVelocityBuff, nonOverlapVelocityBuff) * distRatio;
+
+ // Penalize for rhythm changes.
+ velocityChangeBonus *= Math.Pow(Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime) / Math.Max(osuCurrObj.StrainTime, osuLastObj.StrainTime), 2);
}
if (osuCurrObj.TravelTime != 0)
{
- sliderBonus = osuCurrObj.TravelDistance / osuCurrObj.TravelTime; // add some slider rewards
+ // Reward sliders based on velocity.
+ sliderBonus = osuCurrObj.TravelDistance / osuCurrObj.TravelTime;
}
- // Add in acute angle bonus or wide angle bonus + velchange bonus, whichever is larger.
- aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier + velChangeBonus * vel_change_multiplier);
- aimStrain += sliderBonus * slider_multiplier; // Add in additional slider velocity.
+ // Add in acute angle bonus or wide angle bonus + velocity change bonus, whichever is larger.
+ aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier + velocityChangeBonus * velocity_change_multiplier);
+
+ // Add in additional slider velocity bonus.
+ aimStrain += sliderBonus * slider_multiplier;
return aimStrain;
}
diff --git a/osu.Game.Rulesets.Osu/Statistics/AccuracyHeatmap.cs b/osu.Game.Rulesets.Osu/Statistics/AccuracyHeatmap.cs
index 3c2077b3c8..db4a6eb50b 100644
--- a/osu.Game.Rulesets.Osu/Statistics/AccuracyHeatmap.cs
+++ b/osu.Game.Rulesets.Osu/Statistics/AccuracyHeatmap.cs
@@ -136,10 +136,9 @@ namespace osu.Game.Rulesets.Osu.Statistics
}
}
},
- bufferedGrid = new BufferedContainer
+ bufferedGrid = new BufferedContainer(cachedFrameBuffer: true)
{
RelativeSizeAxes = Axes.Both,
- CacheDrawnFrameBuffer = true,
BackgroundColour = Color4Extensions.FromHex("#202624").Opacity(0),
Child = pointGrid = new GridContainer
{
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/Mods/ModDifficultyAdjustTest.cs b/osu.Game.Tests/Mods/ModDifficultyAdjustTest.cs
index 84cf796835..fd620a0e95 100644
--- a/osu.Game.Tests/Mods/ModDifficultyAdjustTest.cs
+++ b/osu.Game.Tests/Mods/ModDifficultyAdjustTest.cs
@@ -105,6 +105,9 @@ namespace osu.Game.Tests.Mods
testMod.ResetSettingsToDefaults();
Assert.That(testMod.DrainRate.Value, Is.Null);
+
+ // ReSharper disable once HeuristicUnreachableCode
+ // see https://youtrack.jetbrains.com/issue/RIDER-70159.
Assert.That(testMod.OverallDifficulty.Value, Is.Null);
var applied = applyDifficulty(new BeatmapDifficulty
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/NonVisual/FirstAvailableHitWindowsTest.cs b/osu.Game.Tests/NonVisual/FirstAvailableHitWindowsTest.cs
index 97105b6b6a..8386a10ebb 100644
--- a/osu.Game.Tests/NonVisual/FirstAvailableHitWindowsTest.cs
+++ b/osu.Game.Tests/NonVisual/FirstAvailableHitWindowsTest.cs
@@ -79,8 +79,17 @@ namespace osu.Game.Tests.NonVisual
public List HitObjects;
public override IEnumerable Objects => HitObjects;
- public override event Action NewResult;
- public override event Action RevertResult;
+ public override event Action NewResult
+ {
+ add => throw new InvalidOperationException();
+ remove => throw new InvalidOperationException();
+ }
+
+ public override event Action RevertResult
+ {
+ add => throw new InvalidOperationException();
+ remove => throw new InvalidOperationException();
+ }
public override Playfield Playfield { get; }
public override Container Overlays { get; }
@@ -95,9 +104,6 @@ namespace osu.Game.Tests.NonVisual
public TestDrawableRuleset()
: base(new OsuRuleset())
{
- // won't compile without this.
- NewResult?.Invoke(null);
- RevertResult?.Invoke(null);
}
public override void SetReplayScore(Score replayScore) => throw new NotImplementedException();
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/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs
index 5e7ce3abf5..e3e2304990 100644
--- a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs
+++ b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs
@@ -168,19 +168,19 @@ namespace osu.Game.Tests.Online
return new TestBeatmapModelManager(this, storage, contextFactory, rulesets, api, host);
}
- protected override BeatmapModelDownloader CreateBeatmapModelDownloader(IBeatmapModelManager manager, IAPIProvider api, GameHost host)
+ protected override BeatmapModelDownloader CreateBeatmapModelDownloader(IModelImporter manager, IAPIProvider api, GameHost host)
{
return new TestBeatmapModelDownloader(manager, api, host);
}
internal class TestBeatmapModelDownloader : BeatmapModelDownloader
{
- public TestBeatmapModelDownloader(IBeatmapModelManager modelManager, IAPIProvider apiProvider, GameHost gameHost)
- : base(modelManager, apiProvider, gameHost)
+ public TestBeatmapModelDownloader(IModelImporter importer, IAPIProvider apiProvider, GameHost gameHost)
+ : base(importer, apiProvider, gameHost)
{
}
- protected override ArchiveDownloadRequest CreateDownloadRequest(BeatmapSetInfo set, bool minimiseDownloadSize)
+ protected override ArchiveDownloadRequest CreateDownloadRequest(IBeatmapSetInfo set, bool minimiseDownloadSize)
=> new TestDownloadRequest(set);
}
@@ -202,12 +202,12 @@ namespace osu.Game.Tests.Online
}
}
- private class TestDownloadRequest : ArchiveDownloadRequest
+ private class TestDownloadRequest : ArchiveDownloadRequest
{
public new void SetProgress(float progress) => base.SetProgress(progress);
public new void TriggerSuccess(string filename) => base.TriggerSuccess(filename);
- public TestDownloadRequest(BeatmapSetInfo model)
+ public TestDownloadRequest(IBeatmapSetInfo model)
: base(model)
{
}
diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs
index d1b21547dc..2aeb4ab4e2 100644
--- a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs
+++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs
@@ -91,7 +91,7 @@ namespace osu.Game.Tests.Visual.Beatmaps
HasVideo = true,
HasStoryboard = true,
Covers = new BeatmapSetOnlineCovers(),
- Beatmaps = new List
+ Beatmaps = new[]
{
new APIBeatmap
{
@@ -128,7 +128,7 @@ namespace osu.Game.Tests.Visual.Beatmaps
HasVideo = true,
HasStoryboard = true,
Covers = new BeatmapSetOnlineCovers(),
- Beatmaps = beatmaps,
+ Beatmaps = beatmaps.ToArray(),
};
}
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/TestSceneHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs
index 1ba0965ceb..c1260f0231 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs
@@ -235,8 +235,17 @@ namespace osu.Game.Tests.Visual.Gameplay
public override IEnumerable Objects => new[] { new HitCircle { HitWindows = HitWindows } };
- public override event Action NewResult;
- public override event Action RevertResult;
+ public override event Action NewResult
+ {
+ add => throw new InvalidOperationException();
+ remove => throw new InvalidOperationException();
+ }
+
+ public override event Action RevertResult
+ {
+ add => throw new InvalidOperationException();
+ remove => throw new InvalidOperationException();
+ }
public override Playfield Playfield { get; }
public override Container Overlays { get; }
@@ -251,9 +260,6 @@ namespace osu.Game.Tests.Visual.Gameplay
public TestDrawableRuleset()
: base(new OsuRuleset())
{
- // won't compile without this.
- NewResult?.Invoke(null);
- RevertResult?.Invoke(null);
}
public override void SetReplayScore(Score replayScore) => throw new NotImplementedException();
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 f44b0c9716..afd48d5191 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);
}
@@ -310,7 +314,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/Online/TestSceneBeatmapRulesetSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs
index b880633559..90f3eb64e4 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.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;
@@ -37,7 +36,7 @@ namespace osu.Game.Tests.Visual.Online
{
selector.BeatmapSet = new APIBeatmapSet
{
- Beatmaps = enabledRulesets.Select(r => new APIBeatmap { RulesetID = r.OnlineID }).ToList()
+ Beatmaps = enabledRulesets.Select(r => new APIBeatmap { RulesetID = r.OnlineID }).ToArray()
};
});
@@ -55,7 +54,7 @@ namespace osu.Game.Tests.Visual.Online
{
selector.BeatmapSet = new APIBeatmapSet
{
- Beatmaps = new List
+ Beatmaps = new[]
{
new APIBeatmap
{
@@ -71,10 +70,7 @@ namespace osu.Game.Tests.Visual.Online
[Test]
public void TestEmptyBeatmapSet()
{
- AddStep("load empty beatmapset", () => selector.BeatmapSet = new APIBeatmapSet
- {
- 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 bae9af1897..63ce057667 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs
@@ -71,7 +71,7 @@ namespace osu.Game.Tests.Visual.Online
Ratings = Enumerable.Range(0, 11).ToArray(),
HasStoryboard = true,
Covers = new BeatmapSetOnlineCovers(),
- Beatmaps = new List
+ Beatmaps = new[]
{
new APIBeatmap
{
@@ -145,7 +145,7 @@ namespace osu.Game.Tests.Visual.Online
var set = getBeatmapSet();
- set.Beatmaps = beatmaps;
+ set.Beatmaps = beatmaps.ToArray();
overlay.ShowBeatmapSet(set);
});
@@ -211,7 +211,7 @@ namespace osu.Game.Tests.Visual.Online
});
}
- set.Beatmaps = beatmaps;
+ set.Beatmaps = beatmaps.ToArray();
return set;
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs
index 491a2d5d90..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;
@@ -46,7 +45,7 @@ namespace osu.Game.Tests.Visual.Online
static APIBeatmapSet createSet() => new APIBeatmapSet
{
- Beatmaps = new List
+ Beatmaps = new[]
{
new APIBeatmap
{
diff --git a/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs b/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs
index f0cf88840a..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;
@@ -110,7 +109,7 @@ namespace osu.Game.Tests.Visual.Online
private IBeatmapSetInfo getDownloadableBeatmapSet()
{
- var apiBeatmapSet = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo).BeatmapSetInfo.OnlineInfo;
+ var apiBeatmapSet = CreateAPIBeatmapSet();
apiBeatmapSet.HasVideo = true;
apiBeatmapSet.HasStoryboard = true;
@@ -120,7 +119,7 @@ namespace osu.Game.Tests.Visual.Online
private IBeatmapSetInfo getUndownloadableBeatmapSet()
{
- var apiBeatmapSet = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo).BeatmapSetInfo.OnlineInfo;
+ var apiBeatmapSet = CreateAPIBeatmapSet();
apiBeatmapSet.Artist = "test";
apiBeatmapSet.Title = "undownloadable";
diff --git a/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs
index 9a3d998966..a3c8935fa8 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs
@@ -90,7 +90,7 @@ namespace osu.Game.Tests.Visual.Online
HasVideo = true,
HasStoryboard = true,
Covers = new BeatmapSetOnlineCovers(),
- Beatmaps = new List
+ Beatmaps = new[]
{
new APIBeatmap
{
@@ -129,7 +129,7 @@ namespace osu.Game.Tests.Visual.Online
HasVideo = true,
HasStoryboard = true,
Covers = new BeatmapSetOnlineCovers(),
- Beatmaps = beatmaps,
+ Beatmaps = beatmaps.ToArray(),
};
}
}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs
index 9856b28b00..bd15c40271 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs
@@ -7,7 +7,6 @@ using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
-using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Select;
namespace osu.Game.Tests.Visual.SongSelect
@@ -32,159 +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,
- Ruleset = new OsuRuleset().RulesetInfo,
- 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,
- Ruleset = new OsuRuleset().RulesetInfo,
- 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",
},
- Ruleset = new OsuRuleset().RulesetInfo,
- 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(),
},
- Ruleset = new OsuRuleset().RulesetInfo,
- 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",
},
- Ruleset = new OsuRuleset().RulesetInfo,
- 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,
});
}
@@ -197,10 +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,
- Ruleset = new OsuRuleset().RulesetInfo
+ OnlineID = 162,
});
AddStep("set online", () => api.SetState(APIState.Online));
AddStep("set offline", () => api.SetState(APIState.Offline));
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/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/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 0caee8f9cd..e0e5b5e63d 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -29,7 +29,7 @@ namespace osu.Game.Beatmaps
/// Handles general operations related to global beatmap management.
///
[ExcludeFromDynamicCompile]
- public class BeatmapManager : IModelDownloader, IModelManager, IModelFileManager, IWorkingBeatmapCache, IDisposable
+ public class BeatmapManager : IModelDownloader, IModelManager, IModelFileManager, IModelImporter, IWorkingBeatmapCache, IDisposable
{
private readonly BeatmapModelManager beatmapModelManager;
private readonly BeatmapModelDownloader beatmapModelDownloader;
@@ -54,7 +54,7 @@ namespace osu.Game.Beatmaps
}
}
- protected virtual BeatmapModelDownloader CreateBeatmapModelDownloader(IBeatmapModelManager modelManager, IAPIProvider api, GameHost host)
+ protected virtual BeatmapModelDownloader CreateBeatmapModelDownloader(IModelImporter modelManager, IAPIProvider api, GameHost host)
{
return new BeatmapModelDownloader(modelManager, api, host);
}
@@ -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.
@@ -245,33 +246,16 @@ namespace osu.Game.Beatmaps
#region Implementation of IModelDownloader
- public IBindable>> DownloadBegan => beatmapModelDownloader.DownloadBegan;
+ public IBindable>> DownloadBegan => beatmapModelDownloader.DownloadBegan;
- public IBindable>> DownloadFailed => beatmapModelDownloader.DownloadFailed;
+ 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,
- Artist = model.Metadata?.Artist,
- TitleUnicode = model.Metadata?.TitleUnicode,
- ArtistUnicode = model.Metadata?.ArtistUnicode,
- Author = new User { Username = model.Metadata?.Author },
- }
- }, minimiseDownloadSize);
- }
-
- public bool Download(BeatmapSetInfo model, bool minimiseDownloadSize = false)
{
return beatmapModelDownloader.Download(model, minimiseDownloadSize);
}
- public ArchiveDownloadRequest GetExistingDownload(BeatmapSetInfo model)
+ public ArchiveDownloadRequest GetExistingDownload(IBeatmapSetInfo model)
{
return beatmapModelDownloader.GetExistingDownload(model);
}
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/BeatmapModelDownloader.cs b/osu.Game/Beatmaps/BeatmapModelDownloader.cs
index 001726e741..a170edc9f8 100644
--- a/osu.Game/Beatmaps/BeatmapModelDownloader.cs
+++ b/osu.Game/Beatmaps/BeatmapModelDownloader.cs
@@ -8,16 +8,16 @@ using osu.Game.Online.API.Requests;
namespace osu.Game.Beatmaps
{
- public class BeatmapModelDownloader : ModelDownloader
+ public class BeatmapModelDownloader : ModelDownloader
{
- protected override ArchiveDownloadRequest CreateDownloadRequest(BeatmapSetInfo set, bool minimiseDownloadSize) =>
+ protected override ArchiveDownloadRequest CreateDownloadRequest(IBeatmapSetInfo set, bool minimiseDownloadSize) =>
new DownloadBeatmapSetRequest(set, minimiseDownloadSize);
- public override ArchiveDownloadRequest GetExistingDownload(BeatmapSetInfo model)
+ public override ArchiveDownloadRequest GetExistingDownload(IBeatmapSetInfo model)
=> CurrentDownloads.Find(r => r.Model.OnlineID == model.OnlineID);
- public BeatmapModelDownloader(IBeatmapModelManager beatmapModelManager, IAPIProvider api, GameHost host = null)
- : base(beatmapModelManager, api, host)
+ public BeatmapModelDownloader(IModelImporter beatmapImporter, IAPIProvider api, GameHost host = null)
+ : base(beatmapImporter, api, host)
{
}
}
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/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/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..d2f9ee1dc1 100644
--- a/osu.Game/Database/ArchiveModelManager.cs
+++ b/osu.Game/Database/ArchiveModelManager.cs
@@ -30,7 +30,7 @@ namespace osu.Game.Database
///
/// The model type.
/// The associated file join type.
- public abstract class ArchiveModelManager : IModelManager, IModelFileManager
+ public abstract class ArchiveModelManager : IModelImporter, IModelManager, IModelFileManager
where TModel : class, IHasFiles, IHasPrimaryKey, ISoftDelete
where TFileModel : class, INamedFileInfo, IHasPrimaryKey, new()
{
@@ -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/Database/IModelDownloader.cs b/osu.Game/Database/IModelDownloader.cs
index a5573b2190..3c57a277ba 100644
--- a/osu.Game/Database/IModelDownloader.cs
+++ b/osu.Game/Database/IModelDownloader.cs
@@ -10,35 +10,35 @@ namespace osu.Game.Database
///
/// Represents a that can download new models from an external source.
///
- /// The model type.
- public interface IModelDownloader : IPostNotifications
- where TModel : class
+ /// The item's interface type.
+ public interface IModelDownloader : IPostNotifications
+ where T : class
{
///
- /// Fired when a download begins.
+ /// Fired when a download begins.
/// This is NOT run on the update thread and should be scheduled.
///
- IBindable>> DownloadBegan { get; }
+ IBindable>> DownloadBegan { get; }
///
- /// Fired when a download is interrupted, either due to user cancellation or failure.
+ /// Fired when a download is interrupted, either due to user cancellation or failure.
/// This is NOT run on the update thread and should be scheduled.
///
- IBindable>> DownloadFailed { get; }
+ IBindable>> DownloadFailed { get; }
///
- /// Begin a download for the requested .
+ /// Begin a download for the requested .
///
- /// The to be downloaded.
+ /// The to be downloaded.
/// Whether this download should be optimised for slow connections. Generally means extras are not included in the download bundle..
/// Whether the download was started.
- bool Download(TModel model, bool minimiseDownloadSize);
+ bool Download(T item, bool minimiseDownloadSize);
///
- /// Gets an existing download request if it exists.
+ /// Gets an existing download request if it exists.
///
- /// The whose request is wanted.
- /// The object if it exists, otherwise null.
- ArchiveDownloadRequest GetExistingDownload(TModel model);
+ /// The whose request is wanted.
+ /// The object if it exists, otherwise null.
+ ArchiveDownloadRequest GetExistingDownload(T item);
}
}
diff --git a/osu.Game/Database/IModelManager.cs b/osu.Game/Database/IModelManager.cs
index f5e401cdfb..0be927322d 100644
--- a/osu.Game/Database/IModelManager.cs
+++ b/osu.Game/Database/IModelManager.cs
@@ -14,7 +14,7 @@ namespace osu.Game.Database
/// Represents a model manager that publishes events when s are added or removed.
///
/// The model type.
- public interface IModelManager : IModelImporter
+ public interface IModelManager
where TModel : class
{
///
diff --git a/osu.Game/Database/ModelDownloader.cs b/osu.Game/Database/ModelDownloader.cs
index 12bf5e9ce7..e44ae21ed6 100644
--- a/osu.Game/Database/ModelDownloader.cs
+++ b/osu.Game/Database/ModelDownloader.cs
@@ -14,39 +14,40 @@ using osu.Game.Overlays.Notifications;
namespace osu.Game.Database
{
- public abstract class ModelDownloader : IModelDownloader
- where TModel : class, IHasPrimaryKey, ISoftDelete, IEquatable
+ public abstract class ModelDownloader : IModelDownloader
+ where TModel : class, IHasPrimaryKey, ISoftDelete, IEquatable, T
+ where T : class
{
public Action PostNotification { protected get; set; }
- public IBindable>> DownloadBegan => downloadBegan;
+ public IBindable>> DownloadBegan => downloadBegan;
- private readonly Bindable>> downloadBegan = new Bindable>>();
+ private readonly Bindable>> downloadBegan = new Bindable>>();
- public IBindable>> DownloadFailed => downloadFailed;
+ public IBindable>> DownloadFailed => downloadFailed;
- private readonly Bindable>> downloadFailed = new Bindable>>();
+ private readonly Bindable>> downloadFailed = new Bindable>>();
- private readonly IModelManager modelManager;
+ private readonly IModelImporter importer;
private readonly IAPIProvider api;
- protected readonly List> CurrentDownloads = new List>();
+ protected readonly List> CurrentDownloads = new List>();
- protected ModelDownloader(IModelManager modelManager, IAPIProvider api, IIpcHost importHost = null)
+ protected ModelDownloader(IModelImporter importer, IAPIProvider api, IIpcHost importHost = null)
{
- this.modelManager = modelManager;
+ this.importer = importer;
this.api = api;
}
///
- /// Creates the download request for this .
+ /// Creates the download request for this .
///
- /// The to be downloaded.
+ /// The to be downloaded.
/// Whether this download should be optimised for slow connections. Generally means extras are not included in the download bundle.
/// The request object.
- protected abstract ArchiveDownloadRequest CreateDownloadRequest(TModel model, bool minimiseDownloadSize);
+ protected abstract ArchiveDownloadRequest CreateDownloadRequest(T model, bool minimiseDownloadSize);
- public bool Download(TModel model, bool minimiseDownloadSize = false)
+ public bool Download(T model, bool minimiseDownloadSize = false)
{
if (!canDownload(model)) return false;
@@ -68,11 +69,11 @@ namespace osu.Game.Database
Task.Factory.StartNew(async () =>
{
// This gets scheduled back to the update thread, but we want the import to run in the background.
- var imported = await modelManager.Import(notification, new ImportTask(filename)).ConfigureAwait(false);
+ var imported = await importer.Import(notification, new ImportTask(filename)).ConfigureAwait(false);
// for now a failed import will be marked as a failed download for simplicity.
if (!imported.Any())
- downloadFailed.Value = new WeakReference>(request);
+ downloadFailed.Value = new WeakReference>(request);
CurrentDownloads.Remove(request);
}, TaskCreationOptions.LongRunning);
@@ -91,25 +92,25 @@ namespace osu.Game.Database
api.PerformAsync(request);
- downloadBegan.Value = new WeakReference>(request);
+ downloadBegan.Value = new WeakReference>(request);
return true;
void triggerFailure(Exception error)
{
CurrentDownloads.Remove(request);
- downloadFailed.Value = new WeakReference>(request);
+ downloadFailed.Value = new WeakReference>(request);
notification.State = ProgressNotificationState.Cancelled;
if (!(error is OperationCanceledException))
- Logger.Error(error, $"{modelManager.HumanisedModelName.Titleize()} download failed!");
+ Logger.Error(error, $"{importer.HumanisedModelName.Titleize()} download failed!");
}
}
- public abstract ArchiveDownloadRequest GetExistingDownload(TModel model);
+ public abstract ArchiveDownloadRequest GetExistingDownload(T model);
- private bool canDownload(TModel model) => GetExistingDownload(model) == null && api != null;
+ private bool canDownload(T model) => GetExistingDownload(model) == null && api != null;
private class DownloadNotification : ProgressNotification
{
diff --git a/osu.Game/Graphics/Backgrounds/Background.cs b/osu.Game/Graphics/Backgrounds/Background.cs
index cfc1eb1806..353054a1f1 100644
--- a/osu.Game/Graphics/Backgrounds/Background.cs
+++ b/osu.Game/Graphics/Backgrounds/Background.cs
@@ -58,10 +58,9 @@ namespace osu.Game.Graphics.Backgrounds
{
RemoveInternal(Sprite);
- AddInternal(bufferedContainer = new BufferedContainer
+ AddInternal(bufferedContainer = new BufferedContainer(cachedFrameBuffer: true)
{
RelativeSizeAxes = Axes.Both,
- CacheDrawnFrameBuffer = true,
RedrawOnScale = false,
Child = Sprite
});
diff --git a/osu.Game/Graphics/Sprites/GlowingSpriteText.cs b/osu.Game/Graphics/Sprites/GlowingSpriteText.cs
index fb273d7293..9c43383a29 100644
--- a/osu.Game/Graphics/Sprites/GlowingSpriteText.cs
+++ b/osu.Game/Graphics/Sprites/GlowingSpriteText.cs
@@ -69,12 +69,11 @@ namespace osu.Game.Graphics.Sprites
Children = new Drawable[]
{
- new BufferedContainer
+ new BufferedContainer(cachedFrameBuffer: true)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
BlurSigma = new Vector2(4),
- CacheDrawnFrameBuffer = true,
RedrawOnScale = false,
RelativeSizeAxes = Axes.Both,
Blending = BlendingParameters.Additive,
diff --git a/osu.Game/Graphics/UserInterface/LoadingButton.cs b/osu.Game/Graphics/UserInterface/LoadingButton.cs
index 81dc023d7e..a75cf0639c 100644
--- a/osu.Game/Graphics/UserInterface/LoadingButton.cs
+++ b/osu.Game/Graphics/UserInterface/LoadingButton.cs
@@ -1,7 +1,9 @@
// 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.Input.Events;
using osu.Game.Graphics.Containers;
using osuTK;
@@ -22,15 +24,9 @@ namespace osu.Game.Graphics.UserInterface
Enabled.Value = !isLoading;
if (value)
- {
loading.Show();
- OnLoadStarted();
- }
else
- {
loading.Hide();
- OnLoadFinished();
- }
}
}
@@ -44,18 +40,34 @@ namespace osu.Game.Graphics.UserInterface
protected LoadingButton()
{
- AddRange(new[]
+ Add(loading = new LoadingSpinner
{
- CreateContent(),
- loading = new LoadingSpinner
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Size = new Vector2(12)
- }
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(12),
+ Depth = -1,
});
}
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Add(CreateContent());
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ loading.State.BindValueChanged(s =>
+ {
+ if (s.NewValue == Visibility.Visible)
+ OnLoadStarted();
+ else
+ OnLoadFinished();
+ }, true);
+ }
+
protected override bool OnClick(ClickEvent e)
{
if (!Enabled.Value)
diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs
index 95884f1515..1e6032c1d0 100644
--- a/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs
+++ b/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs
@@ -168,7 +168,7 @@ namespace osu.Game.Graphics.UserInterfaceV2
{
descriptionText.Text = value;
- if (value == default)
+ if (!string.IsNullOrEmpty(value.ToString()))
descriptionText.Show();
else
descriptionText.Hide();
diff --git a/osu.Game/Online/API/Requests/DownloadBeatmapSetRequest.cs b/osu.Game/Online/API/Requests/DownloadBeatmapSetRequest.cs
index 2898955de7..5254dc3cf8 100644
--- a/osu.Game/Online/API/Requests/DownloadBeatmapSetRequest.cs
+++ b/osu.Game/Online/API/Requests/DownloadBeatmapSetRequest.cs
@@ -6,11 +6,11 @@ using osu.Game.Beatmaps;
namespace osu.Game.Online.API.Requests
{
- public class DownloadBeatmapSetRequest : ArchiveDownloadRequest
+ public class DownloadBeatmapSetRequest : ArchiveDownloadRequest
{
private readonly bool noVideo;
- public DownloadBeatmapSetRequest(BeatmapSetInfo set, bool noVideo)
+ public DownloadBeatmapSetRequest(IBeatmapSetInfo set, bool noVideo)
: base(set)
{
this.noVideo = noVideo;
@@ -25,6 +25,6 @@ namespace osu.Game.Online.API.Requests
protected override string FileExtension => ".osz";
- protected override string Target => $@"beatmapsets/{Model.OnlineBeatmapSetID}/download{(noVideo ? "?noVideo=1" : "")}";
+ protected override string Target => $@"beatmapsets/{Model.OnlineID}/download{(noVideo ? "?noVideo=1" : "")}";
}
}
diff --git a/osu.Game/Online/API/Requests/DownloadReplayRequest.cs b/osu.Game/Online/API/Requests/DownloadReplayRequest.cs
index 6fd052653d..77174f0bb5 100644
--- a/osu.Game/Online/API/Requests/DownloadReplayRequest.cs
+++ b/osu.Game/Online/API/Requests/DownloadReplayRequest.cs
@@ -5,15 +5,15 @@ using osu.Game.Scoring;
namespace osu.Game.Online.API.Requests
{
- public class DownloadReplayRequest : ArchiveDownloadRequest
+ public class DownloadReplayRequest : ArchiveDownloadRequest
{
- public DownloadReplayRequest(ScoreInfo score)
+ public DownloadReplayRequest(IScoreInfo score)
: base(score)
{
}
protected override string FileExtension => ".osr";
- protected override string Target => $@"scores/{Model.Ruleset.ShortName}/{Model.OnlineScoreID}/download";
+ protected override string Target => $@"scores/{Model.Ruleset.ShortName}/{Model.OnlineID}/download";
}
}
diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs
index 653b011f73..2560502173 100644
--- a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs
+++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs
@@ -81,34 +81,6 @@ namespace osu.Game.Online.API.Requests.Responses
public double BPM { get; set; }
- public virtual BeatmapInfo ToBeatmapInfo(RulesetStore rulesets)
- {
- var set = BeatmapSet?.ToBeatmapSet(rulesets);
-
- return new BeatmapInfo
- {
- Metadata = set?.Metadata ?? new BeatmapMetadata(),
- Ruleset = rulesets.GetRuleset(RulesetID),
- StarDifficulty = StarRating,
- OnlineBeatmapID = OnlineID,
- Version = DifficultyName,
- // this is actually an incorrect mapping (Length is calculated as drain length in lazer's import process, see BeatmapManager.calculateLength).
- Length = Length,
- Status = Status,
- MD5Hash = Checksum,
- BeatmapSet = set,
- MaxCombo = MaxCombo,
- BaseDifficulty = new BeatmapDifficulty
- {
- DrainRate = DrainRate,
- CircleSize = CircleSize,
- ApproachRate = ApproachRate,
- OverallDifficulty = OverallDifficulty,
- },
- OnlineInfo = this,
- };
- }
-
#region Implementation of IBeatmapInfo
public IBeatmapMetadataInfo Metadata => (BeatmapSet as IBeatmapSetInfo)?.Metadata ?? new BeatmapMetadata();
diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs
index d8efa20b39..47536879b2 100644
--- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs
+++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs
@@ -3,11 +3,9 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using Newtonsoft.Json;
using osu.Game.Beatmaps;
using osu.Game.Database;
-using osu.Game.Rulesets;
using osu.Game.Users;
#nullable enable
@@ -119,28 +117,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 virtual BeatmapSetInfo ToBeatmapSet(RulesetStore rulesets)
- {
- var beatmapSet = new BeatmapSetInfo
- {
- OnlineBeatmapSetID = OnlineID,
- Metadata = metadata,
- Status = Status,
- OnlineInfo = this
- };
-
- beatmapSet.Beatmaps = Beatmaps.Select(b =>
- {
- var beatmap = b.ToBeatmapInfo(rulesets);
- beatmap.BeatmapSet = beatmapSet;
- beatmap.Metadata = beatmapSet.Metadata;
- return beatmap;
- }).ToList();
-
- return beatmapSet;
- }
+ public APIBeatmap[] Beatmaps { get; set; } = Array.Empty();
private BeatmapMetadata metadata => new BeatmapMetadata
{
diff --git a/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs
index 5395fe0429..82f56d27fd 100644
--- a/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs
+++ b/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs
@@ -98,7 +98,7 @@ namespace osu.Game.Online.API.Requests.Responses
{
TotalScore = TotalScore,
MaxCombo = MaxCombo,
- BeatmapInfo = Beatmap?.ToBeatmapInfo(rulesets),
+ BeatmapInfo = beatmap,
User = User,
Accuracy = Accuracy,
OnlineScoreID = OnlineID,
@@ -111,9 +111,6 @@ namespace osu.Game.Online.API.Requests.Responses
Mods = modInstances,
};
- if (beatmap != null)
- scoreInfo.BeatmapInfo = beatmap;
-
if (Statistics != null)
{
foreach (var kvp in Statistics)
diff --git a/osu.Game/Online/BeatmapDownloadTracker.cs b/osu.Game/Online/BeatmapDownloadTracker.cs
index 4a7d0b660a..12cbcdbec7 100644
--- a/osu.Game/Online/BeatmapDownloadTracker.cs
+++ b/osu.Game/Online/BeatmapDownloadTracker.cs
@@ -16,7 +16,7 @@ namespace osu.Game.Online
[Resolved(CanBeNull = true)]
protected BeatmapManager? Manager { get; private set; }
- private ArchiveDownloadRequest? attachedRequest;
+ private ArchiveDownloadRequest? attachedRequest;
public BeatmapDownloadTracker(IBeatmapSetInfo trackedItem)
: base(trackedItem)
@@ -25,8 +25,8 @@ namespace osu.Game.Online
private IBindable>? managerUpdated;
private IBindable>? managerRemoved;
- private IBindable>>? managerDownloadBegan;
- private IBindable>>? managerDownloadFailed;
+ private IBindable>>? managerDownloadBegan;
+ private IBindable>>? managerDownloadFailed;
[BackgroundDependencyLoader(true)]
private void load()
@@ -52,7 +52,7 @@ namespace osu.Game.Online
managerRemoved.BindValueChanged(itemRemoved);
}
- private void downloadBegan(ValueChangedEvent>> weakRequest)
+ private void downloadBegan(ValueChangedEvent>> weakRequest)
{
if (weakRequest.NewValue.TryGetTarget(out var request))
{
@@ -64,7 +64,7 @@ namespace osu.Game.Online
}
}
- private void downloadFailed(ValueChangedEvent>> weakRequest)
+ private void downloadFailed(ValueChangedEvent>> weakRequest)
{
if (weakRequest.NewValue.TryGetTarget(out var request))
{
@@ -76,7 +76,7 @@ namespace osu.Game.Online
}
}
- private void attachDownload(ArchiveDownloadRequest? request)
+ private void attachDownload(ArchiveDownloadRequest? request)
{
if (attachedRequest != null)
{
diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs
index 0586e0ae60..6c4747ea54 100644
--- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs
+++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs
@@ -17,6 +17,7 @@ using osu.Framework.Logging;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Online.API;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Rooms;
using osu.Game.Online.Rooms.RoomStatuses;
using osu.Game.Rulesets;
@@ -644,24 +645,32 @@ namespace osu.Game.Online.Multiplayer
RoomUpdated?.Invoke();
- GetOnlineBeatmapSet(settings.BeatmapID, cancellationToken).ContinueWith(set => Schedule(() =>
+ GetOnlineBeatmapSet(settings.BeatmapID, cancellationToken).ContinueWith(task => Schedule(() =>
{
if (cancellationToken.IsCancellationRequested)
return;
- updatePlaylist(settings, set.Result);
+ APIBeatmapSet beatmapSet = task.Result;
+
+ // 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 beatmapSet.Beatmaps)
+ b.BeatmapSet = beatmapSet;
+
+ updatePlaylist(settings, beatmapSet);
}), TaskContinuationOptions.OnlyOnRanToCompletion);
}, cancellationToken);
- private void updatePlaylist(MultiplayerRoomSettings settings, BeatmapSetInfo beatmapSet)
+ private void updatePlaylist(MultiplayerRoomSettings settings, APIBeatmapSet beatmapSet)
{
if (Room == null || !Room.Settings.Equals(settings))
return;
Debug.Assert(APIRoom != null);
- var beatmap = beatmapSet.Beatmaps.Single(b => b.OnlineBeatmapID == settings.BeatmapID);
- beatmap.MD5Hash = settings.BeatmapChecksum;
+ var beatmap = beatmapSet.Beatmaps.Single(b => b.OnlineID == settings.BeatmapID);
+
+ beatmap.Checksum = settings.BeatmapChecksum;
var ruleset = Rulesets.GetRuleset(settings.RulesetID).CreateInstance();
var mods = settings.RequiredMods.Select(m => m.ToMod(ruleset));
@@ -694,12 +703,12 @@ namespace osu.Game.Online.Multiplayer
}
///
- /// Retrieves a from an online source.
+ /// 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);
+ /// 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 965674c2f2..a28abc78ca 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
@@ -148,9 +148,9 @@ namespace osu.Game.Online.Multiplayer
return connection.InvokeAsync(nameof(IMultiplayerServer.StartMatch));
}
- 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 =>
@@ -161,7 +161,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/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 a642e283f9..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,6 +53,8 @@ namespace osu.Game.Online.Rooms
downloadTracker?.RemoveAndDisposeImmediately();
+ Debug.Assert(item.NewValue.Beatmap.Value.BeatmapSet != null);
+
downloadTracker = new BeatmapDownloadTracker(item.NewValue.Beatmap.Value.BeatmapSet);
AddInternal(downloadTracker);
diff --git a/osu.Game/Online/Rooms/PlaylistItem.cs b/osu.Game/Online/Rooms/PlaylistItem.cs
index 7fcce1514d..cb550281a9 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/ScoreDownloadTracker.cs b/osu.Game/Online/ScoreDownloadTracker.cs
index e679071ac1..9ea6d5b79a 100644
--- a/osu.Game/Online/ScoreDownloadTracker.cs
+++ b/osu.Game/Online/ScoreDownloadTracker.cs
@@ -16,7 +16,7 @@ namespace osu.Game.Online
[Resolved(CanBeNull = true)]
protected ScoreManager? Manager { get; private set; }
- private ArchiveDownloadRequest? attachedRequest;
+ private ArchiveDownloadRequest? attachedRequest;
public ScoreDownloadTracker(ScoreInfo trackedItem)
: base(trackedItem)
@@ -25,8 +25,8 @@ namespace osu.Game.Online
private IBindable>? managerUpdated;
private IBindable>? managerRemoved;
- private IBindable>>? managerDownloadBegan;
- private IBindable>>? managerDownloadFailed;
+ private IBindable>>? managerDownloadBegan;
+ private IBindable>>? managerDownloadFailed;
[BackgroundDependencyLoader(true)]
private void load()
@@ -56,7 +56,7 @@ namespace osu.Game.Online
managerRemoved.BindValueChanged(itemRemoved);
}
- private void downloadBegan(ValueChangedEvent>> weakRequest)
+ private void downloadBegan(ValueChangedEvent>> weakRequest)
{
if (weakRequest.NewValue.TryGetTarget(out var request))
{
@@ -68,7 +68,7 @@ namespace osu.Game.Online
}
}
- private void downloadFailed(ValueChangedEvent>> weakRequest)
+ private void downloadFailed(ValueChangedEvent>> weakRequest)
{
if (weakRequest.NewValue.TryGetTarget(out var request))
{
@@ -80,7 +80,7 @@ namespace osu.Game.Online
}
}
- private void attachDownload(ArchiveDownloadRequest? request)
+ private void attachDownload(ArchiveDownloadRequest? request)
{
if (attachedRequest != null)
{
@@ -144,7 +144,7 @@ namespace osu.Game.Online
}
}
- private bool checkEquality(ScoreInfo x, ScoreInfo y) => x.OnlineScoreID == y.OnlineScoreID;
+ private bool checkEquality(IScoreInfo x, IScoreInfo y) => x.OnlineID == y.OnlineID;
#region Disposal
diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs
index e0632ace58..461a06a634 100644
--- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs
+++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@@ -22,6 +23,11 @@ namespace osu.Game.Overlays.BeatmapListing
public BeatmapSearchMultipleSelectionFilterRow(LocalisableString header)
: base(header)
+ {
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
{
Current.BindTo(filter.Current);
}
@@ -31,6 +37,7 @@ namespace osu.Game.Overlays.BeatmapListing
///
/// Creates a filter control that can be used to simultaneously select multiple values of type .
///
+ [NotNull]
protected virtual MultipleSelectionFilter CreateMultipleSelectionFilter() => new MultipleSelectionFilter();
protected class MultipleSelectionFilter : FillFlowContainer
diff --git a/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanel.cs b/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanel.cs
index 2fd05f6742..34086c214f 100644
--- a/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanel.cs
+++ b/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanel.cs
@@ -147,7 +147,7 @@ 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.Where(b => b.RulesetID == ruleset.OnlineID).ToList(), ruleset, this is ListBeatmapPanel ? Color4.White : colours.Gray5));
diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs
index 4a00c8b4a0..69739b3352 100644
--- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs
+++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.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.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -66,7 +67,18 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
if (value?.Scores.Any() != true)
return;
- scoreManager.OrderByTotalScoreAsync(value.Scores.Select(s => s.CreateScoreInfo(rulesets, Beatmap.Value.ToBeatmapInfo(rulesets))).ToArray(), loadCancellationSource.Token)
+ var apiBeatmap = Beatmap.Value;
+
+ Debug.Assert(apiBeatmap != null);
+
+ // TODO: temporary. should be removed once `OrderByTotalScore` can accept `IScoreInfo`.
+ var beatmapInfo = new BeatmapInfo
+ {
+ MaxCombo = apiBeatmap.MaxCombo,
+ Status = apiBeatmap.Status
+ };
+
+ scoreManager.OrderByTotalScoreAsync(value.Scores.Select(s => s.CreateScoreInfo(rulesets, beatmapInfo)).ToArray(), loadCancellationSource.Token)
.ContinueWith(ordered => Schedule(() =>
{
if (loadCancellationSource.IsCancellationRequested)
@@ -74,11 +86,11 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
var topScore = ordered.Result.First();
- scoreTable.DisplayScores(ordered.Result, topScore.BeatmapInfo?.Status.GrantsPerformancePoints() == true);
+ scoreTable.DisplayScores(ordered.Result, apiBeatmap.Status.GrantsPerformancePoints());
scoreTable.Show();
var userScore = value.UserScore;
- var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets, Beatmap.Value.ToBeatmapInfo(rulesets));
+ var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets, beatmapInfo);
topScoresContainer.Add(new DrawableTopScore(topScore));
diff --git a/osu.Game/Overlays/Changelog/ChangelogHeader.cs b/osu.Game/Overlays/Changelog/ChangelogHeader.cs
index 52dea63ab7..49a33ee5d6 100644
--- a/osu.Game/Overlays/Changelog/ChangelogHeader.cs
+++ b/osu.Game/Overlays/Changelog/ChangelogHeader.cs
@@ -26,6 +26,8 @@ namespace osu.Game.Overlays.Changelog
public static LocalisableString ListingString => LayoutStrings.HeaderChangelogIndex;
+ private readonly Bindable currentStream = new Bindable();
+
private Box streamsBackground;
public ChangelogHeader()
@@ -39,7 +41,7 @@ namespace osu.Game.Overlays.Changelog
Build.ValueChanged += showBuild;
- Streams.Current.ValueChanged += e =>
+ currentStream.ValueChanged += e =>
{
if (e.NewValue?.LatestBuild != null && !e.NewValue.Equals(Build.Value?.UpdateStream))
Build.Value = e.NewValue.LatestBuild;
@@ -67,7 +69,7 @@ namespace osu.Game.Overlays.Changelog
else
{
Current.Value = ListingString;
- Streams.Current.Value = null;
+ currentStream.Value = null;
}
}
@@ -92,7 +94,7 @@ namespace osu.Game.Overlays.Changelog
Horizontal = 65,
Vertical = 20
},
- Child = Streams = new ChangelogUpdateStreamControl()
+ Child = Streams = new ChangelogUpdateStreamControl { Current = currentStream },
}
}
};
@@ -110,7 +112,7 @@ namespace osu.Game.Overlays.Changelog
if (Build.Value == null)
return;
- Streams.Current.Value = Streams.Items.FirstOrDefault(s => s.Name == Build.Value.UpdateStream.Name);
+ currentStream.Value = Streams.Items.FirstOrDefault(s => s.Name == Build.Value.UpdateStream.Name);
}
private class ChangelogHeaderTitle : OverlayTitle
diff --git a/osu.Game/Overlays/Comments/CommentEditor.cs b/osu.Game/Overlays/Comments/CommentEditor.cs
index 20a8ab64f7..3ff4cfad4a 100644
--- a/osu.Game/Overlays/Comments/CommentEditor.cs
+++ b/osu.Game/Overlays/Comments/CommentEditor.cs
@@ -175,6 +175,8 @@ namespace osu.Game.Overlays.Comments
protected override IEnumerable EffectTargets => new[] { background };
+ private readonly string text;
+
[Resolved]
private OverlayColourProvider colourProvider { get; set; }
@@ -184,10 +186,10 @@ namespace osu.Game.Overlays.Comments
public CommitButton(string text)
{
+ this.text = text;
+
AutoSizeAxes = Axes.Both;
LoadingAnimationSize = new Vector2(10);
-
- drawableText.Text = text;
}
[BackgroundDependencyLoader]
@@ -232,7 +234,8 @@ namespace osu.Game.Overlays.Comments
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
- Margin = new MarginPadding { Horizontal = 20 }
+ Margin = new MarginPadding { Horizontal = 20 },
+ Text = text,
}
}
};
diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs
index 5619d7b38a..f37e6bedf7 100644
--- a/osu.Game/Overlays/NowPlayingOverlay.cs
+++ b/osu.Game/Overlays/NowPlayingOverlay.cs
@@ -366,14 +366,13 @@ namespace osu.Game.Overlays
private readonly WorkingBeatmap beatmap;
public Background(WorkingBeatmap beatmap = null)
+ : base(cachedFrameBuffer: true)
{
this.beatmap = beatmap;
Depth = float.MaxValue;
RelativeSizeAxes = Axes.Both;
- CacheDrawnFrameBuffer = true;
-
Children = new Drawable[]
{
sprite = new Sprite
diff --git a/osu.Game/Overlays/OverlayScrollContainer.cs b/osu.Game/Overlays/OverlayScrollContainer.cs
index ca5fc90027..7fe188eb04 100644
--- a/osu.Game/Overlays/OverlayScrollContainer.cs
+++ b/osu.Game/Overlays/OverlayScrollContainer.cs
@@ -37,11 +37,7 @@ namespace osu.Game.Overlays
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
Margin = new MarginPadding(20),
- Action = () =>
- {
- ScrollToStart();
- Button.State = Visibility.Hidden;
- }
+ Action = scrollToTop
});
}
@@ -58,6 +54,12 @@ namespace osu.Game.Overlays
Button.State = Target > button_scroll_position ? Visibility.Visible : Visibility.Hidden;
}
+ private void scrollToTop()
+ {
+ ScrollToStart();
+ Button.State = Visibility.Hidden;
+ }
+
public class ScrollToTopButton : OsuHoverContainer
{
private const int fade_duration = 500;
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/Rulesets/Mods/ModAutoplay.cs b/osu.Game/Rulesets/Mods/ModAutoplay.cs
index 4849d6ea36..60b9c29fe0 100644
--- a/osu.Game/Rulesets/Mods/ModAutoplay.cs
+++ b/osu.Game/Rulesets/Mods/ModAutoplay.cs
@@ -30,11 +30,6 @@ namespace osu.Game.Rulesets.Mods
public override bool HasImplementation => GetType().GenericTypeArguments.Length == 0;
- [Obsolete("Use the mod-supporting override")] // can be removed 20210731
- public virtual Score CreateReplayScore(IBeatmap beatmap) => new Score { Replay = new Replay() };
-
-#pragma warning disable 618
- public virtual Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList mods) => CreateReplayScore(beatmap);
-#pragma warning restore 618
+ public virtual Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList mods) => new Score { Replay = new Replay() };
}
}
diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs
index 253591eb56..676baf511a 100644
--- a/osu.Game/Scoring/ScoreManager.cs
+++ b/osu.Game/Scoring/ScoreManager.cs
@@ -25,7 +25,7 @@ using osu.Game.Rulesets.Scoring;
namespace osu.Game.Scoring
{
- public class ScoreManager : IModelManager, IModelFileManager, IModelDownloader
+ public class ScoreManager : IModelManager, IModelImporter, IModelFileManager, IModelDownloader
{
private readonly Scheduler scheduler;
private readonly Func difficulties;
@@ -350,16 +350,14 @@ namespace osu.Game.Scoring
#region Implementation of IModelDownloader
- public IBindable>> DownloadBegan => scoreModelDownloader.DownloadBegan;
+ public IBindable>> DownloadBegan => scoreModelDownloader.DownloadBegan;
- public IBindable>> DownloadFailed => scoreModelDownloader.DownloadFailed;
+ public IBindable>> DownloadFailed => scoreModelDownloader.DownloadFailed;
- public bool Download(ScoreInfo model, bool minimiseDownloadSize)
- {
- return scoreModelDownloader.Download(model, minimiseDownloadSize);
- }
+ public bool Download(IScoreInfo model, bool minimiseDownloadSize) =>
+ scoreModelDownloader.Download(model, minimiseDownloadSize);
- public ArchiveDownloadRequest GetExistingDownload(ScoreInfo model)
+ public ArchiveDownloadRequest GetExistingDownload(IScoreInfo model)
{
return scoreModelDownloader.GetExistingDownload(model);
}
diff --git a/osu.Game/Scoring/ScoreModelDownloader.cs b/osu.Game/Scoring/ScoreModelDownloader.cs
index 52355585a9..6c63e2aa71 100644
--- a/osu.Game/Scoring/ScoreModelDownloader.cs
+++ b/osu.Game/Scoring/ScoreModelDownloader.cs
@@ -8,16 +8,16 @@ using osu.Game.Online.API.Requests;
namespace osu.Game.Scoring
{
- public class ScoreModelDownloader : ModelDownloader
+ public class ScoreModelDownloader : ModelDownloader
{
- public ScoreModelDownloader(ScoreModelManager scoreManager, IAPIProvider api, IIpcHost importHost = null)
+ public ScoreModelDownloader(IModelImporter scoreManager, IAPIProvider api, IIpcHost importHost = null)
: base(scoreManager, api, importHost)
{
}
- protected override ArchiveDownloadRequest CreateDownloadRequest(ScoreInfo score, bool minimiseDownload) => new DownloadReplayRequest(score);
+ protected override ArchiveDownloadRequest CreateDownloadRequest(IScoreInfo score, bool minimiseDownload) => new DownloadReplayRequest(score);
- public override ArchiveDownloadRequest GetExistingDownload(ScoreInfo model)
- => CurrentDownloads.Find(r => r.Model.OnlineScoreID == model.OnlineScoreID);
+ public override ArchiveDownloadRequest GetExistingDownload(IScoreInfo model)
+ => CurrentDownloads.Find(r => r.Model.OnlineID == model.OnlineID);
}
}
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/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs
index 48ced63182..d171e481b1 100644
--- a/osu.Game/Screens/Menu/IntroTriangles.cs
+++ b/osu.Game/Screens/Menu/IntroTriangles.cs
@@ -393,6 +393,7 @@ namespace osu.Game.Screens.Menu
public class OutlineTriangle : BufferedContainer
{
public OutlineTriangle(bool outlineOnly, float size)
+ : base(cachedFrameBuffer: true)
{
Size = new Vector2(size);
@@ -414,7 +415,6 @@ namespace osu.Game.Screens.Menu
}
Blending = BlendingParameters.Additive;
- CacheDrawnFrameBuffer = true;
}
}
}
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 675b5e4c04..0681ac23ad 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;
@@ -45,7 +46,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();
@@ -96,6 +97,7 @@ namespace osu.Game.Screens.OnlinePlay
}
private ScheduledDelegate scheduledRefresh;
+ private PanelBackground panelBackground;
private void scheduleRefresh()
{
@@ -105,23 +107,25 @@ namespace osu.Game.Screens.OnlinePlay
private void refresh()
{
- difficultyIconContainer.Child = new DifficultyIcon(beatmap.Value, ruleset.Value, requiredMods, performBackgroundDifficultyLookup: false) { 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;
});
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();
@@ -145,10 +149,9 @@ namespace osu.Game.Screens.OnlinePlay
Alpha = 0,
AlwaysPresent = true
},
- new PanelBackground
+ panelBackground = new PanelBackground
{
RelativeSizeAxes = Axes.Both,
- Beatmap = { BindTarget = beatmap }
},
new GridContainer
{
@@ -181,8 +184,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
{
@@ -334,7 +340,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/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/Break/BlurredIcon.cs b/osu.Game/Screens/Play/Break/BlurredIcon.cs
index a88112a0db..1e974ec916 100644
--- a/osu.Game/Screens/Play/Break/BlurredIcon.cs
+++ b/osu.Game/Screens/Play/Break/BlurredIcon.cs
@@ -32,9 +32,9 @@ namespace osu.Game.Screens.Play.Break
}
public BlurredIcon()
+ : base(cachedFrameBuffer: true)
{
RelativePositionAxes = Axes.X;
- CacheDrawnFrameBuffer = true;
Child = icon = new SpriteIcon
{
Origin = Anchor.Centre,
diff --git a/osu.Game/Screens/Play/SoloSpectator.cs b/osu.Game/Screens/Play/SoloSpectator.cs
index 83ea660092..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(res);
+ 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/Play/SquareGraph.cs b/osu.Game/Screens/Play/SquareGraph.cs
index 67abcb66e6..a7d4454701 100644
--- a/osu.Game/Screens/Play/SquareGraph.cs
+++ b/osu.Game/Screens/Play/SquareGraph.cs
@@ -98,9 +98,8 @@ namespace osu.Game.Screens.Play
///
protected virtual void RecreateGraph()
{
- var newColumns = new BufferedContainer
+ var newColumns = new BufferedContainer(cachedFrameBuffer: true)
{
- CacheDrawnFrameBuffer = true,
RedrawOnScale = false,
RelativeSizeAxes = Axes.Both,
};
diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/RankText.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/RankText.cs
index cc732382f4..5aea0184ee 100644
--- a/osu.Game/Screens/Ranking/Expanded/Accuracy/RankText.cs
+++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/RankText.cs
@@ -51,13 +51,12 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy
Font = OsuFont.Numeric.With(size: 76),
UseFullGlyphHeight = false
},
- superFlash = new BufferedContainer
+ superFlash = new BufferedContainer(cachedFrameBuffer: true)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
BlurSigma = new Vector2(85),
Size = new Vector2(600),
- CacheDrawnFrameBuffer = true,
Blending = BlendingParameters.Additive,
Alpha = 0,
Children = new[]
@@ -71,14 +70,13 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy
},
},
},
- flash = new BufferedContainer
+ flash = new BufferedContainer(cachedFrameBuffer: true)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
BlurSigma = new Vector2(35),
BypassAutoSizeAxes = Axes.Both,
Size = new Vector2(200),
- CacheDrawnFrameBuffer = true,
Blending = BlendingParameters.Additive,
Alpha = 0,
Scale = new Vector2(1.8f),
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 ece16a8e57..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?.OnlineInfo?.Ratings;
+ var onlineInfo = beatmapInfo as IBeatmapOnlineInfo;
+ var onlineSetInfo = beatmapInfo.BeatmapSet as IBeatmapSetOnlineInfo;
+
+ failTimes = onlineInfo?.FailTimes;
+ ratings = onlineSetInfo?.Ratings;
Scheduler.AddOnce(updateStatistics);
}
@@ -178,9 +181,9 @@ 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;
// failTimes may have been previously fetched
if (ratings != null && failTimes != null)
@@ -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/BeatmapInfoWedgeBackground.cs b/osu.Game/Screens/Select/BeatmapInfoWedgeBackground.cs
index f50fb4dc8a..25056790cc 100644
--- a/osu.Game/Screens/Select/BeatmapInfoWedgeBackground.cs
+++ b/osu.Game/Screens/Select/BeatmapInfoWedgeBackground.cs
@@ -27,9 +27,8 @@ namespace osu.Game.Screens.Select
{
RelativeSizeAxes = Axes.Both;
- InternalChild = new BufferedContainer
+ InternalChild = new BufferedContainer(cachedFrameBuffer: true)
{
- CacheDrawnFrameBuffer = true,
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
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/Carousel/SetPanelBackground.cs b/osu.Game/Screens/Select/Carousel/SetPanelBackground.cs
index 25139b27db..b4279cce51 100644
--- a/osu.Game/Screens/Select/Carousel/SetPanelBackground.cs
+++ b/osu.Game/Screens/Select/Carousel/SetPanelBackground.cs
@@ -15,8 +15,8 @@ namespace osu.Game.Screens.Select.Carousel
public class SetPanelBackground : BufferedContainer
{
public SetPanelBackground(WorkingBeatmap working)
+ : base(cachedFrameBuffer: true)
{
- CacheDrawnFrameBuffer = true;
RedrawOnScale = false;
Children = new Drawable[]
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/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 c6634abe82..70d907ba15 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.Rooms;
@@ -265,18 +266,24 @@ namespace osu.Game.Tests.Visual.Multiplayer
return ((IMultiplayerClient)this).LoadRequested();
}
- 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/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 972d64a997..7811de5764 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -36,7 +36,7 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index f6e4f61fde..9d95b7c765 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -70,7 +70,7 @@
-
+
@@ -93,7 +93,7 @@
-
+