From 339fa77692f9810305ff3ea0279fbf33d18c597b Mon Sep 17 00:00:00 2001 From: bd_ Date: Mon, 29 Aug 2022 16:28:53 -0700 Subject: [PATCH] Revert "Remove bone proxy" This reverts commit f0fa188d68e1098d53caf17412c0762f5b5fa093. --- .../Editor/BoneProxyHook.cs | 35 +++++ .../Editor/BoneProxyHook.cs.meta | 3 + .../Runtime/ModularAvatarBoneProxy.cs | 135 ++++++++++++++++++ .../Runtime/ModularAvatarBoneProxy.cs.meta | 3 + 4 files changed, 176 insertions(+) create mode 100644 Packages/net.fushizen.modular-avatar/Editor/BoneProxyHook.cs create mode 100644 Packages/net.fushizen.modular-avatar/Editor/BoneProxyHook.cs.meta create mode 100644 Packages/net.fushizen.modular-avatar/Runtime/ModularAvatarBoneProxy.cs create mode 100644 Packages/net.fushizen.modular-avatar/Runtime/ModularAvatarBoneProxy.cs.meta diff --git a/Packages/net.fushizen.modular-avatar/Editor/BoneProxyHook.cs b/Packages/net.fushizen.modular-avatar/Editor/BoneProxyHook.cs new file mode 100644 index 00000000..c2954878 --- /dev/null +++ b/Packages/net.fushizen.modular-avatar/Editor/BoneProxyHook.cs @@ -0,0 +1,35 @@ +using UnityEngine; +using VRC.SDKBase.Editor.BuildPipeline; + +namespace net.fushizen.modular_avatar.core.editor +{ + public class BoneProxyHook : IVRCSDKPreprocessAvatarCallback + { + public int callbackOrder => HookSequence.SEQ_BONE_PROXY; + + public bool OnPreprocessAvatar(GameObject avatarGameObject) + { + var boneProxies = avatarGameObject.GetComponentsInChildren(true); + + foreach (var proxy in boneProxies) + { + if (proxy.constraint != null) UnityEngine.Object.DestroyImmediate(proxy.constraint); + if (proxy.target != null) + { + var oldPath = RuntimeUtil.AvatarRootPath(proxy.gameObject); + Transform transform = proxy.transform; + transform.SetParent(proxy.target, false); + transform.localPosition = Vector3.zero; + transform.localRotation = Quaternion.identity; + PathMappings.Remap(oldPath, new PathMappings.MappingEntry() { + path = RuntimeUtil.AvatarRootPath(proxy.gameObject), + transformPath = RuntimeUtil.AvatarRootPath(proxy.gameObject) + }); + } + Object.DestroyImmediate(proxy); + } + + return true; + } + } +} \ No newline at end of file diff --git a/Packages/net.fushizen.modular-avatar/Editor/BoneProxyHook.cs.meta b/Packages/net.fushizen.modular-avatar/Editor/BoneProxyHook.cs.meta new file mode 100644 index 00000000..649c6bb2 --- /dev/null +++ b/Packages/net.fushizen.modular-avatar/Editor/BoneProxyHook.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 21339639c2ce435e97773a969d21f43a +timeCreated: 1661649405 \ No newline at end of file diff --git a/Packages/net.fushizen.modular-avatar/Runtime/ModularAvatarBoneProxy.cs b/Packages/net.fushizen.modular-avatar/Runtime/ModularAvatarBoneProxy.cs new file mode 100644 index 00000000..0545c8d1 --- /dev/null +++ b/Packages/net.fushizen.modular-avatar/Runtime/ModularAvatarBoneProxy.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Animations; +using Object = System.Object; + +namespace net.fushizen.modular_avatar.core +{ + public class ModularAvatarBoneProxy : AvatarTagComponent + { + public Transform target; + + public HumanBodyBones boneReference = HumanBodyBones.LastBone; + public string subPath; + + [SerializeField] [HideInInspector] public ParentConstraint constraint; + +#if UNITY_EDITOR + void OnValidate() + { + UnityEditor.EditorApplication.delayCall += CheckReferences; + } + + void CheckReferences() { + if (this == null) return; // post-destroy + + if (target == null && (boneReference != HumanBodyBones.LastBone || !string.IsNullOrWhiteSpace(subPath))) + { + UpdateDynamicMapping(); + if (target != null) + { + RuntimeUtil.MarkDirty(this); + } + } else if (target != null) + { + var origBoneReference = boneReference; + var origSubpath = subPath; + UpdateStaticMapping(); + if (origSubpath != subPath || origBoneReference != boneReference) + { + RuntimeUtil.MarkDirty(this); + } + } + + CheckConstraint(); + } + + private void CheckConstraint() + { + if (constraint != null) + { + if (!UnityEditor.PrefabUtility.IsPartOfPrefabAsset(constraint)) + { + UnityEngine.Object.DestroyImmediate(constraint); + } + } + } + + private void OnDestroy() + { + if (constraint != null) DestroyImmediate(constraint); + } + + private void UpdateDynamicMapping() + { + var avatar = RuntimeUtil.FindAvatarInParents(transform); + if (avatar == null) return; + + if (subPath == "$$AVATAR") + { + target = avatar.transform; + return; + } + + if (boneReference == HumanBodyBones.LastBone) + { + target = avatar.transform.Find(subPath); + return; + } + + var animator = avatar.GetComponent(); + if (animator == null) return; + var bone = animator.GetBoneTransform(boneReference); + if (bone == null) return; + if (string.IsNullOrWhiteSpace(subPath)) target = bone; + else target = bone.Find(subPath); + } + + private void UpdateStaticMapping() + { + var avatar = RuntimeUtil.FindAvatarInParents(transform); + var humanBones = new Dictionary(); + var animator = avatar.GetComponent(); + if (animator == null) + { + return; + } + + foreach (var boneTypeObj in Enum.GetValues(typeof(HumanBodyBones))) + { + var boneType = (HumanBodyBones) boneTypeObj; + if (boneType == HumanBodyBones.LastBone) continue; + var bone = animator.GetBoneTransform(boneType); + if (bone != null) humanBones[bone] = boneType; + } + + Transform iter = target; + Transform avatarTransform = avatar.transform; + + if (target == avatarTransform) + { + boneReference = HumanBodyBones.LastBone; + subPath = "$$AVATAR"; + return; + } + + while (iter != avatarTransform && !humanBones.ContainsKey(iter)) + { + iter = iter.parent; + } + + if (iter == avatarTransform) + { + boneReference = HumanBodyBones.LastBone; + } + else + { + boneReference = humanBones[iter]; + } + + subPath = RuntimeUtil.RelativePath(iter.gameObject, target.gameObject); + } +#endif + } +} \ No newline at end of file diff --git a/Packages/net.fushizen.modular-avatar/Runtime/ModularAvatarBoneProxy.cs.meta b/Packages/net.fushizen.modular-avatar/Runtime/ModularAvatarBoneProxy.cs.meta new file mode 100644 index 00000000..3f37902f --- /dev/null +++ b/Packages/net.fushizen.modular-avatar/Runtime/ModularAvatarBoneProxy.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 42581d8044b64899834d3d515ab3a144 +timeCreated: 1661648057 \ No newline at end of file