mirror of
https://github.com/ppy/osu
synced 2024-12-25 16:22:23 +00:00
Change serialisation format of skin layouts to allow more flexibility
Also adds per-ruleset storage for each container type.
This commit is contained in:
parent
9685fb2114
commit
6b3652f567
@ -66,7 +66,7 @@ namespace osu.Game.Tests.Skins
|
||||
{
|
||||
var skin = new TestSkin(new SkinInfo(), null, storage);
|
||||
|
||||
foreach (var target in skin.DrawableComponentInfo)
|
||||
foreach (var target in skin.LayoutInfos)
|
||||
{
|
||||
foreach (var info in target.Value)
|
||||
instantiatedTypes.Add(info.Type);
|
||||
@ -87,8 +87,8 @@ namespace osu.Game.Tests.Skins
|
||||
{
|
||||
var skin = new TestSkin(new SkinInfo(), null, storage);
|
||||
|
||||
Assert.That(skin.DrawableComponentInfo, Has.Count.EqualTo(2));
|
||||
Assert.That(skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.MainHUDComponents], Has.Length.EqualTo(9));
|
||||
Assert.That(skin.LayoutInfos, Has.Count.EqualTo(2));
|
||||
Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents], Has.Length.EqualTo(9));
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,11 +100,11 @@ namespace osu.Game.Tests.Skins
|
||||
{
|
||||
var skin = new TestSkin(new SkinInfo(), null, storage);
|
||||
|
||||
Assert.That(skin.DrawableComponentInfo, Has.Count.EqualTo(2));
|
||||
Assert.That(skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.MainHUDComponents], Has.Length.EqualTo(6));
|
||||
Assert.That(skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.SongSelect], Has.Length.EqualTo(1));
|
||||
Assert.That(skin.LayoutInfos, Has.Count.EqualTo(2));
|
||||
Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents], Has.Length.EqualTo(6));
|
||||
Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.SongSelect], Has.Length.EqualTo(1));
|
||||
|
||||
var skinnableInfo = skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.SongSelect].First();
|
||||
var skinnableInfo = skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.SongSelect].First();
|
||||
|
||||
Assert.That(skinnableInfo.Type, Is.EqualTo(typeof(SkinnableSprite)));
|
||||
Assert.That(skinnableInfo.Settings.First().Key, Is.EqualTo("sprite_name"));
|
||||
@ -115,10 +115,10 @@ namespace osu.Game.Tests.Skins
|
||||
using (var storage = new ZipArchiveReader(stream))
|
||||
{
|
||||
var skin = new TestSkin(new SkinInfo(), null, storage);
|
||||
Assert.That(skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.MainHUDComponents], Has.Length.EqualTo(8));
|
||||
Assert.That(skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(UnstableRateCounter)));
|
||||
Assert.That(skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(ColourHitErrorMeter)));
|
||||
Assert.That(skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(LegacySongProgress)));
|
||||
Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents], Has.Length.EqualTo(8));
|
||||
Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(UnstableRateCounter)));
|
||||
Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(ColourHitErrorMeter)));
|
||||
Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(LegacySongProgress)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,9 +37,10 @@ namespace osu.Game.Skinning
|
||||
|
||||
public SkinConfiguration Configuration { get; set; }
|
||||
|
||||
public IDictionary<SkinComponentsContainerLookup.TargetArea, SerialisedDrawableInfo[]> DrawableComponentInfo => drawableComponentInfo;
|
||||
public IDictionary<SkinComponentsContainerLookup.TargetArea, SkinLayoutInfo> LayoutInfos => layoutInfos;
|
||||
|
||||
private readonly Dictionary<SkinComponentsContainerLookup.TargetArea, SerialisedDrawableInfo[]> drawableComponentInfo = new Dictionary<SkinComponentsContainerLookup.TargetArea, SerialisedDrawableInfo[]>();
|
||||
private readonly Dictionary<SkinComponentsContainerLookup.TargetArea, SkinLayoutInfo> layoutInfos =
|
||||
new Dictionary<SkinComponentsContainerLookup.TargetArea, SkinLayoutInfo>();
|
||||
|
||||
public abstract ISample? GetSample(ISampleInfo sampleInfo);
|
||||
|
||||
@ -113,18 +114,37 @@ namespace osu.Game.Skinning
|
||||
{
|
||||
string jsonContent = Encoding.UTF8.GetString(bytes);
|
||||
|
||||
// handle namespace changes...
|
||||
SkinLayoutInfo? layoutInfo = null;
|
||||
|
||||
// can be removed 2023-01-31
|
||||
jsonContent = jsonContent.Replace(@"osu.Game.Screens.Play.SongProgress", @"osu.Game.Screens.Play.HUD.DefaultSongProgress");
|
||||
jsonContent = jsonContent.Replace(@"osu.Game.Screens.Play.HUD.LegacyComboCounter", @"osu.Game.Skinning.LegacyComboCounter");
|
||||
try
|
||||
{
|
||||
// First attempt to deserialise using the new SkinLayoutInfo format
|
||||
layoutInfo = JsonConvert.DeserializeObject<SkinLayoutInfo>(jsonContent);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
var deserializedContent = JsonConvert.DeserializeObject<IEnumerable<SerialisedDrawableInfo>>(jsonContent);
|
||||
// if that fails, attempt to deserialise using the old naked list.
|
||||
if (layoutInfo == null)
|
||||
{
|
||||
// handle namespace changes...
|
||||
// can be removed 2023-01-31
|
||||
jsonContent = jsonContent.Replace(@"osu.Game.Screens.Play.SongProgress", @"osu.Game.Screens.Play.HUD.DefaultSongProgress");
|
||||
jsonContent = jsonContent.Replace(@"osu.Game.Screens.Play.HUD.LegacyComboCounter", @"osu.Game.Skinning.LegacyComboCounter");
|
||||
|
||||
if (deserializedContent == null)
|
||||
continue;
|
||||
var deserializedContent = JsonConvert.DeserializeObject<IEnumerable<SerialisedDrawableInfo>>(jsonContent);
|
||||
|
||||
DrawableComponentInfo[skinnableTarget] = deserializedContent.ToArray();
|
||||
if (deserializedContent == null)
|
||||
continue;
|
||||
|
||||
layoutInfo = new SkinLayoutInfo();
|
||||
layoutInfo.Update(null, deserializedContent.ToArray());
|
||||
|
||||
Logger.Log($"Ferrying {deserializedContent.Count()} components in {skinnableTarget} to global section of new {nameof(SkinLayoutInfo)} format");
|
||||
}
|
||||
|
||||
LayoutInfos[skinnableTarget] = layoutInfo;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -145,7 +165,7 @@ namespace osu.Game.Skinning
|
||||
/// <param name="targetContainer">The target container to reset.</param>
|
||||
public void ResetDrawableTarget(SkinComponentsContainer targetContainer)
|
||||
{
|
||||
DrawableComponentInfo.Remove(targetContainer.Lookup.Target);
|
||||
LayoutInfos.Remove(targetContainer.Lookup.Target);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -154,7 +174,10 @@ namespace osu.Game.Skinning
|
||||
/// <param name="targetContainer">The target container to serialise to this skin.</param>
|
||||
public void UpdateDrawableTarget(SkinComponentsContainer targetContainer)
|
||||
{
|
||||
DrawableComponentInfo[targetContainer.Lookup.Target] = ((ISerialisableDrawableContainer)targetContainer).CreateSerialisedInfo().ToArray();
|
||||
if (!LayoutInfos.TryGetValue(targetContainer.Lookup.Target, out var layoutInfo))
|
||||
layoutInfos[targetContainer.Lookup.Target] = layoutInfo = new SkinLayoutInfo();
|
||||
|
||||
layoutInfo.Update(targetContainer.Lookup.Ruleset, ((ISerialisableDrawableContainer)targetContainer).CreateSerialisedInfo().ToArray());
|
||||
}
|
||||
|
||||
public virtual Drawable? GetDrawableComponent(ISkinComponentLookup lookup)
|
||||
@ -166,18 +189,16 @@ namespace osu.Game.Skinning
|
||||
return this.GetAnimation(sprite.LookupName, false, false);
|
||||
|
||||
case SkinComponentsContainerLookup containerLookup:
|
||||
if (!DrawableComponentInfo.TryGetValue(containerLookup.Target, out var skinnableInfo))
|
||||
return null;
|
||||
|
||||
var components = new List<Drawable>();
|
||||
|
||||
foreach (var i in skinnableInfo)
|
||||
components.Add(i.CreateInstance());
|
||||
// It is important to return null if the user has not configured this yet.
|
||||
// This allows skin transformers the opportunity to provide default components.
|
||||
if (!LayoutInfos.TryGetValue(containerLookup.Target, out var layoutInfo)) return null;
|
||||
if (!layoutInfo.TryGetDrawableInfo(containerLookup.Ruleset, out var drawableInfos)) return null;
|
||||
|
||||
return new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = components,
|
||||
ChildrenEnumerable = drawableInfos.Select(i => i.CreateInstance())
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -201,7 +201,7 @@ namespace osu.Game.Skinning
|
||||
}
|
||||
|
||||
// Then serialise each of the drawable component groups into respective files.
|
||||
foreach (var drawableInfo in skin.DrawableComponentInfo)
|
||||
foreach (var drawableInfo in skin.LayoutInfos)
|
||||
{
|
||||
string json = JsonConvert.SerializeObject(drawableInfo.Value, new JsonSerializerSettings { Formatting = Formatting.Indented });
|
||||
|
||||
|
33
osu.Game/Skinning/SkinLayoutInfo.cs
Normal file
33
osu.Game/Skinning/SkinLayoutInfo.cs
Normal file
@ -0,0 +1,33 @@
|
||||
// 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 System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Skinning
|
||||
{
|
||||
/// <summary>
|
||||
/// A serialisable model describing layout of a <see cref="SkinComponentsContainer"/>.
|
||||
/// May contain multiple configurations for different rulesets, each of which should manifest their own <see cref="SkinComponentsContainer"/> as required.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SkinLayoutInfo
|
||||
{
|
||||
private const string global_identifier = "global";
|
||||
|
||||
[JsonProperty]
|
||||
public Dictionary<string, SerialisedDrawableInfo[]> DrawableInfo { get; set; } = new Dictionary<string, SerialisedDrawableInfo[]>();
|
||||
|
||||
public bool TryGetDrawableInfo(Ruleset? ruleset, [NotNullWhen(true)] out SerialisedDrawableInfo[]? components) =>
|
||||
DrawableInfo.TryGetValue(ruleset?.ShortName ?? global_identifier, out components);
|
||||
|
||||
public void Reset(Ruleset? ruleset) =>
|
||||
DrawableInfo.Remove(ruleset?.ShortName ?? global_identifier);
|
||||
|
||||
public void Update(Ruleset? ruleset, SerialisedDrawableInfo[] components) =>
|
||||
DrawableInfo[ruleset?.ShortName ?? global_identifier] = components;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user