diff --git a/osu.Android.props b/osu.Android.props
index 161a15fa4e..aaac6ec427 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,6 +52,6 @@
-
+
diff --git a/osu.Game.Rulesets.Catch.Tests/CatchSkinnableTestScene.cs b/osu.Game.Rulesets.Catch.Tests/CatchSkinnableTestScene.cs
new file mode 100644
index 0000000000..0c46b078b5
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests/CatchSkinnableTestScene.cs
@@ -0,0 +1,21 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using osu.Game.Rulesets.Catch.Skinning;
+using osu.Game.Tests.Visual;
+
+namespace osu.Game.Rulesets.Catch.Tests
+{
+ public abstract class CatchSkinnableTestScene : SkinnableTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(CatchRuleset),
+ typeof(CatchLegacySkinTransformer),
+ };
+
+ protected override Ruleset CreateRulesetForSkinProvider() => new CatchRuleset();
+ }
+}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs
index fe0d512166..acc5f4e428 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs
@@ -4,21 +4,21 @@
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Game.Rulesets.Catch.UI;
-using osu.Game.Tests.Visual;
using System;
using System.Collections.Generic;
+using System.Linq;
using osu.Framework.Graphics;
namespace osu.Game.Rulesets.Catch.Tests
{
[TestFixture]
- public class TestSceneCatcher : SkinnableTestScene
+ public class TestSceneCatcher : CatchSkinnableTestScene
{
- public override IReadOnlyList RequiredTypes => new[]
+ public override IReadOnlyList RequiredTypes => base.RequiredTypes.Concat(new[]
{
typeof(CatcherArea),
typeof(CatcherSprite)
- };
+ }).ToList();
[BackgroundDependencyLoader]
private void load()
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs
index cf68c5424d..2b30edb70b 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs
@@ -17,12 +17,11 @@ using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
-using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Catch.Tests
{
[TestFixture]
- public class TestSceneCatcherArea : SkinnableTestScene
+ public class TestSceneCatcherArea : CatchSkinnableTestScene
{
private RulesetInfo catchRuleset;
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs
index 82d5aa936f..cd674bb754 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs
@@ -3,20 +3,20 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Objects.Drawables;
using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces;
-using osu.Game.Tests.Visual;
using osuTK;
namespace osu.Game.Rulesets.Catch.Tests
{
[TestFixture]
- public class TestSceneFruitObjects : SkinnableTestScene
+ public class TestSceneFruitObjects : CatchSkinnableTestScene
{
- public override IReadOnlyList RequiredTypes => new[]
+ public override IReadOnlyList RequiredTypes => base.RequiredTypes.Concat(new[]
{
typeof(CatchHitObject),
typeof(Fruit),
@@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Catch.Tests
typeof(DrawableBanana),
typeof(DrawableBananaShower),
typeof(Pulp),
- };
+ }).ToList();
protected override void LoadComplete()
{
diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaSkinnableTestScene.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaSkinnableTestScene.cs
index eaa2a56e36..7f0503913f 100644
--- a/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaSkinnableTestScene.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaSkinnableTestScene.cs
@@ -1,12 +1,15 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
+using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
+using osu.Game.Rulesets.Mania.Skinning;
using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Rulesets.UI.Scrolling.Algorithms;
using osu.Game.Tests.Visual;
@@ -24,6 +27,14 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
[Cached(Type = typeof(IScrollingInfo))]
private readonly TestScrollingInfo scrollingInfo = new TestScrollingInfo();
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(ManiaRuleset),
+ typeof(ManiaLegacySkinTransformer),
+ };
+
+ protected override Ruleset CreateRulesetForSkinProvider() => new ManiaRuleset();
+
protected ManiaSkinnableTestScene()
{
scrollingInfo.Direction.Value = ScrollingDirection.Down;
diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneDrawableJudgement.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneDrawableJudgement.cs
index a6bc64550f..6ab8a68176 100644
--- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneDrawableJudgement.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneDrawableJudgement.cs
@@ -10,11 +10,10 @@ using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
-using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Mania.Tests.Skinning
{
- public class TestSceneDrawableJudgement : SkinnableTestScene
+ public class TestSceneDrawableJudgement : ManiaSkinnableTestScene
{
public override IReadOnlyList RequiredTypes => new[]
{
diff --git a/osu.Game.Rulesets.Mania/Skinning/LegacyNotePiece.cs b/osu.Game.Rulesets.Mania/Skinning/LegacyNotePiece.cs
index d2ceb06d0b..85523ae3c0 100644
--- a/osu.Game.Rulesets.Mania/Skinning/LegacyNotePiece.cs
+++ b/osu.Game.Rulesets.Mania/Skinning/LegacyNotePiece.cs
@@ -20,6 +20,8 @@ namespace osu.Game.Rulesets.Mania.Skinning
private Container directionContainer;
private Sprite noteSprite;
+ private float? minimumColumnWidth;
+
public LegacyNotePiece()
{
RelativeSizeAxes = Axes.X;
@@ -29,6 +31,8 @@ namespace osu.Game.Rulesets.Mania.Skinning
[BackgroundDependencyLoader]
private void load(ISkinSource skin, IScrollingInfo scrollingInfo)
{
+ minimumColumnWidth = skin.GetConfig(new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.MinimumColumnWidth))?.Value;
+
InternalChild = directionContainer = new Container
{
Origin = Anchor.BottomCentre,
@@ -47,8 +51,10 @@ namespace osu.Game.Rulesets.Mania.Skinning
if (noteSprite.Texture != null)
{
- var scale = DrawWidth / noteSprite.Texture.DisplayWidth;
- noteSprite.Scale = new Vector2(scale);
+ // The height is scaled to the minimum column width, if provided.
+ float minimumWidth = minimumColumnWidth ?? DrawWidth;
+
+ noteSprite.Scale = Vector2.Divide(new Vector2(DrawWidth, minimumWidth), noteSprite.Texture.DisplayWidth);
}
}
diff --git a/osu.Game.Rulesets.Mania/Skinning/ManiaLegacySkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/ManiaLegacySkinTransformer.cs
index cbe2036343..78ea4b68ae 100644
--- a/osu.Game.Rulesets.Mania/Skinning/ManiaLegacySkinTransformer.cs
+++ b/osu.Game.Rulesets.Mania/Skinning/ManiaLegacySkinTransformer.cs
@@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Mania.Skinning
{
isLegacySkin = new Lazy(() => source.GetConfig(LegacySkinConfiguration.LegacySetting.Version) != null);
hasKeyTexture = new Lazy(() => source.GetAnimation(
- source.GetConfig(
+ GetConfig(
new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.KeyImage, 0))?.Value
?? "mania-key1", true, true) != null);
}
diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs
index c8c537964f..14cad39b04 100644
--- a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs
+++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs
@@ -64,6 +64,7 @@ namespace osu.Game.Rulesets.Mania.UI
{
// Mania doesn't care about global velocity
p.Velocity = 1;
+ p.BaseBeatLength *= Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier;
// For non-mania beatmap, speed changes should only happen through timing points
if (!isForCurrentRuleset)
diff --git a/osu.Game.Rulesets.Osu.Tests/OsuSkinnableTestScene.cs b/osu.Game.Rulesets.Osu.Tests/OsuSkinnableTestScene.cs
new file mode 100644
index 0000000000..90ebbd9f04
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests/OsuSkinnableTestScene.cs
@@ -0,0 +1,21 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using osu.Game.Rulesets.Osu.Skinning;
+using osu.Game.Tests.Visual;
+
+namespace osu.Game.Rulesets.Osu.Tests
+{
+ public abstract class OsuSkinnableTestScene : SkinnableTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(OsuRuleset),
+ typeof(OsuLegacySkinTransformer),
+ };
+
+ protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
+ }
+}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs
index 02d4406809..f867630df6 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs
@@ -10,17 +10,16 @@ using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
-using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Osu.Tests
{
- public class TestSceneDrawableJudgement : SkinnableTestScene
+ public class TestSceneDrawableJudgement : OsuSkinnableTestScene
{
- public override IReadOnlyList RequiredTypes => new[]
+ public override IReadOnlyList RequiredTypes => base.RequiredTypes.Concat(new[]
{
typeof(DrawableJudgement),
typeof(DrawableOsuJudgement)
- };
+ }).ToList();
public TestSceneDrawableJudgement()
{
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs
index 7b96e2ec6a..22dacc6f5e 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs
@@ -3,26 +3,32 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Testing.Input;
using osu.Game.Configuration;
+using osu.Game.Rulesets.Osu.Skinning;
using osu.Game.Rulesets.Osu.UI.Cursor;
+using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play;
-using osu.Game.Tests.Visual;
using osuTK;
namespace osu.Game.Rulesets.Osu.Tests
{
[TestFixture]
- public class TestSceneGameplayCursor : SkinnableTestScene
+ public class TestSceneGameplayCursor : OsuSkinnableTestScene
{
- public override IReadOnlyList RequiredTypes => new[]
+ public override IReadOnlyList RequiredTypes => base.RequiredTypes.Concat(new[]
{
+ typeof(GameplayCursorContainer),
typeof(OsuCursorContainer),
+ typeof(OsuCursor),
+ typeof(LegacyCursor),
+ typeof(LegacyCursorTrail),
typeof(CursorTrail)
- };
+ }).ToList();
[Cached]
private GameplayBeatmap gameplayBeatmap;
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs
index ae5a28217c..e117729f01 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs
@@ -14,12 +14,11 @@ using osu.Game.Rulesets.Mods;
using System.Linq;
using NUnit.Framework;
using osu.Game.Rulesets.Scoring;
-using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Osu.Tests
{
[TestFixture]
- public class TestSceneHitCircle : SkinnableTestScene
+ public class TestSceneHitCircle : OsuSkinnableTestScene
{
public override IReadOnlyList RequiredTypes => new[]
{
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs
index a201364de4..eb6130c8a6 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs
@@ -22,12 +22,11 @@ using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
-using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Osu.Tests
{
[TestFixture]
- public class TestSceneSlider : SkinnableTestScene
+ public class TestSceneSlider : OsuSkinnableTestScene
{
public override IReadOnlyList RequiredTypes => new[]
{
diff --git a/osu.Game.Rulesets.Taiko.Tests/TaikoSkinnableTestScene.cs b/osu.Game.Rulesets.Taiko.Tests/TaikoSkinnableTestScene.cs
new file mode 100644
index 0000000000..6db2a6907f
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko.Tests/TaikoSkinnableTestScene.cs
@@ -0,0 +1,21 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using osu.Game.Rulesets.Taiko.Skinning;
+using osu.Game.Tests.Visual;
+
+namespace osu.Game.Rulesets.Taiko.Tests
+{
+ public abstract class TaikoSkinnableTestScene : SkinnableTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(TaikoRuleset),
+ typeof(TaikoLegacySkinTransformer),
+ };
+
+ protected override Ruleset CreateRulesetForSkinProvider() => new TaikoRuleset();
+ }
+}
diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneInputDrum.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneInputDrum.cs
index c79088056f..1928e9f66f 100644
--- a/osu.Game.Rulesets.Taiko.Tests/TestSceneInputDrum.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneInputDrum.cs
@@ -3,24 +3,26 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osuTK;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Rulesets.Taiko.Skinning;
using osu.Game.Rulesets.Taiko.UI;
-using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Taiko.Tests
{
[TestFixture]
- public class TestSceneInputDrum : SkinnableTestScene
+ public class TestSceneInputDrum : TaikoSkinnableTestScene
{
- public override IReadOnlyList RequiredTypes => new[]
+ public override IReadOnlyList RequiredTypes => base.RequiredTypes.Concat(new[]
{
typeof(InputDrum),
- };
+ typeof(LegacyInputDrum),
+ }).ToList();
[BackgroundDependencyLoader]
private void load()
diff --git a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs
index cef38bbbb8..aedf26ee75 100644
--- a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs
+++ b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs
@@ -106,7 +106,7 @@ namespace osu.Game.Tests.Skins
var decoder = new LegacySkinDecoder();
using (var resStream = TestResources.OpenResource("skin-empty.ini"))
using (var stream = new LineBufferedReader(resStream))
- Assert.IsNull(decoder.Decode(stream).LegacyVersion);
+ Assert.That(decoder.Decode(stream).LegacyVersion, Is.EqualTo(1.0m));
}
}
}
diff --git a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs
index 35313ee858..685decf097 100644
--- a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs
+++ b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
@@ -12,7 +13,10 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Textures;
using osu.Framework.Testing;
using osu.Game.Audio;
+using osu.Game.IO;
+using osu.Game.Rulesets.Osu;
using osu.Game.Skinning;
+using osu.Game.Tests.Beatmaps;
using osu.Game.Tests.Visual;
using osuTK.Graphics;
@@ -22,15 +26,15 @@ namespace osu.Game.Tests.Skins
[HeadlessTest]
public class TestSceneSkinConfigurationLookup : OsuTestScene
{
- private SkinSource source1;
- private SkinSource source2;
+ private UserSkinSource userSource;
+ private BeatmapSkinSource beatmapSource;
private SkinRequester requester;
[SetUp]
public void SetUp() => Schedule(() =>
{
- Add(new SkinProvidingContainer(source1 = new SkinSource())
- .WithChild(new SkinProvidingContainer(source2 = new SkinSource())
+ Add(new SkinProvidingContainer(userSource = new UserSkinSource())
+ .WithChild(new SkinProvidingContainer(beatmapSource = new BeatmapSkinSource())
.WithChild(requester = new SkinRequester())));
});
@@ -39,31 +43,31 @@ namespace osu.Game.Tests.Skins
{
AddStep("Add config values", () =>
{
- source1.Configuration.ConfigDictionary["Lookup"] = "source1";
- source2.Configuration.ConfigDictionary["Lookup"] = "source2";
+ userSource.Configuration.ConfigDictionary["Lookup"] = "user skin";
+ beatmapSource.Configuration.ConfigDictionary["Lookup"] = "beatmap skin";
});
- AddAssert("Check lookup finds source2", () => requester.GetConfig("Lookup")?.Value == "source2");
+ AddAssert("Check lookup finds beatmap skin", () => requester.GetConfig("Lookup")?.Value == "beatmap skin");
}
[Test]
public void TestFloatLookup()
{
- AddStep("Add config values", () => source1.Configuration.ConfigDictionary["FloatTest"] = "1.1");
+ AddStep("Add config values", () => userSource.Configuration.ConfigDictionary["FloatTest"] = "1.1");
AddAssert("Check float parse lookup", () => requester.GetConfig("FloatTest")?.Value == 1.1f);
}
[Test]
public void TestBoolLookup()
{
- AddStep("Add config values", () => source1.Configuration.ConfigDictionary["BoolTest"] = "1");
+ AddStep("Add config values", () => userSource.Configuration.ConfigDictionary["BoolTest"] = "1");
AddAssert("Check bool parse lookup", () => requester.GetConfig("BoolTest")?.Value == true);
}
[Test]
public void TestEnumLookup()
{
- AddStep("Add config values", () => source1.Configuration.ConfigDictionary["Test"] = "Test2");
+ AddStep("Add config values", () => userSource.Configuration.ConfigDictionary["Test"] = "Test2");
AddAssert("Check enum parse lookup", () => requester.GetConfig(LookupType.Test)?.Value == ValueType.Test2);
}
@@ -76,7 +80,7 @@ namespace osu.Game.Tests.Skins
[Test]
public void TestLookupNull()
{
- AddStep("Add config values", () => source1.Configuration.ConfigDictionary["Lookup"] = null);
+ AddStep("Add config values", () => userSource.Configuration.ConfigDictionary["Lookup"] = null);
AddAssert("Check lookup null", () =>
{
@@ -88,7 +92,7 @@ namespace osu.Game.Tests.Skins
[Test]
public void TestColourLookup()
{
- AddStep("Add config colour", () => source1.Configuration.CustomColours["Lookup"] = Color4.Red);
+ AddStep("Add config colour", () => userSource.Configuration.CustomColours["Lookup"] = Color4.Red);
AddAssert("Check colour lookup", () => requester.GetConfig(new SkinCustomColourLookup("Lookup"))?.Value == Color4.Red);
}
@@ -101,7 +105,7 @@ namespace osu.Game.Tests.Skins
[Test]
public void TestWrongColourType()
{
- AddStep("Add config colour", () => source1.Configuration.CustomColours["Lookup"] = Color4.Red);
+ AddStep("Add config colour", () => userSource.Configuration.CustomColours["Lookup"] = Color4.Red);
AddAssert("perform incorrect lookup", () =>
{
@@ -127,26 +131,51 @@ namespace osu.Game.Tests.Skins
[Test]
public void TestEmptyComboColoursNoFallback()
{
- AddStep("Add custom combo colours to source1", () => source1.Configuration.AddComboColours(
+ AddStep("Add custom combo colours to user skin", () => userSource.Configuration.AddComboColours(
new Color4(100, 150, 200, 255),
new Color4(55, 110, 166, 255),
new Color4(75, 125, 175, 255)
));
- AddStep("Disallow default colours fallback in source2", () => source2.Configuration.AllowDefaultComboColoursFallback = false);
+ AddStep("Disallow default colours fallback in beatmap skin", () => beatmapSource.Configuration.AllowDefaultComboColoursFallback = false);
- AddAssert("Check retrieved combo colours from source1", () =>
- requester.GetConfig>(GlobalSkinColours.ComboColours)?.Value?.SequenceEqual(source1.Configuration.ComboColours) ?? false);
+ AddAssert("Check retrieved combo colours from user skin", () =>
+ requester.GetConfig>(GlobalSkinColours.ComboColours)?.Value?.SequenceEqual(userSource.Configuration.ComboColours) ?? false);
}
[Test]
- public void TestLegacyVersionLookup()
+ public void TestNullBeatmapVersionFallsBackToUserSkin()
{
- AddStep("Set source1 version 2.3", () => source1.Configuration.LegacyVersion = 2.3m);
- AddStep("Set source2 version null", () => source2.Configuration.LegacyVersion = null);
+ AddStep("Set user skin version 2.3", () => userSource.Configuration.LegacyVersion = 2.3m);
+ AddStep("Set beatmap skin version null", () => beatmapSource.Configuration.LegacyVersion = null);
AddAssert("Check legacy version lookup", () => requester.GetConfig(LegacySkinConfiguration.LegacySetting.Version)?.Value == 2.3m);
}
+ [Test]
+ public void TestSetBeatmapVersionNoFallback()
+ {
+ AddStep("Set user skin version 2.3", () => userSource.Configuration.LegacyVersion = 2.3m);
+ AddStep("Set beatmap skin version null", () => beatmapSource.Configuration.LegacyVersion = 1.7m);
+ AddAssert("Check legacy version lookup", () => requester.GetConfig(LegacySkinConfiguration.LegacySetting.Version)?.Value == 1.7m);
+ }
+
+ [Test]
+ public void TestNullBeatmapAndUserVersionFallsBackToLatest()
+ {
+ AddStep("Set user skin version 2.3", () => userSource.Configuration.LegacyVersion = null);
+ AddStep("Set beatmap skin version null", () => beatmapSource.Configuration.LegacyVersion = null);
+ AddAssert("Check legacy version lookup",
+ () => requester.GetConfig(LegacySkinConfiguration.LegacySetting.Version)?.Value == LegacySkinConfiguration.LATEST_VERSION);
+ }
+
+ [Test]
+ public void TestIniWithNoVersionFallsBackTo1()
+ {
+ AddStep("Parse skin with no version", () => userSource.Configuration = new LegacySkinDecoder().Decode(new LineBufferedReader(new MemoryStream())));
+ AddStep("Set beatmap skin version null", () => beatmapSource.Configuration.LegacyVersion = null);
+ AddAssert("Check legacy version lookup", () => requester.GetConfig(LegacySkinConfiguration.LegacySetting.Version)?.Value == 1.0m);
+ }
+
public enum LookupType
{
Test
@@ -159,14 +188,22 @@ namespace osu.Game.Tests.Skins
Test3
}
- public class SkinSource : LegacySkin
+ public class UserSkinSource : LegacySkin
{
- public SkinSource()
+ public UserSkinSource()
: base(new SkinInfo(), null, null, string.Empty)
{
}
}
+ public class BeatmapSkinSource : LegacyBeatmapSkin
+ {
+ public BeatmapSkinSource()
+ : base(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo, null, null)
+ {
+ }
+ }
+
public class SkinRequester : Drawable, ISkin
{
private ISkinSource skin;
diff --git a/osu.Game/Skinning/LegacyBeatmapSkin.cs b/osu.Game/Skinning/LegacyBeatmapSkin.cs
index 1c39fc41bb..1190a330fe 100644
--- a/osu.Game/Skinning/LegacyBeatmapSkin.cs
+++ b/osu.Game/Skinning/LegacyBeatmapSkin.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Audio;
+using osu.Framework.Bindables;
using osu.Framework.IO.Stores;
using osu.Game.Beatmaps;
@@ -18,6 +19,20 @@ namespace osu.Game.Skinning
Configuration.AllowDefaultComboColoursFallback = false;
}
+ public override IBindable GetConfig(TLookup lookup)
+ {
+ switch (lookup)
+ {
+ case LegacySkinConfiguration.LegacySetting s when s == LegacySkinConfiguration.LegacySetting.Version:
+ if (Configuration.LegacyVersion is decimal version)
+ return SkinUtils.As(new Bindable(version));
+
+ return null;
+ }
+
+ return base.GetConfig(lookup);
+ }
+
private static SkinInfo createSkinInfo(BeatmapInfo beatmap) =>
new SkinInfo { Name = beatmap.ToString(), Creator = beatmap.Metadata.Author.ToString() };
}
diff --git a/osu.Game/Skinning/LegacyManiaSkinConfiguration.cs b/osu.Game/Skinning/LegacyManiaSkinConfiguration.cs
index ac257b8c80..af7d6007f3 100644
--- a/osu.Game/Skinning/LegacyManiaSkinConfiguration.cs
+++ b/osu.Game/Skinning/LegacyManiaSkinConfiguration.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using osu.Game.Beatmaps.Formats;
using osuTK.Graphics;
@@ -24,6 +25,8 @@ namespace osu.Game.Skinning
public Dictionary CustomColours { get; set; } = new Dictionary();
+ public Dictionary ImageLookups = new Dictionary();
+
public readonly float[] ColumnLineWidth;
public readonly float[] ColumnSpacing;
public readonly float[] ColumnWidth;
@@ -45,5 +48,13 @@ namespace osu.Game.Skinning
ColumnLineWidth.AsSpan().Fill(2);
ColumnWidth.AsSpan().Fill(DEFAULT_COLUMN_SIZE);
}
+
+ private float? minimumColumnWidth;
+
+ public float MinimumColumnWidth
+ {
+ get => minimumColumnWidth ?? ColumnWidth.Min();
+ set => minimumColumnWidth = value;
+ }
}
}
diff --git a/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs b/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs
index 7d3614bf83..f8089a9590 100644
--- a/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs
+++ b/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs
@@ -40,5 +40,6 @@ namespace osu.Game.Skinning
JudgementLineColour,
ColumnBackgroundColour,
ColumnLightColour
+ MinimumColumnWidth
}
}
diff --git a/osu.Game/Skinning/LegacyManiaSkinDecoder.cs b/osu.Game/Skinning/LegacyManiaSkinDecoder.cs
index eb90225d1c..8b76749e3e 100644
--- a/osu.Game/Skinning/LegacyManiaSkinDecoder.cs
+++ b/osu.Game/Skinning/LegacyManiaSkinDecoder.cs
@@ -71,12 +71,6 @@ namespace osu.Game.Skinning
{
var pair = SplitKeyVal(line);
- if (pair.Key.StartsWith("Colour"))
- {
- HandleColours(currentConfig, line);
- continue;
- }
-
switch (pair.Key)
{
case "ColumnLineWidth":
@@ -106,6 +100,22 @@ namespace osu.Game.Skinning
case "LightingNWidth":
parseArrayValue(pair.Value, currentConfig.ExplosionWidth);
break;
+
+ case "WidthForNoteHeightScale":
+ currentConfig.MinimumColumnWidth = float.Parse(pair.Value, CultureInfo.InvariantCulture) * LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR;
+ break;
+
+ case string _ when pair.Key.StartsWith("Colour"):
+ HandleColours(currentConfig, line);
+ break;
+
+ case string _ when pair.Key.StartsWith("NoteImage"):
+ currentConfig.ImageLookups[pair.Key] = pair.Value;
+ break;
+
+ case string _ when pair.Key.StartsWith("KeyImage"):
+ currentConfig.ImageLookups[pair.Key] = pair.Value;
+ break;
}
}
diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs
index 9e0f4007a1..60eb3d8e51 100644
--- a/osu.Game/Skinning/LegacySkin.cs
+++ b/osu.Game/Skinning/LegacySkin.cs
@@ -71,7 +71,7 @@ namespace osu.Game.Skinning
}
}
else
- Configuration = new LegacySkinConfiguration { LegacyVersion = LegacySkinConfiguration.LATEST_VERSION };
+ Configuration = new LegacySkinConfiguration();
}
if (storage != null)
@@ -123,10 +123,7 @@ namespace osu.Game.Skinning
switch (legacy)
{
case LegacySkinConfiguration.LegacySetting.Version:
- if (Configuration.LegacyVersion is decimal version)
- return SkinUtils.As(new Bindable(version));
-
- break;
+ return SkinUtils.As(new Bindable(Configuration.LegacyVersion ?? LegacySkinConfiguration.LATEST_VERSION));
}
break;
@@ -219,6 +216,33 @@ namespace osu.Game.Skinning
case LegacyManiaSkinConfigurationLookups.ColumnLightColour:
Debug.Assert(maniaLookup.TargetColumn != null);
return SkinUtils.As(getCustomColour(existing, $"ColourLight{maniaLookup.TargetColumn + 1}"));
+
+ case LegacyManiaSkinConfigurationLookups.MinimumColumnWidth:
+ return SkinUtils.As(new Bindable(existing.MinimumColumnWidth));
+
+ case LegacyManiaSkinConfigurationLookups.NoteImage:
+ Debug.Assert(maniaLookup.TargetColumn != null);
+ return SkinUtils.As(getManiaImage(existing, $"NoteImage{maniaLookup.TargetColumn}"));
+
+ case LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage:
+ Debug.Assert(maniaLookup.TargetColumn != null);
+ return SkinUtils.As(getManiaImage(existing, $"NoteImage{maniaLookup.TargetColumn}H"));
+
+ case LegacyManiaSkinConfigurationLookups.HoldNoteTailImage:
+ Debug.Assert(maniaLookup.TargetColumn != null);
+ return SkinUtils.As(getManiaImage(existing, $"NoteImage{maniaLookup.TargetColumn}T"));
+
+ case LegacyManiaSkinConfigurationLookups.HoldNoteBodyImage:
+ Debug.Assert(maniaLookup.TargetColumn != null);
+ return SkinUtils.As(getManiaImage(existing, $"NoteImage{maniaLookup.TargetColumn}L"));
+
+ case LegacyManiaSkinConfigurationLookups.KeyImage:
+ Debug.Assert(maniaLookup.TargetColumn != null);
+ return SkinUtils.As(getManiaImage(existing, $"KeyImage{maniaLookup.TargetColumn}"));
+
+ case LegacyManiaSkinConfigurationLookups.KeyImageDown:
+ Debug.Assert(maniaLookup.TargetColumn != null);
+ return SkinUtils.As(getManiaImage(existing, $"KeyImage{maniaLookup.TargetColumn}D"));
}
return null;
@@ -227,6 +251,9 @@ namespace osu.Game.Skinning
private IBindable getCustomColour(IHasCustomColours source, string lookup)
=> source.CustomColours.TryGetValue(lookup, out var col) ? new Bindable(col) : null;
+ private IBindable getManiaImage(LegacyManiaSkinConfiguration source, string lookup)
+ => source.ImageLookups.TryGetValue(lookup, out var image) ? new Bindable(image) : null;
+
public override Drawable GetDrawableComponent(ISkinComponent component)
{
switch (component)
@@ -255,21 +282,24 @@ namespace osu.Game.Skinning
public override Texture GetTexture(string componentName)
{
- componentName = getFallbackName(componentName);
-
- float ratio = 2;
- var texture = Textures?.Get($"{componentName}@2x");
-
- if (texture == null)
+ foreach (var name in getFallbackNames(componentName))
{
- ratio = 1;
- texture = Textures?.Get(componentName);
+ float ratio = 2;
+ var texture = Textures?.Get($"{name}@2x");
+
+ if (texture == null)
+ {
+ ratio = 1;
+ texture = Textures?.Get(name);
+ }
+
+ if (texture != null)
+ texture.ScaleAdjust = ratio;
+
+ return texture;
}
- if (texture != null)
- texture.ScaleAdjust = ratio;
-
- return texture;
+ return null;
}
public override SampleChannel GetSample(ISampleInfo sampleInfo)
@@ -289,10 +319,14 @@ namespace osu.Game.Skinning
return null;
}
- private string getFallbackName(string componentName)
+ private IEnumerable getFallbackNames(string componentName)
{
+ // May be something like "Gameplay/osu/approachcircle" from lazer, or "Arrows/note1" from a user skin.
+ yield return componentName;
+
+ // Fall back to using the last piece for components coming from lazer (e.g. "Gameplay/osu/approachcircle" -> "approachcircle").
string lastPiece = componentName.Split('/').Last();
- return componentName.StartsWith("Gameplay/taiko/") ? "taiko-" + lastPiece : lastPiece;
+ yield return componentName.StartsWith("Gameplay/taiko/") ? "taiko-" + lastPiece : lastPiece;
}
}
}
diff --git a/osu.Game/Skinning/LegacySkinDecoder.cs b/osu.Game/Skinning/LegacySkinDecoder.cs
index 88ba7b23b7..5d4b8de7ac 100644
--- a/osu.Game/Skinning/LegacySkinDecoder.cs
+++ b/osu.Game/Skinning/LegacySkinDecoder.cs
@@ -52,5 +52,12 @@ namespace osu.Game.Skinning
base.ParseLine(skin, section, line);
}
+
+ protected override LegacySkinConfiguration CreateTemplateObject()
+ {
+ var config = base.CreateTemplateObject();
+ config.LegacyVersion = 1.0m;
+ return config;
+ }
}
}
diff --git a/osu.Game/Skinning/LegacySkinResourceStore.cs b/osu.Game/Skinning/LegacySkinResourceStore.cs
index 249d48b34b..05d0dee05f 100644
--- a/osu.Game/Skinning/LegacySkinResourceStore.cs
+++ b/osu.Game/Skinning/LegacySkinResourceStore.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using osu.Framework.Extensions;
using osu.Framework.IO.Stores;
using osu.Game.Database;
@@ -27,7 +28,7 @@ namespace osu.Game.Skinning
foreach (var filename in base.GetFilenames(name))
{
- var path = getPathForFile(filename);
+ var path = getPathForFile(filename.ToStandardisedPath());
if (path != null)
yield return path;
}
diff --git a/osu.Game/Tests/Visual/SkinnableTestScene.cs b/osu.Game/Tests/Visual/SkinnableTestScene.cs
index 71d3266d18..ace24c0d7e 100644
--- a/osu.Game/Tests/Visual/SkinnableTestScene.cs
+++ b/osu.Game/Tests/Visual/SkinnableTestScene.cs
@@ -13,6 +13,7 @@ using osu.Framework.Graphics.Textures;
using osu.Framework.IO.Stores;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Sprites;
+using osu.Game.Rulesets;
using osu.Game.Skinning;
using osuTK;
using osuTK.Graphics;
@@ -26,18 +27,18 @@ namespace osu.Game.Tests.Visual
private Skin specialSkin;
private Skin oldSkin;
- // Keep a static reference to ensure we don't use a dynamically recompiled DLL as a source (resources will be missing).
- private static DllResourceStore dllStore;
-
protected SkinnableTestScene()
: base(2, 3)
{
}
+ // Required to be part of the per-ruleset implementation to construct the newer version of the Ruleset.
+ protected abstract Ruleset CreateRulesetForSkinProvider();
+
[BackgroundDependencyLoader]
private void load(AudioManager audio, SkinManager skinManager)
{
- dllStore ??= new DllResourceStore(GetType().Assembly);
+ var dllStore = new DllResourceStore(DynamicCompilationOriginal.GetType().Assembly);
metricsSkin = new TestLegacySkin(new SkinInfo { Name = "metrics-skin" }, new NamespacedResourceStore(dllStore, "Resources/metrics_skin"), audio, true);
defaultSkin = skinManager.GetSkin(DefaultLegacySkin.Info);
@@ -106,7 +107,7 @@ namespace osu.Game.Tests.Visual
{
new OutlineBox { Alpha = autoSize ? 1 : 0 },
mainProvider.WithChild(
- new SkinProvidingContainer(Ruleset.Value.CreateInstance().CreateLegacySkinProvider(mainProvider, beatmap))
+ new SkinProvidingContainer(CreateRulesetForSkinProvider().CreateLegacySkinProvider(mainProvider, beatmap))
{
Child = created,
RelativeSizeAxes = !autoSize ? Axes.Both : Axes.None,
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index c62aec7250..3e2c2b1599 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -22,7 +22,7 @@
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index 834c0ee956..7903d964ce 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -70,7 +70,7 @@
-
+
@@ -79,7 +79,7 @@
-
+