diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs index 4a11e1785b..8b22309033 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs @@ -10,6 +10,7 @@ using System.Text; using NUnit.Framework; using osu.Framework.Audio.Track; using osu.Framework.Graphics.Textures; +using osu.Framework.IO.Stores; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.Formats; @@ -19,6 +20,7 @@ using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Taiko; +using osu.Game.Skinning; using osu.Game.Tests.Resources; namespace osu.Game.Tests.Beatmaps.Formats @@ -26,18 +28,33 @@ namespace osu.Game.Tests.Beatmaps.Formats [TestFixture] public class LegacyBeatmapEncoderTest { - private static IEnumerable allBeatmaps => TestResources.GetStore().GetAvailableResources().Where(res => res.EndsWith(".osu")); + private static readonly DllResourceStore beatmaps_resource_store = TestResources.GetStore(); + + private static IEnumerable allBeatmaps = beatmaps_resource_store.GetAvailableResources().Where(res => res.EndsWith(".osu")); [TestCaseSource(nameof(allBeatmaps))] public void TestEncodeDecodeStability(string name) { - var decoded = decodeFromLegacy(TestResources.GetStore().GetStream(name)); - var decodedAfterEncode = decodeFromLegacy(encodeToLegacy(decoded)); + var decoded = decodeFromLegacy(beatmaps_resource_store.GetStream(name), name); + var decodedAfterEncode = decodeFromLegacy(encodeToLegacy(decoded), name); - sort(decoded); - sort(decodedAfterEncode); + sort(decoded.beatmap); + sort(decodedAfterEncode.beatmap); - Assert.That(decodedAfterEncode.Serialize(), Is.EqualTo(decoded.Serialize())); + Assert.That(decodedAfterEncode.beatmap.Serialize(), Is.EqualTo(decoded.beatmap.Serialize())); + Assert.IsTrue(areComboColoursEqual(decodedAfterEncode.beatmapSkin.Configuration, decoded.beatmapSkin.Configuration)); + } + + private bool areComboColoursEqual(IHasComboColours a, IHasComboColours b) + { + // equal to null, no need to SequenceEqual + if (a.ComboColours == null && b.ComboColours == null) + return true; + + if (a.ComboColours == null || b.ComboColours == null) + return false; + + return a.ComboColours.SequenceEqual(b.ComboColours); } private void sort(IBeatmap beatmap) @@ -50,18 +67,31 @@ namespace osu.Game.Tests.Beatmaps.Formats } } - private IBeatmap decodeFromLegacy(Stream stream) + private (IBeatmap beatmap, TestLegacySkin beatmapSkin) decodeFromLegacy(Stream stream, string name) { using (var reader = new LineBufferedReader(stream)) - return convert(new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(reader)); + { + var beatmap = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(reader); + var beatmapSkin = new TestLegacySkin(beatmaps_resource_store, name); + return (convert(beatmap), beatmapSkin); + } } - private Stream encodeToLegacy(IBeatmap beatmap) + private class TestLegacySkin : LegacySkin { + public TestLegacySkin(IResourceStore storage, string fileName) + : base(new SkinInfo { Name = "Test Skin", Creator = "Craftplacer" }, storage, null, fileName) + { + } + } + + private Stream encodeToLegacy((IBeatmap beatmap, ISkin beatmapSkin) fullBeatmap) + { + var (beatmap, beatmapSkin) = fullBeatmap; var stream = new MemoryStream(); using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true)) - new LegacyBeatmapEncoder(beatmap).Encode(writer); + new LegacyBeatmapEncoder(beatmap, beatmapSkin).Encode(writer); stream.Position = 0; diff --git a/osu.Game.Tests/Editing/LegacyEditorBeatmapPatcherTest.cs b/osu.Game.Tests/Editing/LegacyEditorBeatmapPatcherTest.cs index ff17f23d50..b491157627 100644 --- a/osu.Game.Tests/Editing/LegacyEditorBeatmapPatcherTest.cs +++ b/osu.Game.Tests/Editing/LegacyEditorBeatmapPatcherTest.cs @@ -351,7 +351,7 @@ namespace osu.Game.Tests.Editing using (var encoded = new MemoryStream()) { using (var sw = new StreamWriter(encoded)) - new LegacyBeatmapEncoder(beatmap).Encode(sw); + new LegacyBeatmapEncoder(beatmap, null).Encode(sw); return encoded.ToArray(); } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 844af31a16..34bb578b2a 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -28,6 +28,7 @@ using osu.Game.Online.API.Requests; using osu.Game.Rulesets; using osu.Game.Rulesets.Objects; using osu.Game.Users; +using osu.Game.Skinning; using Decoder = osu.Game.Beatmaps.Formats.Decoder; namespace osu.Game.Beatmaps @@ -227,14 +228,15 @@ namespace osu.Game.Beatmaps /// /// The to save the content against. The file referenced by will be replaced. /// The content to write. - public void Save(BeatmapInfo info, IBeatmap beatmapContent) + /// The beatmap content to write, null if to be omitted. + public void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) { var setInfo = QueryBeatmapSet(s => s.Beatmaps.Any(b => b.ID == info.ID)); using (var stream = new MemoryStream()) { using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true)) - new LegacyBeatmapEncoder(beatmapContent).Encode(sw); + new LegacyBeatmapEncoder(beatmapContent, beatmapSkin).Encode(sw); stream.Seek(0, SeekOrigin.Begin); diff --git a/osu.Game/Beatmaps/Formats/IHasCustomColours.cs b/osu.Game/Beatmaps/Formats/IHasCustomColours.cs index 8f6c7dc328..dba3a37545 100644 --- a/osu.Game/Beatmaps/Formats/IHasCustomColours.cs +++ b/osu.Game/Beatmaps/Formats/IHasCustomColours.cs @@ -8,6 +8,6 @@ namespace osu.Game.Beatmaps.Formats { public interface IHasCustomColours { - Dictionary CustomColours { get; set; } + Dictionary CustomColours { get; } } } diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs index 57555cce90..80a4d6dea4 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs @@ -7,13 +7,16 @@ using System.Globalization; using System.IO; using System.Linq; using System.Text; +using JetBrains.Annotations; using osu.Game.Audio; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.Legacy; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Rulesets.Objects.Types; +using osu.Game.Skinning; using osuTK; +using osuTK.Graphics; namespace osu.Game.Beatmaps.Formats { @@ -23,9 +26,18 @@ namespace osu.Game.Beatmaps.Formats private readonly IBeatmap beatmap; - public LegacyBeatmapEncoder(IBeatmap beatmap) + [CanBeNull] + private readonly ISkin skin; + + /// + /// Creates a new . + /// + /// The beatmap to encode. + /// The beatmap's skin, used for encoding combo colours. + public LegacyBeatmapEncoder(IBeatmap beatmap, [CanBeNull] ISkin skin) { this.beatmap = beatmap; + this.skin = skin; if (beatmap.BeatmapInfo.RulesetID < 0 || beatmap.BeatmapInfo.RulesetID > 3) throw new ArgumentException("Only beatmaps in the osu, taiko, catch, or mania rulesets can be encoded to the legacy beatmap format.", nameof(beatmap)); @@ -53,6 +65,9 @@ namespace osu.Game.Beatmaps.Formats writer.WriteLine(); handleControlPoints(writer); + writer.WriteLine(); + handleColours(writer); + writer.WriteLine(); handleHitObjects(writer); } @@ -196,6 +211,28 @@ namespace osu.Game.Beatmaps.Formats } } + private void handleColours(TextWriter writer) + { + var colours = skin?.GetConfig>(GlobalSkinColours.ComboColours)?.Value; + + if (colours == null || colours.Count == 0) + return; + + writer.WriteLine("[Colours]"); + + for (var i = 0; i < colours.Count; i++) + { + var comboColour = colours[i]; + + writer.Write(FormattableString.Invariant($"Combo{i}: ")); + writer.Write(FormattableString.Invariant($"{(byte)(comboColour.R * byte.MaxValue)},")); + writer.Write(FormattableString.Invariant($"{(byte)(comboColour.G * byte.MaxValue)},")); + writer.Write(FormattableString.Invariant($"{(byte)(comboColour.B * byte.MaxValue)},")); + writer.Write(FormattableString.Invariant($"{(byte)(comboColour.A * byte.MaxValue)}")); + writer.WriteLine(); + } + } + private void handleHitObjects(TextWriter writer) { if (beatmap.HitObjects.Count == 0) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs index b7f511271c..6a9a71210a 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs @@ -12,7 +12,7 @@ namespace osu.Game.Overlays.BeatmapListing public BeatmapListingTitle() { Title = "beatmap listing"; - Description = "Browse for new beatmaps"; + Description = "browse for new beatmaps"; IconTexture = "Icons/Hexacons/beatmap"; } } diff --git a/osu.Game/Overlays/Changelog/ChangelogHeader.cs b/osu.Game/Overlays/Changelog/ChangelogHeader.cs index bdc59297bb..f4be4328e7 100644 --- a/osu.Game/Overlays/Changelog/ChangelogHeader.cs +++ b/osu.Game/Overlays/Changelog/ChangelogHeader.cs @@ -115,7 +115,7 @@ namespace osu.Game.Overlays.Changelog public ChangelogHeaderTitle() { Title = "changelog"; - Description = "Track recent dev updates in the osu! ecosystem"; + Description = "track recent dev updates in the osu! ecosystem"; IconTexture = "Icons/Hexacons/devtools"; } } diff --git a/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs b/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs index a964d84c4f..36bf589877 100644 --- a/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs +++ b/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs @@ -12,7 +12,7 @@ namespace osu.Game.Overlays.Dashboard public DashboardTitle() { Title = "dashboard"; - Description = "View your friends and other information"; + Description = "view your friends and other information"; IconTexture = "Icons/Hexacons/social"; } } diff --git a/osu.Game/Overlays/News/NewsHeader.cs b/osu.Game/Overlays/News/NewsHeader.cs index 38ac519387..63174128e7 100644 --- a/osu.Game/Overlays/News/NewsHeader.cs +++ b/osu.Game/Overlays/News/NewsHeader.cs @@ -57,7 +57,7 @@ namespace osu.Game.Overlays.News public NewsHeaderTitle() { Title = "news"; - Description = "Get up-to-date on community happenings"; + Description = "get up-to-date on community happenings"; IconTexture = "Icons/Hexacons/news"; } } diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index b7d916c48f..b5714fbcae 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -19,8 +19,8 @@ namespace osu.Game.Overlays public class NotificationOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent { public string IconTexture => "Icons/Hexacons/notification"; - public string Title => "Notifications"; - public string Description => "Waiting for 'ya"; + public string Title => "notifications"; + public string Description => "waiting for 'ya"; private const float width = 320; diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs index d1df1fa936..55adf02a45 100644 --- a/osu.Game/Overlays/NowPlayingOverlay.cs +++ b/osu.Game/Overlays/NowPlayingOverlay.cs @@ -29,7 +29,7 @@ namespace osu.Game.Overlays { public string IconTexture => "Icons/Hexacons/music"; public string Title => "now playing"; - public string Description => "Manage the currently playing track"; + public string Description => "manage the currently playing track"; private const float player_height = 130; private const float transition_length = 800; diff --git a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs index 7039ab8214..92e22f5873 100644 --- a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs +++ b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs @@ -30,7 +30,7 @@ namespace osu.Game.Overlays.Rankings public RankingsTitle() { Title = "ranking"; - Description = "Find out who's the best right now"; + Description = "find out who's the best right now"; IconTexture = "Icons/Hexacons/rankings"; } } diff --git a/osu.Game/Overlays/SettingsOverlay.cs b/osu.Game/Overlays/SettingsOverlay.cs index 0532a031f3..e1bcdbbaf0 100644 --- a/osu.Game/Overlays/SettingsOverlay.cs +++ b/osu.Game/Overlays/SettingsOverlay.cs @@ -17,7 +17,7 @@ namespace osu.Game.Overlays { public string IconTexture => "Icons/Hexacons/settings"; public string Title => "settings"; - public string Description => "Change the way osu! behaves"; + public string Description => "change the way osu! behaves"; protected override IEnumerable CreateSections() => new SettingsSection[] { diff --git a/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs b/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs index 6b2c24c0f3..76fbd40d66 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs @@ -17,8 +17,8 @@ namespace osu.Game.Overlays.Toolbar [BackgroundDependencyLoader] private void load() { - TooltipMain = "Home"; - TooltipSub = "Return to the main menu"; + TooltipMain = "home"; + TooltipSub = "return to the main menu"; SetIcon("Icons/Hexacons/home"); } } diff --git a/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs b/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs index 754b679599..564fd65719 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs @@ -27,7 +27,7 @@ namespace osu.Game.Overlays.Toolbar var rInstance = value.CreateInstance(); ruleset.TooltipMain = rInstance.Description; - ruleset.TooltipSub = $"Play some {rInstance.Description}"; + ruleset.TooltipSub = $"play some {rInstance.Description}"; ruleset.SetIcon(rInstance.CreateIcon()); } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index ef497e3246..3ba3eb108a 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -113,9 +113,8 @@ namespace osu.Game.Screens.Edit return; } - AddInternal(editorBeatmap = new EditorBeatmap(playableBeatmap)); + AddInternal(editorBeatmap = new EditorBeatmap(playableBeatmap, Beatmap.Value.Skin)); dependencies.CacheAs(editorBeatmap); - changeHandler = new EditorChangeHandler(editorBeatmap); dependencies.CacheAs(changeHandler); @@ -418,7 +417,7 @@ namespace osu.Game.Screens.Edit beatmapManager.Update(playableBeatmap.BeatmapInfo.BeatmapSet); // save the loaded beatmap's data stream. - beatmapManager.Save(playableBeatmap.BeatmapInfo, editorBeatmap); + beatmapManager.Save(playableBeatmap.BeatmapInfo, editorBeatmap, editorBeatmap.BeatmapSkin); } private void exportBeatmap() diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 23c8c9f605..061009e519 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -15,6 +15,7 @@ using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; +using osu.Game.Skinning; namespace osu.Game.Screens.Edit { @@ -47,6 +48,8 @@ namespace osu.Game.Screens.Edit public readonly IBeatmap PlayableBeatmap; + public readonly ISkin BeatmapSkin; + [Resolved] private BindableBeatDivisor beatDivisor { get; set; } @@ -54,9 +57,10 @@ namespace osu.Game.Screens.Edit private readonly Dictionary> startTimeBindables = new Dictionary>(); - public EditorBeatmap(IBeatmap playableBeatmap) + public EditorBeatmap(IBeatmap playableBeatmap, ISkin beatmapSkin = null) { PlayableBeatmap = playableBeatmap; + BeatmapSkin = beatmapSkin; beatmapProcessor = playableBeatmap.BeatmapInfo.Ruleset?.CreateInstance().CreateBeatmapProcessor(PlayableBeatmap); diff --git a/osu.Game/Screens/Edit/EditorChangeHandler.cs b/osu.Game/Screens/Edit/EditorChangeHandler.cs index 1553c2d2ef..927c823c64 100644 --- a/osu.Game/Screens/Edit/EditorChangeHandler.cs +++ b/osu.Game/Screens/Edit/EditorChangeHandler.cs @@ -85,7 +85,7 @@ namespace osu.Game.Screens.Edit using (var stream = new MemoryStream()) { using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true)) - new LegacyBeatmapEncoder(editorBeatmap).Encode(sw); + new LegacyBeatmapEncoder(editorBeatmap, editorBeatmap.BeatmapSkin).Encode(sw); savedStates.Add(stream.ToArray()); } diff --git a/osu.Game/Skinning/LegacyManiaSkinConfiguration.cs b/osu.Game/Skinning/LegacyManiaSkinConfiguration.cs index 65d5851455..35a6140cbc 100644 --- a/osu.Game/Skinning/LegacyManiaSkinConfiguration.cs +++ b/osu.Game/Skinning/LegacyManiaSkinConfiguration.cs @@ -23,7 +23,7 @@ namespace osu.Game.Skinning public readonly int Keys; - public Dictionary CustomColours { get; set; } = new Dictionary(); + public Dictionary CustomColours { get; } = new Dictionary(); public Dictionary ImageLookups = new Dictionary(); diff --git a/osu.Game/Skinning/SkinConfiguration.cs b/osu.Game/Skinning/SkinConfiguration.cs index a55870aa6d..25a924c929 100644 --- a/osu.Game/Skinning/SkinConfiguration.cs +++ b/osu.Game/Skinning/SkinConfiguration.cs @@ -45,7 +45,7 @@ namespace osu.Game.Skinning public void AddComboColours(params Color4[] colours) => comboColours.AddRange(colours); - public Dictionary CustomColours { get; set; } = new Dictionary(); + public Dictionary CustomColours { get; } = new Dictionary(); public readonly Dictionary ConfigDictionary = new Dictionary(); }