diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs index b62fb8bd87..c75714032e 100644 --- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs +++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs @@ -29,6 +29,15 @@ namespace osu.Game.Tests.Skins.IO assertCorrectMetadata(import1, "test skin [skin]", "skinner", osu); }); + [Test] + public Task TestSingleImportWeirdIniFileCase() => runSkinTest(async osu => + { + var import1 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni("test skin", "skinner", iniFilename: "Skin.InI"), "skin.osk")); + + // When the import filename doesn't match, it should be appended (and update the skin.ini). + assertCorrectMetadata(import1, "test skin [skin]", "skinner", osu); + }); + [Test] public Task TestSingleImportMatchingFilename() => runSkinTest(async osu => { @@ -190,11 +199,11 @@ namespace osu.Game.Tests.Skins.IO return zipStream; } - private MemoryStream createOskWithIni(string name, string author, bool makeUnique = false) + private MemoryStream createOskWithIni(string name, string author, bool makeUnique = false, string iniFilename = @"skin.ini") { var zipStream = new MemoryStream(); using var zip = ZipArchive.Create(); - zip.AddEntry("skin.ini", generateSkinIni(name, author, makeUnique)); + zip.AddEntry(iniFilename, generateSkinIni(name, author, makeUnique)); zip.SaveTo(zipStream); return zipStream; } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs index b84ac6c2f1..311c3ddc03 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs @@ -13,6 +13,7 @@ using osu.Framework.Bindables; using osu.Framework.Testing; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; using osu.Game.Screens.Ranking; using osuTK.Input; @@ -136,7 +137,8 @@ namespace osu.Game.Tests.Visual.Gameplay { OnlineID = 2553163309, OnlineRulesetID = 0, - Replay = replayAvailable, + Beatmap = CreateAPIBeatmapSet(new OsuRuleset().RulesetInfo).Beatmaps.First(), + HasReplay = replayAvailable, User = new User { Id = 39828, diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDashboardBeatmapListing.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDashboardBeatmapListing.cs index 6727c7560b..06c64a566e 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDashboardBeatmapListing.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDashboardBeatmapListing.cs @@ -56,95 +56,71 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("Set width to 300", () => content.ResizeWidthTo(300, 500)); } - private static readonly List new_beatmaps = new List + private static readonly List new_beatmaps = new List { - new BeatmapSetInfo + new APIBeatmapSet { - Metadata = new BeatmapMetadata + Title = "Very Long Title (TV size) [TATOE]", + Artist = "This artist has a really long name how is this possible", + Author = new User { - Title = "Very Long Title (TV size) [TATOE]", - Artist = "This artist has a really long name how is this possible", - Author = new User - { - Username = "author", - Id = 100 - } + Username = "author", + Id = 100 }, - OnlineInfo = new APIBeatmapSet + Covers = new BeatmapSetOnlineCovers { - Covers = new BeatmapSetOnlineCovers - { - Cover = "https://assets.ppy.sh/beatmaps/1189904/covers/cover.jpg?1595456608", - }, - Ranked = DateTimeOffset.Now - } + Cover = "https://assets.ppy.sh/beatmaps/1189904/covers/cover.jpg?1595456608", + }, + Ranked = DateTimeOffset.Now }, - new BeatmapSetInfo + new APIBeatmapSet { - Metadata = new BeatmapMetadata + Title = "Very Long Title (TV size) [TATOE]", + Artist = "This artist has a really long name how is this possible", + Author = new User { - Title = "Very Long Title (TV size) [TATOE]", - Artist = "This artist has a really long name how is this possible", - Author = new User - { - Username = "author", - Id = 100 - } + Username = "author", + Id = 100 }, - OnlineInfo = new APIBeatmapSet + Covers = new BeatmapSetOnlineCovers { - Covers = new BeatmapSetOnlineCovers - { - Cover = "https://assets.ppy.sh/beatmaps/1189904/covers/cover.jpg?1595456608", - }, - Ranked = DateTimeOffset.MinValue - } + Cover = "https://assets.ppy.sh/beatmaps/1189904/covers/cover.jpg?1595456608", + }, + Ranked = DateTimeOffset.Now } }; - private static readonly List popular_beatmaps = new List + private static readonly List popular_beatmaps = new List { - new BeatmapSetInfo + new APIBeatmapSet { - Metadata = new BeatmapMetadata + Title = "Very Long Title (TV size) [TATOE]", + Artist = "This artist has a really long name how is this possible", + Author = new User { - Title = "Title", - Artist = "Artist", - Author = new User - { - Username = "author", - Id = 100 - } + Username = "author", + Id = 100 }, - OnlineInfo = new APIBeatmapSet + Covers = new BeatmapSetOnlineCovers { - Covers = new BeatmapSetOnlineCovers - { - Cover = "https://assets.ppy.sh/beatmaps/1079428/covers/cover.jpg?1595295586", - }, - FavouriteCount = 100 - } + Cover = "https://assets.ppy.sh/beatmaps/1189904/covers/cover.jpg?1595456608", + }, + Ranked = DateTimeOffset.Now }, - new BeatmapSetInfo + new APIBeatmapSet { - Metadata = new BeatmapMetadata + Title = "Very Long Title (TV size) [TATOE]", + Artist = "This artist has a really long name how is this possible", + Author = new User { - Title = "Title 2", - Artist = "Artist 2", - Author = new User - { - Username = "someone", - Id = 100 - } + Username = "author", + Id = 100 }, - OnlineInfo = new APIBeatmapSet + Covers = new BeatmapSetOnlineCovers { - Covers = new BeatmapSetOnlineCovers - { - Cover = "https://assets.ppy.sh/beatmaps/1079428/covers/cover.jpg?1595295586", - }, - FavouriteCount = 10 - } + Cover = "https://assets.ppy.sh/beatmaps/1189904/covers/cover.jpg?1595456608", + }, + Ranked = DateTimeOffset.Now } }; } diff --git a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs index ed107c3a83..f3550f7465 100644 --- a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs +++ b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs @@ -76,7 +76,7 @@ namespace osu.Game.Tournament.Components { new TournamentSpriteText { - Text = Beatmap.GetDisplayTitleRomanisable(false), + Text = Beatmap.GetDisplayTitleRomanisable(false, false), Font = OsuFont.Torus.With(weight: FontWeight.Bold), }, new FillFlowContainer diff --git a/osu.Game/Beatmaps/BeatmapInfoExtensions.cs b/osu.Game/Beatmaps/BeatmapInfoExtensions.cs index c35370d572..2d69015933 100644 --- a/osu.Game/Beatmaps/BeatmapInfoExtensions.cs +++ b/osu.Game/Beatmaps/BeatmapInfoExtensions.cs @@ -16,9 +16,9 @@ namespace osu.Game.Beatmaps /// /// 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) + public static RomanisableString GetDisplayTitleRomanisable(this IBeatmapInfo beatmapInfo, bool includeDifficultyName = true, bool includeCreator = true) { - var metadata = getClosestMetadata(beatmapInfo).GetDisplayTitleRomanisable(); + var metadata = getClosestMetadata(beatmapInfo).GetDisplayTitleRomanisable(includeCreator); if (includeDifficultyName) { diff --git a/osu.Game/Beatmaps/BeatmapMetadataInfoExtensions.cs b/osu.Game/Beatmaps/BeatmapMetadataInfoExtensions.cs index 732b76e967..fcaad17059 100644 --- a/osu.Game/Beatmaps/BeatmapMetadataInfoExtensions.cs +++ b/osu.Game/Beatmaps/BeatmapMetadataInfoExtensions.cs @@ -34,9 +34,9 @@ namespace osu.Game.Beatmaps /// /// A user-presentable display title representing this beatmap, with localisation handling for potentially romanisable fields. /// - public static RomanisableString GetDisplayTitleRomanisable(this IBeatmapMetadataInfo metadataInfo) + public static RomanisableString GetDisplayTitleRomanisable(this IBeatmapMetadataInfo metadataInfo, bool includeCreator = true) { - string author = string.IsNullOrEmpty(metadataInfo.Author) ? string.Empty : $"({metadataInfo.Author})"; + string author = !includeCreator || string.IsNullOrEmpty(metadataInfo.Author) ? string.Empty : $"({metadataInfo.Author})"; string artistUnicode = string.IsNullOrEmpty(metadataInfo.ArtistUnicode) ? metadataInfo.Artist : metadataInfo.ArtistUnicode; string titleUnicode = string.IsNullOrEmpty(metadataInfo.TitleUnicode) ? metadataInfo.Title : metadataInfo.TitleUnicode; diff --git a/osu.Game/Database/IHasOnlineID.cs b/osu.Game/Database/IHasOnlineID.cs index 36ae4035c4..4e83ed8876 100644 --- a/osu.Game/Database/IHasOnlineID.cs +++ b/osu.Game/Database/IHasOnlineID.cs @@ -8,7 +8,7 @@ namespace osu.Game.Database public interface IHasOnlineID { /// - /// The server-side ID representing this instance, if one exists. Any value 0 or less denotes a missing ID. + /// The server-side ID representing this instance, if one exists. Any value 0 or less denotes a missing ID (except in special cases where autoincrement is not used, like rulesets). /// /// /// Generally we use -1 when specifying "missing" in code, but values of 0 are also considered missing as the online source diff --git a/osu.Game/Localisation/GraphicsSettingsStrings.cs b/osu.Game/Localisation/GraphicsSettingsStrings.cs index f85cc0f2ae..996a1350eb 100644 --- a/osu.Game/Localisation/GraphicsSettingsStrings.cs +++ b/osu.Game/Localisation/GraphicsSettingsStrings.cs @@ -119,6 +119,16 @@ namespace osu.Game.Localisation /// public static LocalisableString ShowCursorInScreenshots => new TranslatableString(getKey(@"show_cursor_in_screenshots"), @"Show menu cursor in screenshots"); + /// + /// "Video" + /// + public static LocalisableString VideoHeader => new TranslatableString(getKey(@"video_header"), @"Video"); + + /// + /// "Use hardware acceleration" + /// + public static LocalisableString UseHardwareAcceleration => new TranslatableString(getKey(@"use_hardware_acceleration"), @"Use hardware acceleration"); + private static string getKey(string key) => $"{prefix}:{key}"; } } diff --git a/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs index 4abb227414..1b66a1dcc3 100644 --- a/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs +++ b/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs @@ -26,13 +26,11 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"user")] public User User { get; set; } - public bool HasReplay { get; set; } - [JsonProperty(@"id")] public long OnlineID { get; set; } [JsonProperty(@"replay")] - public bool Replay { get; set; } + public bool HasReplay { get; set; } [JsonProperty(@"created_at")] public DateTimeOffset Date { get; set; } @@ -52,8 +50,11 @@ namespace osu.Game.Online.API.Requests.Responses set { // in the deserialisation case we need to ferry this data across. - if (Beatmap is APIBeatmap apiBeatmap) - apiBeatmap.BeatmapSet = value; + // the order of properties returned by the API guarantees that the beatmap is populated by this point. + if (!(Beatmap is APIBeatmap apiBeatmap)) + throw new InvalidOperationException("Beatmap set metadata arrived before beatmap metadata in response"); + + apiBeatmap.BeatmapSet = value; } } @@ -91,13 +92,14 @@ namespace osu.Game.Online.API.Requests.Responses { TotalScore = TotalScore, MaxCombo = MaxCombo, + BeatmapInfo = Beatmap.ToBeatmapInfo(rulesets), User = User, Accuracy = Accuracy, OnlineScoreID = OnlineID, Date = Date, PP = PP, RulesetID = OnlineRulesetID, - Hash = Replay ? "online" : string.Empty, // todo: temporary? + Hash = HasReplay ? "online" : string.Empty, // todo: temporary? Rank = Rank, Ruleset = ruleset, Mods = mods, diff --git a/osu.Game/Online/API/Requests/Responses/APIScoreWithPosition.cs b/osu.Game/Online/API/Requests/Responses/APIScoreWithPosition.cs index a0fc549d98..48b7134901 100644 --- a/osu.Game/Online/API/Requests/Responses/APIScoreWithPosition.cs +++ b/osu.Game/Online/API/Requests/Responses/APIScoreWithPosition.cs @@ -17,7 +17,6 @@ namespace osu.Game.Online.API.Requests.Responses public APIScoreInfo Score; public ScoreInfo CreateScoreInfo(RulesetStore rulesets, BeatmapInfo beatmap = null) - { var score = Score.CreateScoreInfo(rulesets, beatmap); score.Position = Position; diff --git a/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs index 88793c7cfc..6cd735af23 100644 --- a/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs +++ b/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs @@ -109,8 +109,7 @@ namespace osu.Game.Online.Rooms int onlineId = SelectedItem.Value.Beatmap.Value.OnlineID; string checksum = SelectedItem.Value.Beatmap.Value.MD5Hash; - var beatmap = beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == onlineId && b.MD5Hash == checksum); - return beatmap?.BeatmapSet.DeletePending == false; + return beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == onlineId && b.MD5Hash == checksum && !b.BeatmapSet.DeletePending) != null; } } } diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs index f94fee7a8b..547b8a6ec3 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs @@ -249,6 +249,7 @@ namespace osu.Game.Overlays.BeatmapSet { downloadTracker = new BeatmapDownloadTracker(setInfo.NewValue); downloadTracker.State.BindValueChanged(_ => updateDownloadButtons()); + AddInternal(downloadTracker); fadeContent.FadeIn(500, Easing.OutQuint); diff --git a/osu.Game/Overlays/Dashboard/Home/DashboardBeatmapListing.cs b/osu.Game/Overlays/Dashboard/Home/DashboardBeatmapListing.cs index 4d96825353..c781aa0cfb 100644 --- a/osu.Game/Overlays/Dashboard/Home/DashboardBeatmapListing.cs +++ b/osu.Game/Overlays/Dashboard/Home/DashboardBeatmapListing.cs @@ -5,17 +5,17 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; using osuTK; namespace osu.Game.Overlays.Dashboard.Home { public class DashboardBeatmapListing : CompositeDrawable { - private readonly List newBeatmaps; - private readonly List popularBeatmaps; + private readonly List newBeatmaps; + private readonly List popularBeatmaps; - public DashboardBeatmapListing(List newBeatmaps, List popularBeatmaps) + public DashboardBeatmapListing(List newBeatmaps, List popularBeatmaps) { this.newBeatmaps = newBeatmaps; this.popularBeatmaps = popularBeatmaps; diff --git a/osu.Game/Overlays/Dashboard/Home/DashboardBeatmapPanel.cs b/osu.Game/Overlays/Dashboard/Home/DashboardBeatmapPanel.cs index 50186def37..9276e6ce80 100644 --- a/osu.Game/Overlays/Dashboard/Home/DashboardBeatmapPanel.cs +++ b/osu.Game/Overlays/Dashboard/Home/DashboardBeatmapPanel.cs @@ -7,11 +7,11 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; -using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests.Responses; using osuTK; namespace osu.Game.Overlays.Dashboard.Home @@ -24,14 +24,14 @@ namespace osu.Game.Overlays.Dashboard.Home [Resolved(canBeNull: true)] private BeatmapSetOverlay beatmapOverlay { get; set; } - protected readonly BeatmapSetInfo SetInfo; + protected readonly APIBeatmapSet BeatmapSet; private Box hoverBackground; private SpriteIcon chevron; - protected DashboardBeatmapPanel(BeatmapSetInfo setInfo) + protected DashboardBeatmapPanel(APIBeatmapSet beatmapSet) { - SetInfo = setInfo; + BeatmapSet = beatmapSet; } [BackgroundDependencyLoader] @@ -82,7 +82,7 @@ namespace osu.Game.Overlays.Dashboard.Home RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, Origin = Anchor.Centre, - OnlineInfo = SetInfo.OnlineInfo + OnlineInfo = BeatmapSet } }, new Container @@ -103,14 +103,14 @@ namespace osu.Game.Overlays.Dashboard.Home RelativeSizeAxes = Axes.X, Truncate = true, Font = OsuFont.GetFont(weight: FontWeight.Regular), - Text = SetInfo.Metadata.Title + Text = BeatmapSet.Title }, new OsuSpriteText { RelativeSizeAxes = Axes.X, Truncate = true, Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular), - Text = SetInfo.Metadata.Artist + Text = BeatmapSet.Artist }, new LinkFlowContainer(f => f.Font = OsuFont.GetFont(size: 10, weight: FontWeight.Regular)) { @@ -121,7 +121,7 @@ namespace osu.Game.Overlays.Dashboard.Home }.With(c => { c.AddText("by"); - c.AddUserLink(SetInfo.Metadata.Author); + c.AddUserLink(BeatmapSet.Author); c.AddArbitraryDrawable(CreateInfo()); }) } @@ -143,8 +143,8 @@ namespace osu.Game.Overlays.Dashboard.Home Action = () => { - if (SetInfo.OnlineBeatmapSetID.HasValue) - beatmapOverlay?.FetchAndShowBeatmapSet(SetInfo.OnlineBeatmapSetID.Value); + if (BeatmapSet.OnlineID > 0) + beatmapOverlay?.FetchAndShowBeatmapSet(BeatmapSet.OnlineID); }; } diff --git a/osu.Game/Overlays/Dashboard/Home/DashboardNewBeatmapPanel.cs b/osu.Game/Overlays/Dashboard/Home/DashboardNewBeatmapPanel.cs index b212eaf20a..249b355be3 100644 --- a/osu.Game/Overlays/Dashboard/Home/DashboardNewBeatmapPanel.cs +++ b/osu.Game/Overlays/Dashboard/Home/DashboardNewBeatmapPanel.cs @@ -3,19 +3,19 @@ using System; using osu.Framework.Graphics; -using osu.Game.Beatmaps; using osu.Game.Graphics; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Dashboard.Home { public class DashboardNewBeatmapPanel : DashboardBeatmapPanel { - public DashboardNewBeatmapPanel(BeatmapSetInfo setInfo) - : base(setInfo) + public DashboardNewBeatmapPanel(APIBeatmapSet beatmapSet) + : base(beatmapSet) { } - protected override Drawable CreateInfo() => new DrawableDate(SetInfo.OnlineInfo.Ranked ?? DateTimeOffset.Now, 10, false) + protected override Drawable CreateInfo() => new DrawableDate(BeatmapSet.Ranked ?? DateTimeOffset.Now, 10, false) { Colour = ColourProvider.Foreground1 }; diff --git a/osu.Game/Overlays/Dashboard/Home/DashboardPopularBeatmapPanel.cs b/osu.Game/Overlays/Dashboard/Home/DashboardPopularBeatmapPanel.cs index e9066c0657..4e50cce890 100644 --- a/osu.Game/Overlays/Dashboard/Home/DashboardPopularBeatmapPanel.cs +++ b/osu.Game/Overlays/Dashboard/Home/DashboardPopularBeatmapPanel.cs @@ -4,17 +4,17 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; -using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests.Responses; using osuTK; namespace osu.Game.Overlays.Dashboard.Home { public class DashboardPopularBeatmapPanel : DashboardBeatmapPanel { - public DashboardPopularBeatmapPanel(BeatmapSetInfo setInfo) - : base(setInfo) + public DashboardPopularBeatmapPanel(APIBeatmapSet beatmapSet) + : base(beatmapSet) { } @@ -34,7 +34,7 @@ namespace osu.Game.Overlays.Dashboard.Home new OsuSpriteText { Font = OsuFont.GetFont(size: 10, weight: FontWeight.Regular), - Text = SetInfo.OnlineInfo.FavouriteCount.ToString() + Text = BeatmapSet.FavouriteCount.ToString() } } }; diff --git a/osu.Game/Overlays/Dashboard/Home/DrawableBeatmapList.cs b/osu.Game/Overlays/Dashboard/Home/DrawableBeatmapList.cs index f6535b7db3..c73cc828e2 100644 --- a/osu.Game/Overlays/Dashboard/Home/DrawableBeatmapList.cs +++ b/osu.Game/Overlays/Dashboard/Home/DrawableBeatmapList.cs @@ -6,20 +6,20 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests.Responses; using osuTK; namespace osu.Game.Overlays.Dashboard.Home { public abstract class DrawableBeatmapList : CompositeDrawable { - private readonly List beatmaps; + private readonly List beatmapSets; - protected DrawableBeatmapList(List beatmaps) + protected DrawableBeatmapList(List beatmapSets) { - this.beatmaps = beatmaps; + this.beatmapSets = beatmapSets; } [BackgroundDependencyLoader] @@ -46,11 +46,11 @@ namespace osu.Game.Overlays.Dashboard.Home } }; - flow.AddRange(beatmaps.Select(CreateBeatmapPanel)); + flow.AddRange(beatmapSets.Select(CreateBeatmapPanel)); } protected abstract string Title { get; } - protected abstract DashboardBeatmapPanel CreateBeatmapPanel(BeatmapSetInfo setInfo); + protected abstract DashboardBeatmapPanel CreateBeatmapPanel(APIBeatmapSet beatmapSet); } } diff --git a/osu.Game/Overlays/Dashboard/Home/DrawableNewBeatmapList.cs b/osu.Game/Overlays/Dashboard/Home/DrawableNewBeatmapList.cs index 75e8ca336d..714e07a7ed 100644 --- a/osu.Game/Overlays/Dashboard/Home/DrawableNewBeatmapList.cs +++ b/osu.Game/Overlays/Dashboard/Home/DrawableNewBeatmapList.cs @@ -2,18 +2,18 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Dashboard.Home { public class DrawableNewBeatmapList : DrawableBeatmapList { - public DrawableNewBeatmapList(List beatmaps) - : base(beatmaps) + public DrawableNewBeatmapList(List beatmapSets) + : base(beatmapSets) { } - protected override DashboardBeatmapPanel CreateBeatmapPanel(BeatmapSetInfo setInfo) => new DashboardNewBeatmapPanel(setInfo); + protected override DashboardBeatmapPanel CreateBeatmapPanel(APIBeatmapSet beatmapSet) => new DashboardNewBeatmapPanel(beatmapSet); protected override string Title => "New Ranked Beatmaps"; } diff --git a/osu.Game/Overlays/Dashboard/Home/DrawablePopularBeatmapList.cs b/osu.Game/Overlays/Dashboard/Home/DrawablePopularBeatmapList.cs index 90bd00008c..48b100b04e 100644 --- a/osu.Game/Overlays/Dashboard/Home/DrawablePopularBeatmapList.cs +++ b/osu.Game/Overlays/Dashboard/Home/DrawablePopularBeatmapList.cs @@ -2,18 +2,18 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Dashboard.Home { public class DrawablePopularBeatmapList : DrawableBeatmapList { - public DrawablePopularBeatmapList(List beatmaps) - : base(beatmaps) + public DrawablePopularBeatmapList(List beatmapSets) + : base(beatmapSets) { } - protected override DashboardBeatmapPanel CreateBeatmapPanel(BeatmapSetInfo setInfo) => new DashboardPopularBeatmapPanel(setInfo); + protected override DashboardBeatmapPanel CreateBeatmapPanel(APIBeatmapSet beatmapSet) => new DashboardPopularBeatmapPanel(beatmapSet); protected override string Title => "Popular Beatmaps"; } diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/VideoSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/VideoSettings.cs new file mode 100644 index 0000000000..921eab63ed --- /dev/null +++ b/osu.Game/Overlays/Settings/Sections/Graphics/VideoSettings.cs @@ -0,0 +1,43 @@ +// 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.Bindables; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Video; +using osu.Framework.Localisation; +using osu.Game.Localisation; + +namespace osu.Game.Overlays.Settings.Sections.Graphics +{ + public class VideoSettings : SettingsSubsection + { + protected override LocalisableString Header => GraphicsSettingsStrings.VideoHeader; + + private Bindable hardwareVideoDecoder; + private SettingsCheckbox hwAccelCheckbox; + + [BackgroundDependencyLoader] + private void load(FrameworkConfigManager config) + { + hardwareVideoDecoder = config.GetBindable(FrameworkSetting.HardwareVideoDecoder); + + Children = new Drawable[] + { + hwAccelCheckbox = new SettingsCheckbox + { + LabelText = GraphicsSettingsStrings.UseHardwareAcceleration, + }, + }; + + hwAccelCheckbox.Current.Default = hardwareVideoDecoder.Default != HardwareVideoDecoder.None; + hwAccelCheckbox.Current.Value = hardwareVideoDecoder.Value != HardwareVideoDecoder.None; + + hwAccelCheckbox.Current.BindValueChanged(val => + { + hardwareVideoDecoder.Value = val.NewValue ? HardwareVideoDecoder.Any : HardwareVideoDecoder.None; + }); + } + } +} diff --git a/osu.Game/Overlays/Settings/Sections/GraphicsSection.cs b/osu.Game/Overlays/Settings/Sections/GraphicsSection.cs index 591848506a..8cd3b841c2 100644 --- a/osu.Game/Overlays/Settings/Sections/GraphicsSection.cs +++ b/osu.Game/Overlays/Settings/Sections/GraphicsSection.cs @@ -24,6 +24,7 @@ namespace osu.Game.Overlays.Settings.Sections { new LayoutSettings(), new RendererSettings(), + new VideoSettings(), new ScreenshotSettings(), }; } diff --git a/osu.Game/Scoring/IScoreInfo.cs b/osu.Game/Scoring/IScoreInfo.cs index 171964206d..77579f23d9 100644 --- a/osu.Game/Scoring/IScoreInfo.cs +++ b/osu.Game/Scoring/IScoreInfo.cs @@ -29,7 +29,7 @@ namespace osu.Game.Scoring IRulesetInfo Ruleset { get; } - public ScoreRank Rank { get; } + ScoreRank Rank { get; } // Mods is currently missing from this interface as the `IMod` class has properties which can't be fulfilled by `APIMod`, // but also doesn't expose `Settings`. We can consider how to implement this in the future if required. diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs index 2747cd48c0..36608e2a74 100644 --- a/osu.Game/Scoring/ScoreInfo.cs +++ b/osu.Game/Scoring/ScoreInfo.cs @@ -244,10 +244,18 @@ namespace osu.Game.Scoring return ReferenceEquals(this, other); } + #region Implementation of IHasOnlineID + public long OnlineID => OnlineScoreID ?? -1; + #endregion + + #region Implementation of IScoreInfo + IBeatmapInfo IScoreInfo.Beatmap => BeatmapInfo; IRulesetInfo IScoreInfo.Ruleset => Ruleset; bool IScoreInfo.HasReplay => Files.Any(); + + #endregion } } diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index c946bf12fd..69ab7225ac 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -248,10 +248,7 @@ namespace osu.Game.Screens.OnlinePlay protected virtual IEnumerable CreateButtons() => new Drawable[] { - new PlaylistDownloadButton(Item) - { - Size = new Vector2(50, 30) - }, + new PlaylistDownloadButton(Item), new PlaylistRemoveButton { Size = new Vector2(30, 30), @@ -292,10 +289,14 @@ namespace osu.Game.Screens.OnlinePlay // required for download tracking, as this button hides itself. can probably be removed with a bit of consideration. public override bool IsPresent => true; + private const float width = 50; + public PlaylistDownloadButton(PlaylistItem playlistItem) : base(playlistItem.Beatmap.Value.BeatmapSet) { this.playlistItem = playlistItem; + + Size = new Vector2(width, 30); Alpha = 0; } @@ -316,12 +317,16 @@ namespace osu.Game.Screens.OnlinePlay if (beatmapManager.QueryBeatmap(b => b.MD5Hash == playlistItem.Beatmap.Value.MD5Hash) == null) State.Value = DownloadState.NotDownloaded; else - this.FadeTo(0, 500); + { + this.FadeTo(0, 500) + .ResizeWidthTo(0, 500, Easing.OutQuint); + } break; default: - this.FadeTo(1, 500); + this.ResizeWidthTo(width, 500, Easing.OutQuint) + .FadeTo(1, 500); break; } } diff --git a/osu.Game/Screens/Play/FailAnimation.cs b/osu.Game/Screens/Play/FailAnimation.cs index edfb8186bb..f3676baf80 100644 --- a/osu.Game/Screens/Play/FailAnimation.cs +++ b/osu.Game/Screens/Play/FailAnimation.cs @@ -10,6 +10,7 @@ using ManagedBass.Fx; using osu.Framework.Allocation; using osu.Framework.Audio.Sample; using osu.Framework.Audio.Track; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -83,7 +84,7 @@ namespace osu.Game.Screens.Play Content, redFlashLayer = new Box { - Colour = Color4.Red, + Colour = Color4.Red.Opacity(0.6f), RelativeSizeAxes = Axes.Both, Blending = BlendingParameters.Additive, Depth = float.MinValue, diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs index e129e75ec2..91c8ce441e 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs @@ -94,9 +94,6 @@ namespace osu.Game.Screens.Select.Details modSettingChangeTracker = new ModSettingChangeTracker(mods.NewValue); modSettingChangeTracker.SettingChanged += m => { - if (!(m is IApplicableToDifficulty)) - return; - debouncedStatisticsUpdate?.Cancel(); debouncedStatisticsUpdate = Scheduler.AddDelayed(updateStatistics, 100); }; diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index a5639c3301..f8f9c1172d 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -93,7 +93,7 @@ namespace osu.Game.Skinning private Stream getConfigurationStream() { - string path = SkinInfo.Files.SingleOrDefault(f => f.Filename == "skin.ini")?.FileInfo.StoragePath; + string path = SkinInfo.Files.SingleOrDefault(f => f.Filename.Equals(@"skin.ini", StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; if (string.IsNullOrEmpty(path)) return null; diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 2187d2d875..76d36ae7d9 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -108,7 +108,7 @@ namespace osu.Game.Skinning } } - protected override bool ShouldDeleteArchive(string path) => Path.GetExtension(path)?.ToLowerInvariant() == ".osk"; + protected override bool ShouldDeleteArchive(string path) => Path.GetExtension(path)?.ToLowerInvariant() == @".osk"; /// /// Returns a list of all usable s. Includes the special default skin plus all skins from . @@ -149,9 +149,9 @@ namespace osu.Game.Skinning CurrentSkinInfo.Value = ModelStore.ConsumableItems.Single(i => i.ID == chosen.ID); } - protected override SkinInfo CreateModel(ArchiveReader archive) => new SkinInfo { Name = archive.Name ?? "No name" }; + protected override SkinInfo CreateModel(ArchiveReader archive) => new SkinInfo { Name = archive.Name ?? @"No name" }; - private const string unknown_creator_string = "Unknown"; + private const string unknown_creator_string = @"Unknown"; protected override bool HasCustomHashFunction => true; @@ -164,7 +164,7 @@ namespace osu.Game.Skinning // `Skin` will parse the skin.ini and populate `Skin.Configuration` during construction above. string skinIniSourcedName = instance.Configuration.SkinInfo.Name; string skinIniSourcedCreator = instance.Configuration.SkinInfo.Creator; - string archiveName = item.Name.Replace(".osk", "", StringComparison.OrdinalIgnoreCase); + string archiveName = item.Name.Replace(@".osk", string.Empty, StringComparison.OrdinalIgnoreCase); bool isImport = item.ID == 0; @@ -177,7 +177,7 @@ namespace osu.Game.Skinning // In an ideal world, skin.ini would be the only source of metadata, but a lot of skin creators and users don't update it when making modifications. // In both of these cases, the expectation from the user is that the filename or folder name is displayed somewhere to identify the skin. if (archiveName != item.Name) - item.Name = $"{item.Name} [{archiveName}]"; + item.Name = @$"{item.Name} [{archiveName}]"; } // By this point, the metadata in SkinInfo will be correct. @@ -191,10 +191,10 @@ namespace osu.Game.Skinning private void updateSkinIniMetadata(SkinInfo item) { - string nameLine = $"Name: {item.Name}"; - string authorLine = $"Author: {item.Creator}"; + string nameLine = @$"Name: {item.Name}"; + string authorLine = @$"Author: {item.Creator}"; - var existingFile = item.Files.SingleOrDefault(f => f.Filename == "skin.ini"); + var existingFile = item.Files.SingleOrDefault(f => f.Filename.Equals(@"skin.ini", StringComparison.OrdinalIgnoreCase)); if (existingFile != null) { @@ -210,12 +210,12 @@ namespace osu.Game.Skinning while ((line = sr.ReadLine()) != null) { - if (line.StartsWith("Name:", StringComparison.Ordinal)) + if (line.StartsWith(@"Name:", StringComparison.Ordinal)) { outputLines.Add(nameLine); addedName = true; } - else if (line.StartsWith("Author:", StringComparison.Ordinal)) + else if (line.StartsWith(@"Author:", StringComparison.Ordinal)) { outputLines.Add(authorLine); addedAuthor = true; @@ -229,7 +229,7 @@ namespace osu.Game.Skinning { outputLines.AddRange(new[] { - "[General]", + @"[General]", nameLine, authorLine, }); @@ -252,13 +252,13 @@ namespace osu.Game.Skinning { using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true)) { - sw.WriteLine("[General]"); + sw.WriteLine(@"[General]"); sw.WriteLine(nameLine); sw.WriteLine(authorLine); - sw.WriteLine("Version: latest"); + sw.WriteLine(@"Version: latest"); } - AddFile(item, stream, "skin.ini"); + AddFile(item, stream, @"skin.ini"); } } } @@ -295,7 +295,7 @@ namespace osu.Game.Skinning // if the user is attempting to save one of the default skin implementations, create a copy first. CurrentSkinInfo.Value = Import(new SkinInfo { - Name = skin.SkinInfo.Name + " (modified)", + Name = skin.SkinInfo.Name + @" (modified)", Creator = skin.SkinInfo.Creator, InstantiationInfo = skin.SkinInfo.InstantiationInfo, }).Result.Value; @@ -312,7 +312,7 @@ namespace osu.Game.Skinning using (var streamContent = new MemoryStream(Encoding.UTF8.GetBytes(json))) { - string filename = $"{drawableInfo.Key}.json"; + string filename = @$"{drawableInfo.Key}.json"; var oldFile = skin.SkinInfo.Files.FirstOrDefault(f => f.Filename == filename);