#region using System; using UnityEditor; using UnityEngine; using static nadena.dev.modular_avatar.core.editor.Localization; using Object = UnityEngine.Object; #endregion namespace nadena.dev.modular_avatar.core.editor { internal class TempObjRef : ScriptableObject { public Transform target; } [CustomPropertyDrawer(typeof(BoneProxyAttachmentMode))] internal class BoneProxyAttachmentModeDrawer : EnumDrawer { protected override string localizationPrefix => "boneproxy.attachment"; protected override Array enumValues => new object[] { BoneProxyAttachmentMode.AsChildAtRoot, BoneProxyAttachmentMode.AsChildKeepWorldPose, BoneProxyAttachmentMode.AsChildKeepRotation, BoneProxyAttachmentMode.AsChildKeepPosition, }; } [CustomEditor(typeof(ModularAvatarBoneProxy))] [CanEditMultipleObjects] internal class BoneProxyEditor : MAEditorBase { private bool foldout = false; private Object[] objRefs; private void OnEnable() { objRefs = new Object[targets.Length]; for (int i = 0; i < targets.Length; i++) { objRefs[i] = CreateInstance(); } } protected override void OnInnerInspectorGUI() { GameObject parentAvatar = null; bool suppressTarget = false; for (int i = 0; i < targets.Length; i++) { var t = (ModularAvatarBoneProxy) targets[i]; var avTr = RuntimeUtil.FindAvatarTransformInParents(t.transform); if (avTr != null && parentAvatar == null) parentAvatar = avTr.gameObject; if (avTr == null || parentAvatar != avTr.gameObject) { suppressTarget = true; break; } ((TempObjRef) objRefs[i]).target = t.target; } if (suppressTarget) { foldout = true; } else { var virtObj = new SerializedObject(objRefs); var virtProp = virtObj.FindProperty(nameof(TempObjRef.target)); if (virtProp.objectReferenceValue is Transform targetTransform) { var validationResult = BoneProxyProcessor.ValidateTarget(parentAvatar, targetTransform); if (validationResult != BoneProxyProcessor.ValidationResult.OK) { EditorGUILayout.HelpBox(S("boneproxy.err." + validationResult), MessageType.Error); } } EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(virtProp, G("boneproxy.target")); if (EditorGUI.EndChangeCheck()) { virtObj.ApplyModifiedPropertiesWithoutUndo(); for (int i = 0; i < targets.Length; i++) { var t = (ModularAvatarBoneProxy) targets[i]; Undo.RecordObjects(targets, "Set targets"); var xform = ((TempObjRef) objRefs[i]).target; if (xform != null && RuntimeUtil.FindAvatarTransformInParents(xform)?.gameObject != parentAvatar) continue; t.target = xform; } } } for (int i = 0; i < targets.Length; i++) { CheckAttachmentMode(targets[i] as ModularAvatarBoneProxy); } serializedObject.UpdateIfRequiredOrScript(); var p_attachmentMode = serializedObject.FindProperty(nameof(ModularAvatarBoneProxy.attachmentMode)); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(p_attachmentMode, G("boneproxy.attachment")); if (EditorGUI.EndChangeCheck()) { serializedObject.ApplyModifiedProperties(); foreach (var target in targets) { var t = (ModularAvatarBoneProxy)target; Undo.RecordObject(t.transform, ""); t.Update(); } } foldout = EditorGUILayout.Foldout(foldout, G("boneproxy.foldout.advanced")); if (foldout) { EditorGUI.indentLevel++; var p_boneReference = serializedObject.FindProperty(nameof(ModularAvatarBoneProxy.boneReference)); var p_subPath = serializedObject.FindProperty(nameof(ModularAvatarBoneProxy.subPath)); EditorGUILayout.PropertyField(p_boneReference, new GUIContent("Bone reference")); EditorGUILayout.PropertyField(p_subPath, new GUIContent("Sub path")); EditorGUI.indentLevel--; } serializedObject.ApplyModifiedProperties(); ShowLanguageUI(); } private void CheckAttachmentMode(ModularAvatarBoneProxy boneProxy) { if (boneProxy.attachmentMode == BoneProxyAttachmentMode.Unset && boneProxy.target != null) { float posDelta = Vector3.Distance(boneProxy.transform.position, boneProxy.target.position); float rotDelta = Quaternion.Angle(boneProxy.transform.rotation, boneProxy.target.rotation); Undo.RecordObject(boneProxy, "Configuring bone proxy attachment mode"); if (posDelta > 0.001f || rotDelta > 0.001f) { boneProxy.attachmentMode = BoneProxyAttachmentMode.AsChildKeepWorldPose; } else { boneProxy.attachmentMode = BoneProxyAttachmentMode.AsChildAtRoot; } } } } }