diff --git a/osu.Game.Tests/Resources/Archives/argon-invalid-drawable.osk b/osu.Game.Tests/Resources/Archives/argon-invalid-drawable.osk new file mode 100644 index 000000000000..23c318149cbe Binary files /dev/null and b/osu.Game.Tests/Resources/Archives/argon-invalid-drawable.osk differ diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs index 82b46ee75f71..73725571613e 100644 --- a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs +++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs @@ -12,6 +12,7 @@ using osu.Game.Audio; using osu.Game.IO; using osu.Game.IO.Archives; +using osu.Game.Screens.Menu; using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.HUD.HitErrorMeters; using osu.Game.Skinning; @@ -125,6 +126,18 @@ public void TestDeserialiseModifiedArgon() } } + [Test] + public void TestDeserialiseInvalidDrawables() + { + using (var stream = TestResources.OpenResource("Archives/argon-invalid-drawable.osk")) + using (var storage = new ZipArchiveReader(stream)) + { + var skin = new TestSkin(new SkinInfo(), null, storage); + + Assert.That(skin.LayoutInfos.Any(kvp => kvp.Value.AllDrawables.Any(d => d.Type == typeof(StarFountain))), Is.False); + } + } + [Test] public void TestDeserialiseModifiedClassic() { diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index 2382253036a9..e93a10d50b64 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -248,9 +248,33 @@ public void UpdateDrawableTarget(SkinnableContainer targetContainer) applyMigration(layout, target, i); layout.Version = SkinLayoutInfo.LATEST_VERSION; + + foreach (var kvp in layout.DrawableInfo.ToArray()) + { + foreach (var di in kvp.Value) + { + if (!isValidDrawable(di)) + layout.DrawableInfo[kvp.Key] = kvp.Value.Where(i => i.Type != di.Type).ToArray(); + } + } + return layout; } + private bool isValidDrawable(SerialisedDrawableInfo di) + { + if (!typeof(ISerialisableDrawable).IsAssignableFrom(di.Type)) + return false; + + foreach (var child in di.Children) + { + if (!isValidDrawable(child)) + return false; + } + + return true; + } + private void applyMigration(SkinLayoutInfo layout, GlobalSkinnableContainers target, int version) { switch (version)