Merge branch 'master' into fix-more-null

This commit is contained in:
Bartłomiej Dach
2021-11-06 15:36:15 +01:00
43 changed files with 249 additions and 464 deletions

View File

@ -52,7 +52,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.1026.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2021.1026.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.1104.0" /> <PackageReference Include="ppy.osu.Framework.Android" Version="2021.1106.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Label="Transitive Dependencies"> <ItemGroup Label="Transitive Dependencies">
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. --> <!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->

View File

@ -86,20 +86,18 @@ namespace osu.Game.Rulesets.Mania.Skinning.Default
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
InternalChild = foregroundBuffer = new BufferedContainer InternalChild = foregroundBuffer = new BufferedContainer(cachedFrameBuffer: true)
{ {
Blending = BlendingParameters.Additive, Blending = BlendingParameters.Additive,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
CacheDrawnFrameBuffer = true,
Children = new Drawable[] Children = new Drawable[]
{ {
new Box { RelativeSizeAxes = Axes.Both }, new Box { RelativeSizeAxes = Axes.Both },
subtractionBuffer = new BufferedContainer subtractionBuffer = new BufferedContainer(cachedFrameBuffer: true)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
// This is needed because we're blending with another object // This is needed because we're blending with another object
BackgroundColour = Color4.White.Opacity(0), BackgroundColour = Color4.White.Opacity(0),
CacheDrawnFrameBuffer = true,
// The 'hole' is achieved by subtracting the result of this container with the parent // The 'hole' is achieved by subtracting the result of this container with the parent
Blending = new BlendingParameters { AlphaEquation = BlendingEquation.ReverseSubtract }, Blending = new BlendingParameters { AlphaEquation = BlendingEquation.ReverseSubtract },
Child = subtractionLayer = new CircularContainer Child = subtractionLayer = new CircularContainer

View File

@ -136,10 +136,9 @@ namespace osu.Game.Rulesets.Osu.Statistics
} }
} }
}, },
bufferedGrid = new BufferedContainer bufferedGrid = new BufferedContainer(cachedFrameBuffer: true)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
CacheDrawnFrameBuffer = true,
BackgroundColour = Color4Extensions.FromHex("#202624").Opacity(0), BackgroundColour = Color4Extensions.FromHex("#202624").Opacity(0),
Child = pointGrid = new GridContainer Child = pointGrid = new GridContainer
{ {

View File

@ -39,8 +39,8 @@ namespace osu.Game.Tests.NonVisual
[Test] [Test]
public void TestCheckNullID() public void TestCheckNullID()
{ {
var ourInfo = new BeatmapSetInfo { Status = BeatmapSetOnlineStatus.Loved }; var ourInfo = new BeatmapSetInfo { Hash = "1" };
var otherInfo = new BeatmapSetInfo { Status = BeatmapSetOnlineStatus.Approved }; var otherInfo = new BeatmapSetInfo { Hash = "2" };
Assert.AreNotEqual(ourInfo, otherInfo); Assert.AreNotEqual(ourInfo, otherInfo);
} }

View File

@ -168,19 +168,19 @@ namespace osu.Game.Tests.Online
return new TestBeatmapModelManager(this, storage, contextFactory, rulesets, api, host); return new TestBeatmapModelManager(this, storage, contextFactory, rulesets, api, host);
} }
protected override BeatmapModelDownloader CreateBeatmapModelDownloader(IBeatmapModelManager manager, IAPIProvider api, GameHost host) protected override BeatmapModelDownloader CreateBeatmapModelDownloader(IModelImporter<BeatmapSetInfo> manager, IAPIProvider api, GameHost host)
{ {
return new TestBeatmapModelDownloader(manager, api, host); return new TestBeatmapModelDownloader(manager, api, host);
} }
internal class TestBeatmapModelDownloader : BeatmapModelDownloader internal class TestBeatmapModelDownloader : BeatmapModelDownloader
{ {
public TestBeatmapModelDownloader(IBeatmapModelManager modelManager, IAPIProvider apiProvider, GameHost gameHost) public TestBeatmapModelDownloader(IModelImporter<BeatmapSetInfo> importer, IAPIProvider apiProvider, GameHost gameHost)
: base(modelManager, apiProvider, gameHost) : base(importer, apiProvider, gameHost)
{ {
} }
protected override ArchiveDownloadRequest<BeatmapSetInfo> CreateDownloadRequest(BeatmapSetInfo set, bool minimiseDownloadSize) protected override ArchiveDownloadRequest<IBeatmapSetInfo> CreateDownloadRequest(IBeatmapSetInfo set, bool minimiseDownloadSize)
=> new TestDownloadRequest(set); => new TestDownloadRequest(set);
} }
@ -202,12 +202,12 @@ namespace osu.Game.Tests.Online
} }
} }
private class TestDownloadRequest : ArchiveDownloadRequest<BeatmapSetInfo> private class TestDownloadRequest : ArchiveDownloadRequest<IBeatmapSetInfo>
{ {
public new void SetProgress(float progress) => base.SetProgress(progress); public new void SetProgress(float progress) => base.SetProgress(progress);
public new void TriggerSuccess(string filename) => base.TriggerSuccess(filename); public new void TriggerSuccess(string filename) => base.TriggerSuccess(filename);
public TestDownloadRequest(BeatmapSetInfo model) public TestDownloadRequest(IBeatmapSetInfo model)
: base(model) : base(model)
{ {
} }

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
@ -223,11 +224,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test] [Test]
public void TestDownloadButtonVisibleInitiallyWhenBeatmapDoesNotExist() public void TestDownloadButtonVisibleInitiallyWhenBeatmapDoesNotExist()
{ {
var byOnlineId = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo; var byOnlineId = CreateAPIBeatmap();
byOnlineId.BeatmapSet.OnlineBeatmapSetID = 1337; // Some random ID that does not exist locally. byOnlineId.OnlineID = 1337; // Some random ID that does not exist locally.
var byChecksum = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo; var byChecksum = CreateAPIBeatmap();
byChecksum.MD5Hash = "1337"; // Some random checksum that does not exist locally. byChecksum.Checksum = "1337"; // Some random checksum that does not exist locally.
createPlaylist(byOnlineId, byChecksum); createPlaylist(byOnlineId, byChecksum);
@ -237,8 +238,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test] [Test]
public void TestExplicitBeatmapItem() public void TestExplicitBeatmapItem()
{ {
var beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo; var beatmap = CreateAPIBeatmap();
beatmap.BeatmapSet.OnlineInfo.HasExplicitContent = true;
Debug.Assert(beatmap.BeatmapSet != null);
beatmap.BeatmapSet.HasExplicitContent = true;
createPlaylist(beatmap); 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)); 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", () => AddStep("create playlist", () =>
{ {

View File

@ -9,7 +9,6 @@ using osu.Game.Beatmaps;
using osu.Game.Online; using osu.Game.Online;
using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.BeatmapListing.Panels; using osu.Game.Overlays.BeatmapListing.Panels;
using osu.Game.Rulesets.Osu;
using osu.Game.Tests.Resources; using osu.Game.Tests.Resources;
using osuTK; using osuTK;
@ -110,7 +109,7 @@ namespace osu.Game.Tests.Visual.Online
private IBeatmapSetInfo getDownloadableBeatmapSet() private IBeatmapSetInfo getDownloadableBeatmapSet()
{ {
var apiBeatmapSet = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo).BeatmapSetInfo.OnlineInfo; var apiBeatmapSet = CreateAPIBeatmapSet();
apiBeatmapSet.HasVideo = true; apiBeatmapSet.HasVideo = true;
apiBeatmapSet.HasStoryboard = true; apiBeatmapSet.HasStoryboard = true;
@ -120,7 +119,7 @@ namespace osu.Game.Tests.Visual.Online
private IBeatmapSetInfo getUndownloadableBeatmapSet() private IBeatmapSetInfo getUndownloadableBeatmapSet()
{ {
var apiBeatmapSet = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo).BeatmapSetInfo.OnlineInfo; var apiBeatmapSet = CreateAPIBeatmapSet();
apiBeatmapSet.Artist = "test"; apiBeatmapSet.Artist = "test";
apiBeatmapSet.Title = "undownloadable"; apiBeatmapSet.Title = "undownloadable";

View File

@ -7,7 +7,6 @@ using osu.Framework.Graphics;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Select; using osu.Game.Screens.Select;
namespace osu.Game.Tests.Visual.SongSelect namespace osu.Game.Tests.Visual.SongSelect
@ -32,159 +31,112 @@ namespace osu.Game.Tests.Visual.SongSelect
[Test] [Test]
public void TestAllMetrics() public void TestAllMetrics()
{ {
AddStep("all metrics", () => details.BeatmapInfo = new BeatmapInfo AddStep("all metrics", () => details.BeatmapInfo = new APIBeatmap
{ {
BeatmapSet = new BeatmapSetInfo BeatmapSet = new APIBeatmapSet
{
OnlineInfo = new APIBeatmapSet
{
Ratings = Enumerable.Range(0, 11).ToArray(),
}
},
Version = "All Metrics",
Metadata = new BeatmapMetadata
{ {
Source = "osu!", Source = "osu!",
Tags = "this beatmap has all the metrics", 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, Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
DrainRate = 1, Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
OverallDifficulty = 5.7f,
ApproachRate = 3.5f,
}, },
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] [Test]
public void TestAllMetricsExceptSource() public void TestAllMetricsExceptSource()
{ {
AddStep("all except source", () => details.BeatmapInfo = new BeatmapInfo AddStep("all except source", () => details.BeatmapInfo = new APIBeatmap
{ {
BeatmapSet = new BeatmapSetInfo BeatmapSet = new APIBeatmapSet
{
OnlineInfo = new APIBeatmapSet
{
Ratings = Enumerable.Range(0, 11).ToArray(),
}
},
Version = "All Metrics",
Metadata = new BeatmapMetadata
{ {
Tags = "this beatmap has all the metrics", 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, Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
DrainRate = 1, Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
OverallDifficulty = 5.7f,
ApproachRate = 3.5f,
}, },
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] [Test]
public void TestOnlyRatings() public void TestOnlyRatings()
{ {
AddStep("ratings", () => details.BeatmapInfo = new BeatmapInfo AddStep("ratings", () => details.BeatmapInfo = new APIBeatmap
{ {
BeatmapSet = new BeatmapSetInfo BeatmapSet = new APIBeatmapSet
{
OnlineInfo = new APIBeatmapSet
{
Ratings = Enumerable.Range(0, 11).ToArray(),
}
},
Version = "Only Ratings",
Metadata = new BeatmapMetadata
{ {
Ratings = Enumerable.Range(0, 11).ToArray(),
Source = "osu!", Source = "osu!",
Tags = "this beatmap has ratings metrics but not retries or fails", Tags = "this beatmap has ratings metrics but not retries or fails",
}, },
Ruleset = new OsuRuleset().RulesetInfo, DifficultyName = "Only Ratings",
BaseDifficulty = new BeatmapDifficulty CircleSize = 6,
{ DrainRate = 9,
CircleSize = 6, OverallDifficulty = 6,
DrainRate = 9, ApproachRate = 6,
OverallDifficulty = 6, StarRating = 4.8f,
ApproachRate = 6,
},
StarDifficulty = 4.8f,
}); });
} }
[Test] [Test]
public void TestOnlyFailsAndRetries() public void TestOnlyFailsAndRetries()
{ {
AddStep("fails retries", () => details.BeatmapInfo = new BeatmapInfo AddStep("fails retries", () => details.BeatmapInfo = new APIBeatmap
{ {
Version = "Only Retries and Fails", DifficultyName = "Only Retries and Fails",
Metadata = new BeatmapMetadata BeatmapSet = new APIBeatmapSet
{ {
Source = "osu!", Source = "osu!",
Tags = "this beatmap has retries and fails but no ratings", 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, Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
DrainRate = 6, Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
OverallDifficulty = 6,
ApproachRate = 7,
}, },
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] [Test]
public void TestNoMetrics() public void TestNoMetrics()
{ {
AddStep("no metrics", () => details.BeatmapInfo = new BeatmapInfo AddStep("no metrics", () => details.BeatmapInfo = new APIBeatmap
{ {
Version = "No Metrics", DifficultyName = "No Metrics",
Metadata = new BeatmapMetadata BeatmapSet = new APIBeatmapSet
{ {
Source = "osu!", Source = "osu!",
Tags = "this beatmap has no metrics", Tags = "this beatmap has no metrics",
}, },
Ruleset = new OsuRuleset().RulesetInfo, CircleSize = 5,
BaseDifficulty = new BeatmapDifficulty DrainRate = 5,
{ OverallDifficulty = 5.5f,
CircleSize = 5, ApproachRate = 6.5f,
DrainRate = 5, StarRating = 1.97f,
OverallDifficulty = 5.5f,
ApproachRate = 6.5f,
},
StarDifficulty = 1.97f,
}); });
} }
@ -197,10 +149,9 @@ namespace osu.Game.Tests.Visual.SongSelect
[Test] [Test]
public void TestOnlineMetrics() public void TestOnlineMetrics()
{ {
AddStep("online ratings/retries/fails", () => details.BeatmapInfo = new BeatmapInfo AddStep("online ratings/retries/fails", () => details.BeatmapInfo = new APIBeatmap
{ {
OnlineBeatmapID = 162, OnlineID = 162,
Ruleset = new OsuRuleset().RulesetInfo
}); });
AddStep("set online", () => api.SetState(APIState.Online)); AddStep("set online", () => api.SetState(APIState.Online));
AddStep("set offline", () => api.SetState(APIState.Offline)); AddStep("set offline", () => api.SetState(APIState.Offline));

View File

@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.UserInterface
{ {
AddStep("setup cover", () => Child = new UpdateableOnlineBeatmapSetCover(coverType) AddStep("setup cover", () => Child = new UpdateableOnlineBeatmapSetCover(coverType)
{ {
OnlineInfo = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet.OnlineInfo, OnlineInfo = CreateAPIBeatmapSet(),
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Masking = true, Masking = true,
}); });
@ -41,7 +41,7 @@ namespace osu.Game.Tests.Visual.UserInterface
AddStep("setup covers", () => AddStep("setup covers", () =>
{ {
BeatmapSetInfo setInfo = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet; var beatmapSet = CreateAPIBeatmapSet();
FillFlowContainer fillFlow; FillFlowContainer fillFlow;
@ -68,7 +68,7 @@ namespace osu.Game.Tests.Visual.UserInterface
var cover = new UpdateableOnlineBeatmapSetCover(coverType) var cover = new UpdateableOnlineBeatmapSetCover(coverType)
{ {
OnlineInfo = setInfo.OnlineInfo, OnlineInfo = beatmapSet,
Height = 100, Height = 100,
Masking = true, Masking = true,
}; };
@ -99,7 +99,7 @@ namespace osu.Game.Tests.Visual.UserInterface
AddStep("setup cover", () => Child = updateableCover = new TestUpdateableOnlineBeatmapSetCover AddStep("setup cover", () => Child = updateableCover = new TestUpdateableOnlineBeatmapSetCover
{ {
OnlineInfo = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet.OnlineInfo, OnlineInfo = CreateAPIBeatmapSet(),
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Masking = true, Masking = true,
}); });
@ -117,7 +117,7 @@ namespace osu.Game.Tests.Visual.UserInterface
AddStep("setup cover", () => Child = updateableCover = new TestUpdateableOnlineBeatmapSetCover(0) 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, RelativeSizeAxes = Axes.Both,
Masking = true, Masking = true,
Alpha = 0.4f Alpha = 0.4f
@ -128,16 +128,13 @@ namespace osu.Game.Tests.Visual.UserInterface
AddUntilStep("wait for fade complete", () => initialCover.Alpha == 1); AddUntilStep("wait for fade complete", () => initialCover.Alpha == 1);
AddStep("switch beatmap", 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<OnlineBeatmapSetCover>().Except(new[] { initialCover }).Any()); AddUntilStep("new cover loaded", () => updateableCover.ChildrenOfType<OnlineBeatmapSetCover>().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 private class TestUpdateableOnlineBeatmapSetCover : UpdateableOnlineBeatmapSetCover

View File

@ -17,7 +17,7 @@ namespace osu.Game.Beatmaps
{ {
[ExcludeFromDynamicCompile] [ExcludeFromDynamicCompile]
[Serializable] [Serializable]
public class BeatmapInfo : IEquatable<BeatmapInfo>, IHasPrimaryKey, IBeatmapInfo, IBeatmapOnlineInfo public class BeatmapInfo : IEquatable<BeatmapInfo>, IHasPrimaryKey, IBeatmapInfo
{ {
public int ID { get; set; } public int ID { get; set; }
@ -201,24 +201,5 @@ namespace osu.Game.Beatmaps
double IBeatmapInfo.StarRating => StarDifficulty; double IBeatmapInfo.StarRating => StarDifficulty;
#endregion #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
} }
} }

View File

@ -29,7 +29,7 @@ namespace osu.Game.Beatmaps
/// Handles general operations related to global beatmap management. /// Handles general operations related to global beatmap management.
/// </summary> /// </summary>
[ExcludeFromDynamicCompile] [ExcludeFromDynamicCompile]
public class BeatmapManager : IModelDownloader<BeatmapSetInfo>, IModelManager<BeatmapSetInfo>, IModelFileManager<BeatmapSetInfo, BeatmapSetFileInfo>, IWorkingBeatmapCache, IDisposable public class BeatmapManager : IModelDownloader<IBeatmapSetInfo>, IModelManager<BeatmapSetInfo>, IModelFileManager<BeatmapSetInfo, BeatmapSetFileInfo>, IModelImporter<BeatmapSetInfo>, IWorkingBeatmapCache, IDisposable
{ {
private readonly BeatmapModelManager beatmapModelManager; private readonly BeatmapModelManager beatmapModelManager;
private readonly BeatmapModelDownloader beatmapModelDownloader; 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<BeatmapSetInfo> modelManager, IAPIProvider api, GameHost host)
{ {
return new BeatmapModelDownloader(modelManager, api, host); return new BeatmapModelDownloader(modelManager, api, host);
} }
@ -246,33 +246,16 @@ namespace osu.Game.Beatmaps
#region Implementation of IModelDownloader<BeatmapSetInfo> #region Implementation of IModelDownloader<BeatmapSetInfo>
public IBindable<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>> DownloadBegan => beatmapModelDownloader.DownloadBegan; public IBindable<WeakReference<ArchiveDownloadRequest<IBeatmapSetInfo>>> DownloadBegan => beatmapModelDownloader.DownloadBegan;
public IBindable<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>> DownloadFailed => beatmapModelDownloader.DownloadFailed; public IBindable<WeakReference<ArchiveDownloadRequest<IBeatmapSetInfo>>> DownloadFailed => beatmapModelDownloader.DownloadFailed;
// Temporary method until this class supports IBeatmapSetInfo or otherwise.
public bool Download(IBeatmapSetInfo model, bool minimiseDownloadSize = false) public bool Download(IBeatmapSetInfo model, bool minimiseDownloadSize = false)
{
return beatmapModelDownloader.Download(new BeatmapSetInfo
{
OnlineBeatmapSetID = model.OnlineID,
Metadata = new BeatmapMetadata
{
Title = model.Metadata?.Title ?? string.Empty,
Artist = model.Metadata?.Artist ?? string.Empty,
TitleUnicode = model.Metadata?.TitleUnicode ?? string.Empty,
ArtistUnicode = model.Metadata?.ArtistUnicode ?? string.Empty,
Author = new User { Username = model.Metadata?.Author },
}
}, minimiseDownloadSize);
}
public bool Download(BeatmapSetInfo model, bool minimiseDownloadSize = false)
{ {
return beatmapModelDownloader.Download(model, minimiseDownloadSize); return beatmapModelDownloader.Download(model, minimiseDownloadSize);
} }
public ArchiveDownloadRequest<BeatmapSetInfo> GetExistingDownload(BeatmapSetInfo model) public ArchiveDownloadRequest<IBeatmapSetInfo> GetExistingDownload(IBeatmapSetInfo model)
{ {
return beatmapModelDownloader.GetExistingDownload(model); return beatmapModelDownloader.GetExistingDownload(model);
} }

View File

@ -8,16 +8,16 @@ using osu.Game.Online.API.Requests;
namespace osu.Game.Beatmaps namespace osu.Game.Beatmaps
{ {
public class BeatmapModelDownloader : ModelDownloader<BeatmapSetInfo> public class BeatmapModelDownloader : ModelDownloader<BeatmapSetInfo, IBeatmapSetInfo>
{ {
protected override ArchiveDownloadRequest<BeatmapSetInfo> CreateDownloadRequest(BeatmapSetInfo set, bool minimiseDownloadSize) => protected override ArchiveDownloadRequest<IBeatmapSetInfo> CreateDownloadRequest(IBeatmapSetInfo set, bool minimiseDownloadSize) =>
new DownloadBeatmapSetRequest(set, minimiseDownloadSize); new DownloadBeatmapSetRequest(set, minimiseDownloadSize);
public override ArchiveDownloadRequest<BeatmapSetInfo> GetExistingDownload(BeatmapSetInfo model) public override ArchiveDownloadRequest<IBeatmapSetInfo> GetExistingDownload(IBeatmapSetInfo model)
=> CurrentDownloads.Find(r => r.Model.OnlineID == model.OnlineID); => CurrentDownloads.Find(r => r.Model.OnlineID == model.OnlineID);
public BeatmapModelDownloader(IBeatmapModelManager beatmapModelManager, IAPIProvider api, GameHost host = null) public BeatmapModelDownloader(IModelImporter<BeatmapSetInfo> beatmapImporter, IAPIProvider api, GameHost host = null)
: base(beatmapModelManager, api, host) : base(beatmapImporter, api, host)
{ {
} }
} }

View File

@ -6,10 +6,8 @@ using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using System.Linq; using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using Newtonsoft.Json;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Database; using osu.Game.Database;
using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Beatmaps namespace osu.Game.Beatmaps
{ {
@ -32,13 +30,11 @@ namespace osu.Game.Beatmaps
public List<BeatmapInfo> Beatmaps { get; set; } public List<BeatmapInfo> Beatmaps { get; set; }
public BeatmapSetOnlineStatus Status { get; set; } = BeatmapSetOnlineStatus.None;
[NotNull] [NotNull]
public List<BeatmapSetFileInfo> Files { get; set; } = new List<BeatmapSetFileInfo>(); public List<BeatmapSetFileInfo> Files { get; set; } = new List<BeatmapSetFileInfo>();
// 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; }
/// <summary> /// <summary>
/// The maximum star difficulty of all beatmaps in this set. /// The maximum star difficulty of all beatmaps in this set.
/// </summary> /// </summary>
@ -100,80 +96,5 @@ namespace osu.Game.Beatmaps
IEnumerable<INamedFileUsage> IBeatmapSetInfo.Files => Files; IEnumerable<INamedFileUsage> IBeatmapSetInfo.Files => Files;
#endregion #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
} }
} }

View File

@ -57,12 +57,7 @@ namespace osu.Game.Beatmaps.Drawables
return new OnlineBeatmapSetCover(online, beatmapSetCoverType); return new OnlineBeatmapSetCover(online, beatmapSetCoverType);
if (model is BeatmapInfo localModel) 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.GetWorkingBeatmap(localModel));
}
return new BeatmapBackgroundSprite(beatmaps.DefaultBeatmap); return new BeatmapBackgroundSprite(beatmaps.DefaultBeatmap);
} }

View File

@ -30,7 +30,7 @@ namespace osu.Game.Database
/// </summary> /// </summary>
/// <typeparam name="TModel">The model type.</typeparam> /// <typeparam name="TModel">The model type.</typeparam>
/// <typeparam name="TFileModel">The associated file join type.</typeparam> /// <typeparam name="TFileModel">The associated file join type.</typeparam>
public abstract class ArchiveModelManager<TModel, TFileModel> : IModelManager<TModel>, IModelFileManager<TModel, TFileModel> public abstract class ArchiveModelManager<TModel, TFileModel> : IModelImporter<TModel>, IModelManager<TModel>, IModelFileManager<TModel, TFileModel>
where TModel : class, IHasFiles<TFileModel>, IHasPrimaryKey, ISoftDelete where TModel : class, IHasFiles<TFileModel>, IHasPrimaryKey, ISoftDelete
where TFileModel : class, INamedFileInfo, IHasPrimaryKey, new() where TFileModel : class, INamedFileInfo, IHasPrimaryKey, new()
{ {

View File

@ -10,35 +10,35 @@ namespace osu.Game.Database
/// <summary> /// <summary>
/// Represents a <see cref="IModelManager{TModel}"/> that can download new models from an external source. /// Represents a <see cref="IModelManager{TModel}"/> that can download new models from an external source.
/// </summary> /// </summary>
/// <typeparam name="TModel">The model type.</typeparam> /// <typeparam name="T">The item's interface type.</typeparam>
public interface IModelDownloader<TModel> : IPostNotifications public interface IModelDownloader<T> : IPostNotifications
where TModel : class where T : class
{ {
/// <summary> /// <summary>
/// Fired when a <typeparamref name="TModel"/> download begins. /// Fired when a <typeparamref name="T"/> download begins.
/// This is NOT run on the update thread and should be scheduled. /// This is NOT run on the update thread and should be scheduled.
/// </summary> /// </summary>
IBindable<WeakReference<ArchiveDownloadRequest<TModel>>> DownloadBegan { get; } IBindable<WeakReference<ArchiveDownloadRequest<T>>> DownloadBegan { get; }
/// <summary> /// <summary>
/// Fired when a <typeparamref name="TModel"/> download is interrupted, either due to user cancellation or failure. /// Fired when a <typeparamref name="T"/> download is interrupted, either due to user cancellation or failure.
/// This is NOT run on the update thread and should be scheduled. /// This is NOT run on the update thread and should be scheduled.
/// </summary> /// </summary>
IBindable<WeakReference<ArchiveDownloadRequest<TModel>>> DownloadFailed { get; } IBindable<WeakReference<ArchiveDownloadRequest<T>>> DownloadFailed { get; }
/// <summary> /// <summary>
/// Begin a download for the requested <typeparamref name="TModel"/>. /// Begin a download for the requested <typeparamref name="T"/>.
/// </summary> /// </summary>
/// <param name="model">The <stypeparamref name="TModel"/> to be downloaded.</param> /// <param name="item">The <stypeparamref name="T"/> to be downloaded.</param>
/// <param name="minimiseDownloadSize">Whether this download should be optimised for slow connections. Generally means extras are not included in the download bundle..</param> /// <param name="minimiseDownloadSize">Whether this download should be optimised for slow connections. Generally means extras are not included in the download bundle..</param>
/// <returns>Whether the download was started.</returns> /// <returns>Whether the download was started.</returns>
bool Download(TModel model, bool minimiseDownloadSize); bool Download(T item, bool minimiseDownloadSize);
/// <summary> /// <summary>
/// Gets an existing <typeparamref name="TModel"/> download request if it exists. /// Gets an existing <typeparamref name="T"/> download request if it exists.
/// </summary> /// </summary>
/// <param name="model">The <typeparamref name="TModel"/> whose request is wanted.</param> /// <param name="item">The <typeparamref name="T"/> whose request is wanted.</param>
/// <returns>The <see cref="ArchiveDownloadRequest{TModel}"/> object if it exists, otherwise null.</returns> /// <returns>The <see cref="ArchiveDownloadRequest{T}"/> object if it exists, otherwise null.</returns>
ArchiveDownloadRequest<TModel> GetExistingDownload(TModel model); ArchiveDownloadRequest<T> GetExistingDownload(T item);
} }
} }

View File

@ -14,7 +14,7 @@ namespace osu.Game.Database
/// Represents a model manager that publishes events when <typeparamref name="TModel"/>s are added or removed. /// Represents a model manager that publishes events when <typeparamref name="TModel"/>s are added or removed.
/// </summary> /// </summary>
/// <typeparam name="TModel">The model type.</typeparam> /// <typeparam name="TModel">The model type.</typeparam>
public interface IModelManager<TModel> : IModelImporter<TModel> public interface IModelManager<TModel>
where TModel : class where TModel : class
{ {
/// <summary> /// <summary>

View File

@ -14,39 +14,40 @@ using osu.Game.Overlays.Notifications;
namespace osu.Game.Database namespace osu.Game.Database
{ {
public abstract class ModelDownloader<TModel> : IModelDownloader<TModel> public abstract class ModelDownloader<TModel, T> : IModelDownloader<T>
where TModel : class, IHasPrimaryKey, ISoftDelete, IEquatable<TModel> where TModel : class, IHasPrimaryKey, ISoftDelete, IEquatable<TModel>, T
where T : class
{ {
public Action<Notification> PostNotification { protected get; set; } public Action<Notification> PostNotification { protected get; set; }
public IBindable<WeakReference<ArchiveDownloadRequest<TModel>>> DownloadBegan => downloadBegan; public IBindable<WeakReference<ArchiveDownloadRequest<T>>> DownloadBegan => downloadBegan;
private readonly Bindable<WeakReference<ArchiveDownloadRequest<TModel>>> downloadBegan = new Bindable<WeakReference<ArchiveDownloadRequest<TModel>>>(); private readonly Bindable<WeakReference<ArchiveDownloadRequest<T>>> downloadBegan = new Bindable<WeakReference<ArchiveDownloadRequest<T>>>();
public IBindable<WeakReference<ArchiveDownloadRequest<TModel>>> DownloadFailed => downloadFailed; public IBindable<WeakReference<ArchiveDownloadRequest<T>>> DownloadFailed => downloadFailed;
private readonly Bindable<WeakReference<ArchiveDownloadRequest<TModel>>> downloadFailed = new Bindable<WeakReference<ArchiveDownloadRequest<TModel>>>(); private readonly Bindable<WeakReference<ArchiveDownloadRequest<T>>> downloadFailed = new Bindable<WeakReference<ArchiveDownloadRequest<T>>>();
private readonly IModelManager<TModel> modelManager; private readonly IModelImporter<TModel> importer;
private readonly IAPIProvider api; private readonly IAPIProvider api;
protected readonly List<ArchiveDownloadRequest<TModel>> CurrentDownloads = new List<ArchiveDownloadRequest<TModel>>(); protected readonly List<ArchiveDownloadRequest<T>> CurrentDownloads = new List<ArchiveDownloadRequest<T>>();
protected ModelDownloader(IModelManager<TModel> modelManager, IAPIProvider api, IIpcHost importHost = null) protected ModelDownloader(IModelImporter<TModel> importer, IAPIProvider api, IIpcHost importHost = null)
{ {
this.modelManager = modelManager; this.importer = importer;
this.api = api; this.api = api;
} }
/// <summary> /// <summary>
/// Creates the download request for this <typeparamref name="TModel"/>. /// Creates the download request for this <typeparamref name="T"/>.
/// </summary> /// </summary>
/// <param name="model">The <typeparamref name="TModel"/> to be downloaded.</param> /// <param name="model">The <typeparamref name="T"/> to be downloaded.</param>
/// <param name="minimiseDownloadSize">Whether this download should be optimised for slow connections. Generally means extras are not included in the download bundle.</param> /// <param name="minimiseDownloadSize">Whether this download should be optimised for slow connections. Generally means extras are not included in the download bundle.</param>
/// <returns>The request object.</returns> /// <returns>The request object.</returns>
protected abstract ArchiveDownloadRequest<TModel> CreateDownloadRequest(TModel model, bool minimiseDownloadSize); protected abstract ArchiveDownloadRequest<T> 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; if (!canDownload(model)) return false;
@ -68,11 +69,11 @@ namespace osu.Game.Database
Task.Factory.StartNew(async () => Task.Factory.StartNew(async () =>
{ {
// This gets scheduled back to the update thread, but we want the import to run in the background. // 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. // for now a failed import will be marked as a failed download for simplicity.
if (!imported.Any()) if (!imported.Any())
downloadFailed.Value = new WeakReference<ArchiveDownloadRequest<TModel>>(request); downloadFailed.Value = new WeakReference<ArchiveDownloadRequest<T>>(request);
CurrentDownloads.Remove(request); CurrentDownloads.Remove(request);
}, TaskCreationOptions.LongRunning); }, TaskCreationOptions.LongRunning);
@ -91,25 +92,25 @@ namespace osu.Game.Database
api.PerformAsync(request); api.PerformAsync(request);
downloadBegan.Value = new WeakReference<ArchiveDownloadRequest<TModel>>(request); downloadBegan.Value = new WeakReference<ArchiveDownloadRequest<T>>(request);
return true; return true;
void triggerFailure(Exception error) void triggerFailure(Exception error)
{ {
CurrentDownloads.Remove(request); CurrentDownloads.Remove(request);
downloadFailed.Value = new WeakReference<ArchiveDownloadRequest<TModel>>(request); downloadFailed.Value = new WeakReference<ArchiveDownloadRequest<T>>(request);
notification.State = ProgressNotificationState.Cancelled; notification.State = ProgressNotificationState.Cancelled;
if (!(error is OperationCanceledException)) if (!(error is OperationCanceledException))
Logger.Error(error, $"{modelManager.HumanisedModelName.Titleize()} download failed!"); Logger.Error(error, $"{importer.HumanisedModelName.Titleize()} download failed!");
} }
} }
public abstract ArchiveDownloadRequest<TModel> GetExistingDownload(TModel model); public abstract ArchiveDownloadRequest<T> 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 private class DownloadNotification : ProgressNotification
{ {

View File

@ -58,10 +58,9 @@ namespace osu.Game.Graphics.Backgrounds
{ {
RemoveInternal(Sprite); RemoveInternal(Sprite);
AddInternal(bufferedContainer = new BufferedContainer AddInternal(bufferedContainer = new BufferedContainer(cachedFrameBuffer: true)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
CacheDrawnFrameBuffer = true,
RedrawOnScale = false, RedrawOnScale = false,
Child = Sprite Child = Sprite
}); });

View File

@ -69,12 +69,11 @@ namespace osu.Game.Graphics.Sprites
Children = new Drawable[] Children = new Drawable[]
{ {
new BufferedContainer new BufferedContainer(cachedFrameBuffer: true)
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
BlurSigma = new Vector2(4), BlurSigma = new Vector2(4),
CacheDrawnFrameBuffer = true,
RedrawOnScale = false, RedrawOnScale = false,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Blending = BlendingParameters.Additive, Blending = BlendingParameters.Additive,

View File

@ -6,11 +6,11 @@ using osu.Game.Beatmaps;
namespace osu.Game.Online.API.Requests namespace osu.Game.Online.API.Requests
{ {
public class DownloadBeatmapSetRequest : ArchiveDownloadRequest<BeatmapSetInfo> public class DownloadBeatmapSetRequest : ArchiveDownloadRequest<IBeatmapSetInfo>
{ {
private readonly bool noVideo; private readonly bool noVideo;
public DownloadBeatmapSetRequest(BeatmapSetInfo set, bool noVideo) public DownloadBeatmapSetRequest(IBeatmapSetInfo set, bool noVideo)
: base(set) : base(set)
{ {
this.noVideo = noVideo; this.noVideo = noVideo;
@ -25,6 +25,6 @@ namespace osu.Game.Online.API.Requests
protected override string FileExtension => ".osz"; 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" : "")}";
} }
} }

View File

@ -5,15 +5,15 @@ using osu.Game.Scoring;
namespace osu.Game.Online.API.Requests namespace osu.Game.Online.API.Requests
{ {
public class DownloadReplayRequest : ArchiveDownloadRequest<ScoreInfo> public class DownloadReplayRequest : ArchiveDownloadRequest<IScoreInfo>
{ {
public DownloadReplayRequest(ScoreInfo score) public DownloadReplayRequest(IScoreInfo score)
: base(score) : base(score)
{ {
} }
protected override string FileExtension => ".osr"; 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";
} }
} }

View File

@ -81,34 +81,6 @@ namespace osu.Game.Online.API.Requests.Responses
public double BPM { get; set; } 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 #region Implementation of IBeatmapInfo
public IBeatmapMetadataInfo Metadata => (BeatmapSet as IBeatmapSetInfo)?.Metadata ?? new BeatmapMetadata(); public IBeatmapMetadataInfo Metadata => (BeatmapSet as IBeatmapSetInfo)?.Metadata ?? new BeatmapMetadata();

View File

@ -3,11 +3,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json; using Newtonsoft.Json;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Database; using osu.Game.Database;
using osu.Game.Rulesets;
using osu.Game.Users; using osu.Game.Users;
#nullable enable #nullable enable
@ -121,27 +119,6 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"beatmaps")] [JsonProperty(@"beatmaps")]
public APIBeatmap[] Beatmaps { get; set; } = Array.Empty<APIBeatmap>(); public APIBeatmap[] Beatmaps { get; set; } = Array.Empty<APIBeatmap>();
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;
}
private BeatmapMetadata metadata => new BeatmapMetadata private BeatmapMetadata metadata => new BeatmapMetadata
{ {
Title = Title, Title = Title,

View File

@ -98,7 +98,7 @@ namespace osu.Game.Online.API.Requests.Responses
{ {
TotalScore = TotalScore, TotalScore = TotalScore,
MaxCombo = MaxCombo, MaxCombo = MaxCombo,
BeatmapInfo = Beatmap?.ToBeatmapInfo(rulesets), BeatmapInfo = beatmap,
User = User, User = User,
Accuracy = Accuracy, Accuracy = Accuracy,
OnlineScoreID = OnlineID, OnlineScoreID = OnlineID,
@ -111,9 +111,6 @@ namespace osu.Game.Online.API.Requests.Responses
Mods = modInstances, Mods = modInstances,
}; };
if (beatmap != null)
scoreInfo.BeatmapInfo = beatmap;
if (Statistics != null) if (Statistics != null)
{ {
foreach (var kvp in Statistics) foreach (var kvp in Statistics)

View File

@ -16,7 +16,7 @@ namespace osu.Game.Online
[Resolved(CanBeNull = true)] [Resolved(CanBeNull = true)]
protected BeatmapManager? Manager { get; private set; } protected BeatmapManager? Manager { get; private set; }
private ArchiveDownloadRequest<BeatmapSetInfo>? attachedRequest; private ArchiveDownloadRequest<IBeatmapSetInfo>? attachedRequest;
public BeatmapDownloadTracker(IBeatmapSetInfo trackedItem) public BeatmapDownloadTracker(IBeatmapSetInfo trackedItem)
: base(trackedItem) : base(trackedItem)
@ -25,8 +25,8 @@ namespace osu.Game.Online
private IBindable<WeakReference<BeatmapSetInfo>>? managerUpdated; private IBindable<WeakReference<BeatmapSetInfo>>? managerUpdated;
private IBindable<WeakReference<BeatmapSetInfo>>? managerRemoved; private IBindable<WeakReference<BeatmapSetInfo>>? managerRemoved;
private IBindable<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>>? managerDownloadBegan; private IBindable<WeakReference<ArchiveDownloadRequest<IBeatmapSetInfo>>>? managerDownloadBegan;
private IBindable<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>>? managerDownloadFailed; private IBindable<WeakReference<ArchiveDownloadRequest<IBeatmapSetInfo>>>? managerDownloadFailed;
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load() private void load()
@ -52,7 +52,7 @@ namespace osu.Game.Online
managerRemoved.BindValueChanged(itemRemoved); managerRemoved.BindValueChanged(itemRemoved);
} }
private void downloadBegan(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>> weakRequest) private void downloadBegan(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<IBeatmapSetInfo>>> weakRequest)
{ {
if (weakRequest.NewValue.TryGetTarget(out var request)) if (weakRequest.NewValue.TryGetTarget(out var request))
{ {
@ -64,7 +64,7 @@ namespace osu.Game.Online
} }
} }
private void downloadFailed(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>> weakRequest) private void downloadFailed(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<IBeatmapSetInfo>>> weakRequest)
{ {
if (weakRequest.NewValue.TryGetTarget(out var request)) if (weakRequest.NewValue.TryGetTarget(out var request))
{ {
@ -76,7 +76,7 @@ namespace osu.Game.Online
} }
} }
private void attachDownload(ArchiveDownloadRequest<BeatmapSetInfo>? request) private void attachDownload(ArchiveDownloadRequest<IBeatmapSetInfo>? request)
{ {
if (attachedRequest != null) if (attachedRequest != null)
{ {

View File

@ -16,7 +16,7 @@ namespace osu.Game.Online
[Resolved(CanBeNull = true)] [Resolved(CanBeNull = true)]
protected ScoreManager? Manager { get; private set; } protected ScoreManager? Manager { get; private set; }
private ArchiveDownloadRequest<ScoreInfo>? attachedRequest; private ArchiveDownloadRequest<IScoreInfo>? attachedRequest;
public ScoreDownloadTracker(ScoreInfo trackedItem) public ScoreDownloadTracker(ScoreInfo trackedItem)
: base(trackedItem) : base(trackedItem)
@ -25,8 +25,8 @@ namespace osu.Game.Online
private IBindable<WeakReference<ScoreInfo>>? managerUpdated; private IBindable<WeakReference<ScoreInfo>>? managerUpdated;
private IBindable<WeakReference<ScoreInfo>>? managerRemoved; private IBindable<WeakReference<ScoreInfo>>? managerRemoved;
private IBindable<WeakReference<ArchiveDownloadRequest<ScoreInfo>>>? managerDownloadBegan; private IBindable<WeakReference<ArchiveDownloadRequest<IScoreInfo>>>? managerDownloadBegan;
private IBindable<WeakReference<ArchiveDownloadRequest<ScoreInfo>>>? managerDownloadFailed; private IBindable<WeakReference<ArchiveDownloadRequest<IScoreInfo>>>? managerDownloadFailed;
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load() private void load()
@ -56,7 +56,7 @@ namespace osu.Game.Online
managerRemoved.BindValueChanged(itemRemoved); managerRemoved.BindValueChanged(itemRemoved);
} }
private void downloadBegan(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<ScoreInfo>>> weakRequest) private void downloadBegan(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<IScoreInfo>>> weakRequest)
{ {
if (weakRequest.NewValue.TryGetTarget(out var request)) if (weakRequest.NewValue.TryGetTarget(out var request))
{ {
@ -68,7 +68,7 @@ namespace osu.Game.Online
} }
} }
private void downloadFailed(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<ScoreInfo>>> weakRequest) private void downloadFailed(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<IScoreInfo>>> weakRequest)
{ {
if (weakRequest.NewValue.TryGetTarget(out var request)) if (weakRequest.NewValue.TryGetTarget(out var request))
{ {
@ -80,7 +80,7 @@ namespace osu.Game.Online
} }
} }
private void attachDownload(ArchiveDownloadRequest<ScoreInfo>? request) private void attachDownload(ArchiveDownloadRequest<IScoreInfo>? request)
{ {
if (attachedRequest != null) 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 #region Disposal

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -66,7 +67,18 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
if (value?.Scores.Any() != true) if (value?.Scores.Any() != true)
return; 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(() => .ContinueWith(ordered => Schedule(() =>
{ {
if (loadCancellationSource.IsCancellationRequested) if (loadCancellationSource.IsCancellationRequested)
@ -74,11 +86,11 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
var topScore = ordered.Result.First(); var topScore = ordered.Result.First();
scoreTable.DisplayScores(ordered.Result, topScore.BeatmapInfo?.Status.GrantsPerformancePoints() == true); scoreTable.DisplayScores(ordered.Result, apiBeatmap.Status.GrantsPerformancePoints());
scoreTable.Show(); scoreTable.Show();
var userScore = value.UserScore; 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)); topScoresContainer.Add(new DrawableTopScore(topScore));

View File

@ -366,14 +366,13 @@ namespace osu.Game.Overlays
private readonly WorkingBeatmap beatmap; private readonly WorkingBeatmap beatmap;
public Background(WorkingBeatmap beatmap = null) public Background(WorkingBeatmap beatmap = null)
: base(cachedFrameBuffer: true)
{ {
this.beatmap = beatmap; this.beatmap = beatmap;
Depth = float.MaxValue; Depth = float.MaxValue;
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
CacheDrawnFrameBuffer = true;
Children = new Drawable[] Children = new Drawable[]
{ {
sprite = new Sprite sprite = new Sprite

View File

@ -25,7 +25,7 @@ using osu.Game.Rulesets.Scoring;
namespace osu.Game.Scoring namespace osu.Game.Scoring
{ {
public class ScoreManager : IModelManager<ScoreInfo>, IModelFileManager<ScoreInfo, ScoreFileInfo>, IModelDownloader<ScoreInfo> public class ScoreManager : IModelManager<ScoreInfo>, IModelImporter<ScoreInfo>, IModelFileManager<ScoreInfo, ScoreFileInfo>, IModelDownloader<IScoreInfo>
{ {
private readonly Scheduler scheduler; private readonly Scheduler scheduler;
private readonly Func<BeatmapDifficultyCache> difficulties; private readonly Func<BeatmapDifficultyCache> difficulties;
@ -350,16 +350,14 @@ namespace osu.Game.Scoring
#region Implementation of IModelDownloader<ScoreInfo> #region Implementation of IModelDownloader<ScoreInfo>
public IBindable<WeakReference<ArchiveDownloadRequest<ScoreInfo>>> DownloadBegan => scoreModelDownloader.DownloadBegan; public IBindable<WeakReference<ArchiveDownloadRequest<IScoreInfo>>> DownloadBegan => scoreModelDownloader.DownloadBegan;
public IBindable<WeakReference<ArchiveDownloadRequest<ScoreInfo>>> DownloadFailed => scoreModelDownloader.DownloadFailed; public IBindable<WeakReference<ArchiveDownloadRequest<IScoreInfo>>> DownloadFailed => scoreModelDownloader.DownloadFailed;
public bool Download(ScoreInfo model, bool minimiseDownloadSize) public bool Download(IScoreInfo model, bool minimiseDownloadSize) =>
{ scoreModelDownloader.Download(model, minimiseDownloadSize);
return scoreModelDownloader.Download(model, minimiseDownloadSize);
}
public ArchiveDownloadRequest<ScoreInfo> GetExistingDownload(ScoreInfo model) public ArchiveDownloadRequest<IScoreInfo> GetExistingDownload(IScoreInfo model)
{ {
return scoreModelDownloader.GetExistingDownload(model); return scoreModelDownloader.GetExistingDownload(model);
} }

View File

@ -8,16 +8,16 @@ using osu.Game.Online.API.Requests;
namespace osu.Game.Scoring namespace osu.Game.Scoring
{ {
public class ScoreModelDownloader : ModelDownloader<ScoreInfo> public class ScoreModelDownloader : ModelDownloader<ScoreInfo, IScoreInfo>
{ {
public ScoreModelDownloader(ScoreModelManager scoreManager, IAPIProvider api, IIpcHost importHost = null) public ScoreModelDownloader(IModelImporter<ScoreInfo> scoreManager, IAPIProvider api, IIpcHost importHost = null)
: base(scoreManager, api, importHost) : base(scoreManager, api, importHost)
{ {
} }
protected override ArchiveDownloadRequest<ScoreInfo> CreateDownloadRequest(ScoreInfo score, bool minimiseDownload) => new DownloadReplayRequest(score); protected override ArchiveDownloadRequest<IScoreInfo> CreateDownloadRequest(IScoreInfo score, bool minimiseDownload) => new DownloadReplayRequest(score);
public override ArchiveDownloadRequest<ScoreInfo> GetExistingDownload(ScoreInfo model) public override ArchiveDownloadRequest<IScoreInfo> GetExistingDownload(IScoreInfo model)
=> CurrentDownloads.Find(r => r.Model.OnlineScoreID == model.OnlineScoreID); => CurrentDownloads.Find(r => r.Model.OnlineID == model.OnlineID);
} }
} }

View File

@ -393,6 +393,7 @@ namespace osu.Game.Screens.Menu
public class OutlineTriangle : BufferedContainer public class OutlineTriangle : BufferedContainer
{ {
public OutlineTriangle(bool outlineOnly, float size) public OutlineTriangle(bool outlineOnly, float size)
: base(cachedFrameBuffer: true)
{ {
Size = new Vector2(size); Size = new Vector2(size);
@ -414,7 +415,6 @@ namespace osu.Game.Screens.Menu
} }
Blending = BlendingParameters.Additive; Blending = BlendingParameters.Additive;
CacheDrawnFrameBuffer = true;
} }
} }
} }

View File

@ -32,9 +32,9 @@ namespace osu.Game.Screens.Play.Break
} }
public BlurredIcon() public BlurredIcon()
: base(cachedFrameBuffer: true)
{ {
RelativePositionAxes = Axes.X; RelativePositionAxes = Axes.X;
CacheDrawnFrameBuffer = true;
Child = icon = new SpriteIcon Child = icon = new SpriteIcon
{ {
Origin = Anchor.Centre, Origin = Anchor.Centre,

View File

@ -98,9 +98,8 @@ namespace osu.Game.Screens.Play
/// </summary> /// </summary>
protected virtual void RecreateGraph() protected virtual void RecreateGraph()
{ {
var newColumns = new BufferedContainer<Column> var newColumns = new BufferedContainer<Column>(cachedFrameBuffer: true)
{ {
CacheDrawnFrameBuffer = true,
RedrawOnScale = false, RedrawOnScale = false,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
}; };

View File

@ -51,13 +51,12 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy
Font = OsuFont.Numeric.With(size: 76), Font = OsuFont.Numeric.With(size: 76),
UseFullGlyphHeight = false UseFullGlyphHeight = false
}, },
superFlash = new BufferedContainer superFlash = new BufferedContainer(cachedFrameBuffer: true)
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
BlurSigma = new Vector2(85), BlurSigma = new Vector2(85),
Size = new Vector2(600), Size = new Vector2(600),
CacheDrawnFrameBuffer = true,
Blending = BlendingParameters.Additive, Blending = BlendingParameters.Additive,
Alpha = 0, Alpha = 0,
Children = new[] Children = new[]
@ -71,14 +70,13 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy
}, },
}, },
}, },
flash = new BufferedContainer flash = new BufferedContainer(cachedFrameBuffer: true)
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
BlurSigma = new Vector2(35), BlurSigma = new Vector2(35),
BypassAutoSizeAxes = Axes.Both, BypassAutoSizeAxes = Axes.Both,
Size = new Vector2(200), Size = new Vector2(200),
CacheDrawnFrameBuffer = true,
Blending = BlendingParameters.Additive, Blending = BlendingParameters.Additive,
Alpha = 0, Alpha = 0,
Scale = new Vector2(1.8f), Scale = new Vector2(1.8f),

View File

@ -41,13 +41,13 @@ namespace osu.Game.Screens.Select
[Resolved] [Resolved]
private RulesetStore rulesets { get; set; } private RulesetStore rulesets { get; set; }
private BeatmapInfo beatmapInfo; private IBeatmapInfo beatmapInfo;
private APIFailTimes failTimes; private APIFailTimes failTimes;
private int[] ratings; private int[] ratings;
public BeatmapInfo BeatmapInfo public IBeatmapInfo BeatmapInfo
{ {
get => beatmapInfo; get => beatmapInfo;
set set
@ -56,8 +56,11 @@ namespace osu.Game.Screens.Select
beatmapInfo = value; beatmapInfo = value;
failTimes = beatmapInfo?.OnlineInfo?.FailTimes; var onlineInfo = beatmapInfo as IBeatmapOnlineInfo;
ratings = beatmapInfo?.BeatmapSet?.OnlineInfo?.Ratings; var onlineSetInfo = beatmapInfo.BeatmapSet as IBeatmapSetOnlineInfo;
failTimes = onlineInfo?.FailTimes;
ratings = onlineSetInfo?.Ratings;
Scheduler.AddOnce(updateStatistics); Scheduler.AddOnce(updateStatistics);
} }
@ -178,9 +181,9 @@ namespace osu.Game.Screens.Select
private void updateStatistics() private void updateStatistics()
{ {
advanced.BeatmapInfo = BeatmapInfo; advanced.BeatmapInfo = BeatmapInfo;
description.Text = BeatmapInfo?.Version; description.Text = BeatmapInfo?.DifficultyName;
source.Text = BeatmapInfo?.Metadata?.Source; source.Text = BeatmapInfo?.Metadata.Source;
tags.Text = BeatmapInfo?.Metadata?.Tags; tags.Text = BeatmapInfo?.Metadata.Tags;
// failTimes may have been previously fetched // failTimes may have been previously fetched
if (ratings != null && failTimes != null) 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). // 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(); updateMetrics();
return; return;

View File

@ -27,9 +27,8 @@ namespace osu.Game.Screens.Select
{ {
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
InternalChild = new BufferedContainer InternalChild = new BufferedContainer(cachedFrameBuffer: true)
{ {
CacheDrawnFrameBuffer = true,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Children = new Drawable[] Children = new Drawable[]
{ {

View File

@ -15,8 +15,8 @@ namespace osu.Game.Screens.Select.Carousel
public class SetPanelBackground : BufferedContainer public class SetPanelBackground : BufferedContainer
{ {
public SetPanelBackground(WorkingBeatmap working) public SetPanelBackground(WorkingBeatmap working)
: base(cachedFrameBuffer: true)
{ {
CacheDrawnFrameBuffer = true;
RedrawOnScale = false; RedrawOnScale = false;
Children = new Drawable[] Children = new Drawable[]

View File

@ -70,14 +70,16 @@ namespace osu.Game.Skinning.Editor
if (anchor.HasFlagFast(Anchor.x1)) scale.X = 0; if (anchor.HasFlagFast(Anchor.x1)) scale.X = 0;
if (anchor.HasFlagFast(Anchor.y1)) scale.Y = 0; if (anchor.HasFlagFast(Anchor.y1)) scale.Y = 0;
bool shouldAspectLock = // for now aspect lock scale adjustments that occur at corners..
// for now aspect lock scale adjustments that occur at corners.. if (!anchor.HasFlagFast(Anchor.x1) && !anchor.HasFlagFast(Anchor.y1))
(!anchor.HasFlagFast(Anchor.x1) && !anchor.HasFlagFast(Anchor.y1)) {
// ..or if any of the selection have been rotated. // project scale vector along diagonal
// this is to avoid requiring skew logic (which would likely not be the user's expected transform anyway). Vector2 diag = (selectionRect.TopLeft - selectionRect.BottomRight).Normalized();
|| SelectedBlueprints.Any(b => !Precision.AlmostEquals(((Drawable)b.Item).Rotation, 0)); scale = Vector2.Dot(scale, diag) * diag;
}
if (shouldAspectLock) // ..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 (anchor.HasFlagFast(Anchor.x1))
// if dragging from the horizontal centre, only a vertical component is available. // if dragging from the horizontal centre, only a vertical component is available.

View File

@ -39,16 +39,6 @@ namespace osu.Game.Tests.Beatmaps
BeatmapInfo.Length = 75000; BeatmapInfo.Length = 75000;
BeatmapInfo.OnlineInfo = new APIBeatmap(); BeatmapInfo.OnlineInfo = new APIBeatmap();
BeatmapInfo.OnlineBeatmapID = Interlocked.Increment(ref onlineBeatmapID); 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(); protected virtual Beatmap CreateBeatmap() => createTestBeatmap();

View File

@ -175,27 +175,42 @@ namespace osu.Game.Tests.Visual
protected virtual IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset); protected virtual IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset);
protected APIBeatmapSet CreateAPIBeatmapSet(RulesetInfo ruleset) /// <summary>
/// Returns a sample API Beatmap with BeatmapSet populated.
/// </summary>
/// <param name="ruleset">The ruleset to create the sample model using. osu! ruleset will be used if not specified.</param>
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<APIBeatmap>();
// Populate the set as that's generally what we expect from the API.
beatmap.BeatmapSet = beatmapSet;
return beatmap;
}
/// <summary>
/// Returns a sample API BeatmapSet with beatmaps populated.
/// </summary>
/// <param name="ruleset">The ruleset to create the sample model using. osu! ruleset will be used if not specified.</param>
protected APIBeatmapSet CreateAPIBeatmapSet(RulesetInfo ruleset = null)
{
var beatmap = CreateBeatmap(ruleset ?? Ruleset.Value).BeatmapInfo;
return new APIBeatmapSet return new APIBeatmapSet
{ {
Covers = beatmap.BeatmapSet.Covers,
OnlineID = beatmap.BeatmapSet.OnlineID, OnlineID = beatmap.BeatmapSet.OnlineID,
Status = beatmap.BeatmapSet.Status, Status = BeatmapSetOnlineStatus.Ranked,
Preview = beatmap.BeatmapSet.Preview, Covers = new BeatmapSetOnlineCovers
HasFavourited = beatmap.BeatmapSet.HasFavourited, {
PlayCount = beatmap.BeatmapSet.PlayCount, Cover = "https://assets.ppy.sh/beatmaps/163112/covers/cover.jpg",
FavouriteCount = beatmap.BeatmapSet.FavouriteCount, Card = "https://assets.ppy.sh/beatmaps/163112/covers/card.jpg",
BPM = beatmap.BeatmapSet.BPM, List = "https://assets.ppy.sh/beatmaps/163112/covers/list.jpg"
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,
Title = beatmap.BeatmapSet.Metadata.Title, Title = beatmap.BeatmapSet.Metadata.Title,
TitleUnicode = beatmap.BeatmapSet.Metadata.TitleUnicode, TitleUnicode = beatmap.BeatmapSet.Metadata.TitleUnicode,
Artist = beatmap.BeatmapSet.Metadata.Artist, Artist = beatmap.BeatmapSet.Metadata.Artist,
@ -203,9 +218,6 @@ namespace osu.Game.Tests.Visual
Author = beatmap.BeatmapSet.Metadata.Author, Author = beatmap.BeatmapSet.Metadata.Author,
AuthorID = beatmap.BeatmapSet.Metadata.AuthorID, AuthorID = beatmap.BeatmapSet.Metadata.AuthorID,
AuthorString = beatmap.BeatmapSet.Metadata.AuthorString, AuthorString = beatmap.BeatmapSet.Metadata.AuthorString,
Availability = beatmap.BeatmapSet.Availability,
Genre = beatmap.BeatmapSet.Genre,
Language = beatmap.BeatmapSet.Language,
Source = beatmap.BeatmapSet.Metadata.Source, Source = beatmap.BeatmapSet.Metadata.Source,
Tags = beatmap.BeatmapSet.Metadata.Tags, Tags = beatmap.BeatmapSet.Metadata.Tags,
Beatmaps = new[] Beatmaps = new[]

View File

@ -36,7 +36,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Realm" Version="10.6.0" /> <PackageReference Include="Realm" Version="10.6.0" />
<PackageReference Include="ppy.osu.Framework" Version="2021.1104.0" /> <PackageReference Include="ppy.osu.Framework" Version="2021.1106.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.1026.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2021.1026.0" />
<PackageReference Include="Sentry" Version="3.10.0" /> <PackageReference Include="Sentry" Version="3.10.0" />
<PackageReference Include="SharpCompress" Version="0.30.0" /> <PackageReference Include="SharpCompress" Version="0.30.0" />

View File

@ -70,7 +70,7 @@
<Reference Include="System.Net.Http" /> <Reference Include="System.Net.Http" />
</ItemGroup> </ItemGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.1104.0" /> <PackageReference Include="ppy.osu.Framework.iOS" Version="2021.1106.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.1026.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2021.1026.0" />
</ItemGroup> </ItemGroup>
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) --> <!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
@ -93,7 +93,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="ppy.osu.Framework" Version="2021.1104.0" /> <PackageReference Include="ppy.osu.Framework" Version="2021.1106.0" />
<PackageReference Include="SharpCompress" Version="0.30.0" /> <PackageReference Include="SharpCompress" Version="0.30.0" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="SharpRaven" Version="2.4.0" /> <PackageReference Include="SharpRaven" Version="2.4.0" />