diff --git a/Editor/Animation/AnimationUtil.cs b/Editor/Animation/AnimationUtil.cs index 819ade03..6f01b246 100644 --- a/Editor/Animation/AnimationUtil.cs +++ b/Editor/Animation/AnimationUtil.cs @@ -29,7 +29,7 @@ namespace nadena.dev.modular_avatar.animation { if (controller == null) return null; - var merger = new AnimatorCombiner(controller.name + " (clone)", context.AssetContainer); + var merger = new AnimatorCombiner(context, controller.name + " (cloned)"); switch (controller) { case AnimatorController ac: diff --git a/Editor/Animation/AnimatorCombiner.cs b/Editor/Animation/AnimatorCombiner.cs index 6864f8fd..05d7c679 100644 --- a/Editor/Animation/AnimatorCombiner.cs +++ b/Editor/Animation/AnimatorCombiner.cs @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2022-2023 bd_ + * Copyright (c) 2022 bd_ * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,38 +22,38 @@ * SOFTWARE. */ -#region - +#if MA_VRCSDK3_AVATARS +#endif using System; using System.Collections.Generic; using System.Linq; +using nadena.dev.modular_avatar.animation; using nadena.dev.modular_avatar.core.editor; +using nadena.dev.modular_avatar.editor.ErrorReporting; +using nadena.dev.ndmf.util; using UnityEditor; using UnityEditor.Animations; using UnityEngine; - -#if MA_VRCSDK3_AVATARS using VRC.SDK3.Avatars.Components; -#endif - +using VRC.SDKBase; using Object = UnityEngine.Object; -#endregion - namespace nadena.dev.modular_avatar.animation { internal class AnimatorCombiner { private readonly AnimatorController _combined; - private bool isSaved; - private AnimatorOverrideController _overrideController; + private readonly DeepClone _deepClone; private List _layers = new List(); private Dictionary _parameters = new Dictionary(); + private Dictionary _parameterSource = + new Dictionary(); + private Dictionary, Motion> _motions = new Dictionary, Motion>(); @@ -62,38 +62,115 @@ namespace nadena.dev.modular_avatar.animation private Dictionary _cloneMap; - private int controllerBaseLayer = 0; + private int _controllerBaseLayer = 0; - public AnimatorCombiner(String assetName, Object assetContainer) + public VRC_AnimatorLayerControl.BlendableLayer? BlendableLayer; + + public AnimatorCombiner(ndmf.BuildContext context, String assetName) { _combined = new AnimatorController(); - if (assetContainer != null) + if (context.AssetContainer != null && EditorUtility.IsPersistent(context.AssetContainer)) { - if (!EditorUtility.IsPersistent(assetContainer) || - string.IsNullOrEmpty(AssetDatabase.GetAssetPath(assetContainer))) - { - // Debug.Log("Nonpersistent asset container: " + assetContainer.name); - } - else - { - AssetDatabase.AddObjectToAsset(_combined, assetContainer); - } + AssetDatabase.AddObjectToAsset(_combined, context.AssetContainer); } - isSaved = assetContainer != null; _combined.name = assetName; + + _deepClone = new DeepClone(context); } public AnimatorController Finish() { + PruneEmptyLayers(); + _combined.parameters = _parameters.Values.ToArray(); _combined.layers = _layers.ToArray(); return _combined; } - public void AddController(string basePath, AnimatorController controller, bool? writeDefaults) + private void PruneEmptyLayers() { - controllerBaseLayer = _layers.Count; + var originalLayers = _layers; + int[] layerIndexMappings = new int[originalLayers.Count]; + + List newLayers = new List(); + + for (int i = 0; i < originalLayers.Count; i++) + { + if (i > 0 && IsEmptyLayer(originalLayers[i])) + { + layerIndexMappings[i] = -1; + } + else + { + layerIndexMappings[i] = newLayers.Count; + newLayers.Add(originalLayers[i]); + } + } + + foreach (var layer in newLayers) + { + if (layer.stateMachine == null) continue; + + foreach (var asset in layer.stateMachine.ReferencedAssets(includeScene: false)) + { + if (asset is AnimatorState alc) + { + alc.behaviours = AdjustStateBehaviors(alc.behaviours); + } + else if (asset is AnimatorStateMachine asm) + { + asm.behaviours = AdjustStateBehaviors(asm.behaviours); + } + } + } + + _layers = newLayers; + + StateMachineBehaviour[] AdjustStateBehaviors(StateMachineBehaviour[] behaviours) + { + if (behaviours.Length == 0) return behaviours; + + var newBehaviors = new List(); + foreach (var b in behaviours) + { + if (b is VRCAnimatorLayerControl alc && alc.playable == BlendableLayer) + { + int newLayer = -1; + if (alc.layer >= 0 && alc.layer < layerIndexMappings.Length) + { + newLayer = layerIndexMappings[alc.layer]; + } + + if (newLayer != -1) + { + alc.layer = newLayer; + newBehaviors.Add(alc); + } + } + else + { + newBehaviors.Add(b); + } + } + + return newBehaviors.ToArray(); + } + } + + private bool IsEmptyLayer(AnimatorControllerLayer layer) + { + if (layer.syncedLayerIndex >= 0) return false; + if (layer.avatarMask != null) return false; + + return layer.stateMachine == null + || (layer.stateMachine.states.Length == 0 && layer.stateMachine.stateMachines.Length == 0); + } + + public void AddController(string basePath, AnimatorController controller, bool? writeDefaults, + bool forceFirstLayerWeight = false) + { + _controllerBaseLayer = _layers.Count; _cloneMap = new Dictionary(); foreach (var param in controller.parameters) @@ -102,21 +179,20 @@ namespace nadena.dev.modular_avatar.animation { if (acp.type != param.type) { - /* - BuildReport.LogFatal("error.merge_animator.param_type_mismatch", new[] - { - param.name, acp.type.ToString(), - param.type.ToString() - }); - */ - // TODO: Error reporting - throw new Exception("Parameter type mismatch"); + BuildReport.LogFatal("error.merge_animator.param_type_mismatch", + param.name, + acp.type.ToString(), + param.type.ToString(), + controller, + _parameterSource[param.name] + ); } continue; } _parameters.Add(param.name, param); + _parameterSource.Add(param.name, controller); } bool first = true; @@ -124,6 +200,11 @@ namespace nadena.dev.modular_avatar.animation foreach (var layer in layers) { insertLayer(basePath, layer, first, writeDefaults, layers); + if (first && forceFirstLayerWeight) + { + _layers[_layers.Count - 1].defaultWeight = 1; + } + first = false; } } @@ -133,14 +214,13 @@ namespace nadena.dev.modular_avatar.animation { AnimatorController controller = overrideController.runtimeAnimatorController as AnimatorController; if (controller == null) return; - _overrideController = overrideController; + _deepClone.OverrideController = overrideController; try { this.AddController(basePath, controller, writeDefaults); } finally { - _overrideController = null; } } @@ -176,24 +256,23 @@ namespace nadena.dev.modular_avatar.animation var overrideMotion = layer.GetOverrideMotion(state); if (overrideMotion != null) { - newLayer.SetOverrideMotion((AnimatorState) _cloneMap[state], overrideMotion); + newLayer.SetOverrideMotion((AnimatorState)_cloneMap[state], overrideMotion); } - var overrideBehaviors = (StateMachineBehaviour[]) layer.GetOverrideBehaviours(state)?.Clone(); + var overrideBehaviors = (StateMachineBehaviour[])layer.GetOverrideBehaviours(state)?.Clone(); if (overrideBehaviors != null) { for (int i = 0; i < overrideBehaviors.Length; i++) { - overrideBehaviors[i] = deepClone(overrideBehaviors[i], x => x, - new Dictionary()); + overrideBehaviors[i] = _deepClone.DoClone(overrideBehaviors[i]); AdjustBehavior(overrideBehaviors[i]); } - newLayer.SetOverrideBehaviours((AnimatorState) _cloneMap[state], overrideBehaviors); + newLayer.SetOverrideBehaviours((AnimatorState)_cloneMap[state], overrideBehaviors); } } - newLayer.syncedLayerIndex += controllerBaseLayer; + newLayer.syncedLayerIndex += _controllerBaseLayer; } _layers.Add(newLayer); @@ -263,7 +342,7 @@ namespace nadena.dev.modular_avatar.animation return asm; } - asm = deepClone(layerStateMachine, (obj) => customClone(obj, basePath), _cloneMap); + asm = _deepClone.DoClone(layerStateMachine, basePath, _cloneMap); foreach (var state in WalkAllStates(asm)) { @@ -286,166 +365,11 @@ namespace nadena.dev.modular_avatar.animation { // TODO - need to figure out how to handle cross-layer references. For now this will handle // intra-animator cases. - layerControl.layer += controllerBaseLayer; + layerControl.layer += _controllerBaseLayer; break; } } #endif } - - private static string MapPath(EditorCurveBinding binding, string basePath) - { - if (binding.type == typeof(Animator) && binding.path == "") - { - return ""; - } - else - { - var newPath = binding.path == "" ? basePath : basePath + binding.path; - if (newPath.EndsWith("/")) - { - newPath = newPath.Substring(0, newPath.Length - 1); - } - - return newPath; - } - } - - private Object customClone(Object o, string basePath) - { - if (o is AnimationClip clip) - { - if (basePath == "" || clip.IsProxyAnimation()) return clip; - - AnimationClip newClip = new AnimationClip(); - newClip.name = clip.name; - if (isSaved) - { - AssetDatabase.AddObjectToAsset(newClip, _combined); - } - - SerializedObject srcSO = new SerializedObject(clip); - SerializedObject destSO = new SerializedObject(newClip); - - SerializedProperty iter = srcSO.GetIterator(); - - while (iter.Next(false)) - { - destSO.CopyFromSerializedProperty(iter); - } - - destSO.ApplyModifiedPropertiesWithoutUndo(); - - return newClip; - } - else if (o is Texture) - { - return o; - } - else - { - return null; - } - } - - private T deepClone(T original, - Func visitor, - Dictionary cloneMap - ) where T : Object - { - if (original == null) return null; - - // We want to avoid trying to copy assets not part of the animation system (eg - textures, meshes, - // MonoScripts...), so check for the types we care about here - switch (original) - { - // Any object referenced by an animator that we intend to mutate needs to be listed here. - case Motion _: - case AnimatorController _: - case AnimatorState _: - case AnimatorStateMachine _: - case AnimatorTransitionBase _: - case StateMachineBehaviour _: - break; // We want to clone these types - - // Leave textures, materials, and script definitions alone - case Texture2D _: - case MonoScript _: - case Material _: - return original; - - // Also avoid copying unknown scriptable objects. - // This ensures compatibility with e.g. avatar remote, which stores state information in a state - // behaviour referencing a custom ScriptableObject - case ScriptableObject _: - return original; - - default: - throw new Exception($"Unknown type referenced from animator: {original.GetType()}"); - } - - // When using AnimatorOverrideController, replace the original AnimationClip based on AnimatorOverrideController. - if (_overrideController != null && original is AnimationClip srcClip) - { - T overrideClip = _overrideController[srcClip] as T; - if (overrideClip != null) - { - original = overrideClip; - } - } - - if (cloneMap.ContainsKey(original)) - { - return (T) cloneMap[original]; - } - - var obj = visitor(original); - if (obj != null) - { - cloneMap[original] = obj; - return (T) obj; - } - - var ctor = original.GetType().GetConstructor(Type.EmptyTypes); - if (ctor == null || original is ScriptableObject) - { - obj = Object.Instantiate(original); - } - else - { - obj = (T) ctor.Invoke(Array.Empty()); - EditorUtility.CopySerialized(original, obj); - } - - cloneMap[original] = obj; - - if (isSaved && _combined != null && EditorUtility.IsPersistent(_combined)) - { - AssetDatabase.AddObjectToAsset(obj, _combined); - } - - SerializedObject so = new SerializedObject(obj); - SerializedProperty prop = so.GetIterator(); - - bool enterChildren = true; - while (prop.Next(enterChildren)) - { - enterChildren = true; - switch (prop.propertyType) - { - case SerializedPropertyType.ObjectReference: - prop.objectReferenceValue = deepClone(prop.objectReferenceValue, visitor, cloneMap); - break; - // Iterating strings can get super slow... - case SerializedPropertyType.String: - enterChildren = false; - break; - } - } - - so.ApplyModifiedPropertiesWithoutUndo(); - - return (T) obj; - } } } \ No newline at end of file diff --git a/Editor/Animation/AnimatorCombiner.cs.meta b/Editor/Animation/AnimatorCombiner.cs.meta index 699e48b0..27e393c7 100644 --- a/Editor/Animation/AnimatorCombiner.cs.meta +++ b/Editor/Animation/AnimatorCombiner.cs.meta @@ -1,3 +1,3 @@ fileFormatVersion: 2 -guid: 00241ec2d86cdae4bb5076af0699b33a -timeCreated: 1691238359 \ No newline at end of file +guid: 614457d82b1a4b109788029754c9fc1a +timeCreated: 1703674134 \ No newline at end of file diff --git a/Editor/Animation/DeepClone.cs b/Editor/Animation/DeepClone.cs index 86d81421..0636bae1 100644 --- a/Editor/Animation/DeepClone.cs +++ b/Editor/Animation/DeepClone.cs @@ -10,20 +10,20 @@ using BuildContext = nadena.dev.ndmf.BuildContext; namespace nadena.dev.modular_avatar.animation { using UnityObject = UnityEngine.Object; - + internal class DeepClone { private bool _isSaved; private UnityObject _combined; - + public AnimatorOverrideController OverrideController { get; set; } - + public DeepClone(BuildContext context) { - _isSaved = context.AssetContainer != null; + _isSaved = context.AssetContainer != null && EditorUtility.IsPersistent(context.AssetContainer); _combined = context.AssetContainer; - } - + } + public T DoClone(T original, string basePath = null, Dictionary cloneMap = null @@ -79,7 +79,7 @@ namespace nadena.dev.modular_avatar.animation if (cloneMap.ContainsKey(original)) { - return (T) cloneMap[original]; + return (T)cloneMap[original]; } var obj = visitor?.Invoke(original); @@ -90,7 +90,8 @@ namespace nadena.dev.modular_avatar.animation { ObjectRegistry.RegisterReplacedObject(original, obj); } - return (T) obj; + + return (T)obj; } var ctor = original.GetType().GetConstructor(Type.EmptyTypes); @@ -100,7 +101,7 @@ namespace nadena.dev.modular_avatar.animation } else { - obj = (T) ctor.Invoke(Array.Empty()); + obj = (T)ctor.Invoke(Array.Empty()); EditorUtility.CopySerialized(original, obj); } @@ -136,9 +137,9 @@ namespace nadena.dev.modular_avatar.animation so.ApplyModifiedPropertiesWithoutUndo(); - return (T) obj; + return (T)obj; } - + private UnityObject CloneWithPathMapping(UnityObject o, string basePath) { if (o is AnimationClip clip) @@ -188,7 +189,7 @@ namespace nadena.dev.modular_avatar.animation return null; } } - + private static string MapPath(EditorCurveBinding binding, string basePath) { if (binding.type == typeof(Animator) && binding.path == "") diff --git a/Editor/AnimatorMerger.cs b/Editor/AnimatorMerger.cs deleted file mode 100644 index a019369e..00000000 --- a/Editor/AnimatorMerger.cs +++ /dev/null @@ -1,370 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2022 bd_ - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -using System; -using System.Collections.Generic; -using System.Linq; -using nadena.dev.modular_avatar.animation; -using nadena.dev.modular_avatar.editor.ErrorReporting; -using nadena.dev.ndmf.util; -using UnityEditor; -using UnityEditor.Animations; -using UnityEngine; -using VRC.SDKBase; - -#if MA_VRCSDK3_AVATARS -using VRC.SDK3.Avatars.Components; -#endif - -using Object = UnityEngine.Object; - -namespace nadena.dev.modular_avatar.core.editor -{ - internal class AnimatorCombiner - { - private readonly AnimatorController _combined; - private bool isSaved; - - private DeepClone _deepClone; - - private AnimatorOverrideController _overrideController; - - private List _layers = new List(); - - private Dictionary _parameters = - new Dictionary(); - - private Dictionary, Motion> _motions = - new Dictionary, Motion>(); - - private Dictionary, AnimatorStateMachine> _stateMachines = - new Dictionary, AnimatorStateMachine>(); - - private Dictionary _cloneMap; - - private int controllerBaseLayer = 0; - - public VRC_AnimatorLayerControl.BlendableLayer? BlendableLayer; - - public AnimatorCombiner(BuildContext context, String assetName) - { - _combined = context.CreateAnimator(); - isSaved = !string.IsNullOrEmpty(AssetDatabase.GetAssetPath(_combined)); - _combined.name = assetName; - - _deepClone = new DeepClone(context.PluginBuildContext); - } - - public AnimatorController Finish() - { - PruneEmptyLayers(); - - _combined.parameters = _parameters.Values.ToArray(); - _combined.layers = _layers.ToArray(); - return _combined; - } - - private void PruneEmptyLayers() - { - var originalLayers = _layers; - int[] layerIndexMappings = new int[originalLayers.Count]; - - List newLayers = new List(); - - for (int i = 0; i < originalLayers.Count; i++) - { - if (i > 0 && IsEmptyLayer(originalLayers[i])) - { - layerIndexMappings[i] = -1; - } - else - { - layerIndexMappings[i] = newLayers.Count; - newLayers.Add(originalLayers[i]); - } - } - - foreach (var layer in newLayers) - { - if (layer.stateMachine == null) continue; - - foreach (var asset in layer.stateMachine.ReferencedAssets(includeScene: false)) - { - if (asset is AnimatorState alc) - { - alc.behaviours = AdjustStateBehaviors(alc.behaviours); - } - else if (asset is AnimatorStateMachine asm) - { - asm.behaviours = AdjustStateBehaviors(asm.behaviours); - } - } - } - - _layers = newLayers; - - StateMachineBehaviour[] AdjustStateBehaviors(StateMachineBehaviour[] behaviours) - { - if (behaviours.Length == 0) return behaviours; - - var newBehaviors = new List(); - foreach (var b in behaviours) - { - if (b is VRCAnimatorLayerControl alc && alc.playable == BlendableLayer) - { - int newLayer = -1; - if (alc.layer >= 0 && alc.layer < layerIndexMappings.Length) - { - newLayer = layerIndexMappings[alc.layer]; - } - - if (newLayer != -1) - { - alc.layer = newLayer; - newBehaviors.Add(alc); - } - } - else - { - newBehaviors.Add(b); - } - } - - return newBehaviors.ToArray(); - } - } - - private bool IsEmptyLayer(AnimatorControllerLayer layer) - { - if (layer.syncedLayerIndex >= 0) return false; - if (layer.avatarMask != null) return false; - - return layer.stateMachine == null - || (layer.stateMachine.states.Length == 0 && layer.stateMachine.stateMachines.Length == 0); - } - - public void AddController(string basePath, AnimatorController controller, bool? writeDefaults, - bool forceFirstLayerWeight = false) - { - controllerBaseLayer = _layers.Count; - _cloneMap = new Dictionary(); - - foreach (var param in controller.parameters) - { - if (_parameters.TryGetValue(param.name, out var acp)) - { - if (acp.type != param.type) - { - BuildReport.LogFatal("error.merge_animator.param_type_mismatch", new[] - { - param.name, acp.type.ToString(), - param.type.ToString() - }); - } - - continue; - } - - _parameters.Add(param.name, param); - } - - bool first = true; - var layers = controller.layers; - foreach (var layer in layers) - { - insertLayer(basePath, layer, first, writeDefaults, layers); - if (first && forceFirstLayerWeight) - { - _layers[_layers.Count - 1].defaultWeight = 1; - } - - first = false; - } - } - - public void AddOverrideController(string basePath, AnimatorOverrideController overrideController, - bool? writeDefaults) - { - AnimatorController controller = overrideController.runtimeAnimatorController as AnimatorController; - if (controller == null) return; - _deepClone.OverrideController = overrideController; - try - { - this.AddController(basePath, controller, writeDefaults); - } - finally - { - _overrideController = null; - } - } - - private void insertLayer( - string basePath, - AnimatorControllerLayer layer, - bool first, - bool? writeDefaults, - AnimatorControllerLayer[] layers - ) - { - var newLayer = new AnimatorControllerLayer() - { - name = layer.name, - avatarMask = layer.avatarMask, // TODO map transforms - blendingMode = layer.blendingMode, - defaultWeight = first ? 1 : layer.defaultWeight, - syncedLayerIndex = layer.syncedLayerIndex, - syncedLayerAffectsTiming = layer.syncedLayerAffectsTiming, - iKPass = layer.iKPass, - stateMachine = mapStateMachine(basePath, layer.stateMachine), - }; - - UpdateWriteDefaults(newLayer.stateMachine, writeDefaults); - - if (newLayer.syncedLayerIndex != -1 && newLayer.syncedLayerIndex >= 0 && - newLayer.syncedLayerIndex < layers.Length) - { - // Transfer any motion overrides onto the new synced layer - var baseLayer = layers[newLayer.syncedLayerIndex]; - foreach (var state in WalkAllStates(baseLayer.stateMachine)) - { - var overrideMotion = layer.GetOverrideMotion(state); - if (overrideMotion != null) - { - newLayer.SetOverrideMotion((AnimatorState)_cloneMap[state], overrideMotion); - } - - var overrideBehaviors = (StateMachineBehaviour[])layer.GetOverrideBehaviours(state)?.Clone(); - if (overrideBehaviors != null) - { - for (int i = 0; i < overrideBehaviors.Length; i++) - { - overrideBehaviors[i] = _deepClone.DoClone(overrideBehaviors[i]); - AdjustBehavior(overrideBehaviors[i]); - } - - newLayer.SetOverrideBehaviours((AnimatorState)_cloneMap[state], overrideBehaviors); - } - } - - newLayer.syncedLayerIndex += controllerBaseLayer; - } - - _layers.Add(newLayer); - } - - IEnumerable WalkAllStates(AnimatorStateMachine animatorStateMachine) - { - HashSet visited = new HashSet(); - - foreach (var state in VisitStateMachine(animatorStateMachine)) - { - yield return state; - } - - IEnumerable VisitStateMachine(AnimatorStateMachine layerStateMachine) - { - if (!visited.Add(layerStateMachine)) yield break; - - foreach (var state in layerStateMachine.states) - { - if (state.state == null) continue; - - yield return state.state; - } - - foreach (var child in layerStateMachine.stateMachines) - { - if (child.stateMachine == null) continue; - - if (visited.Contains(child.stateMachine)) continue; - visited.Add(child.stateMachine); - foreach (var state in VisitStateMachine(child.stateMachine)) - { - yield return state; - } - } - } - } - - private void UpdateWriteDefaults(AnimatorStateMachine stateMachine, bool? writeDefaults) - { - if (!writeDefaults.HasValue) return; - - var queue = new Queue(); - queue.Enqueue(stateMachine); - while (queue.Count > 0) - { - var sm = queue.Dequeue(); - foreach (var state in sm.states) - { - state.state.writeDefaultValues = writeDefaults.Value; - } - - foreach (var child in sm.stateMachines) - { - queue.Enqueue(child.stateMachine); - } - } - } - - private AnimatorStateMachine mapStateMachine(string basePath, AnimatorStateMachine layerStateMachine) - { - var cacheKey = new KeyValuePair(basePath, layerStateMachine); - - if (_stateMachines.TryGetValue(cacheKey, out var asm)) - { - return asm; - } - - asm = _deepClone.DoClone(layerStateMachine, basePath, _cloneMap); - - foreach (var state in WalkAllStates(asm)) - { - foreach (var behavior in state.behaviours) - { - AdjustBehavior(behavior); - } - } - - _stateMachines[cacheKey] = asm; - return asm; - } - - private void AdjustBehavior(StateMachineBehaviour behavior) - { -#if MA_VRCSDK3_AVATARS - switch (behavior) - { - case VRCAnimatorLayerControl layerControl: - { - // TODO - need to figure out how to handle cross-layer references. For now this will handle - // intra-animator cases. - layerControl.layer += controllerBaseLayer; - break; - } - } -#endif - } - } -} \ No newline at end of file diff --git a/Editor/AnimatorMerger.cs.meta b/Editor/AnimatorMerger.cs.meta deleted file mode 100644 index 9c206683..00000000 --- a/Editor/AnimatorMerger.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 3c76e0db714645f7aa6580f208f98e49 -timeCreated: 1661644852 \ No newline at end of file diff --git a/Editor/BuildContext.cs b/Editor/BuildContext.cs index 5f63afc8..f55da35e 100644 --- a/Editor/BuildContext.cs +++ b/Editor/BuildContext.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using nadena.dev.modular_avatar.animation; +using nadena.dev.ndmf; using UnityEditor; using UnityEditor.Animations; using UnityEngine; @@ -94,7 +95,7 @@ namespace nadena.dev.modular_avatar.core.editor { if (controller == null) return null; - var merger = new AnimatorCombiner(this, controller.name + " (clone)"); + var merger = new AnimatorCombiner(PluginBuildContext, controller.name + " (clone)"); switch (controller) { case AnimatorController ac: @@ -107,12 +108,16 @@ namespace nadena.dev.modular_avatar.core.editor throw new Exception("Unknown RuntimeAnimatorContoller type " + controller.GetType()); } - return merger.Finish(); + var result = merger.Finish(); + + ObjectRegistry.RegisterReplacedObject(controller, result); + + return result; } public AnimatorController ConvertAnimatorController(AnimatorOverrideController overrideController) { - var merger = new AnimatorCombiner(this, overrideController.name + " (clone)"); + var merger = new AnimatorCombiner(PluginBuildContext, overrideController.name + " (clone)"); merger.AddOverrideController("", overrideController, null); return merger.Finish(); } diff --git a/Editor/MergeAnimatorProcessor.cs b/Editor/MergeAnimatorProcessor.cs index 3e70ebab..95371310 100644 --- a/Editor/MergeAnimatorProcessor.cs +++ b/Editor/MergeAnimatorProcessor.cs @@ -27,7 +27,7 @@ using System; using System.Collections.Generic; using System.Linq; -using nadena.dev.modular_avatar.editor.ErrorReporting; +using nadena.dev.modular_avatar.animation; using UnityEditor; using UnityEditor.Animations; using UnityEngine; @@ -108,7 +108,7 @@ namespace nadena.dev.modular_avatar.core.editor var afterOriginal = sorted.Where(x => x.layerPriority >= 0) .ToList(); - var session = new AnimatorCombiner(context, layerType.ToString() + " (merged)"); + var session = new AnimatorCombiner(context.PluginBuildContext, layerType.ToString() + " (merged)"); mergeSessions[layerType] = session; mergeSessions[layerType].BlendableLayer = BlendableLayerFor(layerType); @@ -194,7 +194,8 @@ 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, layer.type.ToString()); + mergeSessions[layer.type] = + new AnimatorCombiner(_context.PluginBuildContext, layer.type.ToString()); mergeSessions[layer.type].BlendableLayer = BlendableLayerFor(layer.type); mergeSessions[layer.type].AddController("", controller, null); }