mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2025-01-04 13:45:04 +08:00
chore: automatically save assets referenced at the end of processing
This commit is contained in:
parent
dec90cb6ca
commit
7ce6d93083
@ -31,8 +31,6 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
private Dictionary<string, HashSet<ClipHolder>> _pathToClip =
|
private Dictionary<string, HashSet<ClipHolder>> _pathToClip =
|
||||||
new Dictionary<string, HashSet<ClipHolder>>();
|
new Dictionary<string, HashSet<ClipHolder>>();
|
||||||
|
|
||||||
private HashSet<BlendTree> _processedBlendTrees = new HashSet<BlendTree>();
|
|
||||||
|
|
||||||
internal void Commit()
|
internal void Commit()
|
||||||
{
|
{
|
||||||
foreach (var clip in _clips)
|
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
|
// 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
|
// animation, we'll restore the original in a later pass
|
||||||
var placeholder = Object.Instantiate(state.motion);
|
var placeholder = Object.Instantiate(state.motion);
|
||||||
AssetDatabase.AddObjectToAsset(placeholder, state);
|
|
||||||
clipHolder.CurrentClip = placeholder;
|
clipHolder.CurrentClip = placeholder;
|
||||||
if (isProxyAnim)
|
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);
|
processClip(holder);
|
||||||
recordPaths(holder);
|
recordPaths(holder);
|
||||||
_clips.Add(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;
|
break;
|
||||||
}
|
}
|
||||||
case BlendTree tree:
|
case BlendTree tree:
|
||||||
@ -260,10 +247,6 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
{
|
{
|
||||||
children[i].motion = curClip;
|
children[i].motion = curClip;
|
||||||
dirty = true;
|
dirty = true;
|
||||||
if (string.IsNullOrWhiteSpace(AssetDatabase.GetAssetPath(curClip)))
|
|
||||||
{
|
|
||||||
AssetDatabase.AddObjectToAsset(curClip, AssetDatabase.GetAssetPath(state));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
internal class AnimatorCombiner
|
internal class AnimatorCombiner
|
||||||
{
|
{
|
||||||
private readonly AnimatorController _combined;
|
private readonly AnimatorController _combined;
|
||||||
|
private bool isSaved;
|
||||||
|
|
||||||
private AnimatorOverrideController _overrideController;
|
private AnimatorOverrideController _overrideController;
|
||||||
|
|
||||||
@ -55,9 +56,11 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
private int controllerBaseLayer = 0;
|
private int controllerBaseLayer = 0;
|
||||||
|
|
||||||
public AnimatorCombiner(BuildContext context)
|
public AnimatorCombiner(BuildContext context, String assetName)
|
||||||
{
|
{
|
||||||
_combined = context.CreateAnimator();
|
_combined = context.CreateAnimator();
|
||||||
|
isSaved = !string.IsNullOrEmpty(AssetDatabase.GetAssetPath(_combined));
|
||||||
|
_combined.name = assetName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AnimatorController Finish()
|
public AnimatorController Finish()
|
||||||
@ -289,7 +292,10 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
AnimationClip newClip = new AnimationClip();
|
AnimationClip newClip = new AnimationClip();
|
||||||
newClip.name = "rebased " + clip.name;
|
newClip.name = "rebased " + clip.name;
|
||||||
AssetDatabase.AddObjectToAsset(newClip, _combined);
|
if (isSaved)
|
||||||
|
{
|
||||||
|
AssetDatabase.AddObjectToAsset(newClip, _combined);
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var binding in AnimationUtility.GetCurveBindings(clip))
|
foreach (var binding in AnimationUtility.GetCurveBindings(clip))
|
||||||
{
|
{
|
||||||
@ -396,7 +402,10 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
cloneMap[original] = obj;
|
cloneMap[original] = obj;
|
||||||
|
|
||||||
AssetDatabase.AddObjectToAsset(obj, _combined);
|
if (isSaved)
|
||||||
|
{
|
||||||
|
AssetDatabase.AddObjectToAsset(obj, _combined);
|
||||||
|
}
|
||||||
|
|
||||||
SerializedObject so = new SerializedObject(obj);
|
SerializedObject so = new SerializedObject(obj);
|
||||||
SerializedProperty prop = so.GetIterator();
|
SerializedProperty prop = so.GetIterator();
|
||||||
|
@ -211,11 +211,15 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
new BlendshapeSyncAnimationProcessor().OnPreprocessAvatar(avatarGameObject, context);
|
new BlendshapeSyncAnimationProcessor().OnPreprocessAvatar(avatarGameObject, context);
|
||||||
PhysboneBlockerPass.Process(avatarGameObject);
|
PhysboneBlockerPass.Process(avatarGameObject);
|
||||||
|
|
||||||
|
context.CommitReferencedAssets();
|
||||||
|
|
||||||
AfterProcessing?.Invoke(avatarGameObject, context);
|
AfterProcessing?.Invoke(avatarGameObject, context);
|
||||||
|
|
||||||
context.AnimationDatabase.Commit();
|
context.AnimationDatabase.Commit();
|
||||||
|
|
||||||
new GCGameObjectsPass(context, avatarGameObject).OnPreprocessAvatar();
|
new GCGameObjectsPass(context, avatarGameObject).OnPreprocessAvatar();
|
||||||
|
|
||||||
|
context.CommitReferencedAssets();
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEditor.Animations;
|
using UnityEditor.Animations;
|
||||||
@ -16,6 +17,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
internal readonly AnimationDatabase AnimationDatabase = new AnimationDatabase();
|
internal readonly AnimationDatabase AnimationDatabase = new AnimationDatabase();
|
||||||
internal readonly UnityEngine.Object AssetContainer;
|
internal readonly UnityEngine.Object AssetContainer;
|
||||||
|
|
||||||
|
private bool SaveImmediate = false;
|
||||||
|
|
||||||
internal readonly Dictionary<VRCExpressionsMenu, VRCExpressionsMenu> ClonedMenus
|
internal readonly Dictionary<VRCExpressionsMenu, VRCExpressionsMenu> ClonedMenus
|
||||||
= new Dictionary<VRCExpressionsMenu, VRCExpressionsMenu>();
|
= new Dictionary<VRCExpressionsMenu, VRCExpressionsMenu>();
|
||||||
|
|
||||||
@ -41,7 +44,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
public void SaveAsset(Object obj)
|
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);
|
AssetDatabase.AddObjectToAsset(obj, AssetContainer);
|
||||||
}
|
}
|
||||||
@ -67,7 +70,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
{
|
{
|
||||||
if (controller == null) return null;
|
if (controller == null) return null;
|
||||||
|
|
||||||
var merger = new AnimatorCombiner(this);
|
var merger = new AnimatorCombiner(this, controller.name + " (clone)");
|
||||||
switch (controller)
|
switch (controller)
|
||||||
{
|
{
|
||||||
case AnimatorController ac:
|
case AnimatorController ac:
|
||||||
@ -85,7 +88,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
public AnimatorController ConvertAnimatorController(AnimatorOverrideController overrideController)
|
public AnimatorController ConvertAnimatorController(AnimatorOverrideController overrideController)
|
||||||
{
|
{
|
||||||
var merger = new AnimatorCombiner(this);
|
var merger = new AnimatorCombiner(this, overrideController.name + " (clone)");
|
||||||
merger.AddOverrideController("", overrideController, null);
|
merger.AddOverrideController("", overrideController, null);
|
||||||
return merger.Finish();
|
return merger.Finish();
|
||||||
}
|
}
|
||||||
@ -122,5 +125,64 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
return newMenu;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -92,11 +92,11 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
if (!mergeSessions.TryGetValue(merge.layerType, out var session))
|
if (!mergeSessions.TryGetValue(merge.layerType, out var session))
|
||||||
{
|
{
|
||||||
session = new AnimatorCombiner(context);
|
session = new AnimatorCombiner(context, merge.layerType.ToString() + " (merged)");
|
||||||
mergeSessions[merge.layerType] = session;
|
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
|
// For non-default layers, ensure we always clone the controller for the benefit of subsequent
|
||||||
// processing phases
|
// processing phases
|
||||||
mergeSessions[layer.type] = new AnimatorCombiner(_context);
|
mergeSessions[layer.type] = new AnimatorCombiner(_context, layer.type.ToString());
|
||||||
mergeSessions[layer.type].AddController("", controller, null);
|
mergeSessions[layer.type].AddController("", controller, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,7 +195,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
{
|
{
|
||||||
var path = AssetDatabase.GetAssetPath(obj);
|
var path = AssetDatabase.GetAssetPath(obj);
|
||||||
|
|
||||||
return path != null && path.StartsWith(GetGeneratedAssetsFolder() + "/");
|
return string.IsNullOrEmpty(path) || path.StartsWith(GetGeneratedAssetsFolder() + "/");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Type FindType(string typeName)
|
public static Type FindType(string typeName)
|
||||||
|
Loading…
Reference in New Issue
Block a user