From 7ce6d9308383743c59a4b9c1071bfc8d043449d3 Mon Sep 17 00:00:00 2001 From: bd_ Date: Sun, 30 Jul 2023 00:35:07 +0900 Subject: [PATCH] chore: automatically save assets referenced at the end of processing --- .../Editor/AnimationDatabase.cs | 19 +----- .../Editor/AnimatorMerger.cs | 15 +++- .../Editor/AvatarProcessor.cs | 4 ++ .../Editor/BuildContext.cs | 68 ++++++++++++++++++- .../Editor/MergeAnimatorProcessor.cs | 8 +-- .../nadena.dev.modular-avatar/Editor/Util.cs | 2 +- 6 files changed, 87 insertions(+), 29 deletions(-) diff --git a/Packages/nadena.dev.modular-avatar/Editor/AnimationDatabase.cs b/Packages/nadena.dev.modular-avatar/Editor/AnimationDatabase.cs index c1eca706..97c580a2 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/AnimationDatabase.cs +++ b/Packages/nadena.dev.modular-avatar/Editor/AnimationDatabase.cs @@ -31,8 +31,6 @@ namespace nadena.dev.modular_avatar.core.editor private Dictionary> _pathToClip = new Dictionary>(); - private HashSet _processedBlendTrees = new HashSet(); - internal void Commit() { foreach (var clip in _clips) @@ -115,11 +113,10 @@ namespace nadena.dev.modular_avatar.core.editor // Protect the original animations from mutations by creating temporary clones; in the case of a proxy // animation, we'll restore the original in a later pass var placeholder = Object.Instantiate(state.motion); - AssetDatabase.AddObjectToAsset(placeholder, state); clipHolder.CurrentClip = placeholder; if (isProxyAnim) { - _clipCommitActions.Add(() => { Object.DestroyImmediate(placeholder, true); }); + _clipCommitActions.Add(() => { Object.DestroyImmediate(placeholder); }); } } @@ -177,16 +174,6 @@ namespace nadena.dev.modular_avatar.core.editor processClip(holder); recordPaths(holder); _clips.Add(holder); - _clipCommitActions.Add(() => - { - if (holder.CurrentClip != holder.OriginalClip) - { - if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(holder.CurrentClip))) - { - AssetDatabase.AddObjectToAsset(holder.CurrentClip, AssetDatabase.GetAssetPath(state)); - } - } - }); break; } case BlendTree tree: @@ -260,10 +247,6 @@ namespace nadena.dev.modular_avatar.core.editor { children[i].motion = curClip; dirty = true; - if (string.IsNullOrWhiteSpace(AssetDatabase.GetAssetPath(curClip))) - { - AssetDatabase.AddObjectToAsset(curClip, AssetDatabase.GetAssetPath(state)); - } } } diff --git a/Packages/nadena.dev.modular-avatar/Editor/AnimatorMerger.cs b/Packages/nadena.dev.modular-avatar/Editor/AnimatorMerger.cs index 953caaba..a2090c48 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/AnimatorMerger.cs +++ b/Packages/nadena.dev.modular-avatar/Editor/AnimatorMerger.cs @@ -37,6 +37,7 @@ namespace nadena.dev.modular_avatar.core.editor internal class AnimatorCombiner { private readonly AnimatorController _combined; + private bool isSaved; private AnimatorOverrideController _overrideController; @@ -55,9 +56,11 @@ namespace nadena.dev.modular_avatar.core.editor private int controllerBaseLayer = 0; - public AnimatorCombiner(BuildContext context) + public AnimatorCombiner(BuildContext context, String assetName) { _combined = context.CreateAnimator(); + isSaved = !string.IsNullOrEmpty(AssetDatabase.GetAssetPath(_combined)); + _combined.name = assetName; } public AnimatorController Finish() @@ -289,7 +292,10 @@ namespace nadena.dev.modular_avatar.core.editor AnimationClip newClip = new AnimationClip(); newClip.name = "rebased " + clip.name; - AssetDatabase.AddObjectToAsset(newClip, _combined); + if (isSaved) + { + AssetDatabase.AddObjectToAsset(newClip, _combined); + } foreach (var binding in AnimationUtility.GetCurveBindings(clip)) { @@ -396,7 +402,10 @@ namespace nadena.dev.modular_avatar.core.editor cloneMap[original] = obj; - AssetDatabase.AddObjectToAsset(obj, _combined); + if (isSaved) + { + AssetDatabase.AddObjectToAsset(obj, _combined); + } SerializedObject so = new SerializedObject(obj); SerializedProperty prop = so.GetIterator(); diff --git a/Packages/nadena.dev.modular-avatar/Editor/AvatarProcessor.cs b/Packages/nadena.dev.modular-avatar/Editor/AvatarProcessor.cs index 51b3cb6f..f82eddce 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/AvatarProcessor.cs +++ b/Packages/nadena.dev.modular-avatar/Editor/AvatarProcessor.cs @@ -211,11 +211,15 @@ namespace nadena.dev.modular_avatar.core.editor new BlendshapeSyncAnimationProcessor().OnPreprocessAvatar(avatarGameObject, context); PhysboneBlockerPass.Process(avatarGameObject); + context.CommitReferencedAssets(); + AfterProcessing?.Invoke(avatarGameObject, context); context.AnimationDatabase.Commit(); new GCGameObjectsPass(context, avatarGameObject).OnPreprocessAvatar(); + + context.CommitReferencedAssets(); } finally { diff --git a/Packages/nadena.dev.modular-avatar/Editor/BuildContext.cs b/Packages/nadena.dev.modular-avatar/Editor/BuildContext.cs index fe2c2afa..4d029e07 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/BuildContext.cs +++ b/Packages/nadena.dev.modular-avatar/Editor/BuildContext.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using JetBrains.Annotations; using UnityEditor; using UnityEditor.Animations; @@ -16,6 +17,8 @@ namespace nadena.dev.modular_avatar.core.editor internal readonly AnimationDatabase AnimationDatabase = new AnimationDatabase(); internal readonly UnityEngine.Object AssetContainer; + private bool SaveImmediate = false; + internal readonly Dictionary ClonedMenus = new Dictionary(); @@ -41,7 +44,7 @@ namespace nadena.dev.modular_avatar.core.editor public void SaveAsset(Object obj) { - if (AssetDatabase.IsMainAsset(obj) || AssetDatabase.IsSubAsset(obj)) return; + if (!SaveImmediate || AssetDatabase.IsMainAsset(obj) || AssetDatabase.IsSubAsset(obj)) return; AssetDatabase.AddObjectToAsset(obj, AssetContainer); } @@ -67,7 +70,7 @@ namespace nadena.dev.modular_avatar.core.editor { if (controller == null) return null; - var merger = new AnimatorCombiner(this); + var merger = new AnimatorCombiner(this, controller.name + " (clone)"); switch (controller) { case AnimatorController ac: @@ -85,7 +88,7 @@ namespace nadena.dev.modular_avatar.core.editor public AnimatorController ConvertAnimatorController(AnimatorOverrideController overrideController) { - var merger = new AnimatorCombiner(this); + var merger = new AnimatorCombiner(this, overrideController.name + " (clone)"); merger.AddOverrideController("", overrideController, null); return merger.Finish(); } @@ -122,5 +125,64 @@ namespace nadena.dev.modular_avatar.core.editor return newMenu; } + + public void CommitReferencedAssets() + { + HashSet referencedAssets = new HashSet(); + HashSet sceneAssets = new HashSet(); + + Walk(AvatarDescriptor.gameObject); + + foreach (var asset in referencedAssets + .Where(o => !sceneAssets.Contains(o)) + .Where(o => string.IsNullOrEmpty(AssetDatabase.GetAssetPath(o)))) + { + AssetDatabase.AddObjectToAsset(asset, AssetContainer); + } + + SaveImmediate = true; + + void Walk(GameObject obj) + { + sceneAssets.Add(obj); + + foreach (var component in obj.GetComponents()) + { + sceneAssets.Add(component); + if (component is Transform t) + { + foreach (Transform child in t) + { + Walk(child.gameObject); + } + } + + var so = new SerializedObject(component); + var sp = so.GetIterator(); + bool enterChildren = true; + + while (sp.Next(enterChildren)) + { + 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) + { + referencedAssets.Add(sp.objectReferenceValue); + } + } + } + } + } } } \ No newline at end of file diff --git a/Packages/nadena.dev.modular-avatar/Editor/MergeAnimatorProcessor.cs b/Packages/nadena.dev.modular-avatar/Editor/MergeAnimatorProcessor.cs index c4638803..59b072d7 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/MergeAnimatorProcessor.cs +++ b/Packages/nadena.dev.modular-avatar/Editor/MergeAnimatorProcessor.cs @@ -92,11 +92,11 @@ namespace nadena.dev.modular_avatar.core.editor if (!mergeSessions.TryGetValue(merge.layerType, out var session)) { - session = new AnimatorCombiner(context); + session = new AnimatorCombiner(context, merge.layerType.ToString() + " (merged)"); mergeSessions[merge.layerType] = session; - if (defaultControllers_.ContainsKey(merge.layerType)) + if (defaultControllers_.TryGetValue(merge.layerType, out var defaultController)) { - session.AddController("", defaultControllers_[merge.layerType], null); + session.AddController("", defaultController, null); } } @@ -142,7 +142,7 @@ namespace nadena.dev.modular_avatar.core.editor { // For non-default layers, ensure we always clone the controller for the benefit of subsequent // processing phases - mergeSessions[layer.type] = new AnimatorCombiner(_context); + mergeSessions[layer.type] = new AnimatorCombiner(_context, layer.type.ToString()); mergeSessions[layer.type].AddController("", controller, null); } } diff --git a/Packages/nadena.dev.modular-avatar/Editor/Util.cs b/Packages/nadena.dev.modular-avatar/Editor/Util.cs index 49b2fdbc..341cf76c 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/Util.cs +++ b/Packages/nadena.dev.modular-avatar/Editor/Util.cs @@ -195,7 +195,7 @@ namespace nadena.dev.modular_avatar.core.editor { var path = AssetDatabase.GetAssetPath(obj); - return path != null && path.StartsWith(GetGeneratedAssetsFolder() + "/"); + return string.IsNullOrEmpty(path) || path.StartsWith(GetGeneratedAssetsFolder() + "/"); } public static Type FindType(string typeName)