1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-12 20:22:55 +08:00

Ensure default skins are copied before modifying

This commit is contained in:
Dean Herbert 2021-05-11 17:00:56 +09:00
parent a67cead0b3
commit a7e83aacfb
2 changed files with 31 additions and 25 deletions

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
@ -30,6 +31,8 @@ namespace osu.Game.Skinning.Editor
[Resolved] [Resolved]
private SkinManager skins { get; set; } private SkinManager skins { get; set; }
private Bindable<Skin> currentSkin;
public SkinEditor(Drawable targetScreen) public SkinEditor(Drawable targetScreen)
{ {
this.targetScreen = targetScreen; this.targetScreen = targetScreen;
@ -119,23 +122,25 @@ namespace osu.Game.Skinning.Editor
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
Show(); Show();
// as long as the skin editor is loaded, let's make sure we can modify the current skin.
currentSkin = skins.CurrentSkin.GetBoundCopy();
// schedule ensures this only happens when the skin editor is visible.
// also avoid some weird endless recursion / bindable feedback loop (something to do with tracking skins across three different bindable types).
// probably something which will be factored out in a future database refactor so not too concerning for now.
currentSkin.BindValueChanged(skin => Scheduler.AddOnce(skins.EnsureMutableSkin), true);
} }
private void revert() private void revert()
{ {
var currentSkin = skins.CurrentSkin.Value;
var legacySkin = currentSkin as LegacySkin;
if (legacySkin == null)
return;
SkinnableElementTargetContainer[] targetContainers = targetScreen.ChildrenOfType<SkinnableElementTargetContainer>().ToArray(); SkinnableElementTargetContainer[] targetContainers = targetScreen.ChildrenOfType<SkinnableElementTargetContainer>().ToArray();
foreach (var t in targetContainers) foreach (var t in targetContainers)
{ {
legacySkin.ResetDrawableTarget(t); currentSkin.Value.ResetDrawableTarget(t);
// add back default components // add back default components
getTarget(t.Target).Reload(); getTarget(t.Target).Reload();
@ -144,17 +149,10 @@ namespace osu.Game.Skinning.Editor
private void save() private void save()
{ {
var currentSkin = skins.CurrentSkin.Value;
var legacySkin = currentSkin as LegacySkin;
if (legacySkin == null)
return;
SkinnableElementTargetContainer[] targetContainers = targetScreen.ChildrenOfType<SkinnableElementTargetContainer>().ToArray(); SkinnableElementTargetContainer[] targetContainers = targetScreen.ChildrenOfType<SkinnableElementTargetContainer>().ToArray();
foreach (var t in targetContainers) foreach (var t in targetContainers)
legacySkin.UpdateDrawableTarget(t); currentSkin.Value.UpdateDrawableTarget(t);
skins.Save(skins.CurrentSkin.Value); skins.Save(skins.CurrentSkin.Value);
} }

View File

@ -153,22 +153,30 @@ namespace osu.Game.Skinning
/// <param name="skinInfo">The skin to lookup.</param> /// <param name="skinInfo">The skin to lookup.</param>
/// <returns>A <see cref="Skin"/> instance correlating to the provided <see cref="SkinInfo"/>.</returns> /// <returns>A <see cref="Skin"/> instance correlating to the provided <see cref="SkinInfo"/>.</returns>
public Skin GetSkin(SkinInfo skinInfo) => skinInfo.CreateInstance(legacyDefaultResources, this); public Skin GetSkin(SkinInfo skinInfo) => skinInfo.CreateInstance(legacyDefaultResources, this);
/// <summary>
/// Ensure that the current skin is in a state it can accept user modifications.
/// This will create a copy of any internal skin and being tracking in the database if not already.
/// </summary>
public void EnsureMutableSkin()
{ {
if (skinInfo == SkinInfo.Default) if (CurrentSkinInfo.Value.ID >= 1) return;
return new DefaultSkin();
if (skinInfo == DefaultLegacySkin.Info) var skin = CurrentSkin.Value;
return new DefaultLegacySkin(legacyDefaultResources, this);
return new LegacySkin(skinInfo, this); // if the user is attempting to save one of the default skin implementations, create a copy first.
CurrentSkinInfo.Value = Import(new SkinInfo
{
Name = skin.SkinInfo.Name + " (modified)",
Creator = skin.SkinInfo.Creator,
InstantiationInfo = skin.SkinInfo.InstantiationInfo,
}).Result;
} }
public void Save(Skin skin) public void Save(Skin skin)
{ {
// some skins don't support saving just yet. if (skin.SkinInfo.ID <= 0)
// eventually we will want to create a copy of the skin to allow for customisation. throw new InvalidOperationException($"Attempting to save a skin which is not yet tracked. Call {nameof(EnsureMutableSkin)} first.");
if (skin.SkinInfo.Files == null)
return;
foreach (var drawableInfo in skin.DrawableComponentInfo) foreach (var drawableInfo in skin.DrawableComponentInfo)
{ {