Merge pull request #8513 from smoogipoo/mania-skinning-testability

Implement basis for mania skinning
This commit is contained in:
Dean Herbert 2020-03-31 19:03:18 +09:00 committed by GitHub
commit da129ddf6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 289 additions and 22 deletions

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.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Mania.UI;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Mania.Tests.Skinning
{
/// <summary>
/// A container to be used in a <see cref="ManiaSkinnableTestScene"/> to provide a resolvable <see cref="Column"/> dependency.
/// </summary>
public class ColumnTestContainer : Container
{
protected override Container<Drawable> Content => content;
private readonly Container content;
[Cached]
private readonly Column column;
public ColumnTestContainer(int column, ManiaAction action)
{
this.column = new Column(column)
{
Action = { Value = action },
AccentColour = Color4.Orange
};
InternalChild = content = new ManiaInputManager(new ManiaRuleset().RulesetInfo, 4)
{
RelativeSizeAxes = Axes.Both
};
}
}
}

View File

@ -0,0 +1,67 @@
// 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.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Timing;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.UI.Scrolling;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Mania.Tests.Skinning
{
/// <summary>
/// A test scene for a mania hitobject.
/// </summary>
public abstract class ManiaHitObjectTestScene : ManiaSkinnableTestScene
{
[BackgroundDependencyLoader]
private void load()
{
SetContents(() => new FillFlowContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Height = 0.7f,
Direction = FillDirection.Horizontal,
Children = new Drawable[]
{
new ColumnTestContainer(0, ManiaAction.Key1)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Y,
Width = 80,
Child = new ScrollingHitObjectContainer
{
RelativeSizeAxes = Axes.Both,
Clock = new FramedClock(new StopwatchClock()),
}.With(c =>
{
c.Add(CreateHitObject().With(h => h.AccentColour.Value = Color4.Orange));
})
},
new ColumnTestContainer(1, ManiaAction.Key2)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Y,
Width = 80,
Child = new ScrollingHitObjectContainer
{
RelativeSizeAxes = Axes.Both,
Clock = new FramedClock(new StopwatchClock()),
}.With(c =>
{
c.Add(CreateHitObject().With(h => h.AccentColour.Value = Color4.Orange));
})
},
}
});
}
protected abstract DrawableManiaHitObject CreateHitObject();
}
}

View File

@ -0,0 +1,58 @@
// 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 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.UI.Scrolling;
using osu.Game.Rulesets.UI.Scrolling.Algorithms;
using osu.Game.Tests.Visual;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Mania.Tests.Skinning
{
/// <summary>
/// A test scene for skinnable mania components.
/// </summary>
public abstract class ManiaSkinnableTestScene : SkinnableTestScene
{
[Cached(Type = typeof(IScrollingInfo))]
private readonly TestScrollingInfo scrollingInfo = new TestScrollingInfo();
protected ManiaSkinnableTestScene()
{
scrollingInfo.Direction.Value = ScrollingDirection.Down;
Add(new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.SlateGray.Opacity(0.2f),
Depth = 1
});
}
[Test]
public void TestScrollingDown()
{
AddStep("change direction to down", () => scrollingInfo.Direction.Value = ScrollingDirection.Down);
}
[Test]
public void TestScrollingUp()
{
AddStep("change direction to up", () => scrollingInfo.Direction.Value = ScrollingDirection.Up);
}
private class TestScrollingInfo : IScrollingInfo
{
public readonly Bindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
IBindable<ScrollingDirection> IScrollingInfo.Direction => Direction;
IBindable<double> IScrollingInfo.TimeRange { get; } = new Bindable<double>(1000);
IScrollAlgorithm IScrollingInfo.Algorithm { get; } = new ConstantScrollAlgorithm();
}
}
}

View File

@ -6,13 +6,13 @@ using System.Collections.Generic;
using System.Linq;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Game.Tests.Visual;
using osu.Game.Rulesets.Mania.UI;
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
namespace osu.Game.Rulesets.Mania.Tests.Skinning
{
public class TestSceneDrawableJudgement : SkinnableTestScene
{

View File

@ -16,4 +16,8 @@ namespace osu.Game.Rulesets.Mania
protected override string ComponentName => Component.ToString().ToLower();
}
public enum ManiaSkinComponents
{
}
}

View File

@ -1,9 +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.
namespace osu.Game.Rulesets.Mania
{
public enum ManiaSkinComponents
{
}
}

View File

@ -0,0 +1,41 @@
// 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 JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Mania.UI;
namespace osu.Game.Rulesets.Mania.Skinning
{
/// <summary>
/// A <see cref="CompositeDrawable"/> which is placed somewhere within a <see cref="Column"/>.
/// </summary>
public class LegacyManiaColumnElement : CompositeDrawable
{
[Resolved(CanBeNull = true)]
[CanBeNull]
protected ManiaStage Stage { get; private set; }
[Resolved]
protected Column Column { get; private set; }
/// <summary>
/// The column index to use for texture lookups, in the case of no user-provided configuration.
/// </summary>
protected int FallbackColumnIndex { get; private set; }
[BackgroundDependencyLoader]
private void load()
{
if (Stage == null)
FallbackColumnIndex = Column.Index % 2 + 1;
else
{
int dist = Math.Min(Column.Index, Stage.Columns.Count - Column.Index - 1);
FallbackColumnIndex = dist % 2 + 1;
}
}
}
}

View File

@ -1,6 +1,7 @@
// 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.Graphics;
using osu.Framework.Graphics.Textures;
using osu.Framework.Audio.Sample;
@ -15,9 +16,19 @@ namespace osu.Game.Rulesets.Mania.Skinning
{
private readonly ISkin source;
public ManiaLegacySkinTransformer(ISkin source)
private Lazy<bool> isLegacySkin;
public ManiaLegacySkinTransformer(ISkinSource source)
{
this.source = source;
source.SourceChanged += sourceChanged;
sourceChanged();
}
private void sourceChanged()
{
isLegacySkin = new Lazy<bool>(() => source.GetConfig<LegacySkinConfiguration.LegacySetting, decimal>(LegacySkinConfiguration.LegacySetting.Version) != null);
}
public Drawable GetDrawableComponent(ISkinComponent component)
@ -26,6 +37,12 @@ namespace osu.Game.Rulesets.Mania.Skinning
{
case GameplaySkinComponent<HitResult> resultComponent:
return getResult(resultComponent);
case ManiaSkinComponent _:
if (!isLegacySkin.Value)
return null;
break;
}
return null;

View File

@ -19,6 +19,7 @@ using osuTK;
namespace osu.Game.Rulesets.Mania.UI
{
[Cached]
public class Column : ScrollingPlayfield, IKeyBindingHandler<ManiaAction>, IHasAccentColour
{
public const float COLUMN_WIDTH = 80;

View File

@ -23,6 +23,7 @@ namespace osu.Game.Rulesets.Mania.UI
/// <summary>
/// A collection of <see cref="Column"/>s.
/// </summary>
[Cached]
public class ManiaStage : ScrollingPlayfield
{
public const float COLUMN_SPACING = 1;

View File

@ -17,9 +17,9 @@ namespace osu.Game.IO
private readonly StreamReader streamReader;
private readonly Queue<string> lineBuffer;
public LineBufferedReader(Stream stream)
public LineBufferedReader(Stream stream, bool leaveOpen = false)
{
streamReader = new StreamReader(stream);
streamReader = new StreamReader(stream, Encoding.UTF8, true, 1024, leaveOpen);
lineBuffer = new Queue<string>();
}

View File

@ -9,6 +9,8 @@ namespace osu.Game.Skinning
{
public class LegacyBeatmapSkin : LegacySkin
{
protected override bool AllowManiaSkin => false;
public LegacyBeatmapSkin(BeatmapInfo beatmap, IResourceStore<byte[]> storage, AudioManager audioManager)
: base(createSkinInfo(beatmap), new LegacySkinResourceStore<BeatmapSetFileInfo>(beatmap.BeatmapSet, storage), audioManager, beatmap.Path)
{

View File

@ -0,0 +1,23 @@
// 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.
namespace osu.Game.Skinning
{
public class LegacyManiaSkinConfigurationLookup
{
public readonly int Keys;
public readonly LegacyManiaSkinConfigurationLookups Lookup;
public readonly int? TargetColumn;
public LegacyManiaSkinConfigurationLookup(int keys, LegacyManiaSkinConfigurationLookups lookup, int? targetColumn = null)
{
Keys = keys;
Lookup = lookup;
TargetColumn = targetColumn;
}
}
public enum LegacyManiaSkinConfigurationLookups
{
}
}

View File

@ -26,12 +26,16 @@ namespace osu.Game.Skinning
[CanBeNull]
protected IResourceStore<SampleChannel> Samples;
protected virtual bool AllowManiaSkin => true;
public new LegacySkinConfiguration Configuration
{
get => base.Configuration as LegacySkinConfiguration;
set => base.Configuration = value;
}
private readonly Dictionary<int, LegacyManiaSkinConfiguration> maniaConfigurations = new Dictionary<int, LegacyManiaSkinConfiguration>();
public LegacySkin(SkinInfo skin, IResourceStore<byte[]> storage, AudioManager audioManager)
: this(skin, new LegacySkinResourceStore<SkinFileInfo>(skin, storage), audioManager, "skin.ini")
{
@ -40,15 +44,26 @@ namespace osu.Game.Skinning
protected LegacySkin(SkinInfo skin, IResourceStore<byte[]> storage, AudioManager audioManager, string filename)
: base(skin)
{
Stream stream = storage?.GetStream(filename);
if (stream != null)
using (var stream = storage?.GetStream(filename))
{
using (LineBufferedReader reader = new LineBufferedReader(stream))
Configuration = new LegacySkinDecoder().Decode(reader);
if (stream != null)
{
using (LineBufferedReader reader = new LineBufferedReader(stream, true))
Configuration = new LegacySkinDecoder().Decode(reader);
stream.Seek(0, SeekOrigin.Begin);
using (LineBufferedReader reader = new LineBufferedReader(stream))
{
var maniaList = new LegacyManiaSkinDecoder().Decode(reader);
foreach (var config in maniaList)
maniaConfigurations[config.Keys] = config;
}
}
else
Configuration = new LegacySkinConfiguration { LegacyVersion = LegacySkinConfiguration.LATEST_VERSION };
}
else
Configuration = new LegacySkinConfiguration { LegacyVersion = LegacySkinConfiguration.LATEST_VERSION };
if (storage != null)
{
@ -105,6 +120,15 @@ namespace osu.Game.Skinning
case SkinCustomColourLookup customColour:
return SkinUtils.As<TValue>(getCustomColour(customColour.Lookup.ToString()));
case LegacyManiaSkinConfigurationLookup legacy:
if (!AllowManiaSkin)
return null;
if (!maniaConfigurations.TryGetValue(legacy.Keys, out _))
maniaConfigurations[legacy.Keys] = new LegacyManiaSkinConfiguration(legacy.Keys);
break;
default:
// handles lookups like GlobalSkinConfiguration