diff --git a/osu.Game/Extensions/DrawableExtensions.cs b/osu.Game/Extensions/DrawableExtensions.cs index 3d2ffe0ea1..289b305c27 100644 --- a/osu.Game/Extensions/DrawableExtensions.cs +++ b/osu.Game/Extensions/DrawableExtensions.cs @@ -45,6 +45,15 @@ namespace osu.Game.Extensions public static Vector2 ScreenSpaceDeltaToParentSpace(this Drawable drawable, Vector2 delta) => drawable.Parent.ToLocalSpace(drawable.Parent.ToScreenSpace(Vector2.Zero) + delta); - public static StoredSkinnableInfo CreateSerialisedInformation(this Drawable component) => new StoredSkinnableInfo(component); + public static SkinnableInfo CreateSerialisedInformation(this Drawable component) => new SkinnableInfo(component); + + public static void ApplySerialisedInformation(this Drawable component, ISkinnableInfo info) + { + // todo: can probably make this better via deserialisation directly using a common interface. + component.Position = info.Position; + component.Rotation = info.Rotation; + component.Scale = info.Scale; + component.Anchor = info.Anchor; + } } } diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 2e84c9c97d..0e147f9238 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -13,13 +13,12 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; -using osu.Game.Skinning; using osuTK; using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD.HitErrorMeters { - public class BarHitErrorMeter : HitErrorMeter, ISkinnableComponent + public class BarHitErrorMeter : HitErrorMeter { private readonly Anchor alignment; diff --git a/osu.Game/Screens/Play/HUD/ISkinnableInfo.cs b/osu.Game/Screens/Play/HUD/ISkinnableInfo.cs index 0e571b5cb4..fc4e9680a8 100644 --- a/osu.Game/Screens/Play/HUD/ISkinnableInfo.cs +++ b/osu.Game/Screens/Play/HUD/ISkinnableInfo.cs @@ -4,6 +4,7 @@ using System; using osu.Framework.Graphics; using osu.Game.IO.Serialization; +using osu.Game.Skinning; using osuTK; namespace osu.Game.Screens.Play.HUD @@ -12,7 +13,7 @@ namespace osu.Game.Screens.Play.HUD { public Type Type { get; set; } - public Type Target { get; set; } + public SkinnableTarget? Target { get; set; } public Vector2 Position { get; set; } @@ -22,11 +23,4 @@ namespace osu.Game.Screens.Play.HUD public Anchor Anchor { get; set; } } - - /// - /// A container which supports skinnable components being added to it. - /// - public interface ISkinnableTarget - { - } } diff --git a/osu.Game/Screens/Play/HUD/ISkinnableTarget.cs b/osu.Game/Screens/Play/HUD/ISkinnableTarget.cs new file mode 100644 index 0000000000..6cd269333a --- /dev/null +++ b/osu.Game/Screens/Play/HUD/ISkinnableTarget.cs @@ -0,0 +1,15 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Skinning; + +namespace osu.Game.Screens.Play.HUD +{ + /// + /// A container which supports skinnable components being added to it. + /// + public interface ISkinnableTarget + { + public SkinnableTarget Target { get; } + } +} diff --git a/osu.Game/Screens/Play/HUD/SkinnableElementTargetContainer.cs b/osu.Game/Screens/Play/HUD/SkinnableElementTargetContainer.cs index 8da7950c57..bd82533823 100644 --- a/osu.Game/Screens/Play/HUD/SkinnableElementTargetContainer.cs +++ b/osu.Game/Screens/Play/HUD/SkinnableElementTargetContainer.cs @@ -1,24 +1,28 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; -using System.Collections.Generic; -using osu.Framework.Graphics; using osu.Game.Skinning; namespace osu.Game.Screens.Play.HUD { public class SkinnableElementTargetContainer : SkinReloadableDrawable, ISkinnableTarget { + public SkinnableTarget Target { get; } + + public SkinnableElementTargetContainer(SkinnableTarget target) + { + Target = target; + } + protected override void SkinChanged(ISkinSource skin, bool allowFallback) { base.SkinChanged(skin, allowFallback); - var loadable = skin.GetConfig>(this.GetType()); + var loadable = skin.GetDrawableComponent(new SkinnableTargetComponent(Target)); ClearInternal(); if (loadable != null) - LoadComponentsAsync(loadable.Value, AddRangeInternal); + LoadComponentAsync(loadable, AddInternal); } } } diff --git a/osu.Game/Screens/Play/HUD/StoredSkinnableInfo.cs b/osu.Game/Screens/Play/HUD/SkinnableInfo.cs similarity index 51% rename from osu.Game/Screens/Play/HUD/StoredSkinnableInfo.cs rename to osu.Game/Screens/Play/HUD/SkinnableInfo.cs index e4ec035e68..5b1f840efd 100644 --- a/osu.Game/Screens/Play/HUD/StoredSkinnableInfo.cs +++ b/osu.Game/Screens/Play/HUD/SkinnableInfo.cs @@ -2,7 +2,11 @@ // See the LICENCE file in the repository root for full licence text. using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; using osu.Framework.Graphics; +using osu.Game.Extensions; +using osu.Game.Skinning; using osuTK; namespace osu.Game.Screens.Play.HUD @@ -10,17 +14,20 @@ namespace osu.Game.Screens.Play.HUD /// /// Serialised information governing custom changes to an . /// - public class StoredSkinnableInfo : ISkinnableInfo + [Serializable] + public class SkinnableInfo : ISkinnableInfo { - public StoredSkinnableInfo(Drawable component) + public SkinnableInfo() + { + } + + public SkinnableInfo(Drawable component) { Type = component.GetType(); - var target = component.Parent as ISkinnableTarget - // todo: this is temporary until we serialise the default layouts out of SkinnableDrawables. - ?? component.Parent?.Parent as ISkinnableTarget; + ISkinnableTarget target = component.Parent as ISkinnableTarget; - Target = target?.GetType(); + Target = target?.Target; Position = component.Position; Rotation = component.Rotation; @@ -30,7 +37,8 @@ namespace osu.Game.Screens.Play.HUD public Type Type { get; set; } - public Type Target { get; set; } + [JsonConverter(typeof(StringEnumConverter))] + public SkinnableTarget? Target { get; set; } public Vector2 Position { get; set; } @@ -40,4 +48,14 @@ namespace osu.Game.Screens.Play.HUD public Anchor Anchor { get; set; } } + + public static class SkinnableInfoExtensions + { + public static Drawable CreateInstance(this ISkinnableInfo info) + { + Drawable d = (Drawable)Activator.CreateInstance(info.Type); + d.ApplySerialisedInformation(info); + return d; + } + } } diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 13449e3a2b..1a12ca4cbd 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -91,16 +91,37 @@ namespace osu.Game.Screens.Play { new Drawable[] { - new MainHUDElements + new Container { RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - HealthDisplay = new SkinnableHealthDisplay(), - AccuracyCounter = new SkinnableAccuracyCounter(), - ScoreCounter = new SkinnableScoreCounter(), - new SkinnableComboCounter(), - new HitErrorDisplay(this.drawableRuleset?.FirstAvailableHitWindows), + new SkinnableElementTargetContainer(SkinnableTarget.MainHUDComponents) + { + RelativeSizeAxes = Axes.Both, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + Children = new Drawable[] + { + // remaining cross-dependencies need tidying. + // kept to ensure non-null, but hidden for testing. + HealthDisplay = new SkinnableHealthDisplay(), + AccuracyCounter = new SkinnableAccuracyCounter(), + ScoreCounter = new SkinnableScoreCounter(), + } + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + // still need to be migrated; a bit more involved. + new HitErrorDisplay(this.drawableRuleset?.FirstAvailableHitWindows), + } + }, } }, }, @@ -337,9 +358,5 @@ namespace osu.Game.Screens.Play break; } } - - public class MainHUDElements : SkinnableElementTargetContainer - { - } } } diff --git a/osu.Game/Skinning/DefaultSkin.cs b/osu.Game/Skinning/DefaultSkin.cs index 0b3f5f3cde..48da841c45 100644 --- a/osu.Game/Skinning/DefaultSkin.cs +++ b/osu.Game/Skinning/DefaultSkin.cs @@ -2,12 +2,17 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.IO; +using System.Linq; +using Newtonsoft.Json; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Textures; using osu.Game.Audio; +using osu.Game.Screens.Play.HUD; using osuTK.Graphics; namespace osu.Game.Skinning @@ -20,7 +25,29 @@ namespace osu.Game.Skinning Configuration = new DefaultSkinConfiguration(); } - public override Drawable GetDrawableComponent(ISkinComponent component) => null; + public override Drawable GetDrawableComponent(ISkinComponent component) + { + switch (component) + { + case SkinnableTargetComponent target: + switch (target.Target) + { + case SkinnableTarget.MainHUDComponents: + var infos = JsonConvert.DeserializeObject>(File.ReadAllText("/Users/Dean/json-out.json")).Where(i => i.Target == SkinnableTarget.MainHUDComponents); + + var container = new SkinnableTargetWrapper(target.Target) + { + ChildrenEnumerable = infos.Select(i => i.CreateInstance()) + }; + + return container; + } + + break; + } + + return null; + } public override Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => null; @@ -45,4 +72,14 @@ namespace osu.Game.Skinning return null; } } + + public class SkinnableTargetWrapper : Container, ISkinnableTarget + { + public SkinnableTarget Target { get; } + + public SkinnableTargetWrapper(SkinnableTarget target) + { + Target = target; + } + } } diff --git a/osu.Game/Skinning/ISkin.cs b/osu.Game/Skinning/ISkin.cs index 5371893882..73f7cf6d39 100644 --- a/osu.Game/Skinning/ISkin.cs +++ b/osu.Game/Skinning/ISkin.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; -using System.Collections.Generic; using JetBrains.Annotations; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; diff --git a/osu.Game/Skinning/SkinnableTarget.cs b/osu.Game/Skinning/SkinnableTarget.cs new file mode 100644 index 0000000000..7b1eae126c --- /dev/null +++ b/osu.Game/Skinning/SkinnableTarget.cs @@ -0,0 +1,10 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Skinning +{ + public enum SkinnableTarget + { + MainHUDComponents + } +} diff --git a/osu.Game/Skinning/SkinnableTargetComponent.cs b/osu.Game/Skinning/SkinnableTargetComponent.cs new file mode 100644 index 0000000000..a17aafe6e7 --- /dev/null +++ b/osu.Game/Skinning/SkinnableTargetComponent.cs @@ -0,0 +1,17 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Skinning +{ + public class SkinnableTargetComponent : ISkinComponent + { + public readonly SkinnableTarget Target; + + public string LookupName => Target.ToString(); + + public SkinnableTargetComponent(SkinnableTarget target) + { + Target = target; + } + } +}