From 4dafd9dcd77cdf11c7d32fca66264883f4fd69b6 Mon Sep 17 00:00:00 2001 From: SDraw Date: Sat, 8 Oct 2022 02:28:22 +0300 Subject: [PATCH] Emotes custom detection VRIK component checks for desktop mode Disable head rotation when emote is active --- README.md | 4 +-- ml_amt/Main.cs | 7 +++++ ml_amt/MotionTweaker.cs | 49 +++++++++++++++++++++++++------ ml_amt/Properties/AssemblyInfo.cs | 6 ++-- ml_amt/Settings.cs | 18 +++++++++++- ml_amt/resources/menu.js | 7 +++++ ml_dht/HeadTracked.cs | 9 ++++-- ml_dht/Main.cs | 13 ++++---- ml_dht/Properties/AssemblyInfo.cs | 6 ++-- 9 files changed, 93 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 1280fbc..7a66aac 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ Merged set of MelonLoader mods for ChilloutVR. | Full name | Short name | Latest version | Available in [CVRMA](https://github.com/knah/CVRMelonAssistant) | Current Status | Notes | |-----------|------------|----------------|-----------------------------------------------------------------|----------------|-------| | Avatar Change Info | ml_aci | 1.0.2 | Yes | Working | -| Avatar Motion Tweaker | ml_amt | 1.1.1 | On review | Working | -| Desktop Head Tracking | ml_dht | 1.0.4 | On review | Working | +| Avatar Motion Tweaker | ml_amt | 1.1.2 | On review | Working | +| Desktop Head Tracking | ml_dht | 1.0.5 | On review | Working | | Desktop Reticle Switch | ml_drs | 1.0.0 | Yes | Working | | Four Point Tracking | ml_fpt | 1.0.7 | On review | Working | | Leap Motion Extension | ml_lme | 1.2.0 | On review | Working | diff --git a/ml_amt/Main.cs b/ml_amt/Main.cs index eba1fab..c986cad 100644 --- a/ml_amt/Main.cs +++ b/ml_amt/Main.cs @@ -21,6 +21,7 @@ namespace ml_amt Settings.PoseTransitionsChange += this.OnPoseTransitonsChange; Settings.AdjustedMovementChange += this.OnAdjustedMovementChange; Settings.IKOverrideFlyChange += this.OnIKOverrideFlyChange; + Settings.DetectEmotesChange += this.OnDetectEmotesChange; HarmonyInstance.Patch( typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)), @@ -49,6 +50,7 @@ namespace ml_amt m_localTweaker.SetPoseTransitions(Settings.PoseTransitions); m_localTweaker.SetAdjustedMovement(Settings.AdjustedMovement); m_localTweaker.SetIKOverrideFly(Settings.IKOverrideFly); + m_localTweaker.SetDetectEmotes(Settings.DetectEmotes); } void OnIKOverrideCrouchChange(bool p_state) @@ -86,6 +88,11 @@ namespace ml_amt if(m_localTweaker != null) m_localTweaker.SetIKOverrideFly(p_state); } + void OnDetectEmotesChange(bool p_state) + { + if(m_localTweaker != null) + m_localTweaker.SetDetectEmotes(p_state); + } static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear(); void OnAvatarClear() diff --git a/ml_amt/MotionTweaker.cs b/ml_amt/MotionTweaker.cs index 91b204d..1c3e634 100644 --- a/ml_amt/MotionTweaker.cs +++ b/ml_amt/MotionTweaker.cs @@ -2,14 +2,17 @@ using ABI_RC.Systems.MovementSystem; using RootMotion.FinalIK; using System.Collections.Generic; +using System.Reflection; using UnityEngine; namespace ml_amt { + [DisallowMultipleComponent] class MotionTweaker : MonoBehaviour { - static System.Reflection.FieldInfo ms_rootVelocity = typeof(IKSolverVR).GetField("rootVelocity", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); - static System.Reflection.FieldInfo ms_groundedRaw = typeof(MovementSystem).GetField("_isGroundedRaw", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + static readonly FieldInfo ms_rootVelocity = typeof(IKSolverVR).GetField("rootVelocity", BindingFlags.NonPublic | BindingFlags.Instance); + static readonly FieldInfo ms_groundedRaw = typeof(MovementSystem).GetField("_isGroundedRaw", BindingFlags.NonPublic | BindingFlags.Instance); + static readonly int ms_emoteHash = Animator.StringToHash("Emote"); enum ParameterType { @@ -41,6 +44,8 @@ namespace ml_amt static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f); VRIK m_vrIk = null; + int m_locomotionLayer = 0; + float m_ikWeight = 1f; // Original weight float m_locomotionWeight = 1f; // Original weight float m_avatarScale = 1f; // Instantiated scale @@ -64,6 +69,9 @@ namespace ml_amt bool m_customLocomotionOffset = false; Vector3 m_locomotionOffset = Vector3.zero; + bool m_detectEmotes = true; + bool m_emoteActive = false; + readonly List m_parameters = null; public MotionTweaker() @@ -83,7 +91,7 @@ namespace ml_amt m_upright = Mathf.Clamp(((l_avatarViewHeight > 0f) ? (l_currentHeight / l_avatarViewHeight) : 0f), 0f, 1f); PoseState l_poseState = (m_upright <= m_proneLimit) ? PoseState.Proning : ((m_upright <= m_crouchLimit) ? PoseState.Crouching : PoseState.Standing); - if((m_vrIk != null) && m_vrIk.enabled) + if(PlayerSetup.Instance._inVr && (m_vrIk != null) && m_vrIk.enabled) { if(m_poseState != l_poseState) { @@ -115,6 +123,14 @@ namespace ml_amt m_poseState = l_poseState; + if(m_detectEmotes && (m_locomotionLayer >= 0)) + { + AnimatorStateInfo l_animState = PlayerSetup.Instance._animator.GetCurrentAnimatorStateInfo(m_locomotionLayer); + m_emoteActive = (l_animState.tagHash == ms_emoteHash); + } + else + m_emoteActive = false; + if(m_parameters.Count > 0) { foreach(AdditionalParameterInfo l_param in m_parameters) @@ -129,7 +145,7 @@ namespace ml_amt PlayerSetup.Instance._animator.SetFloat(l_param.m_hash, m_upright); break; case ParameterSyncType.Synced: - PlayerSetup.Instance.changeAnimatorParam(l_param.m_name, m_upright); + PlayerSetup.Instance.animatorManager.SetAnimatorParameterFloat(l_param.m_name, m_upright); break; } } @@ -143,7 +159,7 @@ namespace ml_amt PlayerSetup.Instance._animator.SetBool(l_param.m_hash, (bool)ms_groundedRaw.GetValue(MovementSystem.Instance)); break; case ParameterSyncType.Synced: - PlayerSetup.Instance.changeAnimatorParam(l_param.m_name, (bool)ms_groundedRaw.GetValue(MovementSystem.Instance) ? 1f : 0f); + PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool(l_param.m_name, (bool)ms_groundedRaw.GetValue(MovementSystem.Instance)); break; } } @@ -157,6 +173,7 @@ namespace ml_amt public void OnAvatarClear() { m_vrIk = null; + m_locomotionLayer = -1; m_avatarReady = false; m_compatibleAvatar = false; m_poseState = PoseState.Standing; @@ -165,12 +182,14 @@ namespace ml_amt m_customLocomotionOffset = false; m_locomotionOffset = Vector3.zero; m_avatarScale = 1f; + m_emoteActive = false; m_parameters.Clear(); } public void OnCalibrateAvatar() { m_vrIk = PlayerSetup.Instance._avatar.GetComponent(); + m_locomotionLayer = PlayerSetup.Instance._animator.GetLayerIndex("Locomotion/Emotes"); // Parse animator parameters AnimatorControllerParameter[] l_params = PlayerSetup.Instance._animator.parameters; @@ -227,16 +246,24 @@ namespace ml_amt void OnIKPreUpdate() { + m_ikWeight = m_vrIk.solver.IKPositionWeight; m_locomotionWeight = m_vrIk.solver.locomotion.weight; - if((m_ikOverrideCrouch && (m_poseState != PoseState.Standing)) || (m_ikOverrideProne && (m_poseState == PoseState.Proning))) - m_vrIk.solver.locomotion.weight = 0f; - if(m_ikOverrideFly && MovementSystem.Instance.flying) - m_vrIk.solver.locomotion.weight = 0f; + if(m_detectEmotes && m_emoteActive) + m_vrIk.solver.IKPositionWeight = 0f; + + if(PlayerSetup.Instance._inVr) + { + if((m_ikOverrideCrouch && (m_poseState != PoseState.Standing)) || (m_ikOverrideProne && (m_poseState == PoseState.Proning))) + m_vrIk.solver.locomotion.weight = 0f; + if(m_ikOverrideFly && MovementSystem.Instance.flying) + m_vrIk.solver.locomotion.weight = 0f; + } } void OnIKPostUpdate() { + m_vrIk.solver.IKPositionWeight = m_ikWeight; m_vrIk.solver.locomotion.weight = m_locomotionWeight; } @@ -282,5 +309,9 @@ namespace ml_amt { m_ikOverrideFly = p_state; } + public void SetDetectEmotes(bool p_state) + { + m_detectEmotes = p_state; + } } } diff --git a/ml_amt/Properties/AssemblyInfo.cs b/ml_amt/Properties/AssemblyInfo.cs index a7e9775..bdc1e80 100644 --- a/ml_amt/Properties/AssemblyInfo.cs +++ b/ml_amt/Properties/AssemblyInfo.cs @@ -1,10 +1,10 @@ using System.Reflection; [assembly: AssemblyTitle("AvatarMotionTweaker")] -[assembly: AssemblyVersion("1.1.1")] -[assembly: AssemblyFileVersion("1.1.1")] +[assembly: AssemblyVersion("1.1.2")] +[assembly: AssemblyFileVersion("1.1.2")] -[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.1.1", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.1.2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")] [assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)] \ No newline at end of file diff --git a/ml_amt/Settings.cs b/ml_amt/Settings.cs index b645775..6270a6c 100644 --- a/ml_amt/Settings.cs +++ b/ml_amt/Settings.cs @@ -15,7 +15,8 @@ namespace ml_amt ProneLimit, PoseTransitions, AdjustedMovement, - IKOverrideFly + IKOverrideFly, + DetectEmotes }; static bool ms_ikOverrideCrouch = true; @@ -25,6 +26,7 @@ namespace ml_amt static bool ms_poseTransitions = true; static bool ms_adjustedMovement = true; static bool ms_ikOverrideFly = true; + static bool ms_detectEmotes = true; static MelonLoader.MelonPreferences_Category ms_category = null; static List ms_entries = null; @@ -36,6 +38,7 @@ namespace ml_amt static public event Action PoseTransitionsChange; static public event Action AdjustedMovementChange; static public event Action IKOverrideFlyChange; + static public event Action DetectEmotesChange; public static void Init() { @@ -49,6 +52,7 @@ namespace ml_amt ms_entries.Add(ms_category.CreateEntry(ModSetting.PoseTransitions.ToString(), true)); ms_entries.Add(ms_category.CreateEntry(ModSetting.AdjustedMovement.ToString(), true)); ms_entries.Add(ms_category.CreateEntry(ModSetting.IKOverrideFly.ToString(), true)); + ms_entries.Add(ms_category.CreateEntry(ModSetting.DetectEmotes.ToString(), true)); Load(); @@ -86,6 +90,7 @@ namespace ml_amt ms_poseTransitions = (bool)ms_entries[(int)ModSetting.PoseTransitions].BoxedValue; ms_adjustedMovement = (bool)ms_entries[(int)ModSetting.AdjustedMovement].BoxedValue; ms_ikOverrideFly = (bool)ms_entries[(int)ModSetting.IKOverrideFly].BoxedValue; + ms_detectEmotes = (bool)ms_entries[(int)ModSetting.DetectEmotes].BoxedValue; } static void OnSliderUpdate(string p_name, string p_value) @@ -152,6 +157,13 @@ namespace ml_amt ms_ikOverrideFly = bool.Parse(p_value); IKOverrideFlyChange?.Invoke(ms_ikOverrideFly); } break; + + case ModSetting.DetectEmotes: + { + ms_detectEmotes = bool.Parse(p_value); + DetectEmotesChange?.Invoke(ms_detectEmotes); + } + break; } ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); @@ -186,5 +198,9 @@ namespace ml_amt { get => ms_ikOverrideFly; } + public static bool DetectEmotes + { + get => ms_detectEmotes; + } } } diff --git a/ml_amt/resources/menu.js b/ml_amt/resources/menu.js index 5891d17..c9f6275 100644 --- a/ml_amt/resources/menu.js +++ b/ml_amt/resources/menu.js @@ -228,6 +228,13 @@ function inp_toggle_mod_amt(_obj, _callbackName) {
+ +
+
Detect animations emote tag:
+
+
+
+
`; document.getElementById('settings-implementation').appendChild(l_block); diff --git a/ml_dht/HeadTracked.cs b/ml_dht/HeadTracked.cs index 0fb4b5c..0a76d2c 100644 --- a/ml_dht/HeadTracked.cs +++ b/ml_dht/HeadTracked.cs @@ -1,5 +1,6 @@ using ABI.CCK.Components; using ABI_RC.Core.Player; +using System.Reflection; using UnityEngine; namespace ml_dht @@ -7,6 +8,8 @@ namespace ml_dht [DisallowMultipleComponent] class HeadTracked : MonoBehaviour { + static FieldInfo ms_emotePlaying = typeof(PlayerSetup).GetField("_emotePlaying", BindingFlags.NonPublic | BindingFlags.Instance); + bool m_enabled = false; float m_smoothing = 0.5f; bool m_mirrored = false; @@ -47,7 +50,9 @@ namespace ml_dht if(m_enabled && (m_headBone != null)) { m_lastHeadRotation = Quaternion.Slerp(m_lastHeadRotation, m_avatarDescriptor.transform.rotation * (m_headRotation * m_bindRotation), m_smoothing); - m_headBone.rotation = m_lastHeadRotation; + + if(!(bool)ms_emotePlaying.GetValue(PlayerSetup.Instance)) + m_headBone.rotation = m_lastHeadRotation; } } @@ -71,7 +76,7 @@ namespace ml_dht { if(m_avatarDescriptor != null) m_avatarDescriptor.useVisemeLipsync = false; - + float l_weight = Mathf.Clamp(Mathf.InverseLerp(0.25f, 1f, Mathf.Abs(m_mouthShapes.y)), 0f, 1f) * 100f; p_component.BlendShapeValues[(int)ViveSR.anipal.Lip.LipShape_v2.Jaw_Open] = m_mouthShapes.x * 100f; diff --git a/ml_dht/Main.cs b/ml_dht/Main.cs index 6466b6e..bafda99 100644 --- a/ml_dht/Main.cs +++ b/ml_dht/Main.cs @@ -1,5 +1,6 @@ using ABI.CCK.Components; using ABI_RC.Core.Player; +using System.Reflection; namespace ml_dht { @@ -33,22 +34,22 @@ namespace ml_dht HarmonyInstance.Patch( typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)), null, - new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnAvatarClear_Postfix), System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)) + new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); HarmonyInstance.Patch( typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.CalibrateAvatar)), null, - new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnCalibrateAvatar_Postfix), System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)) + new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnCalibrateAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); HarmonyInstance.Patch( - typeof(CVREyeController).GetMethod("Update", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic), + typeof(CVREyeController).GetMethod("Update", BindingFlags.Instance | BindingFlags.NonPublic), null, - new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnEyeControllerUpdate_Postfix), System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)) + new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnEyeControllerUpdate_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); HarmonyInstance.Patch( - typeof(CVRFaceTracking).GetMethod("Update", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic), + typeof(CVRFaceTracking).GetMethod("Update", BindingFlags.Instance | BindingFlags.NonPublic), null, - new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnFaceTrackingUpdate_Postfix), System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)) + new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnFaceTrackingUpdate_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); MelonLoader.MelonCoroutines.Start(WaitForPlayer()); diff --git a/ml_dht/Properties/AssemblyInfo.cs b/ml_dht/Properties/AssemblyInfo.cs index f05061d..285104a 100644 --- a/ml_dht/Properties/AssemblyInfo.cs +++ b/ml_dht/Properties/AssemblyInfo.cs @@ -1,10 +1,10 @@ using System.Reflection; [assembly: AssemblyTitle("DesktopHeadTracking")] -[assembly: AssemblyVersion("1.0.4")] -[assembly: AssemblyFileVersion("1.0.4")] +[assembly: AssemblyVersion("1.0.5")] +[assembly: AssemblyFileVersion("1.0.5")] -[assembly: MelonLoader.MelonInfo(typeof(ml_dht.DesktopHeadTracking), "DesktopHeadTracking", "1.0.4", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_dht.DesktopHeadTracking), "DesktopHeadTracking", "1.0.5", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")] [assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)] \ No newline at end of file