chore: automatically save assets referenced at the end of processing

This commit is contained in:
bd_ 2023-07-30 00:35:07 +09:00
parent dec90cb6ca
commit 7ce6d93083
6 changed files with 87 additions and 29 deletions

View File

@ -31,8 +31,6 @@ namespace nadena.dev.modular_avatar.core.editor
private Dictionary<string, HashSet<ClipHolder>> _pathToClip =
new Dictionary<string, HashSet<ClipHolder>>();
private HashSet<BlendTree> _processedBlendTrees = new HashSet<BlendTree>();
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));
}
}
}

View File

@ -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();

View File

@ -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
{

View File

@ -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<VRCExpressionsMenu, VRCExpressionsMenu> ClonedMenus
= new Dictionary<VRCExpressionsMenu, VRCExpressionsMenu>();
@ -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<UnityEngine.Object> referencedAssets = new HashSet<UnityEngine.Object>();
HashSet<UnityEngine.Object> sceneAssets = new HashSet<UnityEngine.Object>();
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<Component>())
{
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);
}
}
}
}
}
}
}

View File

@ -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);
}
}

View File

@ -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)