mirror of
https://github.com/ppy/osu.git
synced 2026-05-18 01:30:05 +08:00
Fix skin editor sometimes dropping anchor/origin specification on paste (#35957)
* Add failing test for copy->paste not being idempotent * Ensure all elements on default skins use fixed anchors `UsesFixedAnchor` defaults to false, i.e. closest anchors. Combined with manual anchor / origin specs on some drawables, this would get default skins into impossible states wherein a drawable would use "closest anchor" but also explicitly specify anchor / origin that aren't closest, which horribly fails on attempting to copy and paste. Frankly shocked this has gone unnoticed for this long, and I regret not vetoing this "feature" more every time I see its tentacles spread to produce breakage of levels yet unseen. Does this commit contain major levels of suck? For sure. Do I have any better ideas that wouldn't consist of a multi-day rewrite or deletion of this "feature"? No. * Fix skin editor always applying closest anchor / origin on paste regardless of whether the component uses fixed anchor Self-explanatory. Should close https://github.com/ppy/osu/issues/29111 along with previous commit.
This commit is contained in:
committed by
GitHub
Unverified
parent
22825f6509
commit
c4f7dee82b
@@ -72,6 +72,9 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
||||
leaderboard.Origin = Anchor.CentreLeft;
|
||||
leaderboard.X = 10;
|
||||
}
|
||||
|
||||
foreach (var d in container.OfType<ISerialisableDrawable>())
|
||||
d.UsesFixedAnchor = true;
|
||||
})
|
||||
{
|
||||
Children = new Drawable[]
|
||||
|
||||
@@ -57,6 +57,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon
|
||||
|
||||
if (spectatorList != null)
|
||||
spectatorList.Position = new Vector2(36, -66);
|
||||
|
||||
foreach (var d in container.OfType<ISerialisableDrawable>())
|
||||
d.UsesFixedAnchor = true;
|
||||
})
|
||||
{
|
||||
new DrawableGameplayLeaderboard(),
|
||||
|
||||
@@ -122,6 +122,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||
leaderboard.Origin = Anchor.CentreLeft;
|
||||
leaderboard.X = 10;
|
||||
}
|
||||
|
||||
foreach (var d in container.OfType<ISerialisableDrawable>())
|
||||
d.UsesFixedAnchor = true;
|
||||
})
|
||||
{
|
||||
new LegacyManiaComboCounter(),
|
||||
|
||||
@@ -103,6 +103,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
leaderboard.Origin = Anchor.BottomLeft;
|
||||
leaderboard.Position = pos;
|
||||
}
|
||||
|
||||
foreach (var d in container.OfType<ISerialisableDrawable>())
|
||||
d.UsesFixedAnchor = true;
|
||||
})
|
||||
{
|
||||
Children = new Drawable[]
|
||||
|
||||
@@ -51,6 +51,9 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon
|
||||
spectatorList.Anchor = Anchor.BottomLeft;
|
||||
spectatorList.Origin = Anchor.TopLeft;
|
||||
}
|
||||
|
||||
foreach (var d in container.OfType<ISerialisableDrawable>())
|
||||
d.UsesFixedAnchor = true;
|
||||
})
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
|
||||
@@ -51,6 +51,9 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default
|
||||
spectatorList.Origin = Anchor.TopLeft;
|
||||
spectatorList.Position = new Vector2(320, -280);
|
||||
}
|
||||
|
||||
foreach (var d in container.OfType<ISerialisableDrawable>())
|
||||
d.UsesFixedAnchor = true;
|
||||
})
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
|
||||
@@ -79,6 +79,9 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
|
||||
spectatorList.Origin = Anchor.TopLeft;
|
||||
spectatorList.Position = pos;
|
||||
}
|
||||
|
||||
foreach (var d in container.OfType<ISerialisableDrawable>())
|
||||
d.UsesFixedAnchor = true;
|
||||
})
|
||||
{
|
||||
new LegacyDefaultComboCounter(),
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions;
|
||||
@@ -378,6 +379,23 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
() => Is.EqualTo(3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCopyPasteIdempotency()
|
||||
{
|
||||
string state = null!;
|
||||
AddStep("select everything", () => InputManager.Keys(PlatformAction.SelectAll));
|
||||
AddStep("dump state", () =>
|
||||
{
|
||||
state = JsonConvert.SerializeObject(skinEditor.SelectedComponents.Cast<Drawable>().Select(s => s.CreateSerialisedInfo()).ToArray());
|
||||
});
|
||||
AddStep("copy", () => InputManager.Keys(PlatformAction.Copy));
|
||||
AddStep("delete", () => InputManager.Keys(PlatformAction.Delete));
|
||||
AddStep("paste", () => InputManager.Keys(PlatformAction.Paste));
|
||||
AddAssert("pasted state equals dumped",
|
||||
() => JsonConvert.SerializeObject(skinEditor.SelectedComponents.Cast<Drawable>().Select(s => s.CreateSerialisedInfo()).ToArray()),
|
||||
() => Is.EqualTo(state));
|
||||
}
|
||||
|
||||
private SkinnableContainer globalHUDTarget => Player.ChildrenOfType<SkinnableContainer>()
|
||||
.Single(c => c.Lookup.Lookup == GlobalSkinnableContainers.MainHUDComponents && c.Lookup.Ruleset == null);
|
||||
|
||||
|
||||
@@ -529,7 +529,9 @@ namespace osu.Game.Overlays.SkinEditor
|
||||
}
|
||||
|
||||
SelectedComponents.Add(component);
|
||||
SkinSelectionHandler.ApplyClosestAnchorOrigin(drawableComponent);
|
||||
|
||||
if (!component.UsesFixedAnchor)
|
||||
SkinSelectionHandler.ApplyClosestAnchorOrigin(drawableComponent);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -128,6 +128,9 @@ namespace osu.Game.Skinning
|
||||
|
||||
if (spectatorList != null)
|
||||
spectatorList.Position = pos;
|
||||
|
||||
foreach (var d in container.OfType<ISerialisableDrawable>())
|
||||
d.UsesFixedAnchor = true;
|
||||
})
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
@@ -238,6 +241,9 @@ namespace osu.Game.Skinning
|
||||
keyCounter.Position = new Vector2(-(hitError.Width + padding), -(padding * 2 + song_progress_offset_height));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var d in container.OfType<ISerialisableDrawable>())
|
||||
d.UsesFixedAnchor = true;
|
||||
}
|
||||
})
|
||||
{
|
||||
|
||||
@@ -412,6 +412,9 @@ namespace osu.Game.Skinning
|
||||
leaderboard.Origin = Anchor.CentreLeft;
|
||||
leaderboard.X = 10;
|
||||
}
|
||||
|
||||
foreach (var d in container.OfType<ISerialisableDrawable>())
|
||||
d.UsesFixedAnchor = true;
|
||||
})
|
||||
{
|
||||
new LegacyDefaultComboCounter(),
|
||||
@@ -448,6 +451,9 @@ namespace osu.Game.Skinning
|
||||
hitError.Origin = Anchor.CentreLeft;
|
||||
hitError.Rotation = -90;
|
||||
}
|
||||
|
||||
foreach (var d in container.OfType<ISerialisableDrawable>())
|
||||
d.UsesFixedAnchor = true;
|
||||
})
|
||||
{
|
||||
Children = new Drawable[]
|
||||
|
||||
@@ -106,6 +106,9 @@ namespace osu.Game.Skinning
|
||||
spectatorList.Origin = Anchor.BottomLeft;
|
||||
spectatorList.Position = new Vector2(screen_edge_padding, -(song_progress_offset_height + screen_edge_padding));
|
||||
}
|
||||
|
||||
foreach (var d in container.OfType<ISerialisableDrawable>())
|
||||
d.UsesFixedAnchor = true;
|
||||
})
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
@@ -178,6 +181,9 @@ namespace osu.Game.Skinning
|
||||
keyCounter.Origin = Anchor.BottomRight;
|
||||
keyCounter.Position = new Vector2(-screen_edge_padding, -(song_progress_offset_height + screen_edge_padding));
|
||||
}
|
||||
|
||||
foreach (var d in container.OfType<ISerialisableDrawable>())
|
||||
d.UsesFixedAnchor = true;
|
||||
})
|
||||
{
|
||||
Children = new Drawable[]
|
||||
|
||||
Reference in New Issue
Block a user