From 8d790e180d8a2e221e1a691df839d48af22a017d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 16 Mar 2018 17:02:41 +0900 Subject: [PATCH 01/10] Fix juice stream droplets spawning in incorrect locations Closes #2149. --- .../Objects/JuiceStream.cs | 75 ++++++++++--------- .../Tests/CatchBeatmapConversionTest.cs | 2 +- 2 files changed, 41 insertions(+), 36 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index a3e5aba2db..e4d5ae698f 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -65,54 +65,59 @@ namespace osu.Game.Rulesets.Catch.Objects X = X }); - for (var span = 0; span < this.SpanCount(); span++) + double lastDropletTime = StartTime; + + for (int span = 0; span < this.SpanCount(); span++) { var spanStartTime = StartTime + span * spanDuration; var reversed = span % 2 == 1; - for (var d = tickDistance; d <= length; d += tickDistance) + for (double d = 0; d <= length; d += tickDistance) { - if (d > length - minDistanceFromEnd) - break; - var timeProgress = d / length; var distanceProgress = reversed ? 1 - timeProgress : timeProgress; - var lastTickTime = spanStartTime + timeProgress * spanDuration; - AddNested(new Droplet + double time = spanStartTime + timeProgress * spanDuration; + + double tinyTickInterval = time - lastDropletTime; + while (tinyTickInterval > 100) + tinyTickInterval /= 2; + + for (double t = lastDropletTime + tinyTickInterval; t < time; t += tinyTickInterval) { - StartTime = lastTickTime, - ComboColour = ComboColour, - X = X + Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, - Samples = new List(Samples.Select(s => new SampleInfo + double progress = reversed ? 1 - (t - spanStartTime) / spanDuration : (t - spanStartTime) / spanDuration; + + AddNested(new TinyDroplet { - Bank = s.Bank, - Name = @"slidertick", - Volume = s.Volume - })) - }); - } + StartTime = t, + ComboColour = ComboColour, + X = X + Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, + Samples = new List(Samples.Select(s => new SampleInfo + { + Bank = s.Bank, + Name = @"slidertick", + Volume = s.Volume + })) + }); + } - double tinyTickInterval = tickDistance / length * spanDuration; - while (tinyTickInterval > 100) - tinyTickInterval /= 2; - - for (double t = 0; t < spanDuration; t += tinyTickInterval) - { - double progress = reversed ? 1 - t / spanDuration : t / spanDuration; - - AddNested(new TinyDroplet + if (d > minDistanceFromEnd && Math.Abs(d - length) > minDistanceFromEnd) { - StartTime = spanStartTime + t, - ComboColour = ComboColour, - X = X + Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, - Samples = new List(Samples.Select(s => new SampleInfo + AddNested(new Droplet { - Bank = s.Bank, - Name = @"slidertick", - Volume = s.Volume - })) - }); + StartTime = time, + ComboColour = ComboColour, + X = X + Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, + Samples = new List(Samples.Select(s => new SampleInfo + { + Bank = s.Bank, + Name = @"slidertick", + Volume = s.Volume + })) + }); + } + + lastDropletTime = time; } AddNested(new Fruit diff --git a/osu.Game.Rulesets.Catch/Tests/CatchBeatmapConversionTest.cs b/osu.Game.Rulesets.Catch/Tests/CatchBeatmapConversionTest.cs index 826c900140..e40510b71b 100644 --- a/osu.Game.Rulesets.Catch/Tests/CatchBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Catch/Tests/CatchBeatmapConversionTest.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Catch.Tests { protected override string ResourceAssembly => "osu.Game.Rulesets.Catch"; - [TestCase("basic"), Ignore("See: https://github.com/ppy/osu/issues/2149")] + [TestCase("basic"), Ignore("See: https://github.com/ppy/osu/issues/2232")] public new void Test(string name) { base.Test(name); From c4f5b46d72cf523a03be2996e74b46a664267d08 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Mar 2018 19:50:37 +0900 Subject: [PATCH 02/10] Add basic structure for skin configurations --- osu.Game/Skinning/LegacySkinDecoder.cs | 15 +++++++++++++++ osu.Game/Skinning/SkinConfiguration.cs | 18 ++++++++++++++++++ osu.Game/osu.Game.csproj | 2 ++ 3 files changed, 35 insertions(+) create mode 100644 osu.Game/Skinning/LegacySkinDecoder.cs create mode 100644 osu.Game/Skinning/SkinConfiguration.cs diff --git a/osu.Game/Skinning/LegacySkinDecoder.cs b/osu.Game/Skinning/LegacySkinDecoder.cs new file mode 100644 index 0000000000..a867e08495 --- /dev/null +++ b/osu.Game/Skinning/LegacySkinDecoder.cs @@ -0,0 +1,15 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Beatmaps.Formats; + +namespace osu.Game.Skinning +{ + public class LegacySkinDecoder : LegacyDecoder + { + public LegacySkinDecoder(int version) + : base(version) + { + } + } +} diff --git a/osu.Game/Skinning/SkinConfiguration.cs b/osu.Game/Skinning/SkinConfiguration.cs new file mode 100644 index 0000000000..eac77ae753 --- /dev/null +++ b/osu.Game/Skinning/SkinConfiguration.cs @@ -0,0 +1,18 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using osu.Game.Beatmaps.Formats; +using OpenTK.Graphics; + +namespace osu.Game.Skinning +{ + public class SkinConfiguration : IHasComboColours, IHasCustomColours + { + public readonly SkinInfo SkinInfo = new SkinInfo(); + + public List ComboColours { get; set; } = new List(); + + public Dictionary CustomColours { get; set; } = new Dictionary(); + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 091ec3f7ac..b325e52ed1 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -873,7 +873,9 @@ + + From 62e908e22c45939f79901014e15c88b9cfff3be7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 14 Mar 2018 18:41:48 +0900 Subject: [PATCH 03/10] Add default separator character --- osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 8 ++++---- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 1bb67f9e75..74b7d0272e 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -96,7 +96,7 @@ namespace osu.Game.Beatmaps.Formats private void handleGeneral(string line) { - var pair = SplitKeyVal(line, ':'); + var pair = SplitKeyVal(line); var metadata = beatmap.BeatmapInfo.Metadata; switch (pair.Key) @@ -155,7 +155,7 @@ namespace osu.Game.Beatmaps.Formats private void handleEditor(string line) { - var pair = SplitKeyVal(line, ':'); + var pair = SplitKeyVal(line); switch (pair.Key) { @@ -179,7 +179,7 @@ namespace osu.Game.Beatmaps.Formats private void handleMetadata(string line) { - var pair = SplitKeyVal(line, ':'); + var pair = SplitKeyVal(line); var metadata = beatmap.BeatmapInfo.Metadata; switch (pair.Key) @@ -220,7 +220,7 @@ namespace osu.Game.Beatmaps.Formats private void handleDifficulty(string line) { - var pair = SplitKeyVal(line, ':'); + var pair = SplitKeyVal(line); var difficulty = beatmap.BeatmapInfo.BaseDifficulty; switch (pair.Key) diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index e4aa9f5091..67d497ba83 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -55,7 +55,7 @@ namespace osu.Game.Beatmaps.Formats private void handleColours(T output, string line) { - var pair = SplitKeyVal(line, ':'); + var pair = SplitKeyVal(line); bool isCombo = pair.Key.StartsWith(@"Combo"); @@ -89,7 +89,7 @@ namespace osu.Game.Beatmaps.Formats } } - protected KeyValuePair SplitKeyVal(string line, char separator) + protected KeyValuePair SplitKeyVal(string line, char separator = ':') { var split = line.Trim().Split(new[] { separator }, 2); From 8e52d91180b66c13833247504363169de96b8d1b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 14 Mar 2018 18:42:13 +0900 Subject: [PATCH 04/10] Handle missing files without hard failure Also adds support for lookups with file extensions --- osu.Game/Skinning/LegacySkin.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 5525cc483e..0e508e4527 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -60,10 +60,12 @@ namespace osu.Game.Skinning private string getPathForFile(string filename) { + bool hasExtension = filename.Contains('.'); + string lastPiece = filename.Split('/').Last(); var file = skin.Files.FirstOrDefault(f => - string.Equals(Path.GetFileNameWithoutExtension(f.Filename), lastPiece, StringComparison.InvariantCultureIgnoreCase)); + string.Equals(hasExtension ? f.Filename : Path.GetFileNameWithoutExtension(f.Filename), lastPiece, StringComparison.InvariantCultureIgnoreCase)); return file?.FileInfo.StoragePath; } @@ -73,9 +75,17 @@ namespace osu.Game.Skinning this.underlyingStore = underlyingStore; } - public Stream GetStream(string name) => underlyingStore.GetStream(getPathForFile(name)); + public Stream GetStream(string name) + { + string path = getPathForFile(name); + return path == null ? null : underlyingStore.GetStream(path); + } - byte[] IResourceStore.Get(string name) => underlyingStore.Get(getPathForFile(name)); + byte[] IResourceStore.Get(string name) + { + string path = getPathForFile(name); + return path == null ? null : underlyingStore.Get(path); + } } } } From 397b06283ac1deac1d212f61a97024c42881227e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Mar 2018 20:05:31 +0900 Subject: [PATCH 05/10] Add basic skin configuration decoding support --- osu.Game/Skinning/LegacySkin.cs | 5 +++++ osu.Game/Skinning/LegacySkinDecoder.cs | 27 ++++++++++++++++++++++++-- osu.Game/Skinning/Skin.cs | 2 ++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 0e508e4527..27f15474ba 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -25,6 +25,11 @@ namespace osu.Game.Skinning storage = new LegacySkinResourceStore(skin, storage); samples = audioManager.GetSampleManager(storage); textures = new TextureStore(new RawTextureLoaderStore(storage)); + + var decoder = new LegacySkinDecoder(); + + using (StreamReader reader = new StreamReader(storage.GetStream("skin.ini"))) + Configuration = decoder.Decode(reader); } public override Drawable GetDrawableComponent(string componentName) diff --git a/osu.Game/Skinning/LegacySkinDecoder.cs b/osu.Game/Skinning/LegacySkinDecoder.cs index a867e08495..9a881f9241 100644 --- a/osu.Game/Skinning/LegacySkinDecoder.cs +++ b/osu.Game/Skinning/LegacySkinDecoder.cs @@ -7,9 +7,32 @@ namespace osu.Game.Skinning { public class LegacySkinDecoder : LegacyDecoder { - public LegacySkinDecoder(int version) - : base(version) + public LegacySkinDecoder() + : base(1) { } + + protected override void ParseLine(SkinConfiguration output, Section section, string line) + { + switch (section) + { + case Section.General: + var pair = SplitKeyVal(line); + + switch (pair.Key) + { + case @"Name": + output.SkinInfo.Name = pair.Value; + break; + case @"Author": + output.SkinInfo.Creator = pair.Value; + break; + } + + return; + } + + base.ParseLine(output, section, line); + } } } diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index fafbdec8f0..7b4e894dfd 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -10,6 +10,8 @@ namespace osu.Game.Skinning { public readonly SkinInfo SkinInfo; + public virtual SkinConfiguration Configuration { get; protected set; } + public abstract Drawable GetDrawableComponent(string componentName); public abstract SampleChannel GetSample(string sampleName); From ec851648da6df51ce9d31622d00d9c0bbc9ceb57 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 14 Mar 2018 19:09:30 +0900 Subject: [PATCH 06/10] Add better ToString output from SkinInfo --- osu.Game/Overlays/Settings/Sections/SkinSection.cs | 2 +- osu.Game/Skinning/SkinInfo.cs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index bc0b8b4aaa..5df5304751 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -47,7 +47,7 @@ namespace osu.Game.Overlays.Settings.Sections }, }; - void reloadSkins() => skinDropdown.Items = skins.GetAllUsableSkins().Select(s => new KeyValuePair(s.Name, s.ID)); + void reloadSkins() => skinDropdown.Items = skins.GetAllUsableSkins().Select(s => new KeyValuePair(s.ToString(), s.ID)); skins.ItemAdded += _ => reloadSkins(); skins.ItemRemoved += _ => reloadSkins(); diff --git a/osu.Game/Skinning/SkinInfo.cs b/osu.Game/Skinning/SkinInfo.cs index 45c8b97f63..5080b65a37 100644 --- a/osu.Game/Skinning/SkinInfo.cs +++ b/osu.Game/Skinning/SkinInfo.cs @@ -24,5 +24,7 @@ namespace osu.Game.Skinning public static SkinInfo Default { get; } = new SkinInfo { Name = "osu!lazer", Creator = "team osu!" }; public bool Equals(SkinInfo other) => other != null && ID == other.ID; + + public override string ToString() => $"\"{Name}\" by {Creator}"; } } From 7272ba2f1b5429a9fffdb0999d9c4324922b47ff Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 14 Mar 2018 19:35:43 +0900 Subject: [PATCH 07/10] Add migration for skins which didn't get a proper name assigned Also correctly imports new skins --- osu.Game/Skinning/SkinManager.cs | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 88d51eca10..fa65b923fb 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -39,6 +39,31 @@ namespace osu.Game.Skinning Name = archive.Name }; + protected override void Populate(SkinInfo model, ArchiveReader archive) + { + base.Populate(model, archive); + populate(model); + } + + /// + /// Populate a from its (if possible). + /// + /// + private void populate(SkinInfo model) + { + Skin reference = GetSkin(model); + if (!string.IsNullOrEmpty(reference.Configuration.SkinInfo.Name)) + { + model.Name = reference.Configuration.SkinInfo.Name; + model.Creator = reference.Configuration.SkinInfo.Creator; + } + else + { + model.Name = model.Name.Replace(".osk", ""); + model.Creator = "Unknown"; + } + } + /// /// Retrieve a instance for the provided /// @@ -65,6 +90,16 @@ namespace osu.Game.Skinning if (skin.SkinInfo != CurrentSkinInfo.Value) throw new InvalidOperationException($"Setting {nameof(CurrentSkin)}'s value directly is not supported. Use {nameof(CurrentSkinInfo)} instead."); }; + + // migrate older imports which didn't have access to skin.ini + using (ContextFactory.GetForWrite()) + { + foreach (var skinInfo in ModelStore.ConsumableItems.Where(s => s.Name.EndsWith(".osk"))) + { + populate(skinInfo); + Update(skinInfo); + } + } } /// From b71c123214fc56035eaeda692144427876fe64c6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Mar 2018 20:26:16 +0900 Subject: [PATCH 08/10] Allow import of skins which don't have ini files --- osu.Game/Skinning/LegacySkin.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 27f15474ba..b531d791b0 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -26,10 +26,13 @@ namespace osu.Game.Skinning samples = audioManager.GetSampleManager(storage); textures = new TextureStore(new RawTextureLoaderStore(storage)); - var decoder = new LegacySkinDecoder(); + Stream stream = storage.GetStream("skin.ini"); - using (StreamReader reader = new StreamReader(storage.GetStream("skin.ini"))) - Configuration = decoder.Decode(reader); + if (stream != null) + using (StreamReader reader = new StreamReader(stream)) + Configuration = new LegacySkinDecoder().Decode(reader); + else + Configuration = new SkinConfiguration(); } public override Drawable GetDrawableComponent(string componentName) From 553fd3b7897f9edce3b78604f0e33d72b08f18e6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Mar 2018 21:00:27 +0900 Subject: [PATCH 09/10] Give DefaultSkin an empty Configuration --- osu.Game/Skinning/DefaultSkin.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Skinning/DefaultSkin.cs b/osu.Game/Skinning/DefaultSkin.cs index e40a43d400..c469e91250 100644 --- a/osu.Game/Skinning/DefaultSkin.cs +++ b/osu.Game/Skinning/DefaultSkin.cs @@ -11,6 +11,7 @@ namespace osu.Game.Skinning public DefaultSkin() : base(SkinInfo.Default) { + Configuration = new SkinConfiguration(); } public override Drawable GetDrawableComponent(string componentName) From 5a10270a2a6257e9d074b0bff91502d112254954 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 20 Mar 2018 20:32:32 +0900 Subject: [PATCH 10/10] return -> break no real reason but whatever works --- osu.Game/Skinning/LegacySkinDecoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/LegacySkinDecoder.cs b/osu.Game/Skinning/LegacySkinDecoder.cs index 9a881f9241..853abceddf 100644 --- a/osu.Game/Skinning/LegacySkinDecoder.cs +++ b/osu.Game/Skinning/LegacySkinDecoder.cs @@ -29,7 +29,7 @@ namespace osu.Game.Skinning break; } - return; + break; } base.ParseLine(output, section, line);