From 0f2895c14e12313c360a93bcee91f1786b266325 Mon Sep 17 00:00:00 2001 From: bd_ Date: Mon, 31 Jul 2023 21:04:27 +0900 Subject: [PATCH] fix: serialization GC not recursing into scriptable objects --- .../EditModeTests/SerializationSweepTest.cs | 57 ++++++++++++++++++ .../SerializationSweepTest.cs.meta | 3 + .../Editor/BuildContext.cs | 58 ++++++++++++------- 3 files changed, 98 insertions(+), 20 deletions(-) create mode 100644 Assets/_ModularAvatar/EditModeTests/SerializationSweepTest.cs create mode 100644 Assets/_ModularAvatar/EditModeTests/SerializationSweepTest.cs.meta diff --git a/Assets/_ModularAvatar/EditModeTests/SerializationSweepTest.cs b/Assets/_ModularAvatar/EditModeTests/SerializationSweepTest.cs new file mode 100644 index 00000000..3196af7f --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/SerializationSweepTest.cs @@ -0,0 +1,57 @@ +using nadena.dev.modular_avatar.core.editor; +using NUnit.Framework; +using PlasticGui.WorkspaceWindow.QueryViews.Branches; +using UnityEditor; +using UnityEngine; +using VRC.SDK3.Avatars.Components; + +namespace modular_avatar_tests.serialization +{ + class TestComponent : MonoBehaviour + { + public UnityEngine.Object ref1, ref2; + } + + class TestScriptable : ScriptableObject + { + public UnityEngine.Object ref1, ref2; + } + + public class SerializationSweepTest : TestBase + { + [Test] + public void testSerialization() + { + var root = CreateRoot("root"); + var child = CreateChild(root, "child"); + var testComponent = child.AddComponent(); + var testScriptable1 = ScriptableObject.CreateInstance(); + var testScriptable2 = ScriptableObject.CreateInstance(); + var testScriptable3 = ScriptableObject.CreateInstance(); + var testScriptable4 = ScriptableObject.CreateInstance(); + + testComponent.ref1 = testScriptable1; + testComponent.ref2 = root; + + testScriptable1.ref1 = testScriptable2; + testScriptable2.ref1 = testScriptable3; + + testScriptable1.ref2 = testScriptable4; + testScriptable2.ref2 = testScriptable4; + testScriptable3.ref2 = testScriptable4; + + BuildContext bc = new BuildContext(root.GetComponent()); + bc.CommitReferencedAssets(); + + var path = AssetDatabase.GetAssetPath(testScriptable1); + Assert.IsFalse(string.IsNullOrEmpty(path)); + Assert.AreEqual(path, AssetDatabase.GetAssetPath(testScriptable2)); + Assert.AreEqual(path, AssetDatabase.GetAssetPath(testScriptable3)); + Assert.AreEqual(path, AssetDatabase.GetAssetPath(testScriptable4)); + + Assert.IsTrue(string.IsNullOrEmpty(AssetDatabase.GetAssetPath(testComponent))); + Assert.IsTrue(string.IsNullOrEmpty(AssetDatabase.GetAssetPath(root))); + Assert.IsTrue(string.IsNullOrEmpty(AssetDatabase.GetAssetPath(child))); + } + } +} \ No newline at end of file diff --git a/Assets/_ModularAvatar/EditModeTests/SerializationSweepTest.cs.meta b/Assets/_ModularAvatar/EditModeTests/SerializationSweepTest.cs.meta new file mode 100644 index 00000000..d31d3f97 --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/SerializationSweepTest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a8035784f3364865a84cc938682be7a0 +timeCreated: 1690804771 \ No newline at end of file diff --git a/Packages/nadena.dev.modular-avatar/Editor/BuildContext.cs b/Packages/nadena.dev.modular-avatar/Editor/BuildContext.cs index 4d029e07..72adf09d 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/BuildContext.cs +++ b/Packages/nadena.dev.modular-avatar/Editor/BuildContext.cs @@ -133,10 +133,18 @@ namespace nadena.dev.modular_avatar.core.editor Walk(AvatarDescriptor.gameObject); - foreach (var asset in referencedAssets - .Where(o => !sceneAssets.Contains(o)) - .Where(o => string.IsNullOrEmpty(AssetDatabase.GetAssetPath(o)))) + referencedAssets.RemoveWhere(sceneAssets.Contains); + referencedAssets.RemoveWhere(o => !string.IsNullOrEmpty(AssetDatabase.GetAssetPath(o))); + + int index = 0; + + foreach (var asset in referencedAssets) { + if (asset.name == "") + { + asset.name = "Asset " + index++; + } + AssetDatabase.AddObjectToAsset(asset, AssetContainer); } @@ -157,28 +165,38 @@ namespace nadena.dev.modular_avatar.core.editor } } - var so = new SerializedObject(component); - var sp = so.GetIterator(); - bool enterChildren = true; + Queue visitQueue = new Queue(); + visitQueue.Enqueue(component); - while (sp.Next(enterChildren)) + while (visitQueue.Count > 0) { - enterChildren = true; - if (sp.name == "m_GameObject") continue; - if (sp.propertyType == SerializedPropertyType.String) - { - enterChildren = false; - continue; - } + var current = visitQueue.Dequeue(); + if (referencedAssets.Contains(current)) continue; + referencedAssets.Add(current); - if (sp.propertyType != SerializedPropertyType.ObjectReference) - { - continue; - } + var so = new SerializedObject(current); + var sp = so.GetIterator(); + bool enterChildren = true; - if (sp.objectReferenceValue != null) + while (sp.Next(enterChildren)) { - referencedAssets.Add(sp.objectReferenceValue); + enterChildren = true; + if (sp.name == "m_GameObject") continue; + if (sp.propertyType == SerializedPropertyType.String) + { + enterChildren = false; + continue; + } + + if (sp.propertyType != SerializedPropertyType.ObjectReference) + { + continue; + } + + if (sp.objectReferenceValue != null) + { + visitQueue.Enqueue(sp.objectReferenceValue); + } } } }