Refactor skin configuration to be infinitely extensible

This commit is contained in:
Dean Herbert
2019-09-03 17:57:34 +09:00
parent 976f5020c0
commit bebc3309ce
28 changed files with 214 additions and 107 deletions

View File

@ -241,7 +241,11 @@ namespace osu.Game.Rulesets.Objects.Drawables
base.SkinChanged(skin, allowFallback);
if (HitObject is IHasComboInformation combo)
AccentColour.Value = skin.GetValue<SkinConfiguration, Color4?>(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
{
var comboColours = skin.GetConfig<GlobalSkinConfiguration, List<Color4>>(GlobalSkinConfiguration.ComboColours)?.Value;
AccentColour.Value = comboColours?.Count > 0 ? comboColours[combo.ComboIndex % comboColours.Count] : Color4.White;
}
}
/// <summary>

View File

@ -122,7 +122,7 @@ namespace osu.Game.Screens.Menu
Color4 defaultColour = Color4.White.Opacity(0.2f);
if (user.Value?.IsSupporter ?? false)
AccentColour = skin.Value.GetValue<SkinConfiguration, Color4?>(s => s.CustomColours.ContainsKey("MenuGlow") ? s.CustomColours["MenuGlow"] : (Color4?)null) ?? defaultColour;
AccentColour = skin.Value.GetConfig<GlobalSkinColour, Color4>(GlobalSkinColour.MenuGlow)?.Value ?? defaultColour;
else
AccentColour = defaultColour;
}

View File

@ -112,7 +112,7 @@ namespace osu.Game.Screens.Menu
Color4 baseColour = colours.Blue;
if (user.Value?.IsSupporter ?? false)
baseColour = skin.Value.GetValue<SkinConfiguration, Color4?>(s => s.CustomColours.ContainsKey("MenuGlow") ? s.CustomColours["MenuGlow"] : (Color4?)null) ?? baseColour;
baseColour = skin.Value.GetConfig<GlobalSkinColour, Color4>(GlobalSkinColour.MenuGlow)?.Value ?? baseColour;
// linear colour looks better in this case, so let's use it for now.
Color4 gradientDark = baseColour.Opacity(0).ToLinear();

View File

@ -1,7 +1,8 @@
// 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.
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
using osu.Game.Audio;
@ -21,5 +22,7 @@ namespace osu.Game.Skinning
public override Texture GetTexture(string componentName) => null;
public override SampleChannel GetSample(ISampleInfo sampleInfo) => null;
public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => null;
}
}

View File

@ -12,8 +12,6 @@ namespace osu.Game.Skinning
{
public DefaultSkinConfiguration()
{
HitCircleFont = "default";
ComboColours.AddRange(new[]
{
new Color4(17, 136, 170, 255),
@ -21,8 +19,6 @@ namespace osu.Game.Skinning
new Color4(204, 102, 0, 255),
new Color4(121, 9, 13, 255)
});
CursorExpand = true;
}
}
}

View File

@ -5,7 +5,7 @@ using System.Linq;
namespace osu.Game.Skinning
{
public class GameplaySkinComponent<T> : ISkinComponent where T : struct
public class GameplaySkinComponent<T> : ISkinComponent
{
public readonly T Component;

View File

@ -0,0 +1,10 @@
// 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 enum GlobalSkinColour
{
MenuGlow
}
}

View File

@ -0,0 +1,10 @@
// 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 enum GlobalSkinConfiguration
{
ComboColours
}
}

View File

@ -1,8 +1,8 @@
// 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.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
using osu.Game.Audio;
@ -20,6 +20,6 @@ namespace osu.Game.Skinning
SampleChannel GetSample(ISampleInfo sampleInfo);
TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration;
IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup);
}
}

View File

@ -1,10 +1,12 @@
// 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.Collections.Generic;
using System.IO;
using System.Linq;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
using osu.Framework.IO.Stores;
@ -48,6 +50,47 @@ namespace osu.Game.Skinning
Samples?.Dispose();
}
public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
{
switch (lookup)
{
case GlobalSkinConfiguration global:
switch (global)
{
case GlobalSkinConfiguration.ComboColours:
return new Bindable<List<Color4>>(Configuration.ComboColours) as IBindable<TValue>;
}
break;
case GlobalSkinColour colour:
return getCustomColour(colour.ToString()) as IBindable<TValue>;
case SkinCustomColourLookup customColour:
return getCustomColour(customColour.Lookup.ToString()) as IBindable<TValue>;
default:
try
{
if (Configuration.ConfigDictionary.TryGetValue(lookup.ToString(), out var val))
{
var bindable = new Bindable<TValue>();
bindable.Parse(val);
return bindable;
}
}
catch
{
}
break;
}
return null;
}
private IBindable<Color4> getCustomColour(string lookup) => Configuration.CustomColours.TryGetValue(lookup, out var col) ? new Bindable<Color4>(col) : null;
public override Drawable GetDrawableComponent(ISkinComponent component)
{
switch (component)

View File

@ -14,47 +14,31 @@ namespace osu.Game.Skinning
protected override void ParseLine(DefaultSkinConfiguration skin, Section section, string line)
{
line = StripComments(line);
var pair = SplitKeyVal(line);
switch (section)
if (section != Section.Colours)
{
case Section.General:
switch (pair.Key)
{
case @"Name":
skin.SkinInfo.Name = pair.Value;
break;
line = StripComments(line);
case @"Author":
skin.SkinInfo.Creator = pair.Value;
break;
var pair = SplitKeyVal(line);
case @"CursorExpand":
skin.CursorExpand = pair.Value != "0";
break;
switch (section)
{
case Section.General:
switch (pair.Key)
{
case @"Name":
skin.SkinInfo.Name = pair.Value;
return;
case @"SliderBorderSize":
skin.SliderBorderSize = Parsing.ParseFloat(pair.Value);
break;
}
case @"Author":
skin.SkinInfo.Creator = pair.Value;
return;
}
break;
break;
}
case Section.Fonts:
switch (pair.Key)
{
case "HitCirclePrefix":
skin.HitCircleFont = pair.Value;
break;
case "HitCircleOverlap":
skin.HitCircleOverlap = int.Parse(pair.Value);
break;
}
break;
if (!string.IsNullOrEmpty(pair.Key))
skin.ConfigDictionary[$"{section}/{pair.Key}"] = pair.Value;
}
base.ParseLine(skin, section, line);

View File

@ -1,8 +1,9 @@
// 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.
using System;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
using osu.Game.Audio;
@ -13,7 +14,7 @@ namespace osu.Game.Skinning
{
public readonly SkinInfo SkinInfo;
public virtual SkinConfiguration Configuration { get; protected set; }
public SkinConfiguration Configuration { get; protected set; }
public abstract Drawable GetDrawableComponent(ISkinComponent componentName);
@ -21,8 +22,7 @@ namespace osu.Game.Skinning
public abstract Texture GetTexture(string componentName);
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration
=> Configuration is TConfiguration conf ? query.Invoke(conf) : default;
public abstract IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup);
protected Skin(SkinInfo skin)
{

View File

@ -0,0 +1,16 @@
// 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.Configuration;
namespace osu.Game.Skinning
{
public class SkinConfigManager<T> : ConfigManager<T> where T : struct
{
protected override void PerformLoad()
{
}
protected override bool PerformSave() => false;
}
}

View File

@ -18,14 +18,6 @@ namespace osu.Game.Skinning
public Dictionary<string, Color4> CustomColours { get; set; } = new Dictionary<string, Color4>();
public string HitCircleFont { get; set; }
public int HitCircleOverlap { get; set; }
public float? SliderBorderSize { get; set; }
public float? SliderPathRadius { get; set; }
public bool? CursorExpand { get; set; }
public readonly Dictionary<string, string> ConfigDictionary = new Dictionary<string, string>();
}
}

View File

@ -0,0 +1,15 @@
// 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 SkinCustomColourLookup
{
public readonly object Lookup;
public SkinCustomColourLookup(object lookup)
{
Lookup = lookup;
}
}
}

View File

@ -1,4 +1,4 @@
// 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.
using System;
@ -131,6 +131,6 @@ namespace osu.Game.Skinning
public SampleChannel GetSample(ISampleInfo sampleInfo) => CurrentSkin.Value.GetSample(sampleInfo);
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration => CurrentSkin.Value.GetValue(query);
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => CurrentSkin.Value.GetConfig<TLookup, TValue>(lookup);
}
}

View File

@ -4,6 +4,7 @@
using System;
using osu.Framework.Allocation;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Textures;
@ -64,13 +65,16 @@ namespace osu.Game.Skinning
return fallbackSource?.GetSample(sampleInfo);
}
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
{
TValue val;
if (AllowConfigurationLookup && skin != null && (val = skin.GetValue(query)) != null)
return val;
if (AllowConfigurationLookup && skin != null)
{
var bindable = skin.GetConfig<TLookup, TValue>(lookup);
if (bindable != null)
return bindable;
}
return fallbackSource == null ? default : fallbackSource.GetValue(query);
return fallbackSource?.GetConfig<TLookup, TValue>(lookup);
}
protected virtual void TriggerSourceChanged() => SourceChanged?.Invoke();