From a4523c852081e47e521576a1c10c89d60e79e592 Mon Sep 17 00:00:00 2001 From: pandravrc <162582491+pandravrc@users.noreply.github.com> Date: Sun, 8 Sep 2024 06:06:35 +0900 Subject: [PATCH] Close #3 --- Editor/EmotePrefab.cs | 80 ++++++++++++++++ Editor/EmotePrefab.cs.meta | 11 +++ Runtime/EmotePrefab.cs | 10 ++ Runtime/EmotePrefab.cs.meta | 11 +++ Runtime/Generic.cs | 185 ++++++++++++++++++++++++++++++++++++ Runtime/Generic.cs.meta | 11 +++ 6 files changed, 308 insertions(+) create mode 100644 Editor/EmotePrefab.cs create mode 100644 Editor/EmotePrefab.cs.meta create mode 100644 Runtime/EmotePrefab.cs create mode 100644 Runtime/EmotePrefab.cs.meta create mode 100644 Runtime/Generic.cs create mode 100644 Runtime/Generic.cs.meta diff --git a/Editor/EmotePrefab.cs b/Editor/EmotePrefab.cs new file mode 100644 index 0000000..c03ef96 --- /dev/null +++ b/Editor/EmotePrefab.cs @@ -0,0 +1,80 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using nadena.dev.ndmf; +using nadena.dev.modular_avatar.core; +using nadena.dev.modular_avatar.core.editor; +using UnityEngine; +using UnityEditor; +using UnityEditor.Animations; +using VRC.SDK3.Avatars.Components; +using com.github.pandrabox.emoteprefab.runtime; +using static com.github.pandrabox.emoteprefab.runtime.Generic; +using com.github.pandrabox.emoteprefab.editor; +using Pan.Lib; + +[assembly: ExportsPlugin(typeof(EmotePrefabPass))] + +namespace com.github.pandrabox.emoteprefab.editor +{ + /// + /// To call from Unity menu (Debug Only, Comment out upon release.) + /// + public class EmotePrefabUnityMenu : MonoBehaviour + { + [MenuItem("PanDev/EmotePrefab")] + static void GenEmotePrefab() + { + var Target = Selection.activeGameObject; + var AvatarDescriptor = FindComponentFromParent(Target); + new EmotePrefabMain().Run(AvatarDescriptor); + } + } + /// + /// To call from NDMF + /// + public class EmotePrefabPass : Plugin + { + protected override void Configure() + { + //try + //{ + InPhase(BuildPhase.Transforming).BeforePlugin("nadena.dev.modular-avatar").Run("PanEmotePrefab", ctx => + { + var TargetComponents = ctx.AvatarRootTransform.GetComponentsInChildren(false); + foreach (var T in TargetComponents) + { + new EmotePrefabMain().Run(ctx.AvatarDescriptor); + return; + } + }); + //} + //catch (Exception e) + //{ + // Debug.LogError($@"[Pan:EmotePrefab]{e}"); + //} + } + } + /// + /// Actual operation + /// + public class EmotePrefabMain : MonoBehaviour + { + VRCAvatarDescriptor AvatarDescriptor; + public void Run(VRCAvatarDescriptor AvatarDescriptor)//,GameObject AvatarRootObject + { + this.AvatarDescriptor = AvatarDescriptor; + ActionLayerReplace(); + } + private void ActionLayerReplace() + { + string ActionAnimatorPath = $@"Packages\com.github.pandrabox.emoteprefab\Assets\BearsDen\CustomAnimatorControllers\Action.controller"; + var AssignController= AssetDatabase.LoadAssetAtPath(ActionAnimatorPath); + if (AssignController == null) { + throw new Exception("EmotePrefab ActionLayerReplace AssignController Not Found"); + } + AvatarDescriptor.baseAnimationLayers[3].isDefault = false; + AvatarDescriptor.baseAnimationLayers[3].animatorController = AssignController; + } + } +} diff --git a/Editor/EmotePrefab.cs.meta b/Editor/EmotePrefab.cs.meta new file mode 100644 index 0000000..2427de5 --- /dev/null +++ b/Editor/EmotePrefab.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 68305e62a0c630a49990bb9f73cb1102 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/EmotePrefab.cs b/Runtime/EmotePrefab.cs new file mode 100644 index 0000000..ba224d8 --- /dev/null +++ b/Runtime/EmotePrefab.cs @@ -0,0 +1,10 @@ +using UnityEngine; + +namespace com.github.pandrabox.emoteprefab.runtime +{ + [AddComponentMenu("Pan/EmotePrefab")] + public class EmotePrefab : MonoBehaviour, VRC.SDKBase.IEditorOnly + { + // public RuntimeAnimatorController animator; + } +} \ No newline at end of file diff --git a/Runtime/EmotePrefab.cs.meta b/Runtime/EmotePrefab.cs.meta new file mode 100644 index 0000000..0d05e33 --- /dev/null +++ b/Runtime/EmotePrefab.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2811c4e709a521c45bf91cd7041f1db2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Generic.cs b/Runtime/Generic.cs new file mode 100644 index 0000000..dd00d41 --- /dev/null +++ b/Runtime/Generic.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using com.github.pandrabox.emoteprefab.runtime; +using VRC.SDK3.Avatars.Components; + + +namespace com.github.pandrabox.emoteprefab.runtime +{ + public static class Generic + { + /// + /// Searches for a specific component in the self or parent direction. + /// Example of use: var Descriptor = FindComponentFromParent(MyGameObject); + /// + /// Target Component Name + /// GameObject to search from + /// The first component found, or null if none. + public static T FindComponentFromParent(GameObject CurrentObject) where T : Component + { + while (CurrentObject != null) + { + var component = CurrentObject.GetComponent(); + if (component != null) + { + return component; + } + CurrentObject = CurrentObject.transform.parent?.gameObject; + } + return null; + } + /// + /// Searches for a specific component in the self or parent direction. + /// Example of use: var Descriptor = FindComponentFromParent(MyTransform); + /// + /// Target Component Name + /// Transform to search from + /// The first component found, or null if none. + public static T FindComponentFromParent(Transform CurrentTransform) where T : Component + { + return FindComponentFromParent(CurrentTransform?.gameObject); + } + public static GameObject GetAvatarRootObject(GameObject Target) + { + return FindComponentFromParent(Target)?.gameObject; + } + public static GameObject GetAvatarRootObject(Transform Target) + { + return FindComponentFromParent(Target)?.gameObject; + } + public static Transform GetAvatarRootTransform(GameObject Target) + { + return FindComponentFromParent(Target)?.gameObject?.transform; + } + public static Transform GetAvatarRootTransform(Transform Target) + { + return FindComponentFromParent(Target)?.gameObject?.transform; + } + public static bool IsInAvatar(GameObject Target) + { + return GetAvatarRootObject(Target) != null; + } + public static bool IsInAvatar(Transform Target) + { + return IsInAvatar(Target.gameObject); + } + + public static GUIStyle TitleStyle() + { + GUIStyle style = new GUIStyle(GUI.skin.label); + style.normal.background = MakeTex(1, 1, new Color(255f / 255f, 128f / 255f, 0f / 255f, 1f)); + style.normal.textColor = Color.black; + style.fontStyle = FontStyle.Bold; + return style; + } + public static Texture2D MakeTex(int width, int height, Color color) + { + Color[] pix = new Color[width * height]; + for (int i = 0; i < pix.Length; ++i) + { + pix[i] = color; + } + Texture2D result = new Texture2D(width, height); + result.SetPixels(pix); + result.Apply(); + return result; + } + public static bool IsWithinErrorRange(Vector3 vector3, float referenceValue, float errorThreshold) + { + return Mathf.Abs(vector3.x - referenceValue) <= errorThreshold && + Mathf.Abs(vector3.y - referenceValue) <= errorThreshold && + Mathf.Abs(vector3.z - referenceValue) <= errorThreshold; + } + + public static void SetEditorOnly(string TargetName, bool SW, GameObject ParentObject = null) + { + var Targets = GetGameObjectsByName(TargetName, ParentObject); + foreach (var Target in Targets) + { + SetEditorOnly(Target, SW); + } + } + public static void SetEditorOnly(GameObject Target, bool SW) + { + if (SW) + { + Target.tag = "EditorOnly"; + Target.SetActive(false); + } + else + { + Target.tag = "Untagged"; + Target.SetActive(true); + } + } + public static void SetEditorOnly(Transform Target, bool SW) + { + SetEditorOnly(Target.gameObject, SW); + } + + + public static Transform[] GetTransformsByName(string TargetName, Transform ParentTransform = null) + { + Transform[] Transforms; + if (ParentTransform != null) + { + Transforms = ParentTransform.GetComponentsInChildren(true)?.Where(t => t.name == TargetName)?.ToArray(); + } + else + { + Transforms = GameObject.FindObjectsOfType()?.Where(t => t.name == TargetName)?.ToArray(); + } + return Transforms; + } + public static Transform[] GetTransformsByName(string TargetName, GameObject ParentObject = null) + { + return GetTransformsByName(TargetName, ParentObject.transform); + } + public static GameObject[] GetGameObjectsByName(string TargetName, Transform ParentTransform = null) + { + Transform[] Transforms = GetTransformsByName(TargetName, ParentTransform); + GameObject[] GameObjects = new GameObject[Transforms.Length]; + for (int i = 0; i < Transforms.Length; i++) + { + GameObjects[i] = Transforms[i].gameObject; + } + return GameObjects; + } + public static GameObject[] GetGameObjectsByName(string TargetName, GameObject ParentGameObject = null) + { + return GetGameObjectsByName(TargetName, ParentGameObject.transform); + } + + + + + public static bool IsTargetEditorOnly(string TargetName, GameObject ParentObject = null) + { + Transform[] Transforms = GetTransformsByName(TargetName, ParentObject); + if (Transforms == null || Transforms.Length < 1) { return false; } + return IsTargetEditorOnly(Transforms[0].gameObject); + } + public static bool IsTargetEditorOnly(GameObject target) + { + return target.tag == "EditorOnly" && target.activeSelf == false; + } + + public static float DELTA = 0.00001f; + + public static string[] GestureNames = new string[] { "Neutral", "Fist", "HandOpen", "FingerPoint", "Victory", "RocknRoll", "HandGun", "Thumbsup" }; + public enum Gesture + { + Neutral, + Fist, + HandOpen, + FingerPoint, + Victory, + RocknRoll, + HandGun, + Thumbsup + } + public const int GESTURENUM = 8; + } +} diff --git a/Runtime/Generic.cs.meta b/Runtime/Generic.cs.meta new file mode 100644 index 0000000..07d134d --- /dev/null +++ b/Runtime/Generic.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be10de7f91398bf41847f1fcae5172de +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: