From 2cf5967a42f0d6ca57c143da1f0480f1253a36b1 Mon Sep 17 00:00:00 2001 From: bd_ Date: Mon, 12 Feb 2024 14:59:39 +0900 Subject: [PATCH] feat: allow animator-only defaults to be set using MA Parameters (#648) * feat: allow animator-only defaults to be set using MA Parameters * chore: add unit tests for new default parameter behavior --- Editor/ApplyAnimatorDefaultValuesPass.cs | 53 +++ Editor/ApplyAnimatorDefaultValuesPass.cs.meta | 3 + Editor/PluginDefinition/PluginDefinition.cs | 1 + Editor/RenameParametersHook.cs | 16 +- .../AnimatorOnlyParameterValues.meta | 8 + .../AnimatorOnlyParameterValues/AOPV.prefab | 408 ++++++++++++++++++ .../AOPV.prefab.meta | 7 + .../ac1.controller | 67 +++ .../ac1.controller.meta | 8 + .../ac2.controller | 67 +++ .../ac2.controller.meta | 8 + .../RenameParametersTests.cs | 37 ++ 12 files changed, 681 insertions(+), 2 deletions(-) create mode 100644 Editor/ApplyAnimatorDefaultValuesPass.cs create mode 100644 Editor/ApplyAnimatorDefaultValuesPass.cs.meta create mode 100644 UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues.meta create mode 100644 UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues/AOPV.prefab create mode 100644 UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues/AOPV.prefab.meta create mode 100644 UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues/ac1.controller create mode 100644 UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues/ac1.controller.meta create mode 100644 UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues/ac2.controller create mode 100644 UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues/ac2.controller.meta diff --git a/Editor/ApplyAnimatorDefaultValuesPass.cs b/Editor/ApplyAnimatorDefaultValuesPass.cs new file mode 100644 index 00000000..f416a3bd --- /dev/null +++ b/Editor/ApplyAnimatorDefaultValuesPass.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Immutable; +using System.Linq; +using nadena.dev.ndmf; +using UnityEngine; + +namespace nadena.dev.modular_avatar.core.editor +{ + internal class ApplyAnimatorDefaultValuesPass : Pass + { + protected override void Execute(ndmf.BuildContext context) + { + var values = context.GetState()?.InitialValue + ?? ImmutableDictionary.Empty; + + foreach (var layer in context.AvatarDescriptor.baseAnimationLayers + .Concat(context.AvatarDescriptor.specialAnimationLayers)) + { + if (layer.isDefault || layer.animatorController == null) continue; + + // We should have converted anything that's not an AnimationController by now + var controller = layer.animatorController as UnityEditor.Animations.AnimatorController; + if (controller == null || !context.IsTemporaryAsset(controller)) + { + throw new Exception("Leaked unexpected controller: " + layer.animatorController + " (type " + layer.animatorController?.GetType() + ")"); + } + + var parameters = controller.parameters; + for (int i = 0; i < parameters.Length; i++) + { + if (!values.TryGetValue(parameters[i].name, out var defaultValue)) continue; + + switch (parameters[i].type) + { + case AnimatorControllerParameterType.Bool: + parameters[i].defaultBool = defaultValue > 0.5f; + break; + case AnimatorControllerParameterType.Int: + parameters[i].defaultInt = Mathf.RoundToInt(defaultValue); + break; + case AnimatorControllerParameterType.Float: + parameters[i].defaultFloat = defaultValue; + break; + default: + continue; // unhandled type, e.g. trigger + } + } + + controller.parameters = parameters; + } + } + } +} \ No newline at end of file diff --git a/Editor/ApplyAnimatorDefaultValuesPass.cs.meta b/Editor/ApplyAnimatorDefaultValuesPass.cs.meta new file mode 100644 index 00000000..1a912c6b --- /dev/null +++ b/Editor/ApplyAnimatorDefaultValuesPass.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e8f311932a744459aed7d22dee0e126c +timeCreated: 1707045893 \ No newline at end of file diff --git a/Editor/PluginDefinition/PluginDefinition.cs b/Editor/PluginDefinition/PluginDefinition.cs index a80c4b80..c8e31e5d 100644 --- a/Editor/PluginDefinition/PluginDefinition.cs +++ b/Editor/PluginDefinition/PluginDefinition.cs @@ -40,6 +40,7 @@ namespace nadena.dev.modular_avatar.core.editor.plugin seq.Run(RenameParametersPluginPass.Instance); seq.Run(MergeBlendTreePass.Instance); seq.Run(MergeAnimatorPluginPass.Instance); + seq.Run(ApplyAnimatorDefaultValuesPass.Instance); seq.Run(MenuInstallPluginPass.Instance); #endif seq.WithRequiredExtension(typeof(AnimationServicesContext), _s2 => diff --git a/Editor/RenameParametersHook.cs b/Editor/RenameParametersHook.cs index 201c070e..ec52e580 100644 --- a/Editor/RenameParametersHook.cs +++ b/Editor/RenameParametersHook.cs @@ -20,6 +20,11 @@ using UnityObject = UnityEngine.Object; namespace nadena.dev.modular_avatar.core.editor { + internal class DefaultValues + { + public ImmutableDictionary InitialValue; + } + internal class RenameParametersHook { private const string DEFAULT_EXP_PARAMS_ASSET_GUID = "03a6d797deb62f0429471c4e17ea99a7"; @@ -114,10 +119,17 @@ namespace nadena.dev.modular_avatar.core.editor var syncParams = WalkTree(avatar, ImmutableDictionary.Empty, ImmutableDictionary.Empty); SetExpressionParameters(avatar, syncParams); + + _context.PluginBuildContext.GetState().InitialValue + = syncParams.Where(p => p.Value.ResolvedParameter.HasDefaultValue) + .ToImmutableDictionary(p => p.Key, p => p.Value.ResolvedParameter.defaultValue); } - private void SetExpressionParameters(GameObject avatarRoot, ImmutableDictionary syncParams) + private void SetExpressionParameters(GameObject avatarRoot, ImmutableDictionary allParams) { + var syncParams = allParams.Where(kvp => kvp.Value.ResolvedParameter.syncType != ParameterSyncType.NotSynced) + .ToImmutableDictionary(); + var avatar = avatarRoot.GetComponent(); var expParams = avatar.expressionParameters; @@ -648,7 +660,7 @@ namespace nadena.dev.modular_avatar.core.editor } } - if (!param.isPrefix && param.syncType != ParameterSyncType.NotSynced) + if (!param.isPrefix) { if (rv.ContainsKey(remapTo)) { diff --git a/UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues.meta b/UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues.meta new file mode 100644 index 00000000..140472cd --- /dev/null +++ b/UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1d959d2dcc6c65c4ba75b587e56a76f7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues/AOPV.prefab b/UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues/AOPV.prefab new file mode 100644 index 00000000..a1fef137 --- /dev/null +++ b/UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues/AOPV.prefab @@ -0,0 +1,408 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1146842459033375789 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1388565123683326355} + - component: {fileID: 6641584435979314703} + m_Layer: 0 + m_Name: GameObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1388565123683326355 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1146842459033375789} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 4755457544124752861} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &6641584435979314703 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1146842459033375789} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 71a96d4ea0c344f39e277d82035bf9bd, type: 3} + m_Name: + m_EditorClassIdentifier: + parameters: + - nameOrPrefix: float + remapTo: + internalParameter: 0 + isPrefix: 0 + syncType: 0 + localOnly: 0 + defaultValue: 0.5 + saved: 0 + hasExplicitDefaultValue: 1 + - nameOrPrefix: bool + remapTo: + internalParameter: 0 + isPrefix: 0 + syncType: 0 + localOnly: 0 + defaultValue: 1 + saved: 0 + hasExplicitDefaultValue: 1 + - nameOrPrefix: int + remapTo: + internalParameter: 0 + isPrefix: 0 + syncType: 0 + localOnly: 0 + defaultValue: 23 + saved: 0 + hasExplicitDefaultValue: 1 + - nameOrPrefix: trigger + remapTo: + internalParameter: 0 + isPrefix: 0 + syncType: 0 + localOnly: 0 + defaultValue: 1 + saved: 0 + hasExplicitDefaultValue: 1 +--- !u!1 &2576168357133539830 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4755457544124752861} + - component: {fileID: 9113738387598123670} + - component: {fileID: 6292158377587651209} + - component: {fileID: 3191642752103959841} + m_Layer: 0 + m_Name: AOPV + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4755457544124752861 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2576168357133539830} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -0.49291945, y: 1.0160161, z: -0.18302894} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1388565123683326355} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!95 &9113738387598123670 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2576168357133539830} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 0} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 + m_WriteDefaultValuesOnDisable: 0 +--- !u!114 &6292158377587651209 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2576168357133539830} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 542108242, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3} + m_Name: + m_EditorClassIdentifier: + Name: + ViewPosition: {x: 0, y: 1.6, z: 0.2} + Animations: 0 + ScaleIPD: 1 + lipSync: 0 + lipSyncJawBone: {fileID: 0} + lipSyncJawClosed: {x: 0, y: 0, z: 0, w: 1} + lipSyncJawOpen: {x: 0, y: 0, z: 0, w: 1} + VisemeSkinnedMesh: {fileID: 0} + MouthOpenBlendShapeName: Facial_Blends.Jaw_Down + VisemeBlendShapes: [] + unityVersion: + portraitCameraPositionOffset: {x: 0, y: 0, z: 0} + portraitCameraRotationOffset: {x: 0, y: 1, z: 0, w: -0.00000004371139} + networkIDs: [] + customExpressions: 0 + expressionsMenu: {fileID: 0} + expressionParameters: {fileID: 0} + enableEyeLook: 0 + customEyeLookSettings: + eyeMovement: + confidence: 0.5 + excitement: 0.5 + leftEye: {fileID: 0} + rightEye: {fileID: 0} + eyesLookingStraight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingUp: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingDown: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingLeft: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingRight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidType: 0 + upperLeftEyelid: {fileID: 0} + upperRightEyelid: {fileID: 0} + lowerLeftEyelid: {fileID: 0} + lowerRightEyelid: {fileID: 0} + eyelidsDefault: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsClosed: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingUp: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingDown: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsSkinnedMesh: {fileID: 0} + eyelidsBlendshapes: + customizeAnimationLayers: 1 + baseAnimationLayers: + - isEnabled: 0 + type: 0 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 4 + animatorController: {fileID: 9100000, guid: 8235cc3d767d4cb489bcf06909ef40ef, + type: 2} + mask: {fileID: 0} + isDefault: 0 + - isEnabled: 0 + type: 5 + animatorController: {fileID: 9100000, guid: f560e47839e8d8d4a986103d445ca36a, + type: 2} + mask: {fileID: 0} + isDefault: 0 + specialAnimationLayers: + - isEnabled: 0 + type: 6 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 7 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 8 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + AnimationPreset: {fileID: 0} + animationHashSet: [] + autoFootsteps: 1 + autoLocomotion: 1 + collider_head: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_torso: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &3191642752103959841 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2576168357133539830} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3} + m_Name: + m_EditorClassIdentifier: + launchedFromSDKPipeline: 0 + completedSDKPipeline: 0 + blueprintId: + contentType: 0 + assetBundleUnityVersion: + fallbackStatus: 0 diff --git a/UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues/AOPV.prefab.meta b/UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues/AOPV.prefab.meta new file mode 100644 index 00000000..d25e18ec --- /dev/null +++ b/UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues/AOPV.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 55a561e6b9d99284cae429cb16700958 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues/ac1.controller b/UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues/ac1.controller new file mode 100644 index 00000000..d399af61 --- /dev/null +++ b/UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues/ac1.controller @@ -0,0 +1,67 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1107 &-7364175626657849038 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Base Layer + m_ChildStates: [] + 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: 0} +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: ac1 + serializedVersion: 5 + m_AnimatorParameters: + - m_Name: float + m_Type: 1 + m_DefaultFloat: 0 + m_DefaultInt: 0 + m_DefaultBool: 0 + m_Controller: {fileID: 0} + - m_Name: int + m_Type: 3 + m_DefaultFloat: 0 + m_DefaultInt: 0 + m_DefaultBool: 0 + m_Controller: {fileID: 0} + - m_Name: bool + m_Type: 4 + m_DefaultFloat: 0 + m_DefaultInt: 0 + m_DefaultBool: 0 + m_Controller: {fileID: 0} + - m_Name: trigger + m_Type: 9 + m_DefaultFloat: 0 + m_DefaultInt: 0 + m_DefaultBool: 0 + m_Controller: {fileID: 0} + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: Base Layer + m_StateMachine: {fileID: -7364175626657849038} + 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~/RenameParametersTests/AnimatorOnlyParameterValues/ac1.controller.meta b/UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues/ac1.controller.meta new file mode 100644 index 00000000..7c8568cb --- /dev/null +++ b/UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues/ac1.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f560e47839e8d8d4a986103d445ca36a +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues/ac2.controller b/UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues/ac2.controller new file mode 100644 index 00000000..284a6105 --- /dev/null +++ b/UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues/ac2.controller @@ -0,0 +1,67 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1107 &-7364175626657849038 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Base Layer + m_ChildStates: [] + 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: 0} +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: ac2 + serializedVersion: 5 + m_AnimatorParameters: + - m_Name: float + m_Type: 1 + m_DefaultFloat: 0 + m_DefaultInt: 0 + m_DefaultBool: 0 + m_Controller: {fileID: 0} + - m_Name: int + m_Type: 3 + m_DefaultFloat: 0 + m_DefaultInt: 0 + m_DefaultBool: 0 + m_Controller: {fileID: 0} + - m_Name: bool + m_Type: 4 + m_DefaultFloat: 0 + m_DefaultInt: 0 + m_DefaultBool: 0 + m_Controller: {fileID: 0} + - m_Name: trigger + m_Type: 9 + m_DefaultFloat: 0 + m_DefaultInt: 0 + m_DefaultBool: 0 + m_Controller: {fileID: 0} + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: Base Layer + m_StateMachine: {fileID: -7364175626657849038} + 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~/RenameParametersTests/AnimatorOnlyParameterValues/ac2.controller.meta b/UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues/ac2.controller.meta new file mode 100644 index 00000000..de0e3daa --- /dev/null +++ b/UnitTests~/RenameParametersTests/AnimatorOnlyParameterValues/ac2.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8235cc3d767d4cb489bcf06909ef40ef +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/RenameParametersTests/RenameParametersTests.cs b/UnitTests~/RenameParametersTests/RenameParametersTests.cs index 2aa381de..ce016f64 100644 --- a/UnitTests~/RenameParametersTests/RenameParametersTests.cs +++ b/UnitTests~/RenameParametersTests/RenameParametersTests.cs @@ -1,10 +1,14 @@ #if MA_VRCSDK3_AVATARS +using System; +using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using nadena.dev.modular_avatar.core; using nadena.dev.modular_avatar.core.editor; using nadena.dev.ndmf; using NUnit.Framework; +using UnityEditor.Animations; using UnityEngine; using VRC.SDK3.Avatars.Components; using VRC.SDK3.Avatars.ScriptableObjects; @@ -120,6 +124,39 @@ namespace modular_avatar_tests.RenameParametersTests Assert.AreEqual(expParams.parameters[0].name, "a"); Assert.IsTrue(Mathf.Abs(expParams.parameters[0].defaultValue - 0.1f) < 0.0001f); } + + [Test] + public void AnimatorOnlyParametersTests() + { + var prefab = CreatePrefab("AnimatorOnlyParameterValues/AOPV.prefab"); + + AvatarProcessor.ProcessAvatar(prefab); + + var fx = prefab.GetComponent().baseAnimationLayers + .First(l => l.type == VRCAvatarDescriptor.AnimLayerType.FX) + .animatorController as AnimatorController; + Assert.NotNull(fx); + + AssertParamStates(fx); + + var action = prefab.GetComponent().baseAnimationLayers + .First(l => l.type == VRCAvatarDescriptor.AnimLayerType.FX) + .animatorController as AnimatorController; + Assert.NotNull(action); + + AssertParamStates(action); + + void AssertParamStates(AnimatorController controller) + { + var parameters = controller.parameters.Select( + p => new KeyValuePair(p.name, p) + ).ToImmutableDictionary(); + + Assert.LessOrEqual(Mathf.Abs(parameters["float"].defaultFloat - 0.5f), 0.005f); + Assert.AreEqual(23, parameters["int"].defaultInt); + Assert.AreEqual(true, parameters["bool"].defaultBool); + } + } } }