Merge pull request #20592 from peppy/mania-column-refactor

Refactor osu!mania skinning to allow skins to specify column accent colours
This commit is contained in:
Dan Balasescu
2022-10-07 17:33:58 +09:00
committed by GitHub
46 changed files with 492 additions and 415 deletions

View File

@ -10,6 +10,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
@ -30,15 +31,18 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
[Cached(typeof(IScrollingInfo))] [Cached(typeof(IScrollingInfo))]
private IScrollingInfo scrollingInfo; private IScrollingInfo scrollingInfo;
[Cached]
private readonly StageDefinition stage = new StageDefinition(5);
protected ManiaPlacementBlueprintTestScene() protected ManiaPlacementBlueprintTestScene()
{ {
scrollingInfo = ((ScrollingTestContainer)HitObjectContainer).ScrollingInfo; scrollingInfo = ((ScrollingTestContainer)HitObjectContainer).ScrollingInfo;
Add(column = new Column(0) Add(column = new Column(0, false)
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
AccentColour = Color4.OrangeRed, AccentColour = { Value = Color4.OrangeRed },
Clock = new FramedClock(new StopwatchClock()), // No scroll Clock = new FramedClock(new StopwatchClock()), // No scroll
}); });
} }

View File

@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
protected ManiaSelectionBlueprintTestScene(int columns) protected ManiaSelectionBlueprintTestScene(int columns)
{ {
var stageDefinitions = new List<StageDefinition> { new StageDefinition { Columns = columns } }; var stageDefinitions = new List<StageDefinition> { new StageDefinition(columns) };
base.Content.Child = scrollingTestContainer = new ScrollingTestContainer(ScrollingDirection.Up) base.Content.Child = scrollingTestContainer = new ScrollingTestContainer(ScrollingDirection.Up)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,

View File

@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
private ScrollingTestContainer.TestScrollingInfo scrollingInfo = new ScrollingTestContainer.TestScrollingInfo(); private ScrollingTestContainer.TestScrollingInfo scrollingInfo = new ScrollingTestContainer.TestScrollingInfo();
[Cached(typeof(EditorBeatmap))] [Cached(typeof(EditorBeatmap))]
private EditorBeatmap editorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition()) private EditorBeatmap editorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition(2))
{ {
BeatmapInfo = BeatmapInfo =
{ {
@ -56,8 +56,8 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
{ {
Playfield = new ManiaPlayfield(new List<StageDefinition> Playfield = new ManiaPlayfield(new List<StageDefinition>
{ {
new StageDefinition { Columns = 4 }, new StageDefinition(4),
new StageDefinition { Columns = 3 } new StageDefinition(3)
}) })
{ {
Clock = new FramedClock(new StopwatchClock()) Clock = new FramedClock(new StopwatchClock())

View File

@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
{ {
AddStep("setup compose screen", () => AddStep("setup compose screen", () =>
{ {
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 4 }) var beatmap = new ManiaBeatmap(new StageDefinition(4))
{ {
BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo }, BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo },
}; };

View File

@ -205,7 +205,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
{ {
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
EditorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition { Columns = 4 }) EditorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition(4))
{ {
BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo } BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo }
}), }),

View File

@ -1,52 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic;
using osu.Game.Rulesets.Mania.Beatmaps;
using NUnit.Framework;
namespace osu.Game.Rulesets.Mania.Tests
{
[TestFixture]
public class ManiaColumnTypeTest
{
[TestCase(new[]
{
ColumnType.Special
}, 1)]
[TestCase(new[]
{
ColumnType.Odd,
ColumnType.Even,
ColumnType.Even,
ColumnType.Odd
}, 4)]
[TestCase(new[]
{
ColumnType.Odd,
ColumnType.Even,
ColumnType.Odd,
ColumnType.Special,
ColumnType.Odd,
ColumnType.Even,
ColumnType.Odd
}, 7)]
public void Test(IEnumerable<ColumnType> expected, int columns)
{
var definition = new StageDefinition
{
Columns = columns
};
var results = getResults(definition);
Assert.AreEqual(expected, results);
}
private IEnumerable<ColumnType> getResults(StageDefinition definition)
{
for (int i = 0; i < definition.Columns; i++)
yield return definition.GetTypeOfColumn(i);
}
}
}

View File

@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Tests
[TestCase(ManiaAction.Key8)] [TestCase(ManiaAction.Key8)]
public void TestEncodeDecodeSingleStage(params ManiaAction[] actions) public void TestEncodeDecodeSingleStage(params ManiaAction[] actions)
{ {
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 9 }); var beatmap = new ManiaBeatmap(new StageDefinition(9));
var frame = new ManiaReplayFrame(0, actions); var frame = new ManiaReplayFrame(0, actions);
var legacyFrame = frame.ToLegacy(beatmap); var legacyFrame = frame.ToLegacy(beatmap);
@ -38,8 +38,8 @@ namespace osu.Game.Rulesets.Mania.Tests
[TestCase(ManiaAction.Key8)] [TestCase(ManiaAction.Key8)]
public void TestEncodeDecodeDualStage(params ManiaAction[] actions) public void TestEncodeDecodeDualStage(params ManiaAction[] actions)
{ {
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 5 }); var beatmap = new ManiaBeatmap(new StageDefinition(5));
beatmap.Stages.Add(new StageDefinition { Columns = 5 }); beatmap.Stages.Add(new StageDefinition(5));
var frame = new ManiaReplayFrame(0, actions); var frame = new ManiaReplayFrame(0, actions);
var legacyFrame = frame.ToLegacy(beatmap); var legacyFrame = frame.ToLegacy(beatmap);

View File

@ -0,0 +1,49 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Collections.Generic;
using osu.Game.Rulesets.Mania.Beatmaps;
using NUnit.Framework;
namespace osu.Game.Rulesets.Mania.Tests
{
[TestFixture]
public class ManiaSpecialColumnTest
{
[TestCase(new[]
{
true
}, 1)]
[TestCase(new[]
{
false,
false,
false,
false
}, 4)]
[TestCase(new[]
{
false,
false,
false,
true,
false,
false,
false
}, 7)]
public void Test(IEnumerable<bool> special, int columns)
{
var definition = new StageDefinition(columns);
var results = getResults(definition);
Assert.AreEqual(special, results);
}
private IEnumerable<bool> getResults(StageDefinition definition)
{
for (int i = 0; i < definition.Columns; i++)
yield return definition.IsSpecialColumn(i);
}
}
}

View File

@ -85,7 +85,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods
private static ManiaBeatmap createRawBeatmap() private static ManiaBeatmap createRawBeatmap()
{ {
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 1 }); var beatmap = new ManiaBeatmap(new StageDefinition(1));
beatmap.ControlPointInfo.Add(0.0, new TimingControlPoint { BeatLength = 1000 }); // Set BPM to 60 beatmap.ControlPointInfo.Add(0.0, new TimingControlPoint { BeatLength = 1000 }); // Set BPM to 60
// Add test hit objects // Add test hit objects

View File

@ -24,15 +24,17 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
[Cached] [Cached]
private readonly Column column; private readonly Column column;
[Cached]
private readonly StageDefinition stageDefinition = new StageDefinition(5);
public ColumnTestContainer(int column, ManiaAction action, bool showColumn = false) public ColumnTestContainer(int column, ManiaAction action, bool showColumn = false)
{ {
InternalChildren = new[] InternalChildren = new[]
{ {
this.column = new Column(column) this.column = new Column(column, false)
{ {
Action = { Value = action }, Action = { Value = action },
AccentColour = Color4.Orange, AccentColour = { Value = Color4.Orange },
ColumnType = column % 2 == 0 ? ColumnType.Even : ColumnType.Odd,
Alpha = showColumn ? 1 : 0 Alpha = showColumn ? 1 : 0
}, },
content = new ManiaInputManager(new ManiaRuleset().RulesetInfo, 4) content = new ManiaInputManager(new ManiaRuleset().RulesetInfo, 4)

View File

@ -9,6 +9,7 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Rulesets.UI.Scrolling.Algorithms; using osu.Game.Rulesets.UI.Scrolling.Algorithms;
using osu.Game.Tests.Visual; using osu.Game.Tests.Visual;
@ -24,6 +25,9 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
[Cached(Type = typeof(IScrollingInfo))] [Cached(Type = typeof(IScrollingInfo))]
private readonly TestScrollingInfo scrollingInfo = new TestScrollingInfo(); private readonly TestScrollingInfo scrollingInfo = new TestScrollingInfo();
[Cached]
private readonly StageDefinition stage = new StageDefinition(4);
protected override Ruleset CreateRulesetForSkinProvider() => new ManiaRuleset(); protected override Ruleset CreateRulesetForSkinProvider() => new ManiaRuleset();
protected ManiaSkinnableTestScene() protected ManiaSkinnableTestScene()

View File

@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
{ {
var stageDefinitions = new List<StageDefinition> var stageDefinitions = new List<StageDefinition>
{ {
new StageDefinition { Columns = 4 }, new StageDefinition(4),
}; };
SetContents(_ => new ManiaPlayfield(stageDefinitions).With(s => SetContents(_ => new ManiaPlayfield(stageDefinitions).With(s =>

View File

@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
{ {
stageDefinitions = new List<StageDefinition> stageDefinitions = new List<StageDefinition>
{ {
new StageDefinition { Columns = 2 } new StageDefinition(2)
}; };
SetContents(_ => new ManiaPlayfield(stageDefinitions)); SetContents(_ => new ManiaPlayfield(stageDefinitions));
@ -36,8 +36,8 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
{ {
stageDefinitions = new List<StageDefinition> stageDefinitions = new List<StageDefinition>
{ {
new StageDefinition { Columns = 2 }, new StageDefinition(2),
new StageDefinition { Columns = 2 } new StageDefinition(2)
}; };
SetContents(_ => new ManiaPlayfield(stageDefinitions)); SetContents(_ => new ManiaPlayfield(stageDefinitions));

View File

@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
return new ManiaInputManager(new ManiaRuleset().RulesetInfo, 4) return new ManiaInputManager(new ManiaRuleset().RulesetInfo, 4)
{ {
Child = new Stage(0, new StageDefinition { Columns = 4 }, ref normalAction, ref specialAction) Child = new Stage(0, new StageDefinition(4), ref normalAction, ref specialAction)
}; };
}); });
} }

View File

@ -5,7 +5,6 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.UI.Components; using osu.Game.Rulesets.Mania.UI.Components;
using osu.Game.Skinning; using osu.Game.Skinning;
@ -16,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
SetContents(_ => new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageBackground, stageDefinition: new StageDefinition { Columns = 4 }), SetContents(_ => new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageBackground),
_ => new DefaultStageBackground()) _ => new DefaultStageBackground())
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,

View File

@ -5,7 +5,6 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Skinning; using osu.Game.Skinning;
namespace osu.Game.Rulesets.Mania.Tests.Skinning namespace osu.Game.Rulesets.Mania.Tests.Skinning
@ -15,7 +14,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
SetContents(_ => new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageForeground, stageDefinition: new StageDefinition { Columns = 4 }), _ => null) SetContents(_ => new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageForeground), _ => null)
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,

View File

@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Mania.Tests
// | - | // | - |
// | | // | |
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 1 }); var beatmap = new ManiaBeatmap(new StageDefinition(1));
beatmap.HitObjects.Add(new Note { StartTime = 1000 }); beatmap.HitObjects.Add(new Note { StartTime = 1000 });
var generated = new ManiaAutoGenerator(beatmap).Generate(); var generated = new ManiaAutoGenerator(beatmap).Generate();
@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Mania.Tests
// | * | // | * |
// | | // | |
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 1 }); var beatmap = new ManiaBeatmap(new StageDefinition(1));
beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 }); beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 });
var generated = new ManiaAutoGenerator(beatmap).Generate(); var generated = new ManiaAutoGenerator(beatmap).Generate();
@ -70,7 +70,7 @@ namespace osu.Game.Rulesets.Mania.Tests
// | - | - | // | - | - |
// | | | // | | |
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 2 }); var beatmap = new ManiaBeatmap(new StageDefinition(2));
beatmap.HitObjects.Add(new Note { StartTime = 1000 }); beatmap.HitObjects.Add(new Note { StartTime = 1000 });
beatmap.HitObjects.Add(new Note { StartTime = 1000, Column = 1 }); beatmap.HitObjects.Add(new Note { StartTime = 1000, Column = 1 });
@ -92,7 +92,7 @@ namespace osu.Game.Rulesets.Mania.Tests
// | * | * | // | * | * |
// | | | // | | |
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 2 }); var beatmap = new ManiaBeatmap(new StageDefinition(2));
beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 }); beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 });
beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000, Column = 1 }); beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000, Column = 1 });
@ -115,7 +115,7 @@ namespace osu.Game.Rulesets.Mania.Tests
// | - | | // | - | |
// | | | // | | |
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 2 }); var beatmap = new ManiaBeatmap(new StageDefinition(2));
beatmap.HitObjects.Add(new Note { StartTime = 1000 }); beatmap.HitObjects.Add(new Note { StartTime = 1000 });
beatmap.HitObjects.Add(new Note { StartTime = 2000, Column = 1 }); beatmap.HitObjects.Add(new Note { StartTime = 2000, Column = 1 });
@ -142,7 +142,7 @@ namespace osu.Game.Rulesets.Mania.Tests
// | * | | // | * | |
// | | | // | | |
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 2 }); var beatmap = new ManiaBeatmap(new StageDefinition(2));
beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 }); beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 });
beatmap.HitObjects.Add(new HoldNote { StartTime = 2000, Duration = 2000, Column = 1 }); beatmap.HitObjects.Add(new HoldNote { StartTime = 2000, Duration = 2000, Column = 1 });
@ -169,7 +169,7 @@ namespace osu.Game.Rulesets.Mania.Tests
// | * | | // | * | |
// | | | // | | |
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 2 }); var beatmap = new ManiaBeatmap(new StageDefinition(2));
beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 }); beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 });
beatmap.HitObjects.Add(new Note { StartTime = 3000, Column = 1 }); beatmap.HitObjects.Add(new Note { StartTime = 3000, Column = 1 });

View File

@ -11,6 +11,7 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mania.UI;
@ -28,6 +29,9 @@ namespace osu.Game.Rulesets.Mania.Tests
[Cached(typeof(IReadOnlyList<Mod>))] [Cached(typeof(IReadOnlyList<Mod>))]
private IReadOnlyList<Mod> mods { get; set; } = Array.Empty<Mod>(); private IReadOnlyList<Mod> mods { get; set; } = Array.Empty<Mod>();
[Cached]
private readonly StageDefinition stage = new StageDefinition(1);
private readonly List<Column> columns = new List<Column>(); private readonly List<Column> columns = new List<Column>();
public TestSceneColumn() public TestSceneColumn()
@ -84,12 +88,12 @@ namespace osu.Game.Rulesets.Mania.Tests
private Drawable createColumn(ScrollingDirection direction, ManiaAction action, int index) private Drawable createColumn(ScrollingDirection direction, ManiaAction action, int index)
{ {
var column = new Column(index) var column = new Column(index, false)
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Height = 0.85f, Height = 0.85f,
AccentColour = Color4.OrangeRed, AccentColour = { Value = Color4.OrangeRed },
Action = { Value = action }, Action = { Value = action },
}; };

View File

@ -4,11 +4,13 @@
#nullable disable #nullable disable
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mania.UI;
@ -24,6 +26,9 @@ namespace osu.Game.Rulesets.Mania.Tests
private Column column; private Column column;
[Cached]
private readonly StageDefinition stage = new StageDefinition(1);
[SetUp] [SetUp]
public void SetUp() => Schedule(() => public void SetUp() => Schedule(() =>
{ {
@ -35,11 +40,11 @@ namespace osu.Game.Rulesets.Mania.Tests
RelativeSizeAxes = Axes.Y, RelativeSizeAxes = Axes.Y,
TimeRange = 2000, TimeRange = 2000,
Clock = new FramedClock(clock), Clock = new FramedClock(clock),
Child = column = new Column(0) Child = column = new Column(0, false)
{ {
Action = { Value = ManiaAction.Key1 }, Action = { Value = ManiaAction.Key1 },
Height = 0.85f, Height = 0.85f,
AccentColour = Color4.Gray AccentColour = { Value = Color4.Gray },
}, },
}; };
}); });

View File

@ -141,7 +141,7 @@ namespace osu.Game.Rulesets.Mania.Tests
{ {
AddStep("load player", () => AddStep("load player", () =>
{ {
Beatmap.Value = CreateWorkingBeatmap(new ManiaBeatmap(new StageDefinition { Columns = 4 }) Beatmap.Value = CreateWorkingBeatmap(new ManiaBeatmap(new StageDefinition(4))
{ {
HitObjects = hitObjects, HitObjects = hitObjects,
BeatmapInfo = BeatmapInfo =

View File

@ -135,7 +135,7 @@ namespace osu.Game.Rulesets.Mania.Tests
{ {
var specialAction = ManiaAction.Special1; var specialAction = ManiaAction.Special1;
var stage = new Stage(0, new StageDefinition { Columns = 2 }, ref action, ref specialAction); var stage = new Stage(0, new StageDefinition(2), ref action, ref specialAction);
stages.Add(stage); stages.Add(stage);
return new ScrollingTestContainer(direction) return new ScrollingTestContainer(direction)

View File

@ -85,7 +85,7 @@ namespace osu.Game.Rulesets.Mania.Tests
{ {
const double beat_length = 500; const double beat_length = 500;
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 1 }) var beatmap = new ManiaBeatmap(new StageDefinition(1))
{ {
HitObjects = HitObjects =
{ {

View File

@ -1,14 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
namespace osu.Game.Rulesets.Mania.Beatmaps
{
public enum ColumnType
{
Even,
Odd,
Special
}
}

View File

@ -3,6 +3,7 @@
#nullable disable #nullable disable
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
@ -60,5 +61,18 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
}, },
}; };
} }
public StageDefinition GetStageForColumnIndex(int column)
{
foreach (var stage in Stages)
{
if (column < stage.Columns)
return stage;
column -= stage.Columns;
}
throw new ArgumentOutOfRangeException(nameof(column), "Provided index exceeds all available stages");
}
} }
} }

View File

@ -93,10 +93,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
protected override Beatmap<ManiaHitObject> CreateBeatmap() protected override Beatmap<ManiaHitObject> CreateBeatmap()
{ {
beatmap = new ManiaBeatmap(new StageDefinition { Columns = TargetColumns }, originalTargetColumns); beatmap = new ManiaBeatmap(new StageDefinition(TargetColumns), originalTargetColumns);
if (Dual) if (Dual)
beatmap.Stages.Add(new StageDefinition { Columns = TargetColumns }); beatmap.Stages.Add(new StageDefinition(TargetColumns));
return beatmap; return beatmap;
} }

View File

@ -11,32 +11,26 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
/// <summary> /// <summary>
/// Defines properties for each stage in a <see cref="ManiaPlayfield"/>. /// Defines properties for each stage in a <see cref="ManiaPlayfield"/>.
/// </summary> /// </summary>
public struct StageDefinition public class StageDefinition
{ {
/// <summary> /// <summary>
/// The number of <see cref="Column"/>s which this stage contains. /// The number of <see cref="Column"/>s which this stage contains.
/// </summary> /// </summary>
public int Columns; public readonly int Columns;
public StageDefinition(int columns)
{
if (columns < 1)
throw new ArgumentException("Column count must be above zero.", nameof(columns));
Columns = columns;
}
/// <summary> /// <summary>
/// Whether the column index is a special column for this stage. /// Whether the column index is a special column for this stage.
/// </summary> /// </summary>
/// <param name="column">The 0-based column index.</param> /// <param name="column">The 0-based column index.</param>
/// <returns>Whether the column is a special column.</returns> /// <returns>Whether the column is a special column.</returns>
public readonly bool IsSpecialColumn(int column) => Columns % 2 == 1 && column == Columns / 2; public bool IsSpecialColumn(int column) => Columns % 2 == 1 && column == Columns / 2;
/// <summary>
/// Get the type of column given a column index.
/// </summary>
/// <param name="column">The 0-based column index.</param>
/// <returns>The type of the column.</returns>
public readonly ColumnType GetTypeOfColumn(int column)
{
if (IsSpecialColumn(column))
return ColumnType.Special;
int distanceToEdge = Math.Min(column, (Columns - 1) - column);
return distanceToEdge % 2 == 0 ? ColumnType.Odd : ColumnType.Even;
}
} }
} }

View File

@ -27,6 +27,7 @@ using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Rulesets.Mania.Replays; using osu.Game.Rulesets.Mania.Replays;
using osu.Game.Rulesets.Mania.Scoring; using osu.Game.Rulesets.Mania.Scoring;
using osu.Game.Rulesets.Mania.Skinning.Argon; using osu.Game.Rulesets.Mania.Skinning.Argon;
using osu.Game.Rulesets.Mania.Skinning.Default;
using osu.Game.Rulesets.Mania.Skinning.Legacy; using osu.Game.Rulesets.Mania.Skinning.Legacy;
using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
@ -67,11 +68,17 @@ namespace osu.Game.Rulesets.Mania
{ {
switch (skin) switch (skin)
{ {
case LegacySkin: case TrianglesSkin:
return new ManiaLegacySkinTransformer(skin, beatmap); return new ManiaTrianglesSkinTransformer(skin, beatmap);
case ArgonSkin: case ArgonSkin:
return new ManiaArgonSkinTransformer(skin); return new ManiaArgonSkinTransformer(skin, beatmap);
case DefaultLegacySkin:
return new ManiaClassicSkinTransformer(skin, beatmap);
case LegacySkin:
return new ManiaLegacySkinTransformer(skin, beatmap);
} }
return null; return null;

View File

@ -3,29 +3,19 @@
#nullable disable #nullable disable
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Skinning; using osu.Game.Skinning;
namespace osu.Game.Rulesets.Mania namespace osu.Game.Rulesets.Mania
{ {
public class ManiaSkinComponent : GameplaySkinComponent<ManiaSkinComponents> public class ManiaSkinComponent : GameplaySkinComponent<ManiaSkinComponents>
{ {
/// <summary>
/// The intended <see cref="StageDefinition"/> for this component.
/// May be null if the component is not a direct member of a <see cref="Stage"/>.
/// </summary>
public readonly StageDefinition? StageDefinition;
/// <summary> /// <summary>
/// Creates a new <see cref="ManiaSkinComponent"/>. /// Creates a new <see cref="ManiaSkinComponent"/>.
/// </summary> /// </summary>
/// <param name="component">The component.</param> /// <param name="component">The component.</param>
/// <param name="stageDefinition">The intended <see cref="StageDefinition"/> for this component. May be null if the component is not a direct member of a <see cref="Stage"/>.</param> public ManiaSkinComponent(ManiaSkinComponents component)
public ManiaSkinComponent(ManiaSkinComponents component, StageDefinition? stageDefinition = null)
: base(component) : base(component)
{ {
StageDefinition = stageDefinition;
} }
protected override string RulesetPrefix => ManiaRuleset.SHORT_NAME; protected override string RulesetPrefix => ManiaRuleset.SHORT_NAME;

View File

@ -30,6 +30,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon
private Container<Circle> bottomIcon = null!; private Container<Circle> bottomIcon = null!;
private CircularContainer topIcon = null!; private CircularContainer topIcon = null!;
private Bindable<Color4> accentColour = null!;
[Resolved] [Resolved]
private Column column { get; set; } = null!; private Column column { get; set; } = null!;
@ -55,7 +57,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon
{ {
Name = "Key gradient", Name = "Key gradient",
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = column.AccentColour.Darken(0.6f),
}, },
hitTargetLine = new Circle hitTargetLine = new Circle
{ {
@ -80,7 +81,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon
Anchor = Anchor.BottomCentre, Anchor = Anchor.BottomCentre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Blending = BlendingParameters.Additive, Blending = BlendingParameters.Additive,
Colour = column.AccentColour,
Y = icon_vertical_offset, Y = icon_vertical_offset,
Children = new[] Children = new[]
{ {
@ -134,6 +134,13 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon
direction.BindTo(scrollingInfo.Direction); direction.BindTo(scrollingInfo.Direction);
direction.BindValueChanged(onDirectionChanged, true); direction.BindValueChanged(onDirectionChanged, true);
accentColour = column.AccentColour.GetBoundCopy();
accentColour.BindValueChanged(colour =>
{
background.Colour = colour.NewValue.Darken(0.6f);
bottomIcon.Colour = colour.NewValue;
}, true);
} }
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction) private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
@ -159,11 +166,11 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon
if (e.Action != column.Action.Value) return false; if (e.Action != column.Action.Value) return false;
const double lighting_fade_in_duration = 50; const double lighting_fade_in_duration = 50;
Color4 lightingColour = column.AccentColour.Lighten(0.9f); Color4 lightingColour = accentColour.Value.Lighten(0.9f);
background background
.FadeColour(column.AccentColour.Lighten(0.4f), 40).Then() .FadeColour(accentColour.Value.Lighten(0.4f), 40).Then()
.FadeColour(column.AccentColour, 150, Easing.OutQuint); .FadeColour(accentColour.Value, 150, Easing.OutQuint);
hitTargetLine.FadeColour(Color4.White, lighting_fade_in_duration, Easing.OutQuint); hitTargetLine.FadeColour(Color4.White, lighting_fade_in_duration, Easing.OutQuint);
hitTargetLine.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters hitTargetLine.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters
@ -201,9 +208,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon
if (e.Action != column.Action.Value) return; if (e.Action != column.Action.Value) return;
const double lighting_fade_out_duration = 300; const double lighting_fade_out_duration = 300;
Color4 lightingColour = column.AccentColour.Lighten(0.9f).Opacity(0); Color4 lightingColour = accentColour.Value.Lighten(0.9f).Opacity(0);
background.FadeColour(column.AccentColour.Darken(0.6f), lighting_fade_out_duration, Easing.OutQuint); background.FadeColour(accentColour.Value.Darken(0.6f), lighting_fade_out_duration, Easing.OutQuint);
topIcon.ScaleTo(1f, 200, Easing.OutQuint); topIcon.ScaleTo(1f, 200, Easing.OutQuint);
topIcon.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters topIcon.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters
@ -221,7 +228,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon
Radius = 30, Radius = 30,
}, lighting_fade_out_duration, Easing.OutQuint); }, lighting_fade_out_duration, Easing.OutQuint);
bottomIcon.FadeColour(column.AccentColour, lighting_fade_out_duration, Easing.OutQuint); bottomIcon.FadeColour(accentColour.Value, lighting_fade_out_duration, Easing.OutQuint);
foreach (var circle in bottomIcon) foreach (var circle in bottomIcon)
{ {

View File

@ -1,16 +1,24 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Skinning; using osu.Game.Skinning;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Mania.Skinning.Argon namespace osu.Game.Rulesets.Mania.Skinning.Argon
{ {
public class ManiaArgonSkinTransformer : SkinTransformer public class ManiaArgonSkinTransformer : SkinTransformer
{ {
public ManiaArgonSkinTransformer(ISkin skin) private readonly ManiaBeatmap beatmap;
public ManiaArgonSkinTransformer(ISkin skin, IBeatmap beatmap)
: base(skin) : base(skin)
{ {
this.beatmap = (ManiaBeatmap)beatmap;
} }
public override Drawable? GetDrawableComponent(ISkinComponent component) public override Drawable? GetDrawableComponent(ISkinComponent component)
@ -33,5 +41,26 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon
return base.GetDrawableComponent(component); return base.GetDrawableComponent(component);
} }
public override IBindable<TValue>? GetConfig<TLookup, TValue>(TLookup lookup)
{
if (lookup is ManiaSkinConfigurationLookup maniaLookup)
{
switch (maniaLookup.Lookup)
{
case LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour:
int column = maniaLookup.ColumnIndex ?? 0;
var stage = beatmap.GetStageForColumnIndex(column);
if (stage.IsSpecialColumn(column))
return SkinUtils.As<TValue>(new Bindable<Color4>(Color4.Yellow));
// TODO: Add actual colours.
return SkinUtils.As<TValue>(new Bindable<Color4>(new Color4(RNG.NextSingle() * 0.5f, RNG.NextSingle() * 0.5f, RNG.NextSingle() * 0.5f, 1)));
}
}
return base.GetConfig<TLookup, TValue>(lookup);
}
} }
} }

View File

@ -0,0 +1,49 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Bindables;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Skinning;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Mania.Skinning.Default
{
public class ManiaTrianglesSkinTransformer : SkinTransformer
{
private readonly ManiaBeatmap beatmap;
public ManiaTrianglesSkinTransformer(ISkin skin, IBeatmap beatmap)
: base(skin)
{
this.beatmap = (ManiaBeatmap)beatmap;
}
private readonly Color4 colourEven = new Color4(6, 84, 0, 255);
private readonly Color4 colourOdd = new Color4(94, 0, 57, 255);
private readonly Color4 colourSpecial = new Color4(0, 48, 63, 255);
public override IBindable<TValue>? GetConfig<TLookup, TValue>(TLookup lookup)
{
if (lookup is ManiaSkinConfigurationLookup maniaLookup)
{
switch (maniaLookup.Lookup)
{
case LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour:
int column = maniaLookup.ColumnIndex ?? 0;
var stage = beatmap.GetStageForColumnIndex(column);
if (stage.IsSpecialColumn(column))
return SkinUtils.As<TValue>(new Bindable<Color4>(colourSpecial));
int distanceToEdge = Math.Min(column, (stage.Columns - 1) - column);
return SkinUtils.As<TValue>(new Bindable<Color4>(distanceToEdge % 2 == 0 ? colourOdd : colourEven));
}
}
return base.GetConfig<TLookup, TValue>(lookup);
}
}
}

View File

@ -3,6 +3,7 @@
#nullable disable #nullable disable
using System;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -20,6 +21,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
[Resolved] [Resolved]
protected Column Column { get; private set; } protected Column Column { get; private set; }
[Resolved]
private StageDefinition stage { get; set; }
/// <summary> /// <summary>
/// The column type identifier to use for texture lookups, in the case of no user-provided configuration. /// The column type identifier to use for texture lookups, in the case of no user-provided configuration.
/// </summary> /// </summary>
@ -28,19 +32,12 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
switch (Column.ColumnType) if (Column.IsSpecial)
FallbackColumnIndex = "S";
else
{ {
case ColumnType.Special: int distanceToEdge = Math.Min(Column.Index, (stage.Columns - 1) - Column.Index);
FallbackColumnIndex = "S"; FallbackColumnIndex = distanceToEdge % 2 == 0 ? "1" : "2";
break;
case ColumnType.Odd:
FallbackColumnIndex = "1";
break;
case ColumnType.Even:
FallbackColumnIndex = "2";
break;
} }
} }

View File

@ -18,20 +18,17 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
{ {
public class LegacyStageBackground : CompositeDrawable public class LegacyStageBackground : CompositeDrawable
{ {
private readonly StageDefinition stageDefinition;
private Drawable leftSprite; private Drawable leftSprite;
private Drawable rightSprite; private Drawable rightSprite;
private ColumnFlow<Drawable> columnBackgrounds; private ColumnFlow<Drawable> columnBackgrounds;
public LegacyStageBackground(StageDefinition stageDefinition) public LegacyStageBackground()
{ {
this.stageDefinition = stageDefinition;
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(ISkinSource skin) private void load(ISkinSource skin, StageDefinition stageDefinition)
{ {
string leftImage = skin.GetManiaSkinConfig<string>(LegacyManiaSkinConfigurationLookups.LeftStageImage)?.Value string leftImage = skin.GetManiaSkinConfig<string>(LegacyManiaSkinConfigurationLookups.LeftStageImage)?.Value
?? "mania-stage-left"; ?? "mania-stage-left";

View File

@ -0,0 +1,38 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Bindables;
using osu.Game.Beatmaps;
using osu.Game.Skinning;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
{
public class ManiaClassicSkinTransformer : ManiaLegacySkinTransformer
{
public ManiaClassicSkinTransformer(ISkin skin, IBeatmap beatmap)
: base(skin, beatmap)
{
}
public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
{
if (lookup is ManiaSkinConfigurationLookup maniaLookup)
{
var baseLookup = base.GetConfig<TLookup, TValue>(lookup);
if (baseLookup != null)
return baseLookup;
// default provisioning.
switch (maniaLookup.Lookup)
{
case LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour:
return SkinUtils.As<TValue>(new Bindable<Color4>(Color4.Black));
}
}
return base.GetConfig<TLookup, TValue>(lookup);
}
}
}

View File

@ -5,7 +5,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using osu.Framework.Audio.Sample; using osu.Framework.Audio.Sample;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -20,8 +19,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
{ {
public class ManiaLegacySkinTransformer : LegacySkinTransformer public class ManiaLegacySkinTransformer : LegacySkinTransformer
{ {
private readonly ManiaBeatmap beatmap;
/// <summary> /// <summary>
/// Mapping of <see cref="HitResult"/> to their corresponding /// Mapping of <see cref="HitResult"/> to their corresponding
/// <see cref="LegacyManiaSkinConfigurationLookups"/> value. /// <see cref="LegacyManiaSkinConfigurationLookups"/> value.
@ -60,6 +57,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
/// </summary> /// </summary>
private readonly Lazy<bool> hasKeyTexture; private readonly Lazy<bool> hasKeyTexture;
private readonly ManiaBeatmap beatmap;
public ManiaLegacySkinTransformer(ISkin skin, IBeatmap beatmap) public ManiaLegacySkinTransformer(ISkin skin, IBeatmap beatmap)
: base(skin) : base(skin)
{ {
@ -113,8 +112,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
return new LegacyHitExplosion(); return new LegacyHitExplosion();
case ManiaSkinComponents.StageBackground: case ManiaSkinComponents.StageBackground:
Debug.Assert(maniaComponent.StageDefinition != null); return new LegacyStageBackground();
return new LegacyStageBackground(maniaComponent.StageDefinition.Value);
case ManiaSkinComponents.StageForeground: case ManiaSkinComponents.StageForeground:
return new LegacyStageForeground(); return new LegacyStageForeground();
@ -151,7 +149,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
{ {
if (lookup is ManiaSkinConfigurationLookup maniaLookup) if (lookup is ManiaSkinConfigurationLookup maniaLookup)
return base.GetConfig<LegacyManiaSkinConfigurationLookup, TValue>(new LegacyManiaSkinConfigurationLookup(beatmap.TotalColumns, maniaLookup.Lookup, maniaLookup.TargetColumn)); {
return base.GetConfig<LegacyManiaSkinConfigurationLookup, TValue>(new LegacyManiaSkinConfigurationLookup(beatmap.TotalColumns, maniaLookup.Lookup, maniaLookup.ColumnIndex));
}
return base.GetConfig<TLookup, TValue>(lookup); return base.GetConfig<TLookup, TValue>(lookup);
} }

View File

@ -15,9 +15,9 @@ namespace osu.Game.Rulesets.Mania.Skinning
/// </summary> /// </summary>
/// <param name="skin">The skin from which configuration is retrieved.</param> /// <param name="skin">The skin from which configuration is retrieved.</param>
/// <param name="lookup">The value to retrieve.</param> /// <param name="lookup">The value to retrieve.</param>
/// <param name="index">If not null, denotes the index of the column to which the entry applies.</param> /// <param name="columnIndex">If not null, denotes the index of the column to which the entry applies.</param>
public static IBindable<T> GetManiaSkinConfig<T>(this ISkin skin, LegacyManiaSkinConfigurationLookups lookup, int? index = null) public static IBindable<T> GetManiaSkinConfig<T>(this ISkin skin, LegacyManiaSkinConfigurationLookups lookup, int? columnIndex = null)
=> skin.GetConfig<ManiaSkinConfigurationLookup, T>( => skin.GetConfig<ManiaSkinConfigurationLookup, T>(
new ManiaSkinConfigurationLookup(lookup, index)); new ManiaSkinConfigurationLookup(lookup, columnIndex));
} }
} }

View File

@ -16,20 +16,21 @@ namespace osu.Game.Rulesets.Mania.Skinning
public readonly LegacyManiaSkinConfigurationLookups Lookup; public readonly LegacyManiaSkinConfigurationLookups Lookup;
/// <summary> /// <summary>
/// The intended <see cref="Column"/> index for the configuration. /// The column which is being looked up.
/// May be null if the configuration does not apply to a <see cref="Column"/>. /// May be null if the configuration does not apply to a <see cref="Column"/>.
/// Note that this is the absolute index across all stages.
/// </summary> /// </summary>
public readonly int? TargetColumn; public readonly int? ColumnIndex;
/// <summary> /// <summary>
/// Creates a new <see cref="ManiaSkinConfigurationLookup"/>. /// Creates a new <see cref="ManiaSkinConfigurationLookup"/>.
/// </summary> /// </summary>
/// <param name="lookup">The lookup value.</param> /// <param name="lookup">The lookup value.</param>
/// <param name="targetColumn">The intended <see cref="Column"/> index for the configuration. May be null if the configuration does not apply to a <see cref="Column"/>.</param> /// <param name="columnIndex">The intended <see cref="Column"/> index for the configuration. May be null if the configuration does not apply to a <see cref="Column"/>.</param>
public ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups lookup, int? targetColumn = null) public ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups lookup, int? columnIndex = null)
{ {
Lookup = lookup; Lookup = lookup;
TargetColumn = targetColumn; ColumnIndex = columnIndex;
} }
} }
} }

View File

@ -3,30 +3,29 @@
#nullable disable #nullable disable
using osuTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Pooling; using osu.Framework.Graphics.Pooling;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Skinning;
using osu.Game.Rulesets.Mania.UI.Components; using osu.Game.Rulesets.Mania.UI.Components;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Skinning; using osu.Game.Skinning;
using osuTK; using osuTK;
using osu.Game.Rulesets.Mania.Beatmaps; using osuTK.Graphics;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mania.UI namespace osu.Game.Rulesets.Mania.UI
{ {
[Cached] [Cached]
public class Column : ScrollingPlayfield, IKeyBindingHandler<ManiaAction>, IHasAccentColour public class Column : ScrollingPlayfield, IKeyBindingHandler<ManiaAction>
{ {
public const float COLUMN_WIDTH = 80; public const float COLUMN_WIDTH = 80;
public const float SPECIAL_COLUMN_WIDTH = 70; public const float SPECIAL_COLUMN_WIDTH = 70;
@ -39,20 +38,48 @@ namespace osu.Game.Rulesets.Mania.UI
public readonly Bindable<ManiaAction> Action = new Bindable<ManiaAction>(); public readonly Bindable<ManiaAction> Action = new Bindable<ManiaAction>();
public readonly ColumnHitObjectArea HitObjectArea; public readonly ColumnHitObjectArea HitObjectArea;
internal readonly Container TopLevelContainer; internal readonly Container TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both };
private readonly DrawablePool<PoolableHitExplosion> hitExplosionPool; private DrawablePool<PoolableHitExplosion> hitExplosionPool;
private readonly OrderedHitPolicy hitPolicy; private readonly OrderedHitPolicy hitPolicy;
public Container UnderlayElements => HitObjectArea.UnderlayElements; public Container UnderlayElements => HitObjectArea.UnderlayElements;
private readonly GameplaySampleTriggerSource sampleTriggerSource; private GameplaySampleTriggerSource sampleTriggerSource;
public Column(int index) /// <summary>
/// Whether this is a special (ie. scratch) column.
/// </summary>
public readonly bool IsSpecial;
public readonly Bindable<Color4> AccentColour = new Bindable<Color4>(Color4.Black);
public Column(int index, bool isSpecial)
{ {
Index = index; Index = index;
IsSpecial = isSpecial;
RelativeSizeAxes = Axes.Y; RelativeSizeAxes = Axes.Y;
Width = COLUMN_WIDTH; Width = COLUMN_WIDTH;
hitPolicy = new OrderedHitPolicy(HitObjectContainer);
HitObjectArea = new ColumnHitObjectArea(HitObjectContainer) { RelativeSizeAxes = Axes.Both };
}
[Resolved]
private ISkinSource skin { get; set; }
[BackgroundDependencyLoader]
private void load()
{
skin.SourceChanged += onSourceChanged;
onSourceChanged();
AccentColour.BindValueChanged(colour =>
{
// Manual transfer as hit objects may be moved between column and unbinding is non-trivial.
foreach (var obj in HitObjectContainer.Objects)
obj.AccentColour.Value = colour.NewValue;
}, true);
Drawable background = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground()) Drawable background = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground())
{ {
RelativeSizeAxes = Axes.Both RelativeSizeAxes = Axes.Both
@ -64,18 +91,16 @@ namespace osu.Game.Rulesets.Mania.UI
sampleTriggerSource = new GameplaySampleTriggerSource(HitObjectContainer), sampleTriggerSource = new GameplaySampleTriggerSource(HitObjectContainer),
// For input purposes, the background is added at the highest depth, but is then proxied back below all other elements // For input purposes, the background is added at the highest depth, but is then proxied back below all other elements
background.CreateProxy(), background.CreateProxy(),
HitObjectArea = new ColumnHitObjectArea(HitObjectContainer) { RelativeSizeAxes = Axes.Both }, HitObjectArea,
new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea), _ => new DefaultKeyArea()) new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea), _ => new DefaultKeyArea())
{ {
RelativeSizeAxes = Axes.Both RelativeSizeAxes = Axes.Both
}, },
background, background,
TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both }, TopLevelContainer,
new ColumnTouchInputArea(this) new ColumnTouchInputArea(this)
}; };
hitPolicy = new OrderedHitPolicy(HitObjectContainer);
TopLevelContainer.Add(HitObjectArea.Explosions.CreateProxy()); TopLevelContainer.Add(HitObjectArea.Explosions.CreateProxy());
RegisterPool<Note, DrawableNote>(10, 50); RegisterPool<Note, DrawableNote>(10, 50);
@ -85,18 +110,24 @@ namespace osu.Game.Rulesets.Mania.UI
RegisterPool<HoldNoteTick, DrawableHoldNoteTick>(50, 250); RegisterPool<HoldNoteTick, DrawableHoldNoteTick>(50, 250);
} }
private void onSourceChanged()
{
AccentColour.Value = skin.GetManiaSkinConfig<Color4>(LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour, Index)?.Value ?? Color4.Black;
}
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
NewResult += OnNewResult; NewResult += OnNewResult;
} }
public ColumnType ColumnType { get; set; } protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
public bool IsSpecial => ColumnType == ColumnType.Special; if (skin != null)
skin.SourceChanged -= onSourceChanged;
public Color4 AccentColour { get; set; } }
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{ {
@ -111,7 +142,7 @@ namespace osu.Game.Rulesets.Mania.UI
DrawableManiaHitObject maniaObject = (DrawableManiaHitObject)drawableHitObject; DrawableManiaHitObject maniaObject = (DrawableManiaHitObject)drawableHitObject;
maniaObject.AccentColour.Value = AccentColour; maniaObject.AccentColour.Value = AccentColour.Value;
maniaObject.CheckHittable = hitPolicy.IsHittable; maniaObject.CheckHittable = hitPolicy.IsHittable;
} }

View File

@ -1,110 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Rulesets.UI.Scrolling;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Mania.UI.Components
{
public class ColumnBackground : CompositeDrawable, IKeyBindingHandler<ManiaAction>, IHasAccentColour
{
private readonly IBindable<ManiaAction> action = new Bindable<ManiaAction>();
private Box background;
private Box backgroundOverlay;
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
[BackgroundDependencyLoader]
private void load(IBindable<ManiaAction> action, IScrollingInfo scrollingInfo)
{
this.action.BindTo(action);
InternalChildren = new[]
{
background = new Box
{
Name = "Background",
RelativeSizeAxes = Axes.Both,
},
backgroundOverlay = new Box
{
Name = "Background Gradient Overlay",
RelativeSizeAxes = Axes.Both,
Height = 0.5f,
Blending = BlendingParameters.Additive,
Alpha = 0
}
};
direction.BindTo(scrollingInfo.Direction);
direction.BindValueChanged(dir =>
{
backgroundOverlay.Anchor = backgroundOverlay.Origin = dir.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft;
updateColours();
}, true);
}
protected override void LoadComplete()
{
base.LoadComplete();
updateColours();
}
private Color4 accentColour;
public Color4 AccentColour
{
get => accentColour;
set
{
if (accentColour == value)
return;
accentColour = value;
updateColours();
}
}
private void updateColours()
{
if (!IsLoaded)
return;
background.Colour = AccentColour.Darken(5);
var brightPoint = AccentColour.Opacity(0.6f);
var dimPoint = AccentColour.Opacity(0);
backgroundOverlay.Colour = ColourInfo.GradientVertical(
direction.Value == ScrollingDirection.Up ? brightPoint : dimPoint,
direction.Value == ScrollingDirection.Up ? dimPoint : brightPoint);
}
public bool OnPressed(KeyBindingPressEvent<ManiaAction> e)
{
if (e.Action == action.Value)
backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint);
return false;
}
public void OnReleased(KeyBindingReleaseEvent<ManiaAction> e)
{
if (e.Action == action.Value)
backgroundOverlay.FadeTo(0, 250, Easing.OutQuint);
}
}
}

View File

@ -30,6 +30,8 @@ namespace osu.Game.Rulesets.Mania.UI.Components
[Resolved] [Resolved]
private Column column { get; set; } private Column column { get; set; }
private Bindable<Color4> accentColour;
public DefaultColumnBackground() public DefaultColumnBackground()
{ {
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
@ -55,9 +57,13 @@ namespace osu.Game.Rulesets.Mania.UI.Components
} }
}; };
background.Colour = column.AccentColour.Darken(5); accentColour = column.AccentColour.GetBoundCopy();
brightColour = column.AccentColour.Opacity(0.6f); accentColour.BindValueChanged(colour =>
dimColour = column.AccentColour.Opacity(0); {
background.Colour = colour.NewValue.Darken(5);
brightColour = colour.NewValue.Opacity(0.6f);
dimColour = colour.NewValue.Opacity(0);
}, true);
direction.BindTo(scrollingInfo.Direction); direction.BindTo(scrollingInfo.Direction);
direction.BindValueChanged(onDirectionChanged, true); direction.BindValueChanged(onDirectionChanged, true);

View File

@ -25,6 +25,8 @@ namespace osu.Game.Rulesets.Mania.UI.Components
private Container hitTargetLine; private Container hitTargetLine;
private Drawable hitTargetBar; private Drawable hitTargetBar;
private Bindable<Color4> accentColour;
[Resolved] [Resolved]
private Column column { get; set; } private Column column { get; set; }
@ -54,12 +56,16 @@ namespace osu.Game.Rulesets.Mania.UI.Components
}, },
}; };
hitTargetLine.EdgeEffect = new EdgeEffectParameters accentColour = column.AccentColour.GetBoundCopy();
accentColour.BindValueChanged(colour =>
{ {
Type = EdgeEffectType.Glow, hitTargetLine.EdgeEffect = new EdgeEffectParameters
Radius = 5, {
Colour = column.AccentColour.Opacity(0.5f), Type = EdgeEffectType.Glow,
}; Radius = 5,
Colour = colour.NewValue.Opacity(0.5f),
};
}, true);
direction.BindTo(scrollingInfo.Direction); direction.BindTo(scrollingInfo.Direction);
direction.BindValueChanged(onDirectionChanged, true); direction.BindValueChanged(onDirectionChanged, true);

View File

@ -30,6 +30,8 @@ namespace osu.Game.Rulesets.Mania.UI.Components
private Container keyIcon; private Container keyIcon;
private Drawable gradient; private Drawable gradient;
private Bindable<Color4> accentColour;
[Resolved] [Resolved]
private Column column { get; set; } private Column column { get; set; }
@ -75,15 +77,19 @@ namespace osu.Game.Rulesets.Mania.UI.Components
} }
}; };
keyIcon.EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Radius = 5,
Colour = column.AccentColour.Opacity(0.5f),
};
direction.BindTo(scrollingInfo.Direction); direction.BindTo(scrollingInfo.Direction);
direction.BindValueChanged(onDirectionChanged, true); direction.BindValueChanged(onDirectionChanged, true);
accentColour = column.AccentColour.GetBoundCopy();
accentColour.BindValueChanged(colour =>
{
keyIcon.EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Radius = 5,
Colour = colour.NewValue.Opacity(0.5f),
};
}, true);
} }
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction) private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)

View File

@ -32,6 +32,10 @@ namespace osu.Game.Rulesets.Mania.UI
private CircularContainer largeFaint; private CircularContainer largeFaint;
private CircularContainer mainGlow1; private CircularContainer mainGlow1;
private CircularContainer mainGlow2;
private CircularContainer mainGlow3;
private Bindable<Color4> accentColour;
public DefaultHitExplosion() public DefaultHitExplosion()
{ {
@ -48,8 +52,6 @@ namespace osu.Game.Rulesets.Mania.UI
const float roundness = 80; const float roundness = 80;
const float initial_height = 10; const float initial_height = 10;
var colour = Interpolation.ValueAt(0.4f, column.AccentColour, Color4.White, 0, 1);
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
largeFaint = new CircularContainer largeFaint = new CircularContainer
@ -61,13 +63,6 @@ namespace osu.Game.Rulesets.Mania.UI
// we want our size to be very small so the glow dominates it. // we want our size to be very small so the glow dominates it.
Size = new Vector2(default_large_faint_size), Size = new Vector2(default_large_faint_size),
Blending = BlendingParameters.Additive, Blending = BlendingParameters.Additive,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = Interpolation.ValueAt(0.1f, column.AccentColour, Color4.White, 0, 1).Opacity(0.3f),
Roundness = 160,
Radius = 200,
},
}, },
mainGlow1 = new CircularContainer mainGlow1 = new CircularContainer
{ {
@ -76,15 +71,8 @@ namespace osu.Game.Rulesets.Mania.UI
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Masking = true, Masking = true,
Blending = BlendingParameters.Additive, Blending = BlendingParameters.Additive,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = Interpolation.ValueAt(0.6f, column.AccentColour, Color4.White, 0, 1),
Roundness = 20,
Radius = 50,
},
}, },
new CircularContainer mainGlow2 = new CircularContainer
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
@ -93,15 +81,8 @@ namespace osu.Game.Rulesets.Mania.UI
Size = new Vector2(0.01f, initial_height), Size = new Vector2(0.01f, initial_height),
Blending = BlendingParameters.Additive, Blending = BlendingParameters.Additive,
Rotation = RNG.NextSingle(-angle_variance, angle_variance), Rotation = RNG.NextSingle(-angle_variance, angle_variance),
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = colour,
Roundness = roundness,
Radius = 40,
},
}, },
new CircularContainer mainGlow3 = new CircularContainer
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
@ -110,18 +91,44 @@ namespace osu.Game.Rulesets.Mania.UI
Size = new Vector2(0.01f, initial_height), Size = new Vector2(0.01f, initial_height),
Blending = BlendingParameters.Additive, Blending = BlendingParameters.Additive,
Rotation = RNG.NextSingle(-angle_variance, angle_variance), Rotation = RNG.NextSingle(-angle_variance, angle_variance),
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = colour,
Roundness = roundness,
Radius = 40,
},
} }
}; };
direction.BindTo(scrollingInfo.Direction); direction.BindTo(scrollingInfo.Direction);
direction.BindValueChanged(onDirectionChanged, true); direction.BindValueChanged(onDirectionChanged, true);
accentColour = column.AccentColour.GetBoundCopy();
accentColour.BindValueChanged(colour =>
{
largeFaint.EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = Interpolation.ValueAt(0.1f, colour.NewValue, Color4.White, 0, 1).Opacity(0.3f),
Roundness = 160,
Radius = 200,
};
mainGlow1.EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = Interpolation.ValueAt(0.6f, colour.NewValue, Color4.White, 0, 1),
Roundness = 20,
Radius = 50,
};
mainGlow2.EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = Interpolation.ValueAt(0.4f, colour.NewValue, Color4.White, 0, 1),
Roundness = roundness,
Radius = 40,
};
mainGlow3.EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = Interpolation.ValueAt(0.4f, colour.NewValue, Color4.White, 0, 1),
Roundness = roundness,
Radius = 40,
};
}, true);
} }
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction) private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)

View File

@ -5,6 +5,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Pooling; using osu.Framework.Graphics.Pooling;
@ -19,7 +20,6 @@ using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Skinning; using osu.Game.Skinning;
using osuTK; using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Mania.UI namespace osu.Game.Rulesets.Mania.UI
{ {
@ -28,6 +28,9 @@ namespace osu.Game.Rulesets.Mania.UI
/// </summary> /// </summary>
public class Stage : ScrollingPlayfield public class Stage : ScrollingPlayfield
{ {
[Cached]
public readonly StageDefinition Definition;
public const float COLUMN_SPACING = 1; public const float COLUMN_SPACING = 1;
public const float HIT_TARGET_POSITION = 110; public const float HIT_TARGET_POSITION = 110;
@ -40,13 +43,6 @@ namespace osu.Game.Rulesets.Mania.UI
private readonly Drawable barLineContainer; private readonly Drawable barLineContainer;
private readonly Dictionary<ColumnType, Color4> columnColours = new Dictionary<ColumnType, Color4>
{
{ ColumnType.Even, new Color4(6, 84, 0, 255) },
{ ColumnType.Odd, new Color4(94, 0, 57, 255) },
{ ColumnType.Special, new Color4(0, 48, 63, 255) }
};
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Columns.Any(c => c.ReceivePositionalInputAt(screenSpacePos)); public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Columns.Any(c => c.ReceivePositionalInputAt(screenSpacePos));
private readonly int firstColumnIndex; private readonly int firstColumnIndex;
@ -54,6 +50,7 @@ namespace osu.Game.Rulesets.Mania.UI
public Stage(int firstColumnIndex, StageDefinition definition, ref ManiaAction normalColumnStartAction, ref ManiaAction specialColumnStartAction) public Stage(int firstColumnIndex, StageDefinition definition, ref ManiaAction normalColumnStartAction, ref ManiaAction specialColumnStartAction)
{ {
this.firstColumnIndex = firstColumnIndex; this.firstColumnIndex = firstColumnIndex;
Definition = definition;
Name = "Stage"; Name = "Stage";
@ -75,7 +72,7 @@ namespace osu.Game.Rulesets.Mania.UI
AutoSizeAxes = Axes.X, AutoSizeAxes = Axes.X,
Children = new Drawable[] Children = new Drawable[]
{ {
new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageBackground, stageDefinition: definition), _ => new DefaultStageBackground()) new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageBackground), _ => new DefaultStageBackground())
{ {
RelativeSizeAxes = Axes.Both RelativeSizeAxes = Axes.Both
}, },
@ -100,7 +97,7 @@ namespace osu.Game.Rulesets.Mania.UI
RelativeSizeAxes = Axes.Y, RelativeSizeAxes = Axes.Y,
} }
}, },
new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageForeground, stageDefinition: definition), _ => null) new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageForeground), _ => null)
{ {
RelativeSizeAxes = Axes.Both RelativeSizeAxes = Axes.Both
}, },
@ -118,15 +115,13 @@ namespace osu.Game.Rulesets.Mania.UI
for (int i = 0; i < definition.Columns; i++) for (int i = 0; i < definition.Columns; i++)
{ {
var columnType = definition.GetTypeOfColumn(i); bool isSpecial = definition.IsSpecialColumn(i);
var column = new Column(firstColumnIndex + i) var column = new Column(firstColumnIndex + i, isSpecial)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Width = 1, Width = 1,
ColumnType = columnType, Action = { Value = isSpecial ? specialColumnStartAction++ : normalColumnStartAction++ }
AccentColour = columnColours[columnType],
Action = { Value = columnType == ColumnType.Special ? specialColumnStartAction++ : normalColumnStartAction++ }
}; };
topLevelContainer.Add(column.TopLevelContainer.CreateProxy()); topLevelContainer.Add(column.TopLevelContainer.CreateProxy());

View File

@ -1,21 +1,34 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
namespace osu.Game.Skinning namespace osu.Game.Skinning
{ {
/// <summary>
/// This class exists for the explicit purpose of ferrying information from ManiaBeatmap in a way LegacySkin can use it.
/// This is because half of the mania legacy skin implementation is in LegacySkin (osu.Game project) which doesn't have visibility
/// over ManiaBeatmap / StageDefinition.
/// </summary>
public class LegacyManiaSkinConfigurationLookup public class LegacyManiaSkinConfigurationLookup
{ {
public readonly int Keys; /// <summary>
public readonly LegacyManiaSkinConfigurationLookups Lookup; /// Total columns across all stages.
public readonly int? TargetColumn; /// </summary>
public readonly int TotalColumns;
public LegacyManiaSkinConfigurationLookup(int keys, LegacyManiaSkinConfigurationLookups lookup, int? targetColumn = null) /// <summary>
/// The column which is being looked up.
/// May be null if the configuration does not apply to a specific column.
/// Note that this is the absolute index across all stages.
/// </summary>
public readonly int? ColumnIndex;
public readonly LegacyManiaSkinConfigurationLookups Lookup;
public LegacyManiaSkinConfigurationLookup(int totalColumns, LegacyManiaSkinConfigurationLookups lookup, int? columnIndex = null)
{ {
Keys = keys; TotalColumns = totalColumns;
Lookup = lookup; Lookup = lookup;
TargetColumn = targetColumn; ColumnIndex = columnIndex;
} }
} }

View File

@ -128,18 +128,18 @@ namespace osu.Game.Skinning
private IBindable<TValue>? lookupForMania<TValue>(LegacyManiaSkinConfigurationLookup maniaLookup) private IBindable<TValue>? lookupForMania<TValue>(LegacyManiaSkinConfigurationLookup maniaLookup)
{ {
if (!maniaConfigurations.TryGetValue(maniaLookup.Keys, out var existing)) if (!maniaConfigurations.TryGetValue(maniaLookup.TotalColumns, out var existing))
maniaConfigurations[maniaLookup.Keys] = existing = new LegacyManiaSkinConfiguration(maniaLookup.Keys); maniaConfigurations[maniaLookup.TotalColumns] = existing = new LegacyManiaSkinConfiguration(maniaLookup.TotalColumns);
switch (maniaLookup.Lookup) switch (maniaLookup.Lookup)
{ {
case LegacyManiaSkinConfigurationLookups.ColumnWidth: case LegacyManiaSkinConfigurationLookups.ColumnWidth:
Debug.Assert(maniaLookup.TargetColumn != null); Debug.Assert(maniaLookup.ColumnIndex != null);
return SkinUtils.As<TValue>(new Bindable<float>(existing.ColumnWidth[maniaLookup.TargetColumn.Value])); return SkinUtils.As<TValue>(new Bindable<float>(existing.ColumnWidth[maniaLookup.ColumnIndex.Value]));
case LegacyManiaSkinConfigurationLookups.ColumnSpacing: case LegacyManiaSkinConfigurationLookups.ColumnSpacing:
Debug.Assert(maniaLookup.TargetColumn != null); Debug.Assert(maniaLookup.ColumnIndex != null);
return SkinUtils.As<TValue>(new Bindable<float>(existing.ColumnSpacing[maniaLookup.TargetColumn.Value])); return SkinUtils.As<TValue>(new Bindable<float>(existing.ColumnSpacing[maniaLookup.ColumnIndex.Value]));
case LegacyManiaSkinConfigurationLookups.HitPosition: case LegacyManiaSkinConfigurationLookups.HitPosition:
return SkinUtils.As<TValue>(new Bindable<float>(existing.HitPosition)); return SkinUtils.As<TValue>(new Bindable<float>(existing.HitPosition));
@ -157,15 +157,15 @@ namespace osu.Game.Skinning
return SkinUtils.As<TValue>(getManiaImage(existing, "LightingN")); return SkinUtils.As<TValue>(getManiaImage(existing, "LightingN"));
case LegacyManiaSkinConfigurationLookups.ExplosionScale: case LegacyManiaSkinConfigurationLookups.ExplosionScale:
Debug.Assert(maniaLookup.TargetColumn != null); Debug.Assert(maniaLookup.ColumnIndex != null);
if (GetConfig<SkinConfiguration.LegacySetting, decimal>(SkinConfiguration.LegacySetting.Version)?.Value < 2.5m) if (GetConfig<SkinConfiguration.LegacySetting, decimal>(SkinConfiguration.LegacySetting.Version)?.Value < 2.5m)
return SkinUtils.As<TValue>(new Bindable<float>(1)); return SkinUtils.As<TValue>(new Bindable<float>(1));
if (existing.ExplosionWidth[maniaLookup.TargetColumn.Value] != 0) if (existing.ExplosionWidth[maniaLookup.ColumnIndex.Value] != 0)
return SkinUtils.As<TValue>(new Bindable<float>(existing.ExplosionWidth[maniaLookup.TargetColumn.Value] / LegacyManiaSkinConfiguration.DEFAULT_COLUMN_SIZE)); return SkinUtils.As<TValue>(new Bindable<float>(existing.ExplosionWidth[maniaLookup.ColumnIndex.Value] / LegacyManiaSkinConfiguration.DEFAULT_COLUMN_SIZE));
return SkinUtils.As<TValue>(new Bindable<float>(existing.ColumnWidth[maniaLookup.TargetColumn.Value] / LegacyManiaSkinConfiguration.DEFAULT_COLUMN_SIZE)); return SkinUtils.As<TValue>(new Bindable<float>(existing.ColumnWidth[maniaLookup.ColumnIndex.Value] / LegacyManiaSkinConfiguration.DEFAULT_COLUMN_SIZE));
case LegacyManiaSkinConfigurationLookups.ColumnLineColour: case LegacyManiaSkinConfigurationLookups.ColumnLineColour:
return SkinUtils.As<TValue>(getCustomColour(existing, "ColourColumnLine")); return SkinUtils.As<TValue>(getCustomColour(existing, "ColourColumnLine"));
@ -174,53 +174,53 @@ namespace osu.Game.Skinning
return SkinUtils.As<TValue>(getCustomColour(existing, "ColourJudgementLine")); return SkinUtils.As<TValue>(getCustomColour(existing, "ColourJudgementLine"));
case LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour: case LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour:
Debug.Assert(maniaLookup.TargetColumn != null); Debug.Assert(maniaLookup.ColumnIndex != null);
return SkinUtils.As<TValue>(getCustomColour(existing, $"Colour{maniaLookup.TargetColumn + 1}")); return SkinUtils.As<TValue>(getCustomColour(existing, $"Colour{maniaLookup.ColumnIndex + 1}"));
case LegacyManiaSkinConfigurationLookups.ColumnLightColour: case LegacyManiaSkinConfigurationLookups.ColumnLightColour:
Debug.Assert(maniaLookup.TargetColumn != null); Debug.Assert(maniaLookup.ColumnIndex != null);
return SkinUtils.As<TValue>(getCustomColour(existing, $"ColourLight{maniaLookup.TargetColumn + 1}")); return SkinUtils.As<TValue>(getCustomColour(existing, $"ColourLight{maniaLookup.ColumnIndex + 1}"));
case LegacyManiaSkinConfigurationLookups.MinimumColumnWidth: case LegacyManiaSkinConfigurationLookups.MinimumColumnWidth:
return SkinUtils.As<TValue>(new Bindable<float>(existing.MinimumColumnWidth)); return SkinUtils.As<TValue>(new Bindable<float>(existing.MinimumColumnWidth));
case LegacyManiaSkinConfigurationLookups.NoteImage: case LegacyManiaSkinConfigurationLookups.NoteImage:
Debug.Assert(maniaLookup.TargetColumn != null); Debug.Assert(maniaLookup.ColumnIndex != null);
return SkinUtils.As<TValue>(getManiaImage(existing, $"NoteImage{maniaLookup.TargetColumn}")); return SkinUtils.As<TValue>(getManiaImage(existing, $"NoteImage{maniaLookup.ColumnIndex}"));
case LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage: case LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage:
Debug.Assert(maniaLookup.TargetColumn != null); Debug.Assert(maniaLookup.ColumnIndex != null);
return SkinUtils.As<TValue>(getManiaImage(existing, $"NoteImage{maniaLookup.TargetColumn}H")); return SkinUtils.As<TValue>(getManiaImage(existing, $"NoteImage{maniaLookup.ColumnIndex}H"));
case LegacyManiaSkinConfigurationLookups.HoldNoteTailImage: case LegacyManiaSkinConfigurationLookups.HoldNoteTailImage:
Debug.Assert(maniaLookup.TargetColumn != null); Debug.Assert(maniaLookup.ColumnIndex != null);
return SkinUtils.As<TValue>(getManiaImage(existing, $"NoteImage{maniaLookup.TargetColumn}T")); return SkinUtils.As<TValue>(getManiaImage(existing, $"NoteImage{maniaLookup.ColumnIndex}T"));
case LegacyManiaSkinConfigurationLookups.HoldNoteBodyImage: case LegacyManiaSkinConfigurationLookups.HoldNoteBodyImage:
Debug.Assert(maniaLookup.TargetColumn != null); Debug.Assert(maniaLookup.ColumnIndex != null);
return SkinUtils.As<TValue>(getManiaImage(existing, $"NoteImage{maniaLookup.TargetColumn}L")); return SkinUtils.As<TValue>(getManiaImage(existing, $"NoteImage{maniaLookup.ColumnIndex}L"));
case LegacyManiaSkinConfigurationLookups.HoldNoteLightImage: case LegacyManiaSkinConfigurationLookups.HoldNoteLightImage:
return SkinUtils.As<TValue>(getManiaImage(existing, "LightingL")); return SkinUtils.As<TValue>(getManiaImage(existing, "LightingL"));
case LegacyManiaSkinConfigurationLookups.HoldNoteLightScale: case LegacyManiaSkinConfigurationLookups.HoldNoteLightScale:
Debug.Assert(maniaLookup.TargetColumn != null); Debug.Assert(maniaLookup.ColumnIndex != null);
if (GetConfig<SkinConfiguration.LegacySetting, decimal>(SkinConfiguration.LegacySetting.Version)?.Value < 2.5m) if (GetConfig<SkinConfiguration.LegacySetting, decimal>(SkinConfiguration.LegacySetting.Version)?.Value < 2.5m)
return SkinUtils.As<TValue>(new Bindable<float>(1)); return SkinUtils.As<TValue>(new Bindable<float>(1));
if (existing.HoldNoteLightWidth[maniaLookup.TargetColumn.Value] != 0) if (existing.HoldNoteLightWidth[maniaLookup.ColumnIndex.Value] != 0)
return SkinUtils.As<TValue>(new Bindable<float>(existing.HoldNoteLightWidth[maniaLookup.TargetColumn.Value] / LegacyManiaSkinConfiguration.DEFAULT_COLUMN_SIZE)); return SkinUtils.As<TValue>(new Bindable<float>(existing.HoldNoteLightWidth[maniaLookup.ColumnIndex.Value] / LegacyManiaSkinConfiguration.DEFAULT_COLUMN_SIZE));
return SkinUtils.As<TValue>(new Bindable<float>(existing.ColumnWidth[maniaLookup.TargetColumn.Value] / LegacyManiaSkinConfiguration.DEFAULT_COLUMN_SIZE)); return SkinUtils.As<TValue>(new Bindable<float>(existing.ColumnWidth[maniaLookup.ColumnIndex.Value] / LegacyManiaSkinConfiguration.DEFAULT_COLUMN_SIZE));
case LegacyManiaSkinConfigurationLookups.KeyImage: case LegacyManiaSkinConfigurationLookups.KeyImage:
Debug.Assert(maniaLookup.TargetColumn != null); Debug.Assert(maniaLookup.ColumnIndex != null);
return SkinUtils.As<TValue>(getManiaImage(existing, $"KeyImage{maniaLookup.TargetColumn}")); return SkinUtils.As<TValue>(getManiaImage(existing, $"KeyImage{maniaLookup.ColumnIndex}"));
case LegacyManiaSkinConfigurationLookups.KeyImageDown: case LegacyManiaSkinConfigurationLookups.KeyImageDown:
Debug.Assert(maniaLookup.TargetColumn != null); Debug.Assert(maniaLookup.ColumnIndex != null);
return SkinUtils.As<TValue>(getManiaImage(existing, $"KeyImage{maniaLookup.TargetColumn}D")); return SkinUtils.As<TValue>(getManiaImage(existing, $"KeyImage{maniaLookup.ColumnIndex}D"));
case LegacyManiaSkinConfigurationLookups.LeftStageImage: case LegacyManiaSkinConfigurationLookups.LeftStageImage:
return SkinUtils.As<TValue>(getManiaImage(existing, "StageLeft")); return SkinUtils.As<TValue>(getManiaImage(existing, "StageLeft"));
@ -238,12 +238,12 @@ namespace osu.Game.Skinning
return SkinUtils.As<TValue>(getManiaImage(existing, "StageHint")); return SkinUtils.As<TValue>(getManiaImage(existing, "StageHint"));
case LegacyManiaSkinConfigurationLookups.LeftLineWidth: case LegacyManiaSkinConfigurationLookups.LeftLineWidth:
Debug.Assert(maniaLookup.TargetColumn != null); Debug.Assert(maniaLookup.ColumnIndex != null);
return SkinUtils.As<TValue>(new Bindable<float>(existing.ColumnLineWidth[maniaLookup.TargetColumn.Value])); return SkinUtils.As<TValue>(new Bindable<float>(existing.ColumnLineWidth[maniaLookup.ColumnIndex.Value]));
case LegacyManiaSkinConfigurationLookups.RightLineWidth: case LegacyManiaSkinConfigurationLookups.RightLineWidth:
Debug.Assert(maniaLookup.TargetColumn != null); Debug.Assert(maniaLookup.ColumnIndex != null);
return SkinUtils.As<TValue>(new Bindable<float>(existing.ColumnLineWidth[maniaLookup.TargetColumn.Value + 1])); return SkinUtils.As<TValue>(new Bindable<float>(existing.ColumnLineWidth[maniaLookup.ColumnIndex.Value + 1]));
case LegacyManiaSkinConfigurationLookups.Hit0: case LegacyManiaSkinConfigurationLookups.Hit0:
case LegacyManiaSkinConfigurationLookups.Hit50: case LegacyManiaSkinConfigurationLookups.Hit50: