diff --git a/Editor/BuildContext.cs b/Editor/BuildContext.cs index f55da35e..10c06558 100644 --- a/Editor/BuildContext.cs +++ b/Editor/BuildContext.cs @@ -115,11 +115,19 @@ namespace nadena.dev.modular_avatar.core.editor return result; } - public AnimatorController ConvertAnimatorController(AnimatorOverrideController overrideController) + public AnimatorController ConvertAnimatorController(RuntimeAnimatorController anyController) { - var merger = new AnimatorCombiner(PluginBuildContext, overrideController.name + " (clone)"); - merger.AddOverrideController("", overrideController, null); - return merger.Finish(); + switch (anyController) + { + case AnimatorController ac: + return ac; + case AnimatorOverrideController aoc: + var merger = new AnimatorCombiner(PluginBuildContext, anyController.name + " (clone)"); + merger.AddOverrideController("", aoc, null); + return merger.Finish(); + default: + throw new Exception("Unknown RuntimeAnimatorContoller type " + anyController.GetType()); + } } #if MA_VRCSDK3_AVATARS diff --git a/Editor/MergeAnimatorProcessor.cs b/Editor/MergeAnimatorProcessor.cs index d6195868..69fb0e28 100644 --- a/Editor/MergeAnimatorProcessor.cs +++ b/Editor/MergeAnimatorProcessor.cs @@ -131,6 +131,11 @@ namespace nadena.dev.modular_avatar.core.editor private void MergeSingle(BuildContext context, AnimatorCombiner session, ModularAvatarMergeAnimator merge) { + if (merge.animator == null) + { + return; + } + string basePath; if (merge.pathMode == MergeAnimatorPathMode.Relative) { @@ -146,7 +151,8 @@ namespace nadena.dev.modular_avatar.core.editor } bool? writeDefaults = merge.matchAvatarWriteDefaults ? writeDefaults_[merge.layerType] : null; - session.AddController(basePath, (AnimatorController)merge.animator, writeDefaults); + var controller = _context.ConvertAnimatorController(merge.animator); + session.AddController(basePath, controller, writeDefaults); if (merge.deleteAttachedAnimator) { diff --git a/UnitTests~/MergeAnimatorTests/AOC_Base.controller b/UnitTests~/MergeAnimatorTests/AOC_Base.controller new file mode 100644 index 00000000..a9282c4a --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/AOC_Base.controller @@ -0,0 +1,72 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1102 &-7522159772221479498 +AnimatorState: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Anim1 + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: [] + m_StateMachineBehaviours: [] + m_Position: {x: 50, y: 50, z: 0} + m_IKOnFeet: 0 + m_WriteDefaultValues: 1 + m_Mirror: 0 + m_SpeedParameterActive: 0 + m_MirrorParameterActive: 0 + m_CycleOffsetParameterActive: 0 + m_TimeParameterActive: 0 + m_Motion: {fileID: 7400000, guid: 3925d31cc9ff67446906c60ce9c245f2, type: 2} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +--- !u!1107 &-2419141567855426485 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Target + m_ChildStates: + - serializedVersion: 1 + m_State: {fileID: -7522159772221479498} + m_Position: {x: 267, y: 200, z: 0} + m_ChildStateMachines: [] + m_AnyStateTransitions: [] + m_EntryTransitions: [] + m_StateMachineTransitions: {} + m_StateMachineBehaviours: [] + m_AnyStatePosition: {x: 50, y: 20, z: 0} + m_EntryPosition: {x: 50, y: 120, z: 0} + m_ExitPosition: {x: 800, y: 120, z: 0} + m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} + m_DefaultState: {fileID: -7522159772221479498} +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: AOC_Base + serializedVersion: 5 + m_AnimatorParameters: [] + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: Target + m_StateMachine: {fileID: -2419141567855426485} + m_Mask: {fileID: 0} + m_Motions: [] + m_Behaviours: [] + m_BlendingMode: 0 + m_SyncedLayerIndex: -1 + m_DefaultWeight: 0 + m_IKPass: 0 + m_SyncedLayerAffectsTiming: 0 + m_Controller: {fileID: 9100000} diff --git a/UnitTests~/MergeAnimatorTests/AOC_Base.controller.meta b/UnitTests~/MergeAnimatorTests/AOC_Base.controller.meta new file mode 100644 index 00000000..b5363556 --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/AOC_Base.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 603635c9d61945c4a9972f00f9206507 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/MergeAnimatorTests/AOC_Override.overrideController b/UnitTests~/MergeAnimatorTests/AOC_Override.overrideController new file mode 100644 index 00000000..d8bcf9e7 --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/AOC_Override.overrideController @@ -0,0 +1,13 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!221 &22100000 +AnimatorOverrideController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: AOC_Override + m_Controller: {fileID: 9100000, guid: 603635c9d61945c4a9972f00f9206507, type: 2} + m_Clips: + - m_OriginalClip: {fileID: 7400000, guid: 3925d31cc9ff67446906c60ce9c245f2, type: 2} + m_OverrideClip: {fileID: 7400000, guid: de95379b15e98fc4c98670377d47267f, type: 2} diff --git a/UnitTests~/MergeAnimatorTests/AOC_Override.overrideController.meta b/UnitTests~/MergeAnimatorTests/AOC_Override.overrideController.meta new file mode 100644 index 00000000..35898fc0 --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/AOC_Override.overrideController.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ba5804e3851377a4e8eba40c65a7c1f1 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 22100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/MergeAnimatorTests/Anim1.anim b/UnitTests~/MergeAnimatorTests/Anim1.anim new file mode 100644 index 00000000..0c9157a9 --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/Anim1.anim @@ -0,0 +1,53 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Anim1 + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: [] + m_PPtrCurves: [] + m_SampleRate: 60 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: [] + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 1 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: [] + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/UnitTests~/MergeAnimatorTests/Anim1.anim.meta b/UnitTests~/MergeAnimatorTests/Anim1.anim.meta new file mode 100644 index 00000000..2182ac3a --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/Anim1.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3925d31cc9ff67446906c60ce9c245f2 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/MergeAnimatorTests/Anim2.anim b/UnitTests~/MergeAnimatorTests/Anim2.anim new file mode 100644 index 00000000..911c31bf --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/Anim2.anim @@ -0,0 +1,53 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Anim2 + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: [] + m_PPtrCurves: [] + m_SampleRate: 60 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: [] + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 1 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: [] + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/UnitTests~/MergeAnimatorTests/Anim2.anim.meta b/UnitTests~/MergeAnimatorTests/Anim2.anim.meta new file mode 100644 index 00000000..f659c89c --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/Anim2.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: de95379b15e98fc4c98670377d47267f +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/MergeAnimatorTests/MergeSingleTests.cs b/UnitTests~/MergeAnimatorTests/MergeSingleTests.cs new file mode 100644 index 00000000..cc92a835 --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/MergeSingleTests.cs @@ -0,0 +1,51 @@ +using modular_avatar_tests; +using nadena.dev.modular_avatar.animation; +using nadena.dev.modular_avatar.core; +using nadena.dev.modular_avatar.core.editor; +using nadena.dev.ndmf; +using NUnit.Framework; +using PlasticPipe.PlasticProtocol.Messages; +using UnityEngine; +using BuildContext = nadena.dev.ndmf.BuildContext; + +namespace UnitTests.MergeAnimatorTests +{ + internal class MergeSingleTests : TestBase + { + [Test] + public void NoErrorWhenAnimatorIsNull() + { + var av = CreateRoot("root"); + + var merge = av.AddComponent(); + + var ctx = new BuildContext(av, null); + ctx.ActivateExtensionContext(); + ctx.ActivateExtensionContext(); + + var errors = ErrorReport.CaptureErrors(() => new MergeAnimatorProcessor().OnPreprocessAvatar(av, ctx)); + + Assert.IsEmpty(errors); + } + + [Test] + public void MergeAnimationOverrideController() + { + var av = CreateRoot("root"); + + var merge = av.AddComponent(); + merge.animator = LoadAsset("AOC_Override.overrideController"); + + var ctx = new BuildContext(av, null); + ctx.ActivateExtensionContext(); + ctx.ActivateExtensionContext(); + + var errors = ErrorReport.CaptureErrors(() => new MergeAnimatorProcessor().OnPreprocessAvatar(av, ctx)); + + Assert.IsEmpty(errors); + + var state = FindStateInLayer(findFxLayer(av, "Target"), "Anim1"); + Assert.IsTrue(state.motion.name.StartsWith("Anim2")); + } + } +} \ No newline at end of file diff --git a/UnitTests~/MergeAnimatorTests/MergeSingleTests.cs.meta b/UnitTests~/MergeAnimatorTests/MergeSingleTests.cs.meta new file mode 100644 index 00000000..c65d1d1c --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/MergeSingleTests.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 04bbb3c34b0149509cf0fcb4d7fffdc6 +timeCreated: 1708936501 \ No newline at end of file