modular-avatar/Editor/Inspector/BoneProxyEditor.cs

162 lines
5.8 KiB
C#

#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<BoneProxyAttachmentMode>
{
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<TempObjRef>();
}
}
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 (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;
}
}
}
}
}