From a06d002372eeebf1115c1deea5a00a5e3bbba976 Mon Sep 17 00:00:00 2001 From: SDraw Date: Sat, 24 Dec 2022 21:10:21 +0300 Subject: [PATCH 01/32] Update to r170 --- README.md | 8 +- ml_amt/Main.cs | 58 ++++++++ ml_amt/MotionTweaker.cs | 72 ++++++---- ml_amt/Properties/AssemblyInfo.cs | 6 +- ml_amt/README.md | 3 + ml_amt/Utils.cs | 3 + ml_amt/ml_amt.csproj | 2 +- ml_amt/ml_amt.csproj.user | 2 +- ml_amt/resources/menu.js | 2 +- ml_lme/GestureMatcher.cs | 65 ++------- ml_lme/LeapTracked.cs | 218 ++++++++++++++++++++---------- ml_lme/Main.cs | 33 +++-- ml_lme/Properties/AssemblyInfo.cs | 6 +- ml_lme/Utils.cs | 4 +- ml_lme/ml_lme.csproj | 2 +- ml_lme/ml_lme.csproj.user | 2 +- 16 files changed, 311 insertions(+), 175 deletions(-) diff --git a/README.md b/README.md index ddac16e..6dd81a5 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ 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.3 | Yes | Working | -| Avatar Motion Tweaker | ml_amt | 1.1.8 | Yes | Working | -| Desktop Head Tracking | ml_dht | 1.1.1 | Yes, pending update | Working | +| Avatar Motion Tweaker | ml_amt | 1.1.9 | Yes, pending review | Working | +| Desktop Head Tracking | ml_dht | 1.1.1 | Yes, pending review | Working | | Desktop Reticle Switch | ml_drs | 1.0.0 | Yes | Working | -| Four Point Tracking | ml_fpt | 1.0.9 | Yes | Working | -| Leap Motion Extension | ml_lme | 1.2.7 | Yes | Working | +| Four Point Tracking | ml_fpt | 1.0.9 | Retired | Deprecated | Not needed after r170 update +| Leap Motion Extension | ml_lme | 1.2.8 | Yes, pending review | Working | | Server Connection Info | ml_sci | 1.0.2 | Yes | Working | diff --git a/ml_amt/Main.cs b/ml_amt/Main.cs index ea622e4..407096d 100644 --- a/ml_amt/Main.cs +++ b/ml_amt/Main.cs @@ -1,4 +1,5 @@ using ABI_RC.Core.Player; +using ABI_RC.Systems.IK.SubSystems; using System.Reflection; namespace ml_amt @@ -9,6 +10,8 @@ namespace ml_amt MotionTweaker m_localTweaker = null; + static bool ms_fbtDetour = false; + public override void OnInitializeMelon() { if(ms_instance == null) @@ -26,6 +29,27 @@ namespace ml_amt null, new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); + HarmonyInstance.Patch( + typeof(BodySystem).GetMethod(nameof(BodySystem.Calibrate)), + null, + new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnCalibrate_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + ); + HarmonyInstance.Patch( + typeof(BodySystem).GetMethod(nameof(BodySystem.FBTAvailable)), + new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnFBTAvailable_Prefix), BindingFlags.Static | BindingFlags.NonPublic)), + null + ); + + HarmonyInstance.Patch( + typeof(PlayerSetup).GetMethod("Update", BindingFlags.NonPublic | BindingFlags.Instance), + new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(FBTDetour_Prefix), BindingFlags.Static | BindingFlags.NonPublic)), + new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(FBTDetour_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + ); + HarmonyInstance.Patch( + typeof(PlayerSetup).GetMethod("FixedUpdate", BindingFlags.NonPublic | BindingFlags.Instance), + new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(FBTDetour_Prefix), BindingFlags.Static | BindingFlags.NonPublic)), + new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(FBTDetour_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + ); MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); } @@ -83,5 +107,39 @@ namespace ml_amt MelonLoader.MelonLogger.Error(l_exception); } } + + static void OnCalibrate_Postfix() => ms_instance?.OnCalibrate(); + void OnCalibrate() + { + try + { + if(m_localTweaker != null) + m_localTweaker.OnCalibrate(); + } + catch(System.Exception l_exception) + { + MelonLoader.MelonLogger.Error(l_exception); + } + } + + // FBT detection override + static void FBTDetour_Prefix() + { + ms_fbtDetour = true; + } + static void FBTDetour_Postfix() + { + ms_fbtDetour = false; + } + static bool OnFBTAvailable_Prefix(ref bool __result) + { + if(ms_fbtDetour && !BodySystem.isCalibratedAsFullBody) + { + __result = false; + return false; + } + + return true; + } } } diff --git a/ml_amt/MotionTweaker.cs b/ml_amt/MotionTweaker.cs index 45ac987..b646def 100644 --- a/ml_amt/MotionTweaker.cs +++ b/ml_amt/MotionTweaker.cs @@ -1,4 +1,5 @@ using ABI_RC.Core.Player; +using ABI_RC.Systems.IK.SubSystems; using ABI_RC.Systems.MovementSystem; using RootMotion.FinalIK; using System.Collections.Generic; @@ -51,6 +52,8 @@ namespace ml_amt float m_locomotionWeight = 1f; // Original weight float m_avatarScale = 1f; // Instantiated scale Transform m_avatarHips = null; + float m_viewPointHeight = 1f; + bool m_isInVR = false; bool m_avatarReady = false; bool m_compatibleAvatar = false; @@ -91,6 +94,8 @@ namespace ml_amt void Start() { + m_isInVR = Utils.IsInVR(); + Settings.IKOverrideCrouchChange += this.SetIKOverrideCrouch; Settings.CrouchLimitChange += this.SetCrouchLimit; Settings.IKOverrideProneChange += this.SetIKOverrideProne; @@ -126,20 +131,20 @@ namespace ml_amt m_moving = !Mathf.Approximately(MovementSystem.Instance.movementVector.magnitude, 0f); // Update upright - Matrix4x4 l_hmdMatrix = PlayerSetup.Instance.transform.GetMatrix().inverse * (PlayerSetup.Instance._inVr ? PlayerSetup.Instance.vrHeadTracker.transform.GetMatrix() : PlayerSetup.Instance.desktopCameraRig.transform.GetMatrix()); + Matrix4x4 l_hmdMatrix = PlayerSetup.Instance.transform.GetMatrix().inverse * (m_isInVR ? PlayerSetup.Instance.vrHeadTracker.transform.GetMatrix() : PlayerSetup.Instance.desktopCameraRig.transform.GetMatrix()); float l_currentHeight = Mathf.Clamp((l_hmdMatrix * ms_pointVector).y, 0f, float.MaxValue); float l_avatarScale = (m_avatarScale > 0f) ? (PlayerSetup.Instance._avatar.transform.localScale.y / m_avatarScale) : 0f; - float l_avatarViewHeight = Mathf.Clamp(PlayerSetup.Instance.GetViewPointHeight() * l_avatarScale, 0f, float.MaxValue); + float l_avatarViewHeight = Mathf.Clamp(m_viewPointHeight * l_avatarScale, 0f, float.MaxValue); 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_followHips && (m_avatarHips != null)) + if(m_avatarHips != null) { - Vector4 l_hipsToPlayer = (PlayerSetup.Instance.transform.GetMatrix().inverse * m_avatarHips.GetMatrix()) * ms_pointVector; - m_hipsToPlayer.Set(l_hipsToPlayer.x, 0f, l_hipsToPlayer.z); + Vector4 l_hipsToPoint = (PlayerSetup.Instance.transform.GetMatrix().inverse * m_avatarHips.GetMatrix()) * ms_pointVector; + m_hipsToPlayer.Set(l_hipsToPoint.x, 0f, l_hipsToPoint.z); } - if(PlayerSetup.Instance._inVr && (m_vrIk != null) && m_vrIk.enabled) + if(m_isInVR && (m_vrIk != null) && m_vrIk.enabled) { if(m_poseState != l_poseState) { @@ -164,8 +169,8 @@ namespace ml_amt if(m_poseTransitions) { - PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Crouching", (l_poseState == PoseState.Crouching) && !m_compatibleAvatar && !PlayerSetup.Instance.fullBodyActive); - PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Prone", (l_poseState == PoseState.Proning) && !m_compatibleAvatar && !PlayerSetup.Instance.fullBodyActive); + PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Crouching", (l_poseState == PoseState.Crouching) && !m_compatibleAvatar && !BodySystem.isCalibratedAsFullBody); + PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Prone", (l_poseState == PoseState.Proning) && !m_compatibleAvatar && !BodySystem.isCalibratedAsFullBody); } } @@ -249,14 +254,17 @@ namespace ml_amt m_moving = false; m_hipsToPlayer = Vector3.zero; m_avatarHips = null; + m_viewPointHeight = 1f; m_parameters.Clear(); } public void OnSetupAvatar() { + m_isInVR = Utils.IsInVR(); m_vrIk = PlayerSetup.Instance._avatar.GetComponent(); m_locomotionLayer = PlayerSetup.Instance._animator.GetLayerIndex("Locomotion/Emotes"); m_avatarHips = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Hips); + m_viewPointHeight = PlayerSetup.Instance._avatar.GetComponent().viewPosition.y; // Parse animator parameters AnimatorControllerParameter[] l_params = PlayerSetup.Instance._animator.parameters; @@ -304,13 +312,27 @@ namespace ml_amt if(m_customLocomotionOffset) m_vrIk.solver.locomotion.offset = m_locomotionOffset; - m_vrIk.solver.OnPreUpdate += this.OnIKPreUpdate; - m_vrIk.solver.OnPostUpdate += this.OnIKPostUpdate; + m_vrIk.onPreSolverUpdate.AddListener(this.OnIKPreUpdate); + m_vrIk.onPostSolverUpdate.AddListener(this.OnIKPostUpdate); } m_avatarReady = true; } + public void OnCalibrate() + { + if(m_avatarReady && BodySystem.isCalibratedAsFullBody && BodySystem.enableHipTracking && !BodySystem.enableRightFootTracking && !BodySystem.enableLeftFootTracking && !BodySystem.enableLeftKneeTracking && !BodySystem.enableRightKneeTracking) + { + BodySystem.isCalibratedAsFullBody = false; + BodySystem.TrackingLeftLegEnabled = false; + BodySystem.TrackingRightLegEnabled = false; + BodySystem.TrackingLocomotionEnabled = true; + + if(m_vrIk != null) + m_vrIk.solver.spine.maxRootAngle = 25f; // I need to rotate my legs, ffs! + } + } + void OnIKPreUpdate() { bool l_legsOverride = false; @@ -321,22 +343,17 @@ namespace ml_amt if(m_detectEmotes && m_emoteActive) m_vrIk.solver.IKPositionWeight = 0f; - // Game manages VRIK for desktop itself - if(PlayerSetup.Instance._inVr) + if((m_ikOverrideCrouch && (m_poseState != PoseState.Standing)) || (m_ikOverrideProne && (m_poseState == PoseState.Proning))) { - if((m_ikOverrideCrouch && (m_poseState != PoseState.Standing)) || (m_ikOverrideProne && (m_poseState == PoseState.Proning))) - { - m_vrIk.solver.locomotion.weight = 0f; - l_legsOverride = true; - } - if(m_ikOverrideFly && MovementSystem.Instance.flying) - { - m_vrIk.solver.locomotion.weight = 0f; - l_legsOverride = true; - } + m_vrIk.solver.locomotion.weight = 0f; + l_legsOverride = true; + } + if(m_ikOverrideFly && MovementSystem.Instance.flying) + { + m_vrIk.solver.locomotion.weight = 0f; + l_legsOverride = true; } - // But not this if(m_ikOverrideJump && !m_grounded && !MovementSystem.Instance.flying) { m_vrIk.solver.locomotion.weight = 0f; @@ -345,8 +362,11 @@ namespace ml_amt bool l_solverActive = !Mathf.Approximately(m_vrIk.solver.IKPositionWeight, 0f); - if(l_legsOverride && l_solverActive && m_followHips && !m_moving && PlayerSetup.Instance._inVr) + if(l_legsOverride && l_solverActive && m_followHips && (!m_moving || (m_poseState == PoseState.Proning)) && m_isInVR && !BodySystem.isCalibratedAsFullBody) + { + ABI_RC.Systems.IK.IKSystem.VrikRootController.enabled = false; PlayerSetup.Instance._avatar.transform.localPosition = m_hipsToPlayer; + } } void OnIKPostUpdate() @@ -377,7 +397,7 @@ namespace ml_amt { m_poseTransitions = p_state; - if(!m_poseTransitions && m_avatarReady && PlayerSetup.Instance._inVr) + if(!m_poseTransitions && m_avatarReady && m_isInVR) { PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Crouching", false); PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Prone", false); @@ -387,7 +407,7 @@ namespace ml_amt { m_adjustedMovement = p_state; - if(!m_adjustedMovement && m_avatarReady && PlayerSetup.Instance._inVr) + if(!m_adjustedMovement && m_avatarReady && m_isInVR) { MovementSystem.Instance.ChangeCrouch(false); MovementSystem.Instance.ChangeProne(false); diff --git a/ml_amt/Properties/AssemblyInfo.cs b/ml_amt/Properties/AssemblyInfo.cs index a157c8d..c60291c 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.8")] -[assembly: AssemblyFileVersion("1.1.8")] +[assembly: AssemblyVersion("1.1.9")] +[assembly: AssemblyFileVersion("1.1.9")] -[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.1.8", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.1.9", "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/README.md b/ml_amt/README.md index 184b5c5..2b7c739 100644 --- a/ml_amt/README.md +++ b/ml_amt/README.md @@ -37,3 +37,6 @@ Available additional parameters for AAS animator: Additional avatars tweaks: * If avatar has child object with name `LocomotionOffset` its local position will be used for offsetting VRIK locomotion mass center. + +Additional mod's behaviour: +* Overrides FBT behaviour in 4PT mode (head, hands, hips). Be sure to disable legs and knees tracking in `Settings - IK tab`. diff --git a/ml_amt/Utils.cs b/ml_amt/Utils.cs index 1a82c71..31b75d8 100644 --- a/ml_amt/Utils.cs +++ b/ml_amt/Utils.cs @@ -1,9 +1,12 @@ using UnityEngine; +using ABI_RC.Systems.IK; namespace ml_amt { static class Utils { + public static bool IsInVR() => ((ABI_RC.Core.Savior.CheckVR.Instance != null) && ABI_RC.Core.Savior.CheckVR.Instance.hasVrDeviceLoaded); + // Extensions public static Matrix4x4 GetMatrix(this Transform p_transform, bool p_pos = true, bool p_rot = true, bool p_scl = false) { diff --git a/ml_amt/ml_amt.csproj b/ml_amt/ml_amt.csproj index 777a58a..7d2798e 100644 --- a/ml_amt/ml_amt.csproj +++ b/ml_amt/ml_amt.csproj @@ -82,6 +82,6 @@ - copy /y "$(TargetPath)" "C:\Games\Steam\common\ChilloutVR\Mods\" + copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\" \ No newline at end of file diff --git a/ml_amt/ml_amt.csproj.user b/ml_amt/ml_amt.csproj.user index 2539084..04df561 100644 --- a/ml_amt/ml_amt.csproj.user +++ b/ml_amt/ml_amt.csproj.user @@ -1,6 +1,6 @@  - C:\Games\Steam\common\ChilloutVR\MelonLoader\;C:\Games\Steam\common\ChilloutVR\ChilloutVR_Data\Managed\ + D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\;D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\ \ No newline at end of file diff --git a/ml_amt/resources/menu.js b/ml_amt/resources/menu.js index 78c7499..e2466f2 100644 --- a/ml_amt/resources/menu.js +++ b/ml_amt/resources/menu.js @@ -250,7 +250,7 @@ function inp_toggle_mod_amt(_obj, _callbackName) { `; - document.getElementById('settings-implementation').appendChild(l_block); + document.getElementById('settings-ik').appendChild(l_block); // Update sliders in new menu block let l_sliders = l_block.querySelectorAll('.inp_slider'); diff --git a/ml_lme/GestureMatcher.cs b/ml_lme/GestureMatcher.cs index 75bcdb7..dbaa640 100644 --- a/ml_lme/GestureMatcher.cs +++ b/ml_lme/GestureMatcher.cs @@ -7,11 +7,11 @@ namespace ml_lme readonly static Vector2[] ms_fingerLimits = { - new Vector2(0f, 15f), - new Vector2(-20f, 20f), - new Vector2(-50f, 50f), - new Vector2(-7.5f, 7.5f), - new Vector2(-20f, 20f) + new Vector2(-50f, 0f), + new Vector2(-20f, 30f), + new Vector2(-15f, 15f), + new Vector2(-10f, 20f), + new Vector2(-10f, 25f) }; public class GesturesData @@ -156,57 +156,18 @@ namespace ml_lme l_angle -= 360f; // Pain - switch(l_finger.Type) - { - case Leap.Finger.FingerType.TYPE_THUMB: - { - if(p_hand.IsRight) - l_angle *= -1f; - l_angle += ms_fingerLimits[(int)Leap.Finger.FingerType.TYPE_INDEX].y * 2f; - l_angle *= 0.5f; - } - break; + if(p_hand.IsRight) + l_angle *= -1f; - case Leap.Finger.FingerType.TYPE_INDEX: - { - if(p_hand.IsLeft) - l_angle *= -1f; - l_angle += ms_fingerLimits[(int)Leap.Finger.FingerType.TYPE_INDEX].y; - l_angle *= 0.5f; - } - break; - - case Leap.Finger.FingerType.TYPE_MIDDLE: - { - l_angle += (ms_fingerLimits[(int)Leap.Finger.FingerType.TYPE_MIDDLE].y * (p_hand.IsRight ? 0.125f : -0.125f)); - l_angle *= (p_hand.IsLeft ? -4f : 4f); - } - break; - - case Leap.Finger.FingerType.TYPE_RING: - { - if(p_hand.IsRight) - l_angle *= -1f; - l_angle += ms_fingerLimits[(int)Leap.Finger.FingerType.TYPE_RING].y; - l_angle *= 0.5f; - } - break; - - case Leap.Finger.FingerType.TYPE_PINKY: - { - l_angle += (p_hand.IsRight ? ms_fingerLimits[(int)Leap.Finger.FingerType.TYPE_PINKY].x : ms_fingerLimits[(int)Leap.Finger.FingerType.TYPE_PINKY].y); - l_angle *= (p_hand.IsRight ? -0.5f : 0.5f); - } - break; - - } - - p_spreads[(int)l_finger.Type] = Mathf.InverseLerp(ms_fingerLimits[(int)l_finger.Type].x, ms_fingerLimits[(int)l_finger.Type].y, l_angle); if(l_finger.Type != Leap.Finger.FingerType.TYPE_THUMB) { - p_spreads[(int)l_finger.Type] *= 2f; - p_spreads[(int)l_finger.Type] -= 1f; + if(l_angle < 0f) + p_spreads[(int)l_finger.Type] = 0.5f * Mathf.InverseLerp(ms_fingerLimits[(int)l_finger.Type].x, 0f, l_angle); + else + p_spreads[(int)l_finger.Type] = 0.5f + 0.5f * Mathf.InverseLerp(0f, ms_fingerLimits[(int)l_finger.Type].y, l_angle); } + else + p_spreads[(int)l_finger.Type] = Mathf.InverseLerp(ms_fingerLimits[(int)l_finger.Type].x, ms_fingerLimits[(int)l_finger.Type].y, l_angle); } } } diff --git a/ml_lme/LeapTracked.cs b/ml_lme/LeapTracked.cs index 174cce7..1e1f193 100644 --- a/ml_lme/LeapTracked.cs +++ b/ml_lme/LeapTracked.cs @@ -18,9 +18,11 @@ namespace ml_lme static readonly Quaternion ms_offsetRightDesktop = Quaternion.Euler(0f, 270f, 0f); InputModuleSteamVR m_steamVrModule = null; - IndexIK m_indexIK = null; VRIK m_vrIK = null; Vector2 m_armsWeights = Vector2.zero; + bool m_isInVR = false; + Transform m_origElbowLeft = null; + Transform m_origElbowRight = null; bool m_enabled = true; bool m_fingersOnly = false; @@ -28,6 +30,8 @@ namespace ml_lme ArmIK m_leftIK = null; ArmIK m_rightIK = null; + HumanPoseHandler m_poseHandler = null; + HumanPose m_pose; Transform m_leftHand = null; Transform m_rightHand = null; Transform m_leftHandTarget = null; @@ -39,8 +43,8 @@ namespace ml_lme void Start() { - m_indexIK = this.GetComponent(); m_steamVrModule = CVRInputManager.Instance.GetComponent(); + m_isInVR = Utils.IsInVR(); if(m_leftHand != null) { @@ -98,13 +102,7 @@ namespace ml_lme m_rightIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f); } - if(m_vrIK != null) - { - if(m_leftTargetActive) - m_vrIK.solver.leftArm.bendGoalWeight = (m_trackElbows ? 1f : 0f); - if(m_rightTargetActive) - m_vrIK.solver.rightArm.bendGoalWeight = (m_trackElbows ? 1f : 0f); - } + RestoreVRIK(); } public void SetTransforms(Transform p_left, Transform p_right, Transform p_leftElbow, Transform p_rightElbow) @@ -116,101 +114,176 @@ namespace ml_lme m_rightElbow = p_rightElbow; } - public void UpdateTracking(GestureMatcher.GesturesData p_gesturesData) + public void UpdateTracking(GestureMatcher.GesturesData p_data) { if(m_enabled) { if((m_leftIK != null) && (m_rightIK != null)) { - m_leftIK.solver.IKPositionWeight = Mathf.Lerp(m_leftIK.solver.IKPositionWeight, (p_gesturesData.m_handsPresenses[0] && !m_fingersOnly) ? 1f : 0f, 0.25f); - m_leftIK.solver.IKRotationWeight = Mathf.Lerp(m_leftIK.solver.IKRotationWeight, (p_gesturesData.m_handsPresenses[0] && !m_fingersOnly) ? 1f : 0f, 0.25f); - m_rightIK.solver.IKPositionWeight = Mathf.Lerp(m_rightIK.solver.IKPositionWeight, (p_gesturesData.m_handsPresenses[1] && !m_fingersOnly) ? 1f : 0f, 0.25f); - m_rightIK.solver.IKRotationWeight = Mathf.Lerp(m_rightIK.solver.IKRotationWeight, (p_gesturesData.m_handsPresenses[1] && !m_fingersOnly) ? 1f : 0f, 0.25f); - } + m_leftIK.solver.IKPositionWeight = Mathf.Lerp(m_leftIK.solver.IKPositionWeight, (p_data.m_handsPresenses[0] && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_leftIK.solver.IKRotationWeight = Mathf.Lerp(m_leftIK.solver.IKRotationWeight, (p_data.m_handsPresenses[0] && !m_fingersOnly) ? 1f : 0f, 0.25f); + if(m_trackElbows) + m_leftIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_leftIK.solver.arm.bendGoalWeight, (p_data.m_handsPresenses[0] && !m_fingersOnly) ? 1f : 0f, 0.25f); - if(!Utils.AreKnucklesInUse()) - UpdateFingers(p_gesturesData); + m_rightIK.solver.IKPositionWeight = Mathf.Lerp(m_rightIK.solver.IKPositionWeight, (p_data.m_handsPresenses[1] && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_rightIK.solver.IKRotationWeight = Mathf.Lerp(m_rightIK.solver.IKRotationWeight, (p_data.m_handsPresenses[1] && !m_fingersOnly) ? 1f : 0f, 0.25f); + if(m_trackElbows) + m_rightIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_rightIK.solver.arm.bendGoalWeight, (p_data.m_handsPresenses[1] && !m_fingersOnly) ? 1f : 0f, 0.25f); + } if((m_vrIK != null) && !m_fingersOnly) { - if(p_gesturesData.m_handsPresenses[0] && !m_leftTargetActive) + if(p_data.m_handsPresenses[0] && !m_leftTargetActive) { m_vrIK.solver.leftArm.target = m_leftHandTarget; m_vrIK.solver.leftArm.bendGoal = m_leftElbow; m_vrIK.solver.leftArm.bendGoalWeight = (m_trackElbows ? 1f : 0f); m_leftTargetActive = true; } - if(!p_gesturesData.m_handsPresenses[0] && m_leftTargetActive) + if(!p_data.m_handsPresenses[0] && m_leftTargetActive) { m_vrIK.solver.leftArm.target = IKSystem.Instance.leftHandAnchor; - m_vrIK.solver.leftArm.bendGoal = null; - m_vrIK.solver.leftArm.bendGoalWeight = 0f; + m_vrIK.solver.leftArm.bendGoal = m_origElbowLeft; + m_vrIK.solver.leftArm.bendGoalWeight = ((m_origElbowLeft != null) ? 1f : 0f); m_leftTargetActive = false; } - if(p_gesturesData.m_handsPresenses[1] && !m_rightTargetActive) + if(p_data.m_handsPresenses[1] && !m_rightTargetActive) { m_vrIK.solver.rightArm.target = m_rightHandTarget; m_vrIK.solver.rightArm.bendGoal = m_rightElbow; m_vrIK.solver.rightArm.bendGoalWeight = (m_trackElbows ? 1f : 0f); m_rightTargetActive = true; } - if(!p_gesturesData.m_handsPresenses[1] && m_rightTargetActive) + if(!p_data.m_handsPresenses[1] && m_rightTargetActive) { m_vrIK.solver.rightArm.target = IKSystem.Instance.rightHandAnchor; - m_vrIK.solver.rightArm.bendGoal = null; - m_vrIK.solver.rightArm.bendGoalWeight = 0f; + m_vrIK.solver.rightArm.bendGoal = m_origElbowRight; + m_vrIK.solver.rightArm.bendGoalWeight = ((m_origElbowRight != null) ? 1f : 0f); m_rightTargetActive = false; } } - } - } - - public void UpdateFingers(GestureMatcher.GesturesData p_data) - { - if(m_enabled && (m_indexIK != null) && (CVRInputManager.Instance != null)) - { - CVRInputManager.Instance.individualFingerTracking = true; if(p_data.m_handsPresenses[0]) { - m_indexIK.leftThumbCurl = p_data.m_leftFingersBends[0]; - m_indexIK.leftIndexCurl = p_data.m_leftFingersBends[1]; - m_indexIK.leftMiddleCurl = p_data.m_leftFingersBends[2]; - m_indexIK.leftRingCurl = p_data.m_leftFingersBends[3]; - m_indexIK.leftPinkyCurl = p_data.m_leftFingersBends[4]; + CVRInputManager.Instance.individualFingerTracking = true; CVRInputManager.Instance.fingerCurlLeftThumb = p_data.m_leftFingersBends[0]; CVRInputManager.Instance.fingerCurlLeftIndex = p_data.m_leftFingersBends[1]; CVRInputManager.Instance.fingerCurlLeftMiddle = p_data.m_leftFingersBends[2]; CVRInputManager.Instance.fingerCurlLeftRing = p_data.m_leftFingersBends[3]; CVRInputManager.Instance.fingerCurlLeftPinky = p_data.m_leftFingersBends[4]; + + IKSystem.Instance.FingerSystem.controlActive = true; + IKSystem.Instance.FingerSystem.leftThumbCurl = p_data.m_leftFingersBends[0]; + IKSystem.Instance.FingerSystem.leftIndexCurl = p_data.m_leftFingersBends[1]; + IKSystem.Instance.FingerSystem.leftMiddleCurl = p_data.m_leftFingersBends[2]; + IKSystem.Instance.FingerSystem.leftRingCurl = p_data.m_leftFingersBends[3]; + IKSystem.Instance.FingerSystem.leftPinkyCurl = p_data.m_leftFingersBends[4]; } if(p_data.m_handsPresenses[1]) { - m_indexIK.rightThumbCurl = p_data.m_rightFingersBends[0]; - m_indexIK.rightIndexCurl = p_data.m_rightFingersBends[1]; - m_indexIK.rightMiddleCurl = p_data.m_rightFingersBends[2]; - m_indexIK.rightRingCurl = p_data.m_rightFingersBends[3]; - m_indexIK.rightPinkyCurl = p_data.m_rightFingersBends[4]; + CVRInputManager.Instance.individualFingerTracking = true; CVRInputManager.Instance.fingerCurlRightThumb = p_data.m_rightFingersBends[0]; CVRInputManager.Instance.fingerCurlRightIndex = p_data.m_rightFingersBends[1]; CVRInputManager.Instance.fingerCurlRightMiddle = p_data.m_rightFingersBends[2]; CVRInputManager.Instance.fingerCurlRightRing = p_data.m_rightFingersBends[3]; CVRInputManager.Instance.fingerCurlRightPinky = p_data.m_rightFingersBends[4]; + + IKSystem.Instance.FingerSystem.controlActive = true; + IKSystem.Instance.FingerSystem.rightThumbCurl = p_data.m_rightFingersBends[0]; + IKSystem.Instance.FingerSystem.rightIndexCurl = p_data.m_rightFingersBends[1]; + IKSystem.Instance.FingerSystem.rightMiddleCurl = p_data.m_rightFingersBends[2]; + IKSystem.Instance.FingerSystem.rightRingCurl = p_data.m_rightFingersBends[3]; + IKSystem.Instance.FingerSystem.rightPinkyCurl = p_data.m_rightFingersBends[4]; } } } + public void UpdateTrackingLate(GestureMatcher.GesturesData p_data) + { + if(m_enabled && !m_isInVR && (m_poseHandler != null)) + { + m_poseHandler.GetHumanPose(ref m_pose); + UpdateFingers(p_data); + m_poseHandler.SetHumanPose(ref m_pose); + } + } + + void UpdateFingers(GestureMatcher.GesturesData p_data) + { + if(p_data.m_handsPresenses[0]) + { + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb1Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_leftFingersBends[0])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb2Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_leftFingersBends[0])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb3Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_leftFingersBends[0])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumbSpread, Mathf.Lerp(-1.5f, 1.0f, p_data.m_leftFingersSpreads[0])); // Ok + + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[1])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[1])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[1])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndexSpread, Mathf.Lerp(1f, -1f, p_data.m_leftFingersSpreads[1])); // Ok + + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[2])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[2])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[2])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddleSpread, Mathf.Lerp(2f, -2f, p_data.m_leftFingersSpreads[2])); + + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[3])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[3])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[3])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRingSpread, Mathf.Lerp(-2f, 2f, p_data.m_leftFingersSpreads[3])); + + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[4])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[4])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[4])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittleSpread, Mathf.Lerp(-0.5f, 1f, p_data.m_leftFingersSpreads[4])); + } + + if(p_data.m_handsPresenses[1]) + { + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb1Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_rightFingersBends[0])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb2Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_rightFingersBends[0])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb3Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_rightFingersBends[0])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumbSpread, Mathf.Lerp(-1.5f, 1.0f, p_data.m_rightFingersSpreads[0])); // Ok + + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[1])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[1])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[1])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndexSpread, Mathf.Lerp(1f, -1f, p_data.m_rightFingersSpreads[1])); // Ok + + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[2])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[2])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[2])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddleSpread, Mathf.Lerp(2f, -2f, p_data.m_rightFingersSpreads[2])); + + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[3])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[3])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[3])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRingSpread, Mathf.Lerp(-2f, 2f, p_data.m_rightFingersSpreads[3])); + + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[4])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[4])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[4])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittleSpread, Mathf.Lerp(-0.5f, 1f, p_data.m_rightFingersSpreads[4])); + } + } + public void OnAvatarClear() { m_vrIK = null; + m_origElbowLeft = null; + m_origElbowRight = null; m_armsWeights = Vector2.zero; m_leftIK = null; m_rightIK = null; m_leftTargetActive = false; m_rightTargetActive = false; + if(!m_isInVR) + m_poseHandler?.Dispose(); + m_poseHandler = null; + m_leftHandTarget.localPosition = Vector3.zero; m_leftHandTarget.localRotation = Quaternion.identity; m_rightHandTarget.localPosition = Vector3.zero; @@ -219,33 +292,26 @@ namespace ml_lme public void OnSetupAvatar() { + m_isInVR = Utils.IsInVR(); m_vrIK = PlayerSetup.Instance._animator.GetComponent(); - if(m_indexIK != null) - { - m_indexIK.avatarAnimator = PlayerSetup.Instance._animator; - RefreshFingersTracking(); - } + RefreshFingersTracking(); if(PlayerSetup.Instance._animator.isHuman) { - HumanPoseHandler l_poseHandler = null; - HumanPose l_initPose = new HumanPose(); - - // Force desktop non-VRIK avatar into T-Pose - if(m_vrIK == null) + if(!m_isInVR) { - l_poseHandler = new HumanPoseHandler(PlayerSetup.Instance._animator.avatar, PlayerSetup.Instance._avatar.transform); - l_poseHandler.GetHumanPose(ref l_initPose); + // Force desktop avatar into T-Pose + m_poseHandler = new HumanPoseHandler(PlayerSetup.Instance._animator.avatar, PlayerSetup.Instance._avatar.transform); + m_poseHandler.GetHumanPose(ref m_pose); HumanPose l_tPose = new HumanPose(); - l_tPose.bodyPosition = l_initPose.bodyPosition; - l_tPose.bodyRotation = l_initPose.bodyRotation; - l_tPose.muscles = new float[l_initPose.muscles.Length]; + l_tPose.bodyPosition = m_pose.bodyPosition; + l_tPose.bodyRotation = m_pose.bodyRotation; + l_tPose.muscles = new float[m_pose.muscles.Length]; for(int i = 0; i < l_tPose.muscles.Length; i++) l_tPose.muscles[i] = ms_tposeMuscles[i]; - - l_poseHandler.SetHumanPose(ref l_tPose); + m_poseHandler.SetHumanPose(ref l_tPose); } Transform l_hand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand); @@ -294,15 +360,22 @@ namespace ml_lme m_rightIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f); m_rightIK.enabled = (m_enabled && !m_fingersOnly); - l_poseHandler.SetHumanPose(ref l_initPose); + m_poseHandler?.SetHumanPose(ref m_pose); } else { m_vrIK.solver.OnPreUpdate += this.OnIKPreUpdate; m_vrIK.solver.OnPostUpdate += this.OnIKPostUpdate; } + } + } - l_poseHandler?.Dispose(); + public void OnCalibrate() + { + if(m_vrIK != null) + { + m_origElbowLeft = m_vrIK.solver.leftArm.bendGoal; + m_origElbowRight = m_vrIK.solver.rightArm.bendGoal; } } @@ -337,15 +410,15 @@ namespace ml_lme if(m_leftTargetActive) { m_vrIK.solver.leftArm.target = IKSystem.Instance.leftHandAnchor; - m_vrIK.solver.leftArm.bendGoal = null; - m_vrIK.solver.leftArm.bendGoalWeight = 0f; + m_vrIK.solver.leftArm.bendGoal = m_origElbowLeft; + m_vrIK.solver.leftArm.bendGoalWeight = ((m_origElbowLeft != null) ? 1f : 0f); m_leftTargetActive = false; } if(m_rightTargetActive) { m_vrIK.solver.rightArm.target = IKSystem.Instance.rightHandAnchor; - m_vrIK.solver.rightArm.bendGoal = null; - m_vrIK.solver.rightArm.bendGoalWeight = 0f; + m_vrIK.solver.rightArm.bendGoal = m_origElbowRight; + m_vrIK.solver.rightArm.bendGoalWeight = ((m_origElbowRight != null) ? 1f : 0f); m_rightTargetActive = false; } } @@ -362,11 +435,14 @@ namespace ml_lme void RefreshFingersTracking() { - if(m_indexIK != null) - { - m_indexIK.activeControl = (m_enabled || (PlayerSetup.Instance._inVr && Utils.AreKnucklesInUse())); - CVRInputManager.Instance.individualFingerTracking = (m_enabled || (PlayerSetup.Instance._inVr && Utils.AreKnucklesInUse() && !(bool)ms_indexGestureToggle.GetValue(m_steamVrModule))); - } + CVRInputManager.Instance.individualFingerTracking = (m_enabled || (m_isInVR && Utils.AreKnucklesInUse() && !(bool)ms_indexGestureToggle.GetValue(m_steamVrModule))); + IKSystem.Instance.FingerSystem.controlActive = CVRInputManager.Instance.individualFingerTracking; + } + + static void UpdatePoseMuscle(ref HumanPose p_pose, int p_index, float p_value) + { + if(p_pose.muscles.Length > p_index) + p_pose.muscles[p_index] = p_value; } } } diff --git a/ml_lme/Main.cs b/ml_lme/Main.cs index eb5874c..b441b9d 100644 --- a/ml_lme/Main.cs +++ b/ml_lme/Main.cs @@ -1,5 +1,6 @@ using ABI_RC.Core.Player; using ABI_RC.Core.UI; +using ABI_RC.Systems.IK.SubSystems; using System.Reflection; using UnityEngine; @@ -19,6 +20,8 @@ namespace ml_lme GameObject m_leapControllerModel = null; LeapTracked m_leapTracked = null; + bool m_isInVR = false; + public override void OnInitializeMelon() { if(ms_instance == null) @@ -58,9 +61,9 @@ namespace ml_lme new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); HarmonyInstance.Patch( - typeof(PlayerSetup).GetMethod("GetGesturesFromControllers", BindingFlags.Instance | BindingFlags.NonPublic), + typeof(BodySystem).GetMethod(nameof(BodySystem.Calibrate)), null, - new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnGetGesturesFromControllers_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnCalibrate_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); MelonLoader.MelonCoroutines.Start(CreateTrackingObjects()); @@ -81,6 +84,8 @@ namespace ml_lme while(PlayerSetup.Instance.vrCamera == null) yield return null; + m_isInVR = Utils.IsInVR(); + m_leapTrackingRoot = new GameObject("[LeapRoot]"); for(int i = 0; i < GestureMatcher.GesturesData.ms_handsCount; i++) @@ -167,6 +172,12 @@ namespace ml_lme } } + public override void OnLateUpdate() + { + if(Settings.Enabled && !m_isInVR && (m_leapTracked != null)) + m_leapTracked.UpdateTrackingLate(m_gesturesData); + } + // Settings changes void OnEnableChange(bool p_state) { @@ -183,7 +194,7 @@ namespace ml_lme { if((m_leapTrackingRoot != null) && !Settings.HeadAttach) { - if(!PlayerSetup.Instance._inVr) + if(!m_isInVR) m_leapTrackingRoot.transform.localPosition = p_offset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; else m_leapTrackingRoot.transform.localPosition = p_offset; @@ -230,7 +241,7 @@ namespace ml_lme { if(p_state) { - if(!PlayerSetup.Instance._inVr) + if(!m_isInVR) { m_leapTrackingRoot.transform.parent = PlayerSetup.Instance.desktopCamera.transform; m_leapTrackingRoot.transform.localPosition = Settings.HeadOffset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; @@ -245,7 +256,7 @@ namespace ml_lme } else { - if(!PlayerSetup.Instance._inVr) + if(!m_isInVR) { m_leapTrackingRoot.transform.parent = PlayerSetup.Instance.desktopCameraRig.transform; m_leapTrackingRoot.transform.localPosition = Settings.DesktopOffset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; @@ -267,7 +278,7 @@ namespace ml_lme { if((m_leapTrackingRoot != null) && Settings.HeadAttach) { - if(!PlayerSetup.Instance._inVr) + if(!m_isInVR) m_leapTrackingRoot.transform.localPosition = p_offset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; else m_leapTrackingRoot.transform.localPosition = p_offset; @@ -350,6 +361,8 @@ namespace ml_lme { try { + m_isInVR = Utils.IsInVR(); + if(m_leapTracked != null) m_leapTracked.OnSetupAvatar(); @@ -361,13 +374,13 @@ namespace ml_lme } } - static void OnGetGesturesFromControllers_Postfix() => ms_instance?.OnGetGesturesFromControllers(); - void OnGetGesturesFromControllers() + static void OnCalibrate_Postfix() => ms_instance?.OnCalibrate(); + void OnCalibrate() { try { - if(Settings.Enabled && Utils.AreKnucklesInUse() && (m_leapTracked != null)) - m_leapTracked.UpdateFingers(m_gesturesData); + if(m_leapTracked != null) + m_leapTracked.OnCalibrate(); } catch(System.Exception e) { diff --git a/ml_lme/Properties/AssemblyInfo.cs b/ml_lme/Properties/AssemblyInfo.cs index 446d348..e4713ca 100644 --- a/ml_lme/Properties/AssemblyInfo.cs +++ b/ml_lme/Properties/AssemblyInfo.cs @@ -1,10 +1,10 @@ using System.Reflection; [assembly: AssemblyTitle("LeapMotionExtension")] -[assembly: AssemblyVersion("1.2.7")] -[assembly: AssemblyFileVersion("1.2.7")] +[assembly: AssemblyVersion("1.2.8")] +[assembly: AssemblyFileVersion("1.2.8")] -[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.2.7", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.2.8", "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)] diff --git a/ml_lme/Utils.cs b/ml_lme/Utils.cs index 7813d3e..bf493a4 100644 --- a/ml_lme/Utils.cs +++ b/ml_lme/Utils.cs @@ -10,7 +10,9 @@ namespace ml_lme static readonly Quaternion ms_screentopRotationFix = new Quaternion(0f, 0f, -1f, 0f); public static bool AreKnucklesInUse() => PlayerSetup.Instance._trackerManager.trackerNames.Contains("knuckles"); - + + public static bool IsInVR() => ((ABI_RC.Core.Savior.CheckVR.Instance != null) && ABI_RC.Core.Savior.CheckVR.Instance.hasVrDeviceLoaded); + public static Matrix4x4 GetMatrix(this Transform p_transform, bool p_pos = true, bool p_rot = true, bool p_scl = false) { return Matrix4x4.TRS(p_pos ? p_transform.position : Vector3.zero, p_rot ? p_transform.rotation : Quaternion.identity, p_scl ? p_transform.lossyScale : Vector3.one); diff --git a/ml_lme/ml_lme.csproj b/ml_lme/ml_lme.csproj index 8094eec..d1fba4a 100644 --- a/ml_lme/ml_lme.csproj +++ b/ml_lme/ml_lme.csproj @@ -136,6 +136,6 @@ - copy /y "$(TargetPath)" "C:\Games\Steam\common\ChilloutVR\Mods\" + copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\" \ No newline at end of file diff --git a/ml_lme/ml_lme.csproj.user b/ml_lme/ml_lme.csproj.user index 2539084..04df561 100644 --- a/ml_lme/ml_lme.csproj.user +++ b/ml_lme/ml_lme.csproj.user @@ -1,6 +1,6 @@  - C:\Games\Steam\common\ChilloutVR\MelonLoader\;C:\Games\Steam\common\ChilloutVR\ChilloutVR_Data\Managed\ + D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\;D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\ \ No newline at end of file From 04c5fe0a3b484983d7216bf1afa452bf30964da0 Mon Sep 17 00:00:00 2001 From: SDraw Date: Sun, 25 Dec 2022 09:03:23 +0000 Subject: [PATCH 02/32] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 6dd81a5..b061a4b 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ Merged set of MelonLoader mods for ChilloutVR. -**State table for game build 2022r169p1:** +**State table for game build 2022r170:** | Full name | Short name | Latest version | Available in [CVRMA](https://github.com/knah/CVRMelonAssistant) | Current Status | Notes | |-----------|------------|----------------|-----------------------------------------------------------------|----------------|-------| | Avatar Change Info | ml_aci | 1.0.3 | Yes | Working | -| Avatar Motion Tweaker | ml_amt | 1.1.9 | Yes, pending review | Working | -| Desktop Head Tracking | ml_dht | 1.1.1 | Yes, pending review | Working | +| Avatar Motion Tweaker | ml_amt | 1.1.9 | Yes | Working | +| Desktop Head Tracking | ml_dht | 1.1.1 | Yes | Working | | Desktop Reticle Switch | ml_drs | 1.0.0 | Yes | Working | -| Four Point Tracking | ml_fpt | 1.0.9 | Retired | Deprecated | Not needed after r170 update -| Leap Motion Extension | ml_lme | 1.2.8 | Yes, pending review | Working | +| Four Point Tracking | ml_fpt | 1.0.9 | Retired | Deprecated | In-game feature since 2022r170 update +| Leap Motion Extension | ml_lme | 1.2.8 | Yes | Working | | Server Connection Info | ml_sci | 1.0.2 | Yes | Working | From b2945ac7e20201fc10b1ace312fbe4f5ff716aec Mon Sep 17 00:00:00 2001 From: SDraw Date: Sun, 25 Dec 2022 20:02:44 +0300 Subject: [PATCH 03/32] Additional FBT detoured methods --- README.md | 2 +- ml_amt/Main.cs | 32 +++++++++++++++++++------------ ml_amt/MotionTweaker.cs | 25 ++++++++---------------- ml_amt/Properties/AssemblyInfo.cs | 6 +++--- ml_amt/Utils.cs | 8 ++++++++ 5 files changed, 40 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index b061a4b..39ff805 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ 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.3 | Yes | Working | -| Avatar Motion Tweaker | ml_amt | 1.1.9 | Yes | Working | +| Avatar Motion Tweaker | ml_amt | 1.2.0 | Yes, pending review | Working | | Desktop Head Tracking | ml_dht | 1.1.1 | Yes | Working | | Desktop Reticle Switch | ml_drs | 1.0.0 | Yes | Working | | Four Point Tracking | ml_fpt | 1.0.9 | Retired | Deprecated | In-game feature since 2022r170 update diff --git a/ml_amt/Main.cs b/ml_amt/Main.cs index 407096d..a1d5125 100644 --- a/ml_amt/Main.cs +++ b/ml_amt/Main.cs @@ -1,4 +1,5 @@ -using ABI_RC.Core.Player; +using ABI.CCK.Components; +using ABI_RC.Core.Player; using ABI_RC.Systems.IK.SubSystems; using System.Reflection; @@ -6,6 +7,14 @@ namespace ml_amt { public class AvatarMotionTweaker : MelonLoader.MelonMod { + static readonly MethodInfo[] ms_fbtDetouredMethods = + { + typeof(PlayerSetup).GetMethod("Update", BindingFlags.NonPublic | BindingFlags.Instance), + typeof(PlayerSetup).GetMethod("FixedUpdate", BindingFlags.NonPublic | BindingFlags.Instance), + typeof(PlayerSetup).GetMethod("UpdatePlayerAvatarMovementData", BindingFlags.NonPublic | BindingFlags.Instance), + typeof(CVRParameterStreamEntry).GetMethod(nameof(CVRParameterStreamEntry.CheckUpdate)) + }; + static AvatarMotionTweaker ms_instance = null; MotionTweaker m_localTweaker = null; @@ -34,22 +43,21 @@ namespace ml_amt null, new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnCalibrate_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); + + // FBT detour HarmonyInstance.Patch( typeof(BodySystem).GetMethod(nameof(BodySystem.FBTAvailable)), new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnFBTAvailable_Prefix), BindingFlags.Static | BindingFlags.NonPublic)), null ); - - HarmonyInstance.Patch( - typeof(PlayerSetup).GetMethod("Update", BindingFlags.NonPublic | BindingFlags.Instance), - new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(FBTDetour_Prefix), BindingFlags.Static | BindingFlags.NonPublic)), - new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(FBTDetour_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) - ); - HarmonyInstance.Patch( - typeof(PlayerSetup).GetMethod("FixedUpdate", BindingFlags.NonPublic | BindingFlags.Instance), - new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(FBTDetour_Prefix), BindingFlags.Static | BindingFlags.NonPublic)), - new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(FBTDetour_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) - ); + foreach(MethodInfo l_detoured in ms_fbtDetouredMethods) + { + HarmonyInstance.Patch( + l_detoured, + new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(FBTDetour_Prefix), BindingFlags.Static | BindingFlags.NonPublic)), + new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(FBTDetour_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + ); + } MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); } diff --git a/ml_amt/MotionTweaker.cs b/ml_amt/MotionTweaker.cs index b646def..7b5ed0d 100644 --- a/ml_amt/MotionTweaker.cs +++ b/ml_amt/MotionTweaker.cs @@ -13,7 +13,6 @@ namespace ml_amt { static readonly FieldInfo ms_grounded = typeof(MovementSystem).GetField("_isGrounded", BindingFlags.NonPublic | BindingFlags.Instance); static readonly FieldInfo ms_groundedRaw = typeof(MovementSystem).GetField("_isGroundedRaw", BindingFlags.NonPublic | BindingFlags.Instance); - static readonly FieldInfo ms_rootVelocity = typeof(IKSolverVR).GetField("rootVelocity", BindingFlags.NonPublic | BindingFlags.Instance); static readonly int ms_emoteHash = Animator.StringToHash("Emote"); enum ParameterType @@ -136,7 +135,7 @@ namespace ml_amt float l_avatarScale = (m_avatarScale > 0f) ? (PlayerSetup.Instance._avatar.transform.localScale.y / m_avatarScale) : 0f; float l_avatarViewHeight = Mathf.Clamp(m_viewPointHeight * l_avatarScale, 0f, float.MaxValue); 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); + m_poseState = (m_upright <= Mathf.Min(m_proneLimit, m_crouchLimit)) ? PoseState.Proning : ((m_upright <= Mathf.Max(m_proneLimit, m_crouchLimit)) ? PoseState.Crouching : PoseState.Standing); if(m_avatarHips != null) { @@ -146,19 +145,10 @@ namespace ml_amt if(m_isInVR && (m_vrIk != null) && m_vrIk.enabled) { - if(m_poseState != l_poseState) - { - // Weird fix of torso shaking - if(m_ikOverrideCrouch && (l_poseState == PoseState.Standing)) - ms_rootVelocity.SetValue(m_vrIk.solver, Vector3.zero); - if(m_ikOverrideProne && !m_ikOverrideCrouch && (l_poseState == PoseState.Crouching)) - ms_rootVelocity.SetValue(m_vrIk.solver, Vector3.zero); - } - if(m_adjustedMovement) { - MovementSystem.Instance.ChangeCrouch(l_poseState == PoseState.Crouching); - MovementSystem.Instance.ChangeProne(l_poseState == PoseState.Proning); + MovementSystem.Instance.ChangeCrouch(m_poseState == PoseState.Crouching); + MovementSystem.Instance.ChangeProne(m_poseState == PoseState.Proning); if(!m_poseTransitions) { @@ -169,13 +159,11 @@ namespace ml_amt if(m_poseTransitions) { - PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Crouching", (l_poseState == PoseState.Crouching) && !m_compatibleAvatar && !BodySystem.isCalibratedAsFullBody); - PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Prone", (l_poseState == PoseState.Proning) && !m_compatibleAvatar && !BodySystem.isCalibratedAsFullBody); + PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Crouching", (m_poseState == PoseState.Crouching) && !m_compatibleAvatar && !BodySystem.isCalibratedAsFullBody); + PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Prone", (m_poseState == PoseState.Proning) && !m_compatibleAvatar && !BodySystem.isCalibratedAsFullBody); } } - m_poseState = l_poseState; - m_emoteActive = false; if(m_detectEmotes && (m_locomotionLayer >= 0)) { @@ -302,6 +290,9 @@ namespace ml_amt m_customProneLimit = (l_customTransform != null); m_proneLimit = m_customProneLimit ? Mathf.Clamp(l_customTransform.localPosition.y, 0f, 1f) : Settings.ProneLimit; + if(m_proneLimit > m_crouchLimit) + Utils.Swap(ref m_proneLimit, ref m_crouchLimit); + l_customTransform = PlayerSetup.Instance._avatar.transform.Find("LocomotionOffset"); m_customLocomotionOffset = (l_customTransform != null); m_locomotionOffset = m_customLocomotionOffset ? l_customTransform.localPosition : Vector3.zero; diff --git a/ml_amt/Properties/AssemblyInfo.cs b/ml_amt/Properties/AssemblyInfo.cs index c60291c..5577e72 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.9")] -[assembly: AssemblyFileVersion("1.1.9")] +[assembly: AssemblyVersion("1.2.0")] +[assembly: AssemblyFileVersion("1.2.0")] -[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.1.9", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.2.0", "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/Utils.cs b/ml_amt/Utils.cs index 31b75d8..bf5087c 100644 --- a/ml_amt/Utils.cs +++ b/ml_amt/Utils.cs @@ -12,5 +12,13 @@ namespace ml_amt { return Matrix4x4.TRS(p_pos ? p_transform.position : Vector3.zero, p_rot ? p_transform.rotation : Quaternion.identity, p_scl ? p_transform.localScale : Vector3.one); } + + // Usefull + public static void Swap(ref T lhs, ref T rhs) + { + T temp = lhs; + lhs = rhs; + rhs = temp; + } } } From 46616f8b772536258feaf25d94c8d852b857faae Mon Sep 17 00:00:00 2001 From: SDraw Date: Sun, 25 Dec 2022 20:15:46 +0300 Subject: [PATCH 04/32] Uh, not needed --- ml_amt/MotionTweaker.cs | 3 --- ml_amt/Utils.cs | 8 -------- 2 files changed, 11 deletions(-) diff --git a/ml_amt/MotionTweaker.cs b/ml_amt/MotionTweaker.cs index 7b5ed0d..5947147 100644 --- a/ml_amt/MotionTweaker.cs +++ b/ml_amt/MotionTweaker.cs @@ -290,9 +290,6 @@ namespace ml_amt m_customProneLimit = (l_customTransform != null); m_proneLimit = m_customProneLimit ? Mathf.Clamp(l_customTransform.localPosition.y, 0f, 1f) : Settings.ProneLimit; - if(m_proneLimit > m_crouchLimit) - Utils.Swap(ref m_proneLimit, ref m_crouchLimit); - l_customTransform = PlayerSetup.Instance._avatar.transform.Find("LocomotionOffset"); m_customLocomotionOffset = (l_customTransform != null); m_locomotionOffset = m_customLocomotionOffset ? l_customTransform.localPosition : Vector3.zero; diff --git a/ml_amt/Utils.cs b/ml_amt/Utils.cs index bf5087c..31b75d8 100644 --- a/ml_amt/Utils.cs +++ b/ml_amt/Utils.cs @@ -12,13 +12,5 @@ namespace ml_amt { return Matrix4x4.TRS(p_pos ? p_transform.position : Vector3.zero, p_rot ? p_transform.rotation : Quaternion.identity, p_scl ? p_transform.localScale : Vector3.one); } - - // Usefull - public static void Swap(ref T lhs, ref T rhs) - { - T temp = lhs; - lhs = rhs; - rhs = temp; - } } } From 551e1a577f2fcab0a917d78467455a3ee8d60f1b Mon Sep 17 00:00:00 2001 From: SDraw Date: Mon, 26 Dec 2022 08:40:43 +0300 Subject: [PATCH 05/32] Update README.md --- ml_amt/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ml_amt/README.md b/ml_amt/README.md index 2b7c739..b27fb3e 100644 --- a/ml_amt/README.md +++ b/ml_amt/README.md @@ -9,7 +9,7 @@ This mod adds features for AAS animator and avatar locomotion behaviour. * Put `ml_amt.dll` in `Mods` folder of game # Usage -Available mod's settings in `Settings - Implementation - Avatar Motion Tweaker`: +Available mod's settings in `Settings - IK - Avatar Motion Tweaker`: * **IK override while crouching:** disables legs locomotion/autostep upon HMD reaching `Crouch limit`; default value - `true`. * **Crouch limit:** defines crouch limit; default value - `65`. * Note: Can be overrided by avatar. For this avatar has to have child gameobject with name `CrouchLimit`, its Y-axis location will be used as limit, should be in range [0.0, 1.0]. From 027e6c29cd53d9a1e326a95d19edfd9faf2162a7 Mon Sep 17 00:00:00 2001 From: SDraw Date: Tue, 27 Dec 2022 00:12:29 +0300 Subject: [PATCH 06/32] Avatars position fix --- README.md | 2 +- ml_lme/LeapTracked.cs | 12 ++++++++++++ ml_lme/Properties/AssemblyInfo.cs | 6 +++--- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 39ff805..72a6cb2 100644 --- a/README.md +++ b/README.md @@ -8,5 +8,5 @@ Merged set of MelonLoader mods for ChilloutVR. | Desktop Head Tracking | ml_dht | 1.1.1 | Yes | Working | | Desktop Reticle Switch | ml_drs | 1.0.0 | Yes | Working | | Four Point Tracking | ml_fpt | 1.0.9 | Retired | Deprecated | In-game feature since 2022r170 update -| Leap Motion Extension | ml_lme | 1.2.8 | Yes | Working | +| Leap Motion Extension | ml_lme | 1.2.9 | Yes, pending review | Working | | Server Connection Info | ml_sci | 1.0.2 | Yes | Working | diff --git a/ml_lme/LeapTracked.cs b/ml_lme/LeapTracked.cs index 1e1f193..ee1d0ae 100644 --- a/ml_lme/LeapTracked.cs +++ b/ml_lme/LeapTracked.cs @@ -23,6 +23,8 @@ namespace ml_lme bool m_isInVR = false; Transform m_origElbowLeft = null; Transform m_origElbowRight = null; + Transform m_hips = null; + Vector3 m_hipsLocal = Vector3.zero; bool m_enabled = true; bool m_fingersOnly = false; @@ -204,9 +206,15 @@ namespace ml_lme { if(m_enabled && !m_isInVR && (m_poseHandler != null)) { + if(m_hips != null) + m_hipsLocal = m_hips.localPosition; + m_poseHandler.GetHumanPose(ref m_pose); UpdateFingers(p_data); m_poseHandler.SetHumanPose(ref m_pose); + + if(m_hips != null) + m_hips.localPosition = m_hipsLocal; } } @@ -274,6 +282,8 @@ namespace ml_lme m_vrIK = null; m_origElbowLeft = null; m_origElbowRight = null; + m_hips = null; + m_hipsLocal = Vector3.zero; m_armsWeights = Vector2.zero; m_leftIK = null; m_rightIK = null; @@ -299,6 +309,8 @@ namespace ml_lme if(PlayerSetup.Instance._animator.isHuman) { + m_hips = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Hips); + if(!m_isInVR) { // Force desktop avatar into T-Pose diff --git a/ml_lme/Properties/AssemblyInfo.cs b/ml_lme/Properties/AssemblyInfo.cs index e4713ca..ea10aad 100644 --- a/ml_lme/Properties/AssemblyInfo.cs +++ b/ml_lme/Properties/AssemblyInfo.cs @@ -1,10 +1,10 @@ using System.Reflection; [assembly: AssemblyTitle("LeapMotionExtension")] -[assembly: AssemblyVersion("1.2.8")] -[assembly: AssemblyFileVersion("1.2.8")] +[assembly: AssemblyVersion("1.2.9")] +[assembly: AssemblyFileVersion("1.2.9")] -[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.2.8", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.2.9", "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)] From 25969abef9d30b655e716a2928dba356976f0030 Mon Sep 17 00:00:00 2001 From: SDraw Date: Tue, 27 Dec 2022 23:18:35 +0300 Subject: [PATCH 07/32] Alternative collider scale --- README.md | 2 +- ml_amt/Main.cs | 68 +++++++++++++++++++++++++++++++ ml_amt/Properties/AssemblyInfo.cs | 6 +-- ml_amt/README.md | 3 +- ml_amt/Settings.cs | 18 +++++++- ml_amt/ml_amt.csproj | 5 +++ ml_amt/resources/menu.js | 7 ++++ 7 files changed, 103 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 72a6cb2..d20bc17 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ 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.3 | Yes | Working | -| Avatar Motion Tweaker | ml_amt | 1.2.0 | Yes, pending review | Working | +| Avatar Motion Tweaker | ml_amt | 1.2.1 | Yes, pending review | Working | | Desktop Head Tracking | ml_dht | 1.1.1 | Yes | Working | | Desktop Reticle Switch | ml_drs | 1.0.0 | Yes | Working | | Four Point Tracking | ml_fpt | 1.0.9 | Retired | Deprecated | In-game feature since 2022r170 update diff --git a/ml_amt/Main.cs b/ml_amt/Main.cs index a1d5125..cabbf27 100644 --- a/ml_amt/Main.cs +++ b/ml_amt/Main.cs @@ -2,6 +2,8 @@ using ABI_RC.Core.Player; using ABI_RC.Systems.IK.SubSystems; using System.Reflection; +using ABI_RC.Systems.MovementSystem; +using UnityEngine; namespace ml_amt { @@ -59,6 +61,13 @@ namespace ml_amt ); } + // Alternative collider height + HarmonyInstance.Patch( + typeof(MovementSystem).GetMethod("UpdateCollider", BindingFlags.NonPublic | BindingFlags.Instance), + new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnUpdateCollider_Prefix), BindingFlags.Static | BindingFlags.NonPublic)), + null + ); + MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); } @@ -149,5 +158,64 @@ namespace ml_amt return true; } + + // Alternative collider size + static bool OnUpdateCollider_Prefix( + ref MovementSystem __instance, + bool __0, // updateRadius + CharacterController ___controller, + float ____avatarHeight, + float ____avatarHeightFactor, + float ____minimumColliderRadius, + Vector3 ____colliderCenter + ) + { + if(!Settings.CollisionScale) + return true; + + try + { + if(___controller != null) + { + float l_scaledHeight = ____avatarHeight * ____avatarHeightFactor; + float l_newRadius = (__0 ? Mathf.Max(____minimumColliderRadius, l_scaledHeight / 6f) : ___controller.radius); + + float l_newHeight = Mathf.Max(l_scaledHeight, l_newRadius * 2f); + float l_currentHeight = ___controller.height; + + Vector3 l_newCenter = ____colliderCenter; + l_newCenter.y = (l_newHeight + 0.075f * ____avatarHeightFactor) * 0.5f; + Vector3 l_currentCenter = ___controller.center; + + if((Mathf.Abs(l_currentHeight - l_newHeight) > (l_currentHeight * 0.05f)) || (Vector3.Distance(l_currentCenter,l_newCenter) > (l_currentHeight * 0.05f))) + { + bool l_active = ___controller.enabled; + + if(__0) + ___controller.radius = l_newRadius; + ___controller.height = l_newHeight; + ___controller.center = l_newCenter; + + __instance.groundDistance = l_newRadius; + + if(__0) + __instance.proxyCollider.radius = l_newRadius; + __instance.proxyCollider.height = l_newHeight; + __instance.proxyCollider.center = new Vector3(0f, l_newCenter.y, 0f); + + __instance.forceObject.transform.localScale = new Vector3(l_newRadius + 0.1f, l_newHeight, l_newRadius + 0.1f); + __instance.groundCheck.localPosition = ____colliderCenter; + + ___controller.enabled = l_active; + } + } + } + catch(System.Exception l_exception) + { + MelonLoader.MelonLogger.Error(l_exception); + } + + return false; + } } } diff --git a/ml_amt/Properties/AssemblyInfo.cs b/ml_amt/Properties/AssemblyInfo.cs index 5577e72..85eefe4 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.2.0")] -[assembly: AssemblyFileVersion("1.2.0")] +[assembly: AssemblyVersion("1.2.1")] +[assembly: AssemblyFileVersion("1.2.1")] -[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.2.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.2.1", "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/README.md b/ml_amt/README.md index b27fb3e..3f339b1 100644 --- a/ml_amt/README.md +++ b/ml_amt/README.md @@ -22,8 +22,9 @@ Available mod's settings in `Settings - IK - Avatar Motion Tweaker`: * **Pose transitions:** allows regular avatars animator to transit in crouch/prone states; default value - `true`. * Note: Avatar is considered as regular if its AAS animator doesn't have `Upright` parameter. * **Adjusted pose movement speed:** scales movement speed upon crouching/proning; default value - `true`. -* **Detect animations emote tag:** disables avatar's IK entirely if current animator state has `Emote` tag; default value - `true`; +* **Detect animations emote tag:** disables avatar's IK entirely if current animator state has `Emote` tag; default value - `true`. * Note: Created as example for [propoused game feature](https://feedback.abinteractive.net/p/disabling-vr-ik-for-emotes-via-animator-state-tag-7b80d963-053a-41c0-86ac-e3d53c61c1e2). +* **Alternative avatar collider scale:** applies slightly different approach to avatar collider size change; default value - `true` Available additional parameters for AAS animator: * **`Upright`:** defines linear coefficient between current viewpoint height and avatar's viewpoint height; float, range - [0.0, 1.0]. diff --git a/ml_amt/Settings.cs b/ml_amt/Settings.cs index 2048398..7eb0ea2 100644 --- a/ml_amt/Settings.cs +++ b/ml_amt/Settings.cs @@ -18,7 +18,8 @@ namespace ml_amt IKOverrideFly, IKOverrideJump, DetectEmotes, - FollowHips + FollowHips, + CollisionScale }; static bool ms_ikOverrideCrouch = true; @@ -31,6 +32,7 @@ namespace ml_amt static bool ms_ikOverrideJump = true; static bool ms_detectEmotes = true; static bool ms_followHips = true; + static bool ms_collisionScale = true; static MelonLoader.MelonPreferences_Category ms_category = null; static List ms_entries = null; @@ -45,6 +47,7 @@ namespace ml_amt static public event Action IKOverrideJumpChange; static public event Action DetectEmotesChange; static public event Action FollowHipsChange; + static public event Action CollisionScaleChange; public static void Init() { @@ -61,6 +64,7 @@ namespace ml_amt ms_entries.Add(ms_category.CreateEntry(ModSetting.IKOverrideJump.ToString(), true)); ms_entries.Add(ms_category.CreateEntry(ModSetting.DetectEmotes.ToString(), true)); ms_entries.Add(ms_category.CreateEntry(ModSetting.FollowHips.ToString(), true)); + ms_entries.Add(ms_category.CreateEntry(ModSetting.CollisionScale.ToString(), true)); Load(); @@ -101,6 +105,7 @@ namespace ml_amt ms_ikOverrideJump = (bool)ms_entries[(int)ModSetting.IKOverrideJump].BoxedValue; ms_detectEmotes = (bool)ms_entries[(int)ModSetting.DetectEmotes].BoxedValue; ms_followHips = (bool)ms_entries[(int)ModSetting.FollowHips].BoxedValue; + ms_collisionScale = (bool)ms_entries[(int)ModSetting.CollisionScale].BoxedValue; } static void OnSliderUpdate(string p_name, string p_value) @@ -189,6 +194,13 @@ namespace ml_amt FollowHipsChange?.Invoke(ms_followHips); } break; + + case ModSetting.CollisionScale: + { + ms_collisionScale = bool.Parse(p_value); + CollisionScaleChange?.Invoke(ms_collisionScale); + } + break; } ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); @@ -235,5 +247,9 @@ namespace ml_amt { get => ms_followHips; } + public static bool CollisionScale + { + get => ms_collisionScale; + } } } diff --git a/ml_amt/ml_amt.csproj b/ml_amt/ml_amt.csproj index 7d2798e..83cb6a1 100644 --- a/ml_amt/ml_amt.csproj +++ b/ml_amt/ml_amt.csproj @@ -68,6 +68,11 @@ False + + False + D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.PhysicsModule.dll + False + diff --git a/ml_amt/resources/menu.js b/ml_amt/resources/menu.js index e2466f2..1b6ebaa 100644 --- a/ml_amt/resources/menu.js +++ b/ml_amt/resources/menu.js @@ -249,6 +249,13 @@ function inp_toggle_mod_amt(_obj, _callbackName) {
+ +
+
Alternative avatar collider scale:
+
+
+
+
`; document.getElementById('settings-ik').appendChild(l_block); From b1b1a324ad4dd22743e71fc9d553c37b11b30f86 Mon Sep 17 00:00:00 2001 From: SDraw Date: Wed, 28 Dec 2022 10:44:53 +0300 Subject: [PATCH 08/32] Force update on radius update --- ml_amt/Main.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ml_amt/Main.cs b/ml_amt/Main.cs index cabbf27..224b775 100644 --- a/ml_amt/Main.cs +++ b/ml_amt/Main.cs @@ -1,8 +1,8 @@ using ABI.CCK.Components; using ABI_RC.Core.Player; using ABI_RC.Systems.IK.SubSystems; -using System.Reflection; using ABI_RC.Systems.MovementSystem; +using System.Reflection; using UnityEngine; namespace ml_amt @@ -172,7 +172,7 @@ namespace ml_amt { if(!Settings.CollisionScale) return true; - + try { if(___controller != null) @@ -187,25 +187,25 @@ namespace ml_amt l_newCenter.y = (l_newHeight + 0.075f * ____avatarHeightFactor) * 0.5f; Vector3 l_currentCenter = ___controller.center; - if((Mathf.Abs(l_currentHeight - l_newHeight) > (l_currentHeight * 0.05f)) || (Vector3.Distance(l_currentCenter,l_newCenter) > (l_currentHeight * 0.05f))) + if(__0 || (Mathf.Abs(l_currentHeight - l_newHeight) > (l_currentHeight * 0.05f)) || (Vector3.Distance(l_currentCenter, l_newCenter) > (l_currentHeight * 0.05f))) { bool l_active = ___controller.enabled; - + if(__0) ___controller.radius = l_newRadius; ___controller.height = l_newHeight; ___controller.center = l_newCenter; - + __instance.groundDistance = l_newRadius; - + if(__0) __instance.proxyCollider.radius = l_newRadius; __instance.proxyCollider.height = l_newHeight; __instance.proxyCollider.center = new Vector3(0f, l_newCenter.y, 0f); - + __instance.forceObject.transform.localScale = new Vector3(l_newRadius + 0.1f, l_newHeight, l_newRadius + 0.1f); __instance.groundCheck.localPosition = ____colliderCenter; - + ___controller.enabled = l_active; } } From b6bf52b8a14f94146cc34e2a099b88a13426dc77 Mon Sep 17 00:00:00 2001 From: SDraw Date: Fri, 30 Dec 2022 20:43:51 +0300 Subject: [PATCH 09/32] Avatar parameters changes --- ml_amt/AvatarParameter.cs | 78 +++++++++++++++++++++++++++++++ ml_amt/MotionTweaker.cs | 97 +++++++-------------------------------- ml_amt/ml_amt.csproj | 1 + 3 files changed, 95 insertions(+), 81 deletions(-) create mode 100644 ml_amt/AvatarParameter.cs diff --git a/ml_amt/AvatarParameter.cs b/ml_amt/AvatarParameter.cs new file mode 100644 index 0000000..3349104 --- /dev/null +++ b/ml_amt/AvatarParameter.cs @@ -0,0 +1,78 @@ +using ABI_RC.Core.Player; + +namespace ml_amt +{ + class AvatarParameter + { + public enum ParameterType + { + Upright, + GroundedRaw, + Moving + } + + public enum ParameterSyncType + { + Synced, + Local + } + + public readonly ParameterType m_type; + public readonly ParameterSyncType m_sync; + public readonly string m_name; + public readonly int m_hash; // For local only + + + public AvatarParameter(ParameterType p_type, string p_name, ParameterSyncType p_sync = ParameterSyncType.Synced, int p_hash = 0) + { + m_type = p_type; + m_sync = p_sync; + m_name = p_name; + m_hash = p_hash; + } + + public void Update(MotionTweaker p_tweaker) + { + switch(m_type) + { + case ParameterType.Upright: + SetFloat(p_tweaker.GetUpright()); + break; + + case ParameterType.GroundedRaw: + SetBoolean(p_tweaker.GetGroundedRaw()); + break; + + case ParameterType.Moving: + SetBoolean(p_tweaker.GetMoving()); + break; + } + } + + void SetFloat(float p_value) + { + switch(m_sync) + { + case ParameterSyncType.Local: + PlayerSetup.Instance._animator.SetFloat(m_hash, p_value); + break; + case ParameterSyncType.Synced: + PlayerSetup.Instance.animatorManager.SetAnimatorParameterFloat(m_name, p_value); + break; + } + } + + void SetBoolean(bool p_value) + { + switch(m_sync) + { + case ParameterSyncType.Local: + PlayerSetup.Instance._animator.SetBool(m_hash, p_value); + break; + case ParameterSyncType.Synced: + PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool(m_name, p_value); + break; + } + } + } +} diff --git a/ml_amt/MotionTweaker.cs b/ml_amt/MotionTweaker.cs index 5947147..497694f 100644 --- a/ml_amt/MotionTweaker.cs +++ b/ml_amt/MotionTweaker.cs @@ -15,27 +15,6 @@ namespace ml_amt static readonly FieldInfo ms_groundedRaw = typeof(MovementSystem).GetField("_isGroundedRaw", BindingFlags.NonPublic | BindingFlags.Instance); static readonly int ms_emoteHash = Animator.StringToHash("Emote"); - enum ParameterType - { - Upright, - GroundedRaw, - Moving - } - - enum ParameterSyncType - { - Local, - Synced - } - - struct AdditionalParameterInfo - { - public ParameterType m_type; - public ParameterSyncType m_sync; - public string m_name; - public int m_hash; // For local only - } - enum PoseState { Standing = 0, @@ -84,11 +63,11 @@ namespace ml_amt bool m_followHips = true; Vector3 m_hipsToPlayer = Vector3.zero; - readonly List m_parameters = null; + readonly List m_parameters = null; public MotionTweaker() { - m_parameters = new List(); + m_parameters = new List(); } void Start() @@ -173,53 +152,8 @@ namespace ml_amt if(m_parameters.Count > 0) { - foreach(AdditionalParameterInfo l_param in m_parameters) - { - switch(l_param.m_type) - { - case ParameterType.Upright: - { - switch(l_param.m_sync) - { - case ParameterSyncType.Local: - PlayerSetup.Instance._animator.SetFloat(l_param.m_hash, m_upright); - break; - case ParameterSyncType.Synced: - PlayerSetup.Instance.animatorManager.SetAnimatorParameterFloat(l_param.m_name, m_upright); - break; - } - } - break; - - case ParameterType.GroundedRaw: - { - switch(l_param.m_sync) - { - case ParameterSyncType.Local: - PlayerSetup.Instance._animator.SetBool(l_param.m_hash, m_groundedRaw); - break; - case ParameterSyncType.Synced: - PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool(l_param.m_name, m_groundedRaw); - break; - } - } - break; - - case ParameterType.Moving: - { - switch(l_param.m_sync) - { - case ParameterSyncType.Local: - PlayerSetup.Instance._animator.SetBool(l_param.m_hash, m_moving); - break; - case ParameterSyncType.Synced: - PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool(l_param.m_name, m_moving); - break; - } - } - break; - } - } + foreach(AvatarParameter l_param in m_parameters) + l_param.Update(this); } } } @@ -256,30 +190,27 @@ namespace ml_amt // Parse animator parameters AnimatorControllerParameter[] l_params = PlayerSetup.Instance._animator.parameters; - ParameterType[] l_enumParams = (ParameterType[])System.Enum.GetValues(typeof(ParameterType)); - foreach(var l_param in l_params) { - foreach(var l_enumParam in l_enumParams) + foreach(AvatarParameter.ParameterType l_enumParam in System.Enum.GetValues(typeof(AvatarParameter.ParameterType))) { if(l_param.name.Contains(l_enumParam.ToString()) && (m_parameters.FindIndex(p => p.m_type == l_enumParam) == -1)) { bool l_local = (l_param.name[0] == '#'); - m_parameters.Add(new AdditionalParameterInfo - { - m_type = l_enumParam, - m_sync = (l_local ? ParameterSyncType.Local : ParameterSyncType.Synced), - m_name = l_param.name, - m_hash = (l_local ? l_param.nameHash : 0) - }); + m_parameters.Add(new AvatarParameter( + l_enumParam, + l_param.name, + (l_local ? AvatarParameter.ParameterSyncType.Local : AvatarParameter.ParameterSyncType.Synced), + (l_local ? l_param.nameHash : 0) + )); break; } } } - m_compatibleAvatar = m_parameters.Exists(p => p.m_name.Contains("Upright")); + m_compatibleAvatar = m_parameters.Exists(p => p.m_type == AvatarParameter.ParameterType.Upright); m_avatarScale = Mathf.Abs(PlayerSetup.Instance._avatar.transform.localScale.y); Transform l_customTransform = PlayerSetup.Instance._avatar.transform.Find("CrouchLimit"); @@ -417,5 +348,9 @@ namespace ml_amt { m_followHips = p_state; } + + public float GetUpright() => m_upright; + public bool GetGroundedRaw() => m_groundedRaw; + public bool GetMoving() => m_moving; } } diff --git a/ml_amt/ml_amt.csproj b/ml_amt/ml_amt.csproj index 83cb6a1..bea6a67 100644 --- a/ml_amt/ml_amt.csproj +++ b/ml_amt/ml_amt.csproj @@ -75,6 +75,7 @@
+ From 192005a35f982d84daefb179fa382ff0edf444f5 Mon Sep 17 00:00:00 2001 From: SDraw Date: Sat, 31 Dec 2022 12:03:52 +0000 Subject: [PATCH 10/32] Update Main.cs --- ml_amt/Main.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ml_amt/Main.cs b/ml_amt/Main.cs index 224b775..d14c84b 100644 --- a/ml_amt/Main.cs +++ b/ml_amt/Main.cs @@ -184,7 +184,7 @@ namespace ml_amt float l_currentHeight = ___controller.height; Vector3 l_newCenter = ____colliderCenter; - l_newCenter.y = (l_newHeight + 0.075f * ____avatarHeightFactor) * 0.5f; + l_newCenter.y = (l_newHeight + 0.075f) * 0.5f; Vector3 l_currentCenter = ___controller.center; if(__0 || (Mathf.Abs(l_currentHeight - l_newHeight) > (l_currentHeight * 0.05f)) || (Vector3.Distance(l_currentCenter, l_newCenter) > (l_currentHeight * 0.05f))) From 32a460f8b261e0a137710192f8f1cf73a44bf3be Mon Sep 17 00:00:00 2001 From: SDraw Date: Sun, 1 Jan 2023 13:39:49 +0300 Subject: [PATCH 11/32] Fix of game's usage of destroyed objects --- ml_amt/Main.cs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/ml_amt/Main.cs b/ml_amt/Main.cs index d14c84b..4444846 100644 --- a/ml_amt/Main.cs +++ b/ml_amt/Main.cs @@ -184,7 +184,7 @@ namespace ml_amt float l_currentHeight = ___controller.height; Vector3 l_newCenter = ____colliderCenter; - l_newCenter.y = (l_newHeight + 0.075f) * 0.5f; + l_newCenter.y = (l_newHeight + 0.075f) * 0.5f; // Idk where 0.075f has come from Vector3 l_currentCenter = ___controller.center; if(__0 || (Mathf.Abs(l_currentHeight - l_newHeight) > (l_currentHeight * 0.05f)) || (Vector3.Distance(l_currentCenter, l_newCenter) > (l_currentHeight * 0.05f))) @@ -198,13 +198,18 @@ namespace ml_amt __instance.groundDistance = l_newRadius; - if(__0) - __instance.proxyCollider.radius = l_newRadius; - __instance.proxyCollider.height = l_newHeight; - __instance.proxyCollider.center = new Vector3(0f, l_newCenter.y, 0f); + if(__instance.proxyCollider != null) + { + if(__0) + __instance.proxyCollider.radius = l_newRadius; + __instance.proxyCollider.height = l_newHeight; + __instance.proxyCollider.center = new Vector3(0f, l_newCenter.y, 0f); + } - __instance.forceObject.transform.localScale = new Vector3(l_newRadius + 0.1f, l_newHeight, l_newRadius + 0.1f); - __instance.groundCheck.localPosition = ____colliderCenter; + if(__instance.forceObject != null) + __instance.forceObject.transform.localScale = new Vector3(l_newRadius + 0.1f, l_newHeight, l_newRadius + 0.1f); + if(__instance.groundCheck != null) + __instance.groundCheck.localPosition = ____colliderCenter; ___controller.enabled = l_active; } From 779eef4b10c0aef58ef8ccc2273900085842a294 Mon Sep 17 00:00:00 2001 From: SDraw Date: Thu, 5 Jan 2023 00:15:29 +0000 Subject: [PATCH 12/32] Update README.md --- ml_amt/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ml_amt/README.md b/ml_amt/README.md index 3f339b1..0189faf 100644 --- a/ml_amt/README.md +++ b/ml_amt/README.md @@ -19,6 +19,8 @@ Available mod's settings in `Settings - IK - Avatar Motion Tweaker`: * **IK override while flying:** disables legs locomotion/autostep in fly mode; default value - `true`. * **IK override while jumping:** disables legs locomotion/autostep in jump; default value - `true`. * **Follow hips on IK override:** adjust avatar position to overcome animation snapping on IK override; default value - `true`. + * Note: Works perfect with animations that have root transform position (XZ) based on center of mass. + * Note: Made for four point tracking (head, hands, hips) in mind. * **Pose transitions:** allows regular avatars animator to transit in crouch/prone states; default value - `true`. * Note: Avatar is considered as regular if its AAS animator doesn't have `Upright` parameter. * **Adjusted pose movement speed:** scales movement speed upon crouching/proning; default value - `true`. From 5accd02789cc2960eac6478656f0ba57e52a55b5 Mon Sep 17 00:00:00 2001 From: SDraw Date: Thu, 5 Jan 2023 00:19:31 +0000 Subject: [PATCH 13/32] Update README.md --- ml_amt/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ml_amt/README.md b/ml_amt/README.md index 0189faf..0489c8c 100644 --- a/ml_amt/README.md +++ b/ml_amt/README.md @@ -19,7 +19,7 @@ Available mod's settings in `Settings - IK - Avatar Motion Tweaker`: * **IK override while flying:** disables legs locomotion/autostep in fly mode; default value - `true`. * **IK override while jumping:** disables legs locomotion/autostep in jump; default value - `true`. * **Follow hips on IK override:** adjust avatar position to overcome animation snapping on IK override; default value - `true`. - * Note: Works perfect with animations that have root transform position (XZ) based on center of mass. + * Note: Works best with animations that have root transform position (XZ) based on center of mass. * Note: Made for four point tracking (head, hands, hips) in mind. * **Pose transitions:** allows regular avatars animator to transit in crouch/prone states; default value - `true`. * Note: Avatar is considered as regular if its AAS animator doesn't have `Upright` parameter. From 98694078028c9247550adf902ee047b01dc8e74d Mon Sep 17 00:00:00 2001 From: SDraw Date: Sun, 15 Jan 2023 16:50:14 +0000 Subject: [PATCH 14/32] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d20bc17..356baf8 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ 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.3 | Yes | Working | -| Avatar Motion Tweaker | ml_amt | 1.2.1 | Yes, pending review | Working | +| Avatar Motion Tweaker | ml_amt | 1.2.1 | Yes | Working | | Desktop Head Tracking | ml_dht | 1.1.1 | Yes | Working | | Desktop Reticle Switch | ml_drs | 1.0.0 | Yes | Working | | Four Point Tracking | ml_fpt | 1.0.9 | Retired | Deprecated | In-game feature since 2022r170 update -| Leap Motion Extension | ml_lme | 1.2.9 | Yes, pending review | Working | +| Leap Motion Extension | ml_lme | 1.2.9 | Yes | Working | | Server Connection Info | ml_sci | 1.0.2 | Yes | Working | From f6d3d05860c1c82129bad115106b548f3efcb39c Mon Sep 17 00:00:00 2001 From: SDraw Date: Mon, 16 Jan 2023 18:27:20 +0000 Subject: [PATCH 15/32] Notification mods into one --- README.md | 5 +- ml_egn/Main.cs | 86 +++++++++++++++++++++++++++++++ ml_egn/Properties/AssemblyInfo.cs | 10 ++++ ml_egn/README.md | 8 +++ ml_egn/Utils.cs | 46 +++++++++++++++++ ml_egn/ml_egn.csproj | 82 +++++++++++++++++++++++++++++ ml_egn/ml_egn.csproj.user | 6 +++ ml_mods_cvr.sln | 24 +++------ 8 files changed, 247 insertions(+), 20 deletions(-) create mode 100644 ml_egn/Main.cs create mode 100644 ml_egn/Properties/AssemblyInfo.cs create mode 100644 ml_egn/README.md create mode 100644 ml_egn/Utils.cs create mode 100644 ml_egn/ml_egn.csproj create mode 100644 ml_egn/ml_egn.csproj.user diff --git a/README.md b/README.md index 356baf8..546217e 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,11 @@ Merged set of MelonLoader mods for ChilloutVR. **State table for game build 2022r170:** | Full name | Short name | Latest version | Available in [CVRMA](https://github.com/knah/CVRMelonAssistant) | Current Status | Notes | |-----------|------------|----------------|-----------------------------------------------------------------|----------------|-------| -| Avatar Change Info | ml_aci | 1.0.3 | Yes | Working | +| Avatar Change Info | ml_aci | 1.0.3 | Yes | Working | Will be superseded by `Extended Game Notifications` | Avatar Motion Tweaker | ml_amt | 1.2.1 | Yes | Working | | Desktop Head Tracking | ml_dht | 1.1.1 | Yes | Working | | Desktop Reticle Switch | ml_drs | 1.0.0 | Yes | Working | +| Extended Game Notifications | ml_egn | 1.0.0 | On review | Working | Four Point Tracking | ml_fpt | 1.0.9 | Retired | Deprecated | In-game feature since 2022r170 update | Leap Motion Extension | ml_lme | 1.2.9 | Yes | Working | -| Server Connection Info | ml_sci | 1.0.2 | Yes | Working | +| Server Connection Info | ml_sci | 1.0.2 | Yes | Working | Will be superseded by `Extended Game Notifications` diff --git a/ml_egn/Main.cs b/ml_egn/Main.cs new file mode 100644 index 0000000..f250abd --- /dev/null +++ b/ml_egn/Main.cs @@ -0,0 +1,86 @@ +using ABI_RC.Core.EventSystem; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Networking; +using ABI_RC.Core.Util; +using DarkRift.Client; +using System.Reflection; + +namespace ml_egn +{ + public class ExtendedGameNotifications : MelonLoader.MelonMod + { + public override void OnInitializeMelon() + { + HarmonyInstance.Patch( + typeof(AssetManagement).GetMethod(nameof(AssetManagement.LoadLocalAvatar)), + null, + new HarmonyLib.HarmonyMethod(typeof(ExtendedGameNotifications).GetMethod(nameof(OnLocalAvatarLoad), BindingFlags.NonPublic | BindingFlags.Static)) + ); + + HarmonyInstance.Patch( + typeof(CVRSyncHelper).GetMethod(nameof(CVRSyncHelper.SpawnProp)), + null, + new HarmonyLib.HarmonyMethod(typeof(ExtendedGameNotifications).GetMethod(nameof(OnPropSpawned), BindingFlags.NonPublic | BindingFlags.Static)) + ); + + HarmonyInstance.Patch( + typeof(NetworkManager).GetMethod("OnGameNetworkConnectionClosed", BindingFlags.NonPublic | BindingFlags.Instance), + null, + new HarmonyLib.HarmonyMethod(typeof(ExtendedGameNotifications).GetMethod(nameof(OnGameNetworkConnectionClosed), BindingFlags.NonPublic | BindingFlags.Static)) + ); + } + + static void OnLocalAvatarLoad() + { + try + { + if(Utils.IsMenuOpened()) + Utils.ShowMenuNotification("Avatar changed", 1f); + else + Utils.ShowHUDNotification("(Synced) Client", "Avatar changed"); + } + catch(System.Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } + + static void OnPropSpawned() + { + try + { + if(Utils.IsConnected()) + { + if(Utils.IsMenuOpened()) + Utils.ShowMenuNotification("Prop spawned", 1f); + else + Utils.ShowHUDNotification("(Synced) Client", "Prop spawned"); + } + else + { + if(Utils.IsMenuOpened()) + ViewManager.Instance.TriggerAlert("Prop Error", "Not connected to live instance", -1, true); + else + Utils.ShowHUDNotification("(Local) Client", "Unable to spawn prop", "Not connected to live instance"); + } + } + catch(System.Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } + + static void OnGameNetworkConnectionClosed(object __0, DisconnectedEventArgs __1) + { + try + { + if((__1 != null) && (!__1.LocalDisconnect)) + Utils.ShowHUDNotification("(Local) Client", "Connection lost", (__1.Error != System.Net.Sockets.SocketError.Success) ? ("Reason: " + __1.Error.ToString()) : "", true); + } + catch(System.Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } + } +} diff --git a/ml_egn/Properties/AssemblyInfo.cs b/ml_egn/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..de777d8 --- /dev/null +++ b/ml_egn/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Reflection; + +[assembly: AssemblyTitle("ExtendedGameNotifications")] +[assembly: AssemblyVersion("1.0.0")] +[assembly: AssemblyFileVersion("1.0.0")] + +[assembly: MelonLoader.MelonInfo(typeof(ml_egn.ExtendedGameNotifications), "ExtendedGameNotifications", "1.0.0", "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_egn/README.md b/ml_egn/README.md new file mode 100644 index 0000000..7103d28 --- /dev/null +++ b/ml_egn/README.md @@ -0,0 +1,8 @@ +# Extended Game Notifications +This mod shows main menu notifications and HUD popups upon avatar changing, prop spawning and server connection loss. +Basically, merged previous `Avatar Change Info` and `Server Connection Info` mods in one. + +# Installation +* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader) +* Get [latest release DLL](../../../releases/latest): + * Put `ml_egn.dll` in `Mods` folder of game diff --git a/ml_egn/Utils.cs b/ml_egn/Utils.cs new file mode 100644 index 0000000..f4935b9 --- /dev/null +++ b/ml_egn/Utils.cs @@ -0,0 +1,46 @@ +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Networking; +using ABI_RC.Core.UI; +using DarkRift; + +namespace ml_egn +{ + static class Utils + { + public static bool IsMenuOpened() + { + return ((ViewManager.Instance != null) ? ViewManager.Instance.isGameMenuOpen() : false); + } + + public static void ShowMenuNotification(string p_message, float p_time = 1f) + { + if(ViewManager.Instance != null) + ViewManager.Instance.TriggerPushNotification(p_message, p_time); + } + + public static void ShowMenuAlert(string p_title, string p_message) + { + if(ViewManager.Instance != null) + ViewManager.Instance.TriggerAlert(p_title, p_message, -1, true); + } + + public static void ShowHUDNotification(string p_title, string p_message, string p_small = "", bool p_immediate = false) + { + if(CohtmlHud.Instance != null) + { + if(p_immediate) + CohtmlHud.Instance.ViewDropTextImmediate(p_title, p_message, p_small); + else + CohtmlHud.Instance.ViewDropText(p_title, p_message, p_small); + } + } + + public static bool IsConnected() + { + bool l_result = false; + if((NetworkManager.Instance != null) && (NetworkManager.Instance.GameNetwork != null)) + l_result = (NetworkManager.Instance.GameNetwork.ConnectionState == ConnectionState.Connected); + return l_result; + } + } +} diff --git a/ml_egn/ml_egn.csproj b/ml_egn/ml_egn.csproj new file mode 100644 index 0000000..d3728e6 --- /dev/null +++ b/ml_egn/ml_egn.csproj @@ -0,0 +1,82 @@ + + + + + Debug + AnyCPU + {1B5ACA07-6266-4C9A-BA30-D4BBE6634846} + Library + Properties + ml_egn + ml_egn + v4.7.2 + 512 + true + + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + prompt + MinimumRecommendedRules.ruleset + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + + + + False + F:\games\Steam\common\ChilloutVR\MelonLoader\0Harmony.dll + False + + + False + F:\games\Steam\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll + False + + + False + + + False + False + + + False + F:\games\Steam\common\ChilloutVR\MelonLoader\MelonLoader.dll + False + + + + + + + + + + False + False + + + + + + + + + + + + + + copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\" + + \ No newline at end of file diff --git a/ml_egn/ml_egn.csproj.user b/ml_egn/ml_egn.csproj.user new file mode 100644 index 0000000..04df561 --- /dev/null +++ b/ml_egn/ml_egn.csproj.user @@ -0,0 +1,6 @@ + + + + D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\;D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\ + + \ No newline at end of file diff --git a/ml_mods_cvr.sln b/ml_mods_cvr.sln index e7ec63f..2a6635d 100644 --- a/ml_mods_cvr.sln +++ b/ml_mods_cvr.sln @@ -3,38 +3,26 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.28307.1738 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_fpt", "ml_fpt\ml_fpt.csproj", "{EC0A8C41-A429-42CD-B8FA-401A802D4BA6}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_lme", "ml_lme\ml_lme.csproj", "{83CC74B7-F444-40E1-BD06-67CEC995A919}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_aci", "ml_aci\ml_aci.csproj", "{1B5ACA07-6266-4C9A-BA30-D4BBE6634846}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_drs", "ml_drs\ml_drs.csproj", "{06CD5155-4459-48C3-8A53-E0B91136351B}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_amt", "ml_amt\ml_amt.csproj", "{74E13D02-A506-41A2-A2CF-C8B3D5B1E452}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_sci", "ml_sci\ml_sci.csproj", "{E5481D41-196C-4241-AF26-6595EF1863C1}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_dht", "ml_dht\ml_dht.csproj", "{6DD89FC3-A974-4C39-A3EE-F60C24B17B5B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_egn", "ml_egn\ml_egn.csproj", "{1B5ACA07-6266-4C9A-BA30-D4BBE6634846}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {EC0A8C41-A429-42CD-B8FA-401A802D4BA6}.Debug|x64.ActiveCfg = Debug|x64 - {EC0A8C41-A429-42CD-B8FA-401A802D4BA6}.Debug|x64.Build.0 = Debug|x64 - {EC0A8C41-A429-42CD-B8FA-401A802D4BA6}.Release|x64.ActiveCfg = Release|x64 - {EC0A8C41-A429-42CD-B8FA-401A802D4BA6}.Release|x64.Build.0 = Release|x64 {83CC74B7-F444-40E1-BD06-67CEC995A919}.Debug|x64.ActiveCfg = Debug|x64 {83CC74B7-F444-40E1-BD06-67CEC995A919}.Debug|x64.Build.0 = Debug|x64 {83CC74B7-F444-40E1-BD06-67CEC995A919}.Release|x64.ActiveCfg = Release|x64 {83CC74B7-F444-40E1-BD06-67CEC995A919}.Release|x64.Build.0 = Release|x64 - {1B5ACA07-6266-4C9A-BA30-D4BBE6634846}.Debug|x64.ActiveCfg = Debug|x64 - {1B5ACA07-6266-4C9A-BA30-D4BBE6634846}.Debug|x64.Build.0 = Debug|x64 - {1B5ACA07-6266-4C9A-BA30-D4BBE6634846}.Release|x64.ActiveCfg = Release|x64 - {1B5ACA07-6266-4C9A-BA30-D4BBE6634846}.Release|x64.Build.0 = Release|x64 {06CD5155-4459-48C3-8A53-E0B91136351B}.Debug|x64.ActiveCfg = Debug|x64 {06CD5155-4459-48C3-8A53-E0B91136351B}.Debug|x64.Build.0 = Debug|x64 {06CD5155-4459-48C3-8A53-E0B91136351B}.Release|x64.ActiveCfg = Release|x64 @@ -43,14 +31,14 @@ Global {74E13D02-A506-41A2-A2CF-C8B3D5B1E452}.Debug|x64.Build.0 = Debug|x64 {74E13D02-A506-41A2-A2CF-C8B3D5B1E452}.Release|x64.ActiveCfg = Release|x64 {74E13D02-A506-41A2-A2CF-C8B3D5B1E452}.Release|x64.Build.0 = Release|x64 - {E5481D41-196C-4241-AF26-6595EF1863C1}.Debug|x64.ActiveCfg = Debug|x64 - {E5481D41-196C-4241-AF26-6595EF1863C1}.Debug|x64.Build.0 = Debug|x64 - {E5481D41-196C-4241-AF26-6595EF1863C1}.Release|x64.ActiveCfg = Release|x64 - {E5481D41-196C-4241-AF26-6595EF1863C1}.Release|x64.Build.0 = Release|x64 {6DD89FC3-A974-4C39-A3EE-F60C24B17B5B}.Debug|x64.ActiveCfg = Debug|x64 {6DD89FC3-A974-4C39-A3EE-F60C24B17B5B}.Debug|x64.Build.0 = Debug|x64 {6DD89FC3-A974-4C39-A3EE-F60C24B17B5B}.Release|x64.ActiveCfg = Release|x64 {6DD89FC3-A974-4C39-A3EE-F60C24B17B5B}.Release|x64.Build.0 = Release|x64 + {1B5ACA07-6266-4C9A-BA30-D4BBE6634846}.Debug|x64.ActiveCfg = Debug|x64 + {1B5ACA07-6266-4C9A-BA30-D4BBE6634846}.Debug|x64.Build.0 = Debug|x64 + {1B5ACA07-6266-4C9A-BA30-D4BBE6634846}.Release|x64.ActiveCfg = Release|x64 + {1B5ACA07-6266-4C9A-BA30-D4BBE6634846}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From e633fc64886b93982293e0cb7176bd121c2b4c2e Mon Sep 17 00:00:00 2001 From: SDraw Date: Sat, 21 Jan 2023 18:52:28 +0300 Subject: [PATCH 16/32] New mod Plant feet fix --- README.md | 1 + ml_amt/MotionTweaker.cs | 4 ++ ml_amt/Properties/AssemblyInfo.cs | 6 +- ml_mods_cvr.sln | 6 ++ ml_pam/ArmMover.cs | 59 ++++++++++++++++ ml_pam/Main.cs | 107 ++++++++++++++++++++++++++++++ ml_pam/Properties/AssemblyInfo.cs | 10 +++ ml_pam/README.md | 7 ++ ml_pam/Utils.cs | 15 +++++ ml_pam/ml_pam.csproj | 75 +++++++++++++++++++++ ml_pam/ml_pam.csproj.user | 6 ++ 11 files changed, 293 insertions(+), 3 deletions(-) create mode 100644 ml_pam/ArmMover.cs create mode 100644 ml_pam/Main.cs create mode 100644 ml_pam/Properties/AssemblyInfo.cs create mode 100644 ml_pam/README.md create mode 100644 ml_pam/Utils.cs create mode 100644 ml_pam/ml_pam.csproj create mode 100644 ml_pam/ml_pam.csproj.user diff --git a/README.md b/README.md index 546217e..5bdaa68 100644 --- a/README.md +++ b/README.md @@ -10,4 +10,5 @@ Merged set of MelonLoader mods for ChilloutVR. | Extended Game Notifications | ml_egn | 1.0.0 | On review | Working | Four Point Tracking | ml_fpt | 1.0.9 | Retired | Deprecated | In-game feature since 2022r170 update | Leap Motion Extension | ml_lme | 1.2.9 | Yes | Working | +| Pickup Arm Movement | ml_pam | 1.0.0 | On review | Working | Server Connection Info | ml_sci | 1.0.2 | Yes | Working | Will be superseded by `Extended Game Notifications` diff --git a/ml_amt/MotionTweaker.cs b/ml_amt/MotionTweaker.cs index 497694f..1e7e4c2 100644 --- a/ml_amt/MotionTweaker.cs +++ b/ml_amt/MotionTweaker.cs @@ -28,6 +28,7 @@ namespace ml_amt int m_locomotionLayer = 0; float m_ikWeight = 1f; // Original weight float m_locomotionWeight = 1f; // Original weight + bool m_plantFeet = false; // Original plant feet float m_avatarScale = 1f; // Instantiated scale Transform m_avatarHips = null; float m_viewPointHeight = 1f; @@ -258,6 +259,7 @@ namespace ml_amt m_ikWeight = m_vrIk.solver.IKPositionWeight; m_locomotionWeight = m_vrIk.solver.locomotion.weight; + m_plantFeet = m_vrIk.solver.plantFeet; if(m_detectEmotes && m_emoteActive) m_vrIk.solver.IKPositionWeight = 0f; @@ -283,6 +285,7 @@ namespace ml_amt if(l_legsOverride && l_solverActive && m_followHips && (!m_moving || (m_poseState == PoseState.Proning)) && m_isInVR && !BodySystem.isCalibratedAsFullBody) { + m_vrIk.solver.plantFeet = false; ABI_RC.Systems.IK.IKSystem.VrikRootController.enabled = false; PlayerSetup.Instance._avatar.transform.localPosition = m_hipsToPlayer; } @@ -292,6 +295,7 @@ namespace ml_amt { m_vrIk.solver.IKPositionWeight = m_ikWeight; m_vrIk.solver.locomotion.weight = m_locomotionWeight; + m_vrIk.solver.plantFeet = m_plantFeet; } public void SetIKOverrideCrouch(bool p_state) diff --git a/ml_amt/Properties/AssemblyInfo.cs b/ml_amt/Properties/AssemblyInfo.cs index 85eefe4..b79799e 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.2.1")] -[assembly: AssemblyFileVersion("1.2.1")] +[assembly: AssemblyVersion("1.2.2")] +[assembly: AssemblyFileVersion("1.2.2")] -[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.2.1", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.2.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_mods_cvr.sln b/ml_mods_cvr.sln index 2a6635d..d9193c5 100644 --- a/ml_mods_cvr.sln +++ b/ml_mods_cvr.sln @@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_dht", "ml_dht\ml_dht.csp EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_egn", "ml_egn\ml_egn.csproj", "{1B5ACA07-6266-4C9A-BA30-D4BBE6634846}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_pam", "ml_pam\ml_pam.csproj", "{3B5028DE-8C79-40DF-A1EF-BDB29D366125}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -39,6 +41,10 @@ Global {1B5ACA07-6266-4C9A-BA30-D4BBE6634846}.Debug|x64.Build.0 = Debug|x64 {1B5ACA07-6266-4C9A-BA30-D4BBE6634846}.Release|x64.ActiveCfg = Release|x64 {1B5ACA07-6266-4C9A-BA30-D4BBE6634846}.Release|x64.Build.0 = Release|x64 + {3B5028DE-8C79-40DF-A1EF-BDB29D366125}.Debug|x64.ActiveCfg = Debug|x64 + {3B5028DE-8C79-40DF-A1EF-BDB29D366125}.Debug|x64.Build.0 = Debug|x64 + {3B5028DE-8C79-40DF-A1EF-BDB29D366125}.Release|x64.ActiveCfg = Release|x64 + {3B5028DE-8C79-40DF-A1EF-BDB29D366125}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ml_pam/ArmMover.cs b/ml_pam/ArmMover.cs new file mode 100644 index 0000000..4ce512f --- /dev/null +++ b/ml_pam/ArmMover.cs @@ -0,0 +1,59 @@ +using ABI.CCK.Components; +using ABI_RC.Core.Player; +using UnityEngine; + +namespace ml_pam +{ + class ArmMover : MonoBehaviour + { + static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f); + static readonly Quaternion ms_rotationOffset = Quaternion.Euler(0f, 0f, -90f); + + Animator m_animator = null; + CVRPickupObject m_target = null; + Matrix4x4 m_offset = Matrix4x4.identity; + + void Start() + { + m_animator = PlayerSetup.Instance._animator; + } + + void OnAnimatorIK(int p_layerIndex) + { + if((p_layerIndex == 0) && (m_target != null)) // Only main Locomotion/Emotes layer + { + Transform l_camera = PlayerSetup.Instance.GetActiveCamera().transform; + + m_animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 1f); + m_animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 1f); + + switch(m_target.gripType) + { + case CVRPickupObject.GripType.Origin: + { + if(m_target.gripOrigin != null) + { + m_animator.SetIKPosition(AvatarIKGoal.RightHand, m_target.gripOrigin.position); + m_animator.SetIKRotation(AvatarIKGoal.RightHand, l_camera.rotation * ms_rotationOffset); + } + } + break; + + case CVRPickupObject.GripType.Free: + { + Matrix4x4 l_result = m_target.transform.GetMatrix() * m_offset; + m_animator.SetIKPosition(AvatarIKGoal.RightHand, l_result * ms_pointVector); + m_animator.SetIKRotation(AvatarIKGoal.RightHand, l_camera.rotation * ms_rotationOffset); + } + break; + } + } + } + + public void SetTarget(CVRPickupObject p_target, Vector3 p_hit) + { + m_target = p_target; + m_offset = (m_target != null) ? (p_target.transform.GetMatrix().inverse * Matrix4x4.Translate(p_hit)): Matrix4x4.identity; + } + } +} diff --git a/ml_pam/Main.cs b/ml_pam/Main.cs new file mode 100644 index 0000000..3f808c9 --- /dev/null +++ b/ml_pam/Main.cs @@ -0,0 +1,107 @@ +using ABI.CCK.Components; +using ABI_RC.Core.Player; +using System; +using System.Reflection; +using UnityEngine; + +namespace ml_pam +{ + public class PickupArmMovement : MelonLoader.MelonMod + { + static PickupArmMovement ms_instance = null; + + ArmMover m_localPuller = null; + + public override void OnInitializeMelon() + { + if(ms_instance == null) + ms_instance = this; + + HarmonyInstance.Patch( + typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)), + null, + new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.NonPublic | BindingFlags.Static)) + ); + HarmonyInstance.Patch( + typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)), + null, + new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + ); + HarmonyInstance.Patch( + typeof(CVRPickupObject).GetMethod(nameof(CVRPickupObject.Grab)), + null, + new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnCVRPickupObjectGrab_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + ); + HarmonyInstance.Patch( + typeof(CVRPickupObject).GetMethod(nameof(CVRPickupObject.Drop)), + null, + new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnCVRPickupObjectDrop_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + ); + } + + public override void OnDeinitializeMelon() + { + if(ms_instance == this) + ms_instance = null; + } + + static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear(); + void OnAvatarClear() + { + try + { + m_localPuller = null; + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } + + static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar(); + void OnSetupAvatar() + { + try + { + if(!Utils.IsInVR()) + m_localPuller = PlayerSetup.Instance._avatar.AddComponent(); + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } + + static void OnCVRPickupObjectGrab_Postfix(ref CVRPickupObject __instance, Vector3 __2) => ms_instance?.OnCVRPickupObjectGrab(__instance, __2); + void OnCVRPickupObjectGrab(CVRPickupObject p_pickup, Vector3 p_hit) + { + try + { + if(p_pickup.IsGrabbedByMe() && (m_localPuller != null)) + { + m_localPuller.SetTarget(p_pickup, p_hit); + } + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } + + static void OnCVRPickupObjectDrop_Postfix() => ms_instance?.OnCVRPickupObjectDrop(); + void OnCVRPickupObjectDrop() + { + try + { + if(m_localPuller != null) + { + m_localPuller.SetTarget(null, Vector3.zero); + } + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } + } +} diff --git a/ml_pam/Properties/AssemblyInfo.cs b/ml_pam/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..a0e0b87 --- /dev/null +++ b/ml_pam/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Reflection; + +[assembly: AssemblyTitle("PickupArmMovement")] +[assembly: AssemblyVersion("1.0.0")] +[assembly: AssemblyFileVersion("1.0.0")] + +[assembly: MelonLoader.MelonInfo(typeof(ml_pam.PickupArmMovement), "PickupArmMovement", "1.0.0", "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_pam/README.md b/ml_pam/README.md new file mode 100644 index 0000000..dceb34e --- /dev/null +++ b/ml_pam/README.md @@ -0,0 +1,7 @@ +# Pickup Arm Movement +This mod adds arm tracking upon holding pickup. + +# Installation +* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader) +* Get [latest release DLL](../../../releases/latest): + * Put `ml_pam.dll` in `Mods` folder of game diff --git a/ml_pam/Utils.cs b/ml_pam/Utils.cs new file mode 100644 index 0000000..b11b808 --- /dev/null +++ b/ml_pam/Utils.cs @@ -0,0 +1,15 @@ +using UnityEngine; + +namespace ml_pam +{ + static class Utils + { + public static bool IsInVR() => ((ABI_RC.Core.Savior.CheckVR.Instance != null) && ABI_RC.Core.Savior.CheckVR.Instance.hasVrDeviceLoaded); + + // Extensions + public static Matrix4x4 GetMatrix(this Transform p_transform, bool p_pos = true, bool p_rot = true, bool p_scl = false) + { + return Matrix4x4.TRS(p_pos ? p_transform.position : Vector3.zero, p_rot ? p_transform.rotation : Quaternion.identity, p_scl ? p_transform.localScale : Vector3.one); + } + } +} diff --git a/ml_pam/ml_pam.csproj b/ml_pam/ml_pam.csproj new file mode 100644 index 0000000..23e1b5b --- /dev/null +++ b/ml_pam/ml_pam.csproj @@ -0,0 +1,75 @@ + + + + + Debug + AnyCPU + {3B5028DE-8C79-40DF-A1EF-BDB29D366125} + Library + Properties + ml_pam + ml_pam + v4.7.2 + 512 + true + + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + prompt + MinimumRecommendedRules.ruleset + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + + + + False + D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\0Harmony.dll + False + + + False + D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll + False + + + False + D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\MelonLoader.dll + False + + + + + + + + + + False + + + False + False + + + + + + + + + + + copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\" + + \ No newline at end of file diff --git a/ml_pam/ml_pam.csproj.user b/ml_pam/ml_pam.csproj.user new file mode 100644 index 0000000..04df561 --- /dev/null +++ b/ml_pam/ml_pam.csproj.user @@ -0,0 +1,6 @@ + + + + D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\;D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\ + + \ No newline at end of file From 5c7442d60c088fadb79df6765731a3f43a3b0ba9 Mon Sep 17 00:00:00 2001 From: SDraw Date: Sat, 21 Jan 2023 20:11:09 +0300 Subject: [PATCH 17/32] Main layer search --- ml_pam/ArmMover.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ml_pam/ArmMover.cs b/ml_pam/ArmMover.cs index 4ce512f..3e1e584 100644 --- a/ml_pam/ArmMover.cs +++ b/ml_pam/ArmMover.cs @@ -10,17 +10,20 @@ namespace ml_pam static readonly Quaternion ms_rotationOffset = Quaternion.Euler(0f, 0f, -90f); Animator m_animator = null; + + int m_mainLayer = -1; CVRPickupObject m_target = null; Matrix4x4 m_offset = Matrix4x4.identity; void Start() { m_animator = PlayerSetup.Instance._animator; + m_mainLayer = m_animator.GetLayerIndex("Locomotion/Emotes"); } void OnAnimatorIK(int p_layerIndex) { - if((p_layerIndex == 0) && (m_target != null)) // Only main Locomotion/Emotes layer + if((p_layerIndex == m_mainLayer) && (m_target != null)) // Only main Locomotion/Emotes layer { Transform l_camera = PlayerSetup.Instance.GetActiveCamera().transform; From d452afda29271b183209101e7d851dc75a67744d Mon Sep 17 00:00:00 2001 From: SDraw Date: Sun, 22 Jan 2023 14:07:06 +0000 Subject: [PATCH 18/32] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 5bdaa68..aff14e1 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,12 @@ Merged set of MelonLoader mods for ChilloutVR. **State table for game build 2022r170:** | Full name | Short name | Latest version | Available in [CVRMA](https://github.com/knah/CVRMelonAssistant) | Current Status | Notes | |-----------|------------|----------------|-----------------------------------------------------------------|----------------|-------| -| Avatar Change Info | ml_aci | 1.0.3 | Yes | Working | Will be superseded by `Extended Game Notifications` -| Avatar Motion Tweaker | ml_amt | 1.2.1 | Yes | Working | +| Avatar Change Info | ml_aci | 1.0.3 | Yes, retired | Retired | Superseded by `Extended Game Notifications` +| Avatar Motion Tweaker | ml_amt | 1.2.2 | Yes | Working | | Desktop Head Tracking | ml_dht | 1.1.1 | Yes | Working | | Desktop Reticle Switch | ml_drs | 1.0.0 | Yes | Working | -| Extended Game Notifications | ml_egn | 1.0.0 | On review | Working +| Extended Game Notifications | ml_egn | 1.0.0 | Yes | Working | Four Point Tracking | ml_fpt | 1.0.9 | Retired | Deprecated | In-game feature since 2022r170 update | Leap Motion Extension | ml_lme | 1.2.9 | Yes | Working | -| Pickup Arm Movement | ml_pam | 1.0.0 | On review | Working -| Server Connection Info | ml_sci | 1.0.2 | Yes | Working | Will be superseded by `Extended Game Notifications` +| Pickup Arm Movement | ml_pam | 1.0.0 | Yes | Working | +| Server Connection Info | ml_sci | 1.0.2 | Yes, retired | Retired | Superseded by `Extended Game Notifications` From 9afa795626f771ce6ae52a0c2e55d6c866c2c79d Mon Sep 17 00:00:00 2001 From: SDraw Date: Mon, 23 Jan 2023 19:30:32 +0000 Subject: [PATCH 19/32] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index aff14e1..de9850d 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Merged set of MelonLoader mods for ChilloutVR. **State table for game build 2022r170:** | Full name | Short name | Latest version | Available in [CVRMA](https://github.com/knah/CVRMelonAssistant) | Current Status | Notes | |-----------|------------|----------------|-----------------------------------------------------------------|----------------|-------| -| Avatar Change Info | ml_aci | 1.0.3 | Yes, retired | Retired | Superseded by `Extended Game Notifications` +| Avatar Change Info | ml_aci | 1.0.3 | Retired | Retired | Superseded by `Extended Game Notifications` | Avatar Motion Tweaker | ml_amt | 1.2.2 | Yes | Working | | Desktop Head Tracking | ml_dht | 1.1.1 | Yes | Working | | Desktop Reticle Switch | ml_drs | 1.0.0 | Yes | Working | @@ -11,4 +11,4 @@ Merged set of MelonLoader mods for ChilloutVR. | Four Point Tracking | ml_fpt | 1.0.9 | Retired | Deprecated | In-game feature since 2022r170 update | Leap Motion Extension | ml_lme | 1.2.9 | Yes | Working | | Pickup Arm Movement | ml_pam | 1.0.0 | Yes | Working | -| Server Connection Info | ml_sci | 1.0.2 | Yes, retired | Retired | Superseded by `Extended Game Notifications` +| Server Connection Info | ml_sci | 1.0.2 | Retired | Retired | Superseded by `Extended Game Notifications` From 8737f61bdc1c91dc09bd43bc6862741c9b957806 Mon Sep 17 00:00:00 2001 From: SDraw Date: Sat, 28 Jan 2023 16:33:54 +0300 Subject: [PATCH 20/32] Input implementation Internal keyword usage (wow!) --- README.md | 2 +- ml_amt/Main.cs | 3 +- ml_amt/MotionTweaker.cs | 8 +- ml_amt/Settings.cs | 30 +-- ml_dht/HeadTracked.cs | 8 +- ml_dht/Settings.cs | 57 ++--- ml_dht/ml_dht.csproj | 2 +- ml_dht/ml_dht.csproj.user | 2 +- ml_egn/Main.cs | 4 +- ml_lme/GestureMatcher.cs | 139 +++++------- ml_lme/LeapInput.cs | 247 ++++++++++++++++++++++ ml_lme/LeapManager.cs | 204 ++++++++++++++++++ ml_lme/LeapTracked.cs | 261 +++++++++-------------- ml_lme/LeapTracking.cs | 221 ++++++++++++++++++++ ml_lme/Main.cs | 336 +++--------------------------- ml_lme/Properties/AssemblyInfo.cs | 6 +- ml_lme/README.md | 5 +- ml_lme/Settings.cs | 84 ++++++-- ml_lme/Utils.cs | 16 +- ml_lme/ml_lme.csproj | 3 + ml_lme/resources/menu.js | 21 ++ ml_pam/ArmMover.cs | 1 + 22 files changed, 1037 insertions(+), 623 deletions(-) create mode 100644 ml_lme/LeapInput.cs create mode 100644 ml_lme/LeapManager.cs create mode 100644 ml_lme/LeapTracking.cs diff --git a/README.md b/README.md index de9850d..2d62003 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,6 @@ Merged set of MelonLoader mods for ChilloutVR. | Desktop Reticle Switch | ml_drs | 1.0.0 | Yes | Working | | Extended Game Notifications | ml_egn | 1.0.0 | Yes | Working | Four Point Tracking | ml_fpt | 1.0.9 | Retired | Deprecated | In-game feature since 2022r170 update -| Leap Motion Extension | ml_lme | 1.2.9 | Yes | Working | +| Leap Motion Extension | ml_lme | 1.3.0 | Yes, update review | Working | | Pickup Arm Movement | ml_pam | 1.0.0 | Yes | Working | | Server Connection Info | ml_sci | 1.0.2 | Retired | Retired | Superseded by `Extended Game Notifications` diff --git a/ml_amt/Main.cs b/ml_amt/Main.cs index 4444846..450a028 100644 --- a/ml_amt/Main.cs +++ b/ml_amt/Main.cs @@ -4,6 +4,7 @@ using ABI_RC.Systems.IK.SubSystems; using ABI_RC.Systems.MovementSystem; using System.Reflection; using UnityEngine; +using System.Collections; namespace ml_amt { @@ -71,7 +72,7 @@ namespace ml_amt MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); } - System.Collections.IEnumerator WaitForLocalPlayer() + IEnumerator WaitForLocalPlayer() { while(PlayerSetup.Instance == null) yield return null; diff --git a/ml_amt/MotionTweaker.cs b/ml_amt/MotionTweaker.cs index 1e7e4c2..c9077cd 100644 --- a/ml_amt/MotionTweaker.cs +++ b/ml_amt/MotionTweaker.cs @@ -66,7 +66,7 @@ namespace ml_amt readonly List m_parameters = null; - public MotionTweaker() + internal MotionTweaker() { m_parameters = new List(); } @@ -159,7 +159,7 @@ namespace ml_amt } } - public void OnAvatarClear() + internal void OnAvatarClear() { m_vrIk = null; m_locomotionLayer = -1; @@ -181,7 +181,7 @@ namespace ml_amt m_parameters.Clear(); } - public void OnSetupAvatar() + internal void OnSetupAvatar() { m_isInVR = Utils.IsInVR(); m_vrIk = PlayerSetup.Instance._avatar.GetComponent(); @@ -239,7 +239,7 @@ namespace ml_amt m_avatarReady = true; } - public void OnCalibrate() + internal void OnCalibrate() { if(m_avatarReady && BodySystem.isCalibratedAsFullBody && BodySystem.enableHipTracking && !BodySystem.enableRightFootTracking && !BodySystem.enableLeftFootTracking && !BodySystem.enableLeftKneeTracking && !BodySystem.enableRightKneeTracking) { diff --git a/ml_amt/Settings.cs b/ml_amt/Settings.cs index 7eb0ea2..ed548c0 100644 --- a/ml_amt/Settings.cs +++ b/ml_amt/Settings.cs @@ -49,22 +49,24 @@ namespace ml_amt static public event Action FollowHipsChange; static public event Action CollisionScaleChange; - public static void Init() + internal static void Init() { ms_category = MelonLoader.MelonPreferences.CreateCategory("AMT"); - ms_entries = new List(); - ms_entries.Add(ms_category.CreateEntry(ModSetting.IKOverrideCrouch.ToString(), true)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.CrouchLimit.ToString(), 65)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.IKOverrideProne.ToString(), true)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.ProneLimit.ToString(), 30)); - 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.IKOverrideJump.ToString(), true)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.DetectEmotes.ToString(), true)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.FollowHips.ToString(), true)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.CollisionScale.ToString(), true)); + ms_entries = new List() + { + ms_category.CreateEntry(ModSetting.IKOverrideCrouch.ToString(), true), + ms_category.CreateEntry(ModSetting.CrouchLimit.ToString(), 65), + ms_category.CreateEntry(ModSetting.IKOverrideProne.ToString(), true), + ms_category.CreateEntry(ModSetting.ProneLimit.ToString(), 30), + ms_category.CreateEntry(ModSetting.PoseTransitions.ToString(), true), + ms_category.CreateEntry(ModSetting.AdjustedMovement.ToString(), true), + ms_category.CreateEntry(ModSetting.IKOverrideFly.ToString(), true), + ms_category.CreateEntry(ModSetting.IKOverrideJump.ToString(), true), + ms_category.CreateEntry(ModSetting.DetectEmotes.ToString(), true), + ms_category.CreateEntry(ModSetting.FollowHips.ToString(), true), + ms_category.CreateEntry(ModSetting.CollisionScale.ToString(), true) + }; Load(); @@ -194,7 +196,7 @@ namespace ml_amt FollowHipsChange?.Invoke(ms_followHips); } break; - + case ModSetting.CollisionScale: { ms_collisionScale = bool.Parse(p_value); diff --git a/ml_dht/HeadTracked.cs b/ml_dht/HeadTracked.cs index df87e18..7282ed3 100644 --- a/ml_dht/HeadTracked.cs +++ b/ml_dht/HeadTracked.cs @@ -77,7 +77,7 @@ namespace ml_dht } } - public void OnEyeControllerUpdate(CVREyeController p_component) + internal void OnEyeControllerUpdate(CVREyeController p_component) { if(m_enabled) { @@ -99,7 +99,7 @@ namespace ml_dht } } - public void OnFaceTrackingUpdate(CVRFaceTracking p_component) + internal void OnFaceTrackingUpdate(CVRFaceTracking p_component) { if(m_enabled && m_faceOverride) { @@ -117,7 +117,7 @@ namespace ml_dht } } - public void OnSetupAvatar() + internal void OnSetupAvatar() { m_avatarDescriptor = PlayerSetup.Instance._avatar.GetComponent(); m_headBone = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Head); @@ -130,7 +130,7 @@ namespace ml_dht m_lookIK.solver.OnPostUpdate += this.OnLookIKPostUpdate; } - public void OnAvatarClear() + internal void OnAvatarClear() { m_avatarDescriptor = null; m_lookIK = null; diff --git a/ml_dht/Settings.cs b/ml_dht/Settings.cs index bb33b28..12057f2 100644 --- a/ml_dht/Settings.cs +++ b/ml_dht/Settings.cs @@ -17,7 +17,7 @@ namespace ml_dht Smoothing, FaceOverride } - + static bool ms_enabled = false; static bool ms_headTracking = true; static bool ms_eyeTracking = true; @@ -25,10 +25,10 @@ namespace ml_dht static bool ms_mirrored = false; static float ms_smoothing = 0.5f; static bool ms_faceOverride = true; - + static MelonLoader.MelonPreferences_Category ms_category = null; static List ms_entries = null; - + static public event Action EnabledChange; static public event Action HeadTrackingChange; static public event Action EyeTrackingChange; @@ -36,25 +36,27 @@ namespace ml_dht static public event Action MirroredChange; static public event Action SmoothingChange; static public event Action FaceOverrideChange; - - public static void Init() + + internal static void Init() { ms_category = MelonLoader.MelonPreferences.CreateCategory("DHT"); - - ms_entries = new List(); - ms_entries.Add(ms_category.CreateEntry(ModSetting.Enabled.ToString(), false)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.HeadTracking.ToString(), false)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.EyeTracking.ToString(), true)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.Blinking.ToString(), true)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.Mirrored.ToString(), false)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.Smoothing.ToString(), 50)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.FaceOverride.ToString(), true)); - + + ms_entries = new List() + { + ms_category.CreateEntry(ModSetting.Enabled.ToString(), false), + ms_category.CreateEntry(ModSetting.HeadTracking.ToString(), false), + ms_category.CreateEntry(ModSetting.EyeTracking.ToString(), true), + ms_category.CreateEntry(ModSetting.Blinking.ToString(), true), + ms_category.CreateEntry(ModSetting.Mirrored.ToString(), false), + ms_category.CreateEntry(ModSetting.Smoothing.ToString(), 50), + ms_category.CreateEntry(ModSetting.FaceOverride.ToString(), true) + }; + Load(); MelonLoader.MelonCoroutines.Start(WaitMainMenuUi()); } - + static System.Collections.IEnumerator WaitMainMenuUi() { while(ViewManager.Instance == null) @@ -76,18 +78,18 @@ namespace ml_dht ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSettingDHT", l_entry.DisplayName, l_entry.GetValueAsString()); }; } - + static void Load() { ms_enabled = (bool)ms_entries[(int)ModSetting.Enabled].BoxedValue; - ms_headTracking = (bool)ms_entries[(int)ModSetting.HeadTracking].BoxedValue; - ms_eyeTracking = (bool)ms_entries[(int)ModSetting.EyeTracking].BoxedValue; - ms_blinking = (bool)ms_entries[(int)ModSetting.Blinking].BoxedValue; + ms_headTracking = (bool)ms_entries[(int)ModSetting.HeadTracking].BoxedValue; + ms_eyeTracking = (bool)ms_entries[(int)ModSetting.EyeTracking].BoxedValue; + ms_blinking = (bool)ms_entries[(int)ModSetting.Blinking].BoxedValue; ms_mirrored = (bool)ms_entries[(int)ModSetting.Mirrored].BoxedValue; ms_smoothing = ((int)ms_entries[(int)ModSetting.Smoothing].BoxedValue) * 0.01f; ms_faceOverride = (bool)ms_entries[(int)ModSetting.FaceOverride].BoxedValue; } - + static void OnSliderUpdate(string p_name, string p_value) { if(Enum.TryParse(p_name, out ModSetting l_setting)) @@ -105,7 +107,7 @@ namespace ml_dht ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); } } - + static void OnToggleUpdate(string p_name, string p_value) { if(Enum.TryParse(p_name, out ModSetting l_setting)) @@ -130,13 +132,15 @@ namespace ml_dht { ms_eyeTracking = bool.Parse(p_value); EyeTrackingChange?.Invoke(ms_eyeTracking); - } break; + } + break; case ModSetting.Blinking: { ms_blinking = bool.Parse(p_value); BlinkingChange?.Invoke(ms_blinking); - } break; + } + break; case ModSetting.Mirrored: { @@ -149,13 +153,14 @@ namespace ml_dht { ms_faceOverride = bool.Parse(p_value); FaceOverrideChange?.Invoke(ms_faceOverride); - } break; + } + break; } ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); } } - + public static bool Enabled { get => ms_enabled; diff --git a/ml_dht/ml_dht.csproj b/ml_dht/ml_dht.csproj index 76ca014..5093a18 100644 --- a/ml_dht/ml_dht.csproj +++ b/ml_dht/ml_dht.csproj @@ -88,6 +88,6 @@ - copy /y "$(TargetPath)" "C:\Games\Steam\common\ChilloutVR\Mods\" + copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\" \ No newline at end of file diff --git a/ml_dht/ml_dht.csproj.user b/ml_dht/ml_dht.csproj.user index 2539084..04df561 100644 --- a/ml_dht/ml_dht.csproj.user +++ b/ml_dht/ml_dht.csproj.user @@ -1,6 +1,6 @@  - C:\Games\Steam\common\ChilloutVR\MelonLoader\;C:\Games\Steam\common\ChilloutVR\ChilloutVR_Data\Managed\ + D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\;D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\ \ No newline at end of file diff --git a/ml_egn/Main.cs b/ml_egn/Main.cs index f250abd..7b90b53 100644 --- a/ml_egn/Main.cs +++ b/ml_egn/Main.cs @@ -59,7 +59,7 @@ namespace ml_egn else { if(Utils.IsMenuOpened()) - ViewManager.Instance.TriggerAlert("Prop Error", "Not connected to live instance", -1, true); + Utils.ShowMenuAlert("Prop Error", "Not connected to live instance"); else Utils.ShowHUDNotification("(Local) Client", "Unable to spawn prop", "Not connected to live instance"); } @@ -70,7 +70,7 @@ namespace ml_egn } } - static void OnGameNetworkConnectionClosed(object __0, DisconnectedEventArgs __1) + static void OnGameNetworkConnectionClosed(DisconnectedEventArgs __1) { try { diff --git a/ml_lme/GestureMatcher.cs b/ml_lme/GestureMatcher.cs index dbaa640..550af8f 100644 --- a/ml_lme/GestureMatcher.cs +++ b/ml_lme/GestureMatcher.cs @@ -14,100 +14,75 @@ namespace ml_lme new Vector2(-10f, 25f) }; - public class GesturesData + public class HandData { - readonly public static int ms_handsCount = 2; - readonly public static int ms_fingersCount = 5; + public bool m_present = false; + public Vector3 m_position = Vector3.zero; + public Quaternion m_rotation = Quaternion.identity; + public Vector3 m_elbowPosition = Vector3.zero; + public readonly float[] m_spreads = null; + public readonly float[] m_bends = null; + public float m_grabStrength = 0f; - public bool[] m_handsPresenses = null; - public Vector3[] m_handsPositons = null; - public Quaternion[] m_handsRotations = null; - public Vector3[] m_elbowsPositions = null; - public float[] m_leftFingersBends = null; - public float[] m_leftFingersSpreads = null; - public float[] m_rightFingersBends = null; - public float[] m_rightFingersSpreads = null; - - public GesturesData() + public HandData() { - m_handsPresenses = new bool[ms_handsCount]; - m_handsPositons = new Vector3[ms_handsCount]; - m_handsRotations = new Quaternion[ms_handsCount]; - m_elbowsPositions = new Vector3[ms_handsCount]; - m_leftFingersBends = new float[ms_fingersCount]; - m_leftFingersSpreads = new float[ms_fingersCount]; - m_rightFingersBends = new float[ms_fingersCount]; - m_rightFingersSpreads = new float[ms_fingersCount]; + m_spreads = new float[5]; + m_bends = new float[5]; + } + + public void Reset() + { + m_present = false; + for(int i = 0; i < 5; i++) + { + m_bends[i] = 0f; + m_spreads[i] = 0f; + } + m_grabStrength = 0f; } } - public static void GetGestures(Leap.Frame p_frame, ref GesturesData p_data) + public class LeapData { - // Fill as default - for(int i = 0; i < GesturesData.ms_handsCount; i++) - p_data.m_handsPresenses[i] = false; - for(int i = 0; i < GesturesData.ms_fingersCount; i++) + public readonly HandData m_leftHand = null; + public readonly HandData m_rightHand = null; + + public LeapData() { - p_data.m_leftFingersBends[i] = 0f; - p_data.m_leftFingersSpreads[i] = 0f; - p_data.m_rightFingersBends[i] = 0f; - p_data.m_leftFingersSpreads[i] = 0f; + m_leftHand = new HandData(); + m_rightHand = new HandData(); } + public void Reset() + { + m_leftHand.Reset(); + m_rightHand.Reset(); + } + } + + public static void GetFrameData(Leap.Frame p_frame, LeapData p_data) + { + p_data.Reset(); + // Fill hands data foreach(Leap.Hand l_hand in p_frame.Hands) { - int l_sideID = (l_hand.IsLeft ? 0 : 1); - if(!p_data.m_handsPresenses[l_sideID]) - { - p_data.m_handsPresenses[l_sideID] = true; - FillHandPosition(l_hand, ref p_data.m_handsPositons[l_sideID]); - FillHandRotation(l_hand, ref p_data.m_handsRotations[l_sideID]); - FillElbowPosition(l_hand, ref p_data.m_elbowsPositions[l_sideID]); - switch(l_sideID) - { - case 0: - { - FillFingerBends(l_hand, ref p_data.m_leftFingersBends); - FilFingerSpreads(l_hand, ref p_data.m_leftFingersSpreads); - } - break; - case 1: - { - FillFingerBends(l_hand, ref p_data.m_rightFingersBends); - FilFingerSpreads(l_hand, ref p_data.m_rightFingersSpreads); - } - break; - } - } + if(l_hand.IsLeft && !p_data.m_leftHand.m_present) + FillHandData(l_hand, p_data.m_leftHand); + if(l_hand.IsRight && !p_data.m_rightHand.m_present) + FillHandData(l_hand, p_data.m_rightHand); } } - static void FillHandPosition(Leap.Hand p_hand, ref Vector3 p_pos) + static void FillHandData(Leap.Hand p_hand, HandData p_data) { // Unity's IK and FinalIK move hand bones to target, therefore - wrist - p_pos.x = p_hand.WristPosition.x; - p_pos.y = p_hand.WristPosition.y; - p_pos.z = p_hand.WristPosition.z; - } + p_data.m_present = true; + p_data.m_position.Set(p_hand.WristPosition.x, p_hand.WristPosition.y, p_hand.WristPosition.z); + p_data.m_rotation.Set(p_hand.Rotation.x, p_hand.Rotation.y, p_hand.Rotation.z, p_hand.Rotation.w); + p_data.m_elbowPosition.Set(p_hand.Arm.ElbowPosition.x, p_hand.Arm.ElbowPosition.y, p_hand.Arm.ElbowPosition.z); - static void FillHandRotation(Leap.Hand p_hand, ref Quaternion p_rot) - { - p_rot.x = p_hand.Rotation.x; - p_rot.y = p_hand.Rotation.y; - p_rot.z = p_hand.Rotation.z; - p_rot.w = p_hand.Rotation.w; - } - - static void FillElbowPosition(Leap.Hand p_hand, ref Vector3 p_pos) - { - p_pos.x = p_hand.Arm.ElbowPosition.x; - p_pos.y = p_hand.Arm.ElbowPosition.y; - p_pos.z = p_hand.Arm.ElbowPosition.z; - } - - static void FillFingerBends(Leap.Hand p_hand, ref float[] p_bends) - { + // Bends foreach(Leap.Finger l_finger in p_hand.Fingers) { Quaternion l_prevSegment = Quaternion.identity; @@ -132,12 +107,10 @@ namespace ml_lme l_angle += l_curAngle; } - p_bends[(int)l_finger.Type] = Mathf.InverseLerp(0f, (l_finger.Type == Leap.Finger.FingerType.TYPE_THUMB) ? 90f : 180f, l_angle); + p_data.m_bends[(int)l_finger.Type] = Mathf.InverseLerp(0f, (l_finger.Type == Leap.Finger.FingerType.TYPE_THUMB) ? 90f : 180f, l_angle); } - } - static void FilFingerSpreads(Leap.Hand p_hand, ref float[] p_spreads) - { + // Spreads foreach(Leap.Finger l_finger in p_hand.Fingers) { float l_angle = 0f; @@ -162,13 +135,15 @@ namespace ml_lme if(l_finger.Type != Leap.Finger.FingerType.TYPE_THUMB) { if(l_angle < 0f) - p_spreads[(int)l_finger.Type] = 0.5f * Mathf.InverseLerp(ms_fingerLimits[(int)l_finger.Type].x, 0f, l_angle); + p_data.m_spreads[(int)l_finger.Type] = 0.5f * Mathf.InverseLerp(ms_fingerLimits[(int)l_finger.Type].x, 0f, l_angle); else - p_spreads[(int)l_finger.Type] = 0.5f + 0.5f * Mathf.InverseLerp(0f, ms_fingerLimits[(int)l_finger.Type].y, l_angle); + p_data.m_spreads[(int)l_finger.Type] = 0.5f + 0.5f * Mathf.InverseLerp(0f, ms_fingerLimits[(int)l_finger.Type].y, l_angle); } else - p_spreads[(int)l_finger.Type] = Mathf.InverseLerp(ms_fingerLimits[(int)l_finger.Type].x, ms_fingerLimits[(int)l_finger.Type].y, l_angle); + p_data.m_spreads[(int)l_finger.Type] = Mathf.InverseLerp(ms_fingerLimits[(int)l_finger.Type].x, ms_fingerLimits[(int)l_finger.Type].y, l_angle); } + + p_data.m_grabStrength = (p_data.m_bends[1] + p_data.m_bends[2] + p_data.m_bends[3] + p_data.m_bends[4]) * 0.25f; } } } diff --git a/ml_lme/LeapInput.cs b/ml_lme/LeapInput.cs new file mode 100644 index 0000000..b71875e --- /dev/null +++ b/ml_lme/LeapInput.cs @@ -0,0 +1,247 @@ +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using ABI_RC.Systems.IK; +using System.Collections; +using System.Reflection; +using UnityEngine; + +namespace ml_lme +{ + [DisallowMultipleComponent] + class LeapInput : CVRInputModule + { + static readonly FieldInfo ms_indexGestureToggle = typeof(InputModuleSteamVR).GetField("_steamVrIndexGestureToggleValue", BindingFlags.Instance | BindingFlags.NonPublic); + + CVRInputManager m_inputManager = null; + InputModuleSteamVR m_steamVrModule = null; + bool m_inVR = false; + + ControllerRay m_handRayLeft = null; + ControllerRay m_handRayRight = null; + LineRenderer m_lineLeft = null; + LineRenderer m_lineRight = null; + bool m_interactLeft = false; + bool m_interactRight = false; + bool m_gripLeft = false; + bool m_gripRight = false; + + public new void Start() + { + base.Start(); + + m_inputManager = CVRInputManager.Instance; // _inputManager is stripped out, cool beans + m_steamVrModule = this.GetComponent(); + m_inVR = Utils.IsInVR(); + + m_handRayLeft = LeapTracking.GetInstance().GetLeftHand().gameObject.AddComponent(); + m_handRayLeft.hand = true; + m_handRayLeft.generalMask = -1485; + m_handRayLeft.isInteractionRay = true; + m_handRayLeft.triggerGazeEvents = false; + m_handRayLeft.holderRoot = m_handRayLeft.gameObject; + + m_handRayRight = LeapTracking.GetInstance().GetRightHand().gameObject.AddComponent(); + m_handRayRight.hand = false; + m_handRayRight.generalMask = -1485; + m_handRayRight.isInteractionRay = true; + m_handRayRight.triggerGazeEvents = false; + m_handRayRight.holderRoot = m_handRayRight.gameObject; + + m_lineLeft = m_handRayLeft.gameObject.AddComponent(); + m_lineLeft.endWidth = 1f; + m_lineLeft.startWidth = 1f; + m_lineLeft.textureMode = LineTextureMode.Tile; + m_lineLeft.useWorldSpace = false; + m_lineLeft.widthMultiplier = 1f; + m_lineLeft.allowOcclusionWhenDynamic = false; + m_lineLeft.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; + m_lineLeft.enabled = false; + m_lineLeft.receiveShadows = false; + m_handRayLeft.lineRenderer = m_lineLeft; + + m_lineRight = m_handRayRight.gameObject.AddComponent(); + m_lineRight.endWidth = 1f; + m_lineRight.startWidth = 1f; + m_lineRight.textureMode = LineTextureMode.Tile; + m_lineRight.useWorldSpace = false; + m_lineRight.widthMultiplier = 1f; + m_lineRight.allowOcclusionWhenDynamic = false; + m_lineRight.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; + m_lineRight.enabled = false; + m_lineRight.receiveShadows = false; + m_handRayRight.lineRenderer = m_lineRight; + + Settings.EnabledChange += this.OnEnableChange; + Settings.InputChange += this.OnInputChange; + + OnEnableChange(Settings.Enabled); + OnInputChange(Settings.Input); + + MelonLoader.MelonCoroutines.Start(WaitForMaterial()); + } + + IEnumerator WaitForMaterial() + { + while(PlayerSetup.Instance == null) + yield return null; + while(PlayerSetup.Instance.leftRay == null) + yield return null; + while(PlayerSetup.Instance.leftRay.lineRenderer == null) + yield return null; + + m_lineLeft.material = PlayerSetup.Instance.leftRay.lineRenderer.material; + m_lineRight.material = PlayerSetup.Instance.leftRay.lineRenderer.material; + } + + void OnDestroy() + { + Settings.EnabledChange -= this.OnEnableChange; + Settings.InputChange -= this.OnInputChange; + } + + void Update() + { + GestureMatcher.LeapData l_data = LeapManager.GetInstance().GetLatestData(); + + if(Settings.Enabled) + { + if(l_data.m_leftHand.m_present) + SetFingersInput(l_data.m_leftHand, true); + if(l_data.m_rightHand.m_present) + SetFingersInput(l_data.m_rightHand, false); + } + + m_handRayLeft.enabled = (l_data.m_leftHand.m_present && (!m_inVR || (VRTrackerManager.Instance.leftHand == null) || !VRTrackerManager.Instance.leftHand.active || !Settings.FingersOnly)); + m_handRayRight.enabled = (l_data.m_rightHand.m_present && (!m_inVR || (VRTrackerManager.Instance.rightHand == null) || !VRTrackerManager.Instance.rightHand.active || !Settings.FingersOnly)); + } + + public override void UpdateInput() + { + if(Settings.Enabled && Settings.Input) + { + GestureMatcher.LeapData l_data = LeapManager.GetInstance().GetLatestData(); + + if(l_data.m_leftHand.m_present && (!m_inVR || (VRTrackerManager.Instance.leftHand == null) || !VRTrackerManager.Instance.leftHand.active || !Settings.FingersOnly)) + { + float l_strength = l_data.m_leftHand.m_grabStrength; + m_inputManager.interactLeftValue = l_strength; + if(m_interactLeft != (l_strength > Settings.HoldThreadhold)) + { + m_interactLeft = (l_strength > Settings.HoldThreadhold); + m_inputManager.interactLeftUp |= m_interactLeft; + m_inputManager.interactLeftDown |= m_interactLeft; + } + m_inputManager.gripLeftValue = 1f - l_strength; // Inversed + if(m_gripLeft != (l_strength < Settings.ReleaseThreadhold)) + { + m_gripLeft = (l_strength < Settings.ReleaseThreadhold); + m_inputManager.gripLeftUp |= m_gripLeft; + m_inputManager.gripLeftDown |= m_gripLeft; + } + } + + if(l_data.m_rightHand.m_present && (!m_inVR || (VRTrackerManager.Instance.rightHand == null) || !VRTrackerManager.Instance.rightHand.active || !Settings.FingersOnly)) + { + float l_strength = l_data.m_rightHand.m_grabStrength; + m_inputManager.interactRightValue = l_strength; + if(m_interactRight != (l_strength > Settings.HoldThreadhold)) + { + m_interactRight = (l_strength > Settings.HoldThreadhold); + m_inputManager.interactRightUp |= m_interactRight; + m_inputManager.interactRightDown |= m_interactRight; + } + m_inputManager.gripRightValue = 1f - l_strength; + if(m_gripRight != (l_strength < Settings.HoldThreadhold)) + { + m_gripRight = (l_strength < Settings.HoldThreadhold); + m_inputManager.gripRightUp |= m_gripRight; + m_inputManager.gripRightDown |= m_gripRight; + } + } + } + } + + // Settings changes + void OnEnableChange(bool p_state) + { + OnInputChange(p_state && Settings.Input); + UpdateFingerTracking(); + } + + void OnInputChange(bool p_state) + { + (m_handRayLeft as MonoBehaviour).enabled = (p_state && Settings.Enabled); + (m_handRayRight as MonoBehaviour).enabled = (p_state && Settings.Enabled); + m_lineLeft.enabled = (p_state && Settings.Enabled); + m_lineRight.enabled = (p_state && Settings.Enabled); + + if(!p_state) + { + m_handRayLeft.DropObject(true); + m_handRayLeft.ClearGrabbedObject(); + + m_handRayRight.DropObject(true); + m_handRayRight.ClearGrabbedObject(); + + m_interactLeft = false; + m_interactRight = false; + m_gripLeft = false; + m_gripRight = false; + } + } + + // Game events + internal void OnAvatarSetup() + { + m_inVR = Utils.IsInVR(); + UpdateFingerTracking(); + } + + internal void OnRayScale(float p_scale) + { + m_handRayLeft.SetRayScale(p_scale); + m_handRayRight.SetRayScale(p_scale); + } + + // Arbitrary + void UpdateFingerTracking() + { + m_inputManager.individualFingerTracking = (Settings.Enabled || (m_inVR && Utils.AreKnucklesInUse() && !(bool)ms_indexGestureToggle.GetValue(m_steamVrModule))); + IKSystem.Instance.FingerSystem.controlActive = m_inputManager.individualFingerTracking; + } + + void SetFingersInput(GestureMatcher.HandData p_hand, bool p_left) + { + m_inputManager.individualFingerTracking = true; + IKSystem.Instance.FingerSystem.controlActive = true; + + if(p_left) + { + m_inputManager.fingerCurlLeftThumb = p_hand.m_bends[0]; + m_inputManager.fingerCurlLeftIndex = p_hand.m_bends[1]; + m_inputManager.fingerCurlLeftMiddle = p_hand.m_bends[2]; + m_inputManager.fingerCurlLeftRing = p_hand.m_bends[3]; + m_inputManager.fingerCurlLeftPinky = p_hand.m_bends[4]; + IKSystem.Instance.FingerSystem.leftThumbCurl = p_hand.m_bends[0]; + IKSystem.Instance.FingerSystem.leftIndexCurl = p_hand.m_bends[1]; + IKSystem.Instance.FingerSystem.leftMiddleCurl = p_hand.m_bends[2]; + IKSystem.Instance.FingerSystem.leftRingCurl = p_hand.m_bends[3]; + IKSystem.Instance.FingerSystem.leftPinkyCurl = p_hand.m_bends[4]; + } + else + { + m_inputManager.fingerCurlRightThumb = p_hand.m_bends[0]; + m_inputManager.fingerCurlRightIndex = p_hand.m_bends[1]; + m_inputManager.fingerCurlRightMiddle = p_hand.m_bends[2]; + m_inputManager.fingerCurlRightRing = p_hand.m_bends[3]; + m_inputManager.fingerCurlRightPinky = p_hand.m_bends[4]; + IKSystem.Instance.FingerSystem.rightThumbCurl = p_hand.m_bends[0]; + IKSystem.Instance.FingerSystem.rightIndexCurl = p_hand.m_bends[1]; + IKSystem.Instance.FingerSystem.rightMiddleCurl = p_hand.m_bends[2]; + IKSystem.Instance.FingerSystem.rightRingCurl = p_hand.m_bends[3]; + IKSystem.Instance.FingerSystem.rightPinkyCurl = p_hand.m_bends[4]; + } + } + } +} diff --git a/ml_lme/LeapManager.cs b/ml_lme/LeapManager.cs new file mode 100644 index 0000000..33aa249 --- /dev/null +++ b/ml_lme/LeapManager.cs @@ -0,0 +1,204 @@ +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using System.Collections; +using UnityEngine; + +namespace ml_lme +{ + [DisallowMultipleComponent] + class LeapManager : MonoBehaviour + { + static LeapManager ms_instance = null; + + readonly Leap.Controller m_leapController = null; + readonly GestureMatcher.LeapData m_leapData = null; + + LeapTracking m_leapTracking = null; + LeapTracked m_leapTracked = null; + LeapInput m_leapInput = null; + + public static LeapManager GetInstance() => ms_instance; + + internal LeapManager() + { + m_leapController = new Leap.Controller(); + m_leapData = new GestureMatcher.LeapData(); + } + ~LeapManager() + { + m_leapController.StopConnection(); + m_leapController.Dispose(); + } + + void Start() + { + if(ms_instance == null) + ms_instance = this; + + DontDestroyOnLoad(this); + + m_leapController.Device += this.OnLeapDeviceInitialized; + m_leapController.DeviceFailure += this.OnLeapDeviceFailure; + m_leapController.DeviceLost += this.OnLeapDeviceLost; + m_leapController.Connect += this.OnLeapServiceConnect; + m_leapController.Disconnect += this.OnLeapServiceDisconnect; + + Settings.EnabledChange += this.OnEnableChange; + Settings.TrackingModeChange += this.OnTrackingModeChange; + + m_leapTracking = new GameObject("[LeapTrackingRoot]").AddComponent(); + m_leapTracking.transform.parent = this.transform; + + MelonLoader.MelonCoroutines.Start(WaitForInputManager()); + MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); + + OnEnableChange(Settings.Enabled); + OnTrackingModeChange(Settings.TrackingMode); + } + + void OnDestroy() + { + if(ms_instance == this) + ms_instance = null; + + m_leapController.Device -= this.OnLeapDeviceInitialized; + m_leapController.DeviceFailure -= this.OnLeapDeviceFailure; + m_leapController.DeviceLost -= this.OnLeapDeviceLost; + m_leapController.Connect -= this.OnLeapServiceConnect; + m_leapController.Disconnect -= this.OnLeapServiceDisconnect; + + Settings.EnabledChange -= this.OnEnableChange; + Settings.TrackingModeChange -= this.OnTrackingModeChange; + } + + IEnumerator WaitForInputManager() + { + while(CVRInputManager.Instance == null) + yield return null; + + m_leapInput = CVRInputManager.Instance.gameObject.AddComponent(); + } + + IEnumerator WaitForLocalPlayer() + { + while(PlayerSetup.Instance == null) + yield return null; + + m_leapTracked = PlayerSetup.Instance.gameObject.AddComponent(); + } + + void Update() + { + if(Settings.Enabled) + { + m_leapData.Reset(); + + if(m_leapController.IsConnected) + { + Leap.Frame l_frame = m_leapController.Frame(); + GestureMatcher.GetFrameData(l_frame, m_leapData); + } + } + } + + public GestureMatcher.LeapData GetLatestData() => m_leapData; + + // Device events + void OnLeapDeviceInitialized(object p_sender, Leap.DeviceEventArgs p_args) + { + if(Settings.Enabled) + { + m_leapController.SubscribeToDeviceEvents(p_args.Device); + UpdateDeviceTrackingMode(); + } + + Utils.ShowHUDNotification("Leap Motion Extension", "Device initialized"); + } + + void OnLeapDeviceFailure(object p_sender, Leap.DeviceFailureEventArgs p_args) + { + Utils.ShowHUDNotification("Leap Motion Extension", "Device failure", "Code " + p_args.ErrorCode + ": " + p_args.ErrorMessage); + } + + void OnLeapDeviceLost(object p_sender, Leap.DeviceEventArgs p_args) + { + m_leapController.UnsubscribeFromDeviceEvents(p_args.Device); + + Utils.ShowHUDNotification("Leap Motion Extension", "Device lost"); + } + + void OnLeapServiceConnect(object p_sender, Leap.ConnectionEventArgs p_args) + { + Utils.ShowHUDNotification("Leap Motion Extension", "Service connected"); + } + + void OnLeapServiceDisconnect(object p_sender, Leap.ConnectionLostEventArgs p_args) + { + Utils.ShowHUDNotification("Leap Motion Extension", "Service disconnected"); + } + + // Settings + void OnEnableChange(bool p_state) + { + if(p_state) + { + m_leapController.StartConnection(); + UpdateDeviceTrackingMode(); + } + else + m_leapController.StopConnection(); + } + + void OnTrackingModeChange(Settings.LeapTrackingMode p_mode) + { + if(Settings.Enabled) + UpdateDeviceTrackingMode(); + } + + // Game events + internal void OnAvatarClear() + { + if(m_leapTracked != null) + m_leapTracked.OnAvatarClear(); + } + + internal void OnAvatarSetup() + { + if(m_leapTracking != null) + m_leapTracking.OnAvatarSetup(); + if(m_leapInput != null) + m_leapInput.OnAvatarSetup(); + if(m_leapTracked != null) + m_leapTracked.OnAvatarSetup(); + } + + internal void OnCalibrate() + { + if(m_leapTracked != null) + m_leapTracked.OnCalibrate(); + } + + internal void OnRayScale(float p_scale) + { + if(m_leapInput != null) + m_leapInput.OnRayScale(p_scale); + } + + // Arbitrary + void UpdateDeviceTrackingMode() + { + m_leapController.ClearPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_SCREENTOP, null); + m_leapController.ClearPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_HMD, null); + + switch(Settings.TrackingMode) + { + case Settings.LeapTrackingMode.Screentop: + m_leapController.SetPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_SCREENTOP, null); + break; + case Settings.LeapTrackingMode.HMD: + m_leapController.SetPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_HMD, null); + break; + } + } + } +} diff --git a/ml_lme/LeapTracked.cs b/ml_lme/LeapTracked.cs index ee1d0ae..167ba6d 100644 --- a/ml_lme/LeapTracked.cs +++ b/ml_lme/LeapTracked.cs @@ -1,5 +1,4 @@ using ABI_RC.Core.Player; -using ABI_RC.Core.Savior; using ABI_RC.Systems.IK; using RootMotion.FinalIK; using System.Reflection; @@ -11,20 +10,17 @@ namespace ml_lme class LeapTracked : MonoBehaviour { static readonly float[] ms_tposeMuscles = typeof(ABI_RC.Systems.IK.SubSystems.BodySystem).GetField("TPoseMuscles", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null) as float[]; - static readonly FieldInfo ms_indexGestureToggle = typeof(InputModuleSteamVR).GetField("_steamVrIndexGestureToggleValue", BindingFlags.Instance | BindingFlags.NonPublic); static readonly Quaternion ms_offsetLeft = Quaternion.Euler(0f, 0f, 270f); static readonly Quaternion ms_offsetRight = Quaternion.Euler(0f, 0f, 90f); static readonly Quaternion ms_offsetLeftDesktop = Quaternion.Euler(0f, 90f, 0f); static readonly Quaternion ms_offsetRightDesktop = Quaternion.Euler(0f, 270f, 0f); - InputModuleSteamVR m_steamVrModule = null; VRIK m_vrIK = null; Vector2 m_armsWeights = Vector2.zero; - bool m_isInVR = false; + bool m_inVR = false; Transform m_origElbowLeft = null; Transform m_origElbowRight = null; Transform m_hips = null; - Vector3 m_hipsLocal = Vector3.zero; bool m_enabled = true; bool m_fingersOnly = false; @@ -34,38 +30,32 @@ namespace ml_lme ArmIK m_rightIK = null; HumanPoseHandler m_poseHandler = null; HumanPose m_pose; - Transform m_leftHand = null; - Transform m_rightHand = null; Transform m_leftHandTarget = null; Transform m_rightHandTarget = null; - Transform m_leftElbow = null; - Transform m_rightElbow = null; bool m_leftTargetActive = false; bool m_rightTargetActive = false; void Start() { - m_steamVrModule = CVRInputManager.Instance.GetComponent(); - m_isInVR = Utils.IsInVR(); + m_inVR = Utils.IsInVR(); - if(m_leftHand != null) - { - m_leftHandTarget = new GameObject("RotationTarget").transform; - m_leftHandTarget.parent = m_leftHand; - m_leftHandTarget.localPosition = Vector3.zero; - m_leftHandTarget.localRotation = Quaternion.identity; - } - if(m_rightHand != null) - { - m_rightHandTarget = new GameObject("RotationTarget").transform; - m_rightHandTarget.parent = m_rightHand; - m_rightHandTarget.localPosition = Vector3.zero; - m_rightHandTarget.localRotation = Quaternion.identity; - } + m_leftHandTarget = new GameObject("RotationTarget").transform; + m_leftHandTarget.parent = LeapTracking.GetInstance().GetLeftHand(); + m_leftHandTarget.localPosition = Vector3.zero; + m_leftHandTarget.localRotation = Quaternion.identity; + + m_rightHandTarget = new GameObject("RotationTarget").transform; + m_rightHandTarget.parent = LeapTracking.GetInstance().GetRightHand(); + m_rightHandTarget.localPosition = Vector3.zero; + m_rightHandTarget.localRotation = Quaternion.identity; Settings.EnabledChange += this.SetEnabled; Settings.FingersOnlyChange += this.SetFingersOnly; Settings.TrackElbowsChange += this.SetTrackElbows; + + SetEnabled(Settings.Enabled); + SetFingersOnly(Settings.FingersOnly); + SetTrackElbows(Settings.TrackElbows); } void OnDestroy() @@ -75,17 +65,16 @@ namespace ml_lme Settings.TrackElbowsChange -= this.SetTrackElbows; } - public void SetEnabled(bool p_state) + void SetEnabled(bool p_state) { m_enabled = p_state; - RefreshFingersTracking(); RefreshArmIK(); if(!m_enabled || m_fingersOnly) RestoreVRIK(); } - public void SetFingersOnly(bool p_state) + void SetFingersOnly(bool p_state) { m_fingersOnly = p_state; @@ -94,7 +83,7 @@ namespace ml_lme RestoreVRIK(); } - public void SetTrackElbows(bool p_state) + void SetTrackElbows(bool p_state) { m_trackElbows = p_state; @@ -107,190 +96,148 @@ namespace ml_lme RestoreVRIK(); } - public void SetTransforms(Transform p_left, Transform p_right, Transform p_leftElbow, Transform p_rightElbow) - { - m_leftHand = p_left; - m_rightHand = p_right; - - m_leftElbow = p_leftElbow; - m_rightElbow = p_rightElbow; - } - - public void UpdateTracking(GestureMatcher.GesturesData p_data) + void Update() { if(m_enabled) { + GestureMatcher.LeapData l_data = LeapManager.GetInstance().GetLatestData(); + if((m_leftIK != null) && (m_rightIK != null)) { - m_leftIK.solver.IKPositionWeight = Mathf.Lerp(m_leftIK.solver.IKPositionWeight, (p_data.m_handsPresenses[0] && !m_fingersOnly) ? 1f : 0f, 0.25f); - m_leftIK.solver.IKRotationWeight = Mathf.Lerp(m_leftIK.solver.IKRotationWeight, (p_data.m_handsPresenses[0] && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_leftIK.solver.IKPositionWeight = Mathf.Lerp(m_leftIK.solver.IKPositionWeight, (l_data.m_leftHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_leftIK.solver.IKRotationWeight = Mathf.Lerp(m_leftIK.solver.IKRotationWeight, (l_data.m_leftHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); if(m_trackElbows) - m_leftIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_leftIK.solver.arm.bendGoalWeight, (p_data.m_handsPresenses[0] && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_leftIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_leftIK.solver.arm.bendGoalWeight, (l_data.m_leftHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); - m_rightIK.solver.IKPositionWeight = Mathf.Lerp(m_rightIK.solver.IKPositionWeight, (p_data.m_handsPresenses[1] && !m_fingersOnly) ? 1f : 0f, 0.25f); - m_rightIK.solver.IKRotationWeight = Mathf.Lerp(m_rightIK.solver.IKRotationWeight, (p_data.m_handsPresenses[1] && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_rightIK.solver.IKPositionWeight = Mathf.Lerp(m_rightIK.solver.IKPositionWeight, (l_data.m_rightHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_rightIK.solver.IKRotationWeight = Mathf.Lerp(m_rightIK.solver.IKRotationWeight, (l_data.m_rightHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); if(m_trackElbows) - m_rightIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_rightIK.solver.arm.bendGoalWeight, (p_data.m_handsPresenses[1] && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_rightIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_rightIK.solver.arm.bendGoalWeight, (l_data.m_rightHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); } if((m_vrIK != null) && !m_fingersOnly) { - if(p_data.m_handsPresenses[0] && !m_leftTargetActive) + if(l_data.m_leftHand.m_present && !m_leftTargetActive) { m_vrIK.solver.leftArm.target = m_leftHandTarget; - m_vrIK.solver.leftArm.bendGoal = m_leftElbow; + m_vrIK.solver.leftArm.bendGoal = LeapTracking.GetInstance().GetLeftElbow(); m_vrIK.solver.leftArm.bendGoalWeight = (m_trackElbows ? 1f : 0f); m_leftTargetActive = true; } - if(!p_data.m_handsPresenses[0] && m_leftTargetActive) + if(!l_data.m_leftHand.m_present && m_leftTargetActive) { - m_vrIK.solver.leftArm.target = IKSystem.Instance.leftHandAnchor; + m_vrIK.solver.leftArm.target = (m_inVR ? IKSystem.Instance.leftHandAnchor : null); m_vrIK.solver.leftArm.bendGoal = m_origElbowLeft; m_vrIK.solver.leftArm.bendGoalWeight = ((m_origElbowLeft != null) ? 1f : 0f); m_leftTargetActive = false; } - if(p_data.m_handsPresenses[1] && !m_rightTargetActive) + if(l_data.m_rightHand.m_present && !m_rightTargetActive) { m_vrIK.solver.rightArm.target = m_rightHandTarget; - m_vrIK.solver.rightArm.bendGoal = m_rightElbow; + m_vrIK.solver.rightArm.bendGoal = LeapTracking.GetInstance().GetRightElbow(); m_vrIK.solver.rightArm.bendGoalWeight = (m_trackElbows ? 1f : 0f); m_rightTargetActive = true; } - if(!p_data.m_handsPresenses[1] && m_rightTargetActive) + if(!l_data.m_rightHand.m_present && m_rightTargetActive) { - m_vrIK.solver.rightArm.target = IKSystem.Instance.rightHandAnchor; + m_vrIK.solver.rightArm.target = (m_inVR ? IKSystem.Instance.rightHandAnchor : null); m_vrIK.solver.rightArm.bendGoal = m_origElbowRight; m_vrIK.solver.rightArm.bendGoalWeight = ((m_origElbowRight != null) ? 1f : 0f); m_rightTargetActive = false; } } - - if(p_data.m_handsPresenses[0]) - { - CVRInputManager.Instance.individualFingerTracking = true; - CVRInputManager.Instance.fingerCurlLeftThumb = p_data.m_leftFingersBends[0]; - CVRInputManager.Instance.fingerCurlLeftIndex = p_data.m_leftFingersBends[1]; - CVRInputManager.Instance.fingerCurlLeftMiddle = p_data.m_leftFingersBends[2]; - CVRInputManager.Instance.fingerCurlLeftRing = p_data.m_leftFingersBends[3]; - CVRInputManager.Instance.fingerCurlLeftPinky = p_data.m_leftFingersBends[4]; - - IKSystem.Instance.FingerSystem.controlActive = true; - IKSystem.Instance.FingerSystem.leftThumbCurl = p_data.m_leftFingersBends[0]; - IKSystem.Instance.FingerSystem.leftIndexCurl = p_data.m_leftFingersBends[1]; - IKSystem.Instance.FingerSystem.leftMiddleCurl = p_data.m_leftFingersBends[2]; - IKSystem.Instance.FingerSystem.leftRingCurl = p_data.m_leftFingersBends[3]; - IKSystem.Instance.FingerSystem.leftPinkyCurl = p_data.m_leftFingersBends[4]; - } - - if(p_data.m_handsPresenses[1]) - { - CVRInputManager.Instance.individualFingerTracking = true; - CVRInputManager.Instance.fingerCurlRightThumb = p_data.m_rightFingersBends[0]; - CVRInputManager.Instance.fingerCurlRightIndex = p_data.m_rightFingersBends[1]; - CVRInputManager.Instance.fingerCurlRightMiddle = p_data.m_rightFingersBends[2]; - CVRInputManager.Instance.fingerCurlRightRing = p_data.m_rightFingersBends[3]; - CVRInputManager.Instance.fingerCurlRightPinky = p_data.m_rightFingersBends[4]; - - IKSystem.Instance.FingerSystem.controlActive = true; - IKSystem.Instance.FingerSystem.rightThumbCurl = p_data.m_rightFingersBends[0]; - IKSystem.Instance.FingerSystem.rightIndexCurl = p_data.m_rightFingersBends[1]; - IKSystem.Instance.FingerSystem.rightMiddleCurl = p_data.m_rightFingersBends[2]; - IKSystem.Instance.FingerSystem.rightRingCurl = p_data.m_rightFingersBends[3]; - IKSystem.Instance.FingerSystem.rightPinkyCurl = p_data.m_rightFingersBends[4]; - } } } - public void UpdateTrackingLate(GestureMatcher.GesturesData p_data) + void LateUpdate() { - if(m_enabled && !m_isInVR && (m_poseHandler != null)) + if(m_enabled && !m_inVR && (m_poseHandler != null)) { - if(m_hips != null) - m_hipsLocal = m_hips.localPosition; + GestureMatcher.LeapData l_data = LeapManager.GetInstance().GetLatestData(); + + Vector3 l_hipsLocalPos = m_hips.localPosition; m_poseHandler.GetHumanPose(ref m_pose); - UpdateFingers(p_data); + UpdateFingers(l_data); m_poseHandler.SetHumanPose(ref m_pose); - if(m_hips != null) - m_hips.localPosition = m_hipsLocal; + m_hips.localPosition = l_hipsLocalPos; } } - void UpdateFingers(GestureMatcher.GesturesData p_data) + void UpdateFingers(GestureMatcher.LeapData p_data) { - if(p_data.m_handsPresenses[0]) + if(p_data.m_leftHand.m_present) { - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb1Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_leftFingersBends[0])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb2Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_leftFingersBends[0])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb3Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_leftFingersBends[0])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumbSpread, Mathf.Lerp(-1.5f, 1.0f, p_data.m_leftFingersSpreads[0])); // Ok + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb1Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_leftHand.m_bends[0])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb2Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_leftHand.m_bends[0])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb3Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_leftHand.m_bends[0])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumbSpread, Mathf.Lerp(-1.5f, 1.0f, p_data.m_leftHand.m_spreads[0])); // Ok - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[1])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[1])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[1])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndexSpread, Mathf.Lerp(1f, -1f, p_data.m_leftFingersSpreads[1])); // Ok + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[1])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[1])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[1])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndexSpread, Mathf.Lerp(1f, -1f, p_data.m_leftHand.m_spreads[1])); // Ok - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[2])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[2])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[2])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddleSpread, Mathf.Lerp(2f, -2f, p_data.m_leftFingersSpreads[2])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[2])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[2])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[2])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddleSpread, Mathf.Lerp(2f, -2f, p_data.m_leftHand.m_spreads[2])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[3])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[3])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[3])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRingSpread, Mathf.Lerp(-2f, 2f, p_data.m_leftFingersSpreads[3])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[3])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[3])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[3])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRingSpread, Mathf.Lerp(-2f, 2f, p_data.m_leftHand.m_spreads[3])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[4])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[4])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[4])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittleSpread, Mathf.Lerp(-0.5f, 1f, p_data.m_leftFingersSpreads[4])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[4])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[4])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[4])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittleSpread, Mathf.Lerp(-0.5f, 1f, p_data.m_leftHand.m_spreads[4])); } - if(p_data.m_handsPresenses[1]) + if(p_data.m_rightHand.m_present) { - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb1Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_rightFingersBends[0])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb2Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_rightFingersBends[0])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb3Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_rightFingersBends[0])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumbSpread, Mathf.Lerp(-1.5f, 1.0f, p_data.m_rightFingersSpreads[0])); // Ok + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb1Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_rightHand.m_bends[0])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb2Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_rightHand.m_bends[0])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb3Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_rightHand.m_bends[0])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumbSpread, Mathf.Lerp(-1.5f, 1.0f, p_data.m_rightHand.m_spreads[0])); // Ok - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[1])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[1])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[1])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndexSpread, Mathf.Lerp(1f, -1f, p_data.m_rightFingersSpreads[1])); // Ok + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[1])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[1])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[1])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndexSpread, Mathf.Lerp(1f, -1f, p_data.m_rightHand.m_spreads[1])); // Ok - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[2])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[2])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[2])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddleSpread, Mathf.Lerp(2f, -2f, p_data.m_rightFingersSpreads[2])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[2])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[2])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[2])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddleSpread, Mathf.Lerp(2f, -2f, p_data.m_rightHand.m_spreads[2])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[3])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[3])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[3])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRingSpread, Mathf.Lerp(-2f, 2f, p_data.m_rightFingersSpreads[3])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[3])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[3])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[3])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRingSpread, Mathf.Lerp(-2f, 2f, p_data.m_rightHand.m_spreads[3])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[4])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[4])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[4])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittleSpread, Mathf.Lerp(-0.5f, 1f, p_data.m_rightFingersSpreads[4])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[4])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[4])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[4])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittleSpread, Mathf.Lerp(-0.5f, 1f, p_data.m_rightHand.m_spreads[4])); } } - public void OnAvatarClear() + internal void OnAvatarClear() { m_vrIK = null; m_origElbowLeft = null; m_origElbowRight = null; m_hips = null; - m_hipsLocal = Vector3.zero; m_armsWeights = Vector2.zero; m_leftIK = null; m_rightIK = null; m_leftTargetActive = false; m_rightTargetActive = false; - if(!m_isInVR) + if(!m_inVR) m_poseHandler?.Dispose(); m_poseHandler = null; @@ -300,27 +247,27 @@ namespace ml_lme m_rightHandTarget.localRotation = Quaternion.identity; } - public void OnSetupAvatar() + internal void OnAvatarSetup() { - m_isInVR = Utils.IsInVR(); + m_inVR = Utils.IsInVR(); m_vrIK = PlayerSetup.Instance._animator.GetComponent(); - RefreshFingersTracking(); - if(PlayerSetup.Instance._animator.isHuman) { m_hips = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Hips); - if(!m_isInVR) + if(!m_inVR) { // Force desktop avatar into T-Pose m_poseHandler = new HumanPoseHandler(PlayerSetup.Instance._animator.avatar, PlayerSetup.Instance._avatar.transform); m_poseHandler.GetHumanPose(ref m_pose); - HumanPose l_tPose = new HumanPose(); - l_tPose.bodyPosition = m_pose.bodyPosition; - l_tPose.bodyRotation = m_pose.bodyRotation; - l_tPose.muscles = new float[m_pose.muscles.Length]; + HumanPose l_tPose = new HumanPose + { + bodyPosition = m_pose.bodyPosition, + bodyRotation = m_pose.bodyRotation, + muscles = new float[m_pose.muscles.Length] + }; for(int i = 0; i < l_tPose.muscles.Length; i++) l_tPose.muscles[i] = ms_tposeMuscles[i]; m_poseHandler.SetHumanPose(ref l_tPose); @@ -353,7 +300,7 @@ namespace ml_lme PlayerSetup.Instance._animator.transform ); m_leftIK.solver.arm.target = m_leftHandTarget; - m_leftIK.solver.arm.bendGoal = m_leftElbow; + m_leftIK.solver.arm.bendGoal = LeapTracking.GetInstance().GetLeftElbow(); m_leftIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f); m_leftIK.enabled = (m_enabled && !m_fingersOnly); @@ -368,7 +315,7 @@ namespace ml_lme PlayerSetup.Instance._animator.transform ); m_rightIK.solver.arm.target = m_rightHandTarget; - m_rightIK.solver.arm.bendGoal = m_rightElbow; + m_rightIK.solver.arm.bendGoal = LeapTracking.GetInstance().GetRightElbow(); m_rightIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f); m_rightIK.enabled = (m_enabled && !m_fingersOnly); @@ -382,7 +329,7 @@ namespace ml_lme } } - public void OnCalibrate() + internal void OnCalibrate() { if(m_vrIK != null) { @@ -421,14 +368,14 @@ namespace ml_lme { if(m_leftTargetActive) { - m_vrIK.solver.leftArm.target = IKSystem.Instance.leftHandAnchor; + m_vrIK.solver.leftArm.target = (m_inVR ? IKSystem.Instance.leftHandAnchor : null); m_vrIK.solver.leftArm.bendGoal = m_origElbowLeft; m_vrIK.solver.leftArm.bendGoalWeight = ((m_origElbowLeft != null) ? 1f : 0f); m_leftTargetActive = false; } if(m_rightTargetActive) { - m_vrIK.solver.rightArm.target = IKSystem.Instance.rightHandAnchor; + m_vrIK.solver.rightArm.target = (m_inVR ? IKSystem.Instance.rightHandAnchor : null); m_vrIK.solver.rightArm.bendGoal = m_origElbowRight; m_vrIK.solver.rightArm.bendGoalWeight = ((m_origElbowRight != null) ? 1f : 0f); m_rightTargetActive = false; @@ -445,12 +392,6 @@ namespace ml_lme } } - void RefreshFingersTracking() - { - CVRInputManager.Instance.individualFingerTracking = (m_enabled || (m_isInVR && Utils.AreKnucklesInUse() && !(bool)ms_indexGestureToggle.GetValue(m_steamVrModule))); - IKSystem.Instance.FingerSystem.controlActive = CVRInputManager.Instance.individualFingerTracking; - } - static void UpdatePoseMuscle(ref HumanPose p_pose, int p_index, float p_value) { if(p_pose.muscles.Length > p_index) diff --git a/ml_lme/LeapTracking.cs b/ml_lme/LeapTracking.cs new file mode 100644 index 0000000..bc71ac5 --- /dev/null +++ b/ml_lme/LeapTracking.cs @@ -0,0 +1,221 @@ +using ABI_RC.Core.Player; +using System.Collections; +using UnityEngine; + +namespace ml_lme +{ + [DisallowMultipleComponent] + class LeapTracking : MonoBehaviour + { + static LeapTracking ms_instance = null; + static Quaternion ms_identityRotation = Quaternion.identity; + + bool m_inVR = false; + + GameObject m_leapHandLeft = null; + GameObject m_leapHandRight = null; + GameObject m_leapElbowLeft = null; + GameObject m_leapElbowRight = null; + GameObject m_leapControllerModel = null; + + public static LeapTracking GetInstance() => ms_instance; + + void Start() + { + if(ms_instance == null) + ms_instance = this; + + m_inVR = Utils.IsInVR(); + + m_leapHandLeft = new GameObject("LeapHandLeft"); + m_leapHandLeft.transform.parent = this.transform; + m_leapHandLeft.transform.localPosition = Vector3.zero; + m_leapHandLeft.transform.localRotation = Quaternion.identity; + + m_leapHandRight = new GameObject("LeapHandRight"); + m_leapHandRight.transform.parent = this.transform; + m_leapHandRight.transform.localPosition = Vector3.zero; + m_leapHandRight.transform.localRotation = Quaternion.identity; + + m_leapElbowLeft = new GameObject("LeapElbowLeft"); + m_leapElbowLeft.transform.parent = this.transform; + m_leapElbowLeft.transform.localPosition = Vector3.zero; + m_leapElbowLeft.transform.localRotation = Quaternion.identity; + + m_leapElbowRight = new GameObject("LeapElbowRight"); + m_leapElbowRight.transform.parent = this.transform; + m_leapElbowRight.transform.localPosition = Vector3.zero; + m_leapElbowRight.transform.localRotation = Quaternion.identity; + + m_leapControllerModel = AssetsHandler.GetAsset("assets/models/leapmotion/leap_motion_1_0.obj"); + if(m_leapControllerModel != null) + { + m_leapControllerModel.name = "LeapModel"; + m_leapControllerModel.transform.parent = this.transform; + m_leapControllerModel.transform.localPosition = Vector3.zero; + m_leapControllerModel.transform.localRotation = Quaternion.identity; + } + + Settings.DesktopOffsetChange += this.OnDesktopOffsetChange; + Settings.ModelVisibilityChange += this.OnModelVisibilityChange; + Settings.TrackingModeChange += this.OnTrackingModeChange; + Settings.RootAngleChange += this.OnRootAngleChange; + Settings.HeadAttachChange += this.OnHeadAttachChange; + Settings.HeadOffsetChange += this.OnHeadOffsetChange; + + MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); + + OnModelVisibilityChange(Settings.ModelVisibility); + OnTrackingModeChange(Settings.TrackingMode); + OnRootAngleChange(Settings.RootAngle); + } + + IEnumerator WaitForLocalPlayer() + { + while(PlayerSetup.Instance == null) + yield return null; + + OnDesktopOffsetChange(Settings.DesktopOffset); + OnHeadAttachChange(Settings.HeadAttach); + OnHeadOffsetChange(Settings.HeadOffset); + } + + void OnDestroy() + { + if(ms_instance == this) + ms_instance = null; + + Settings.DesktopOffsetChange -= this.OnDesktopOffsetChange; + Settings.ModelVisibilityChange -= this.OnModelVisibilityChange; + Settings.TrackingModeChange -= this.OnTrackingModeChange; + Settings.RootAngleChange -= this.OnRootAngleChange; + Settings.HeadAttachChange -= this.OnHeadAttachChange; + Settings.HeadOffsetChange -= this.OnHeadOffsetChange; + } + + void Update() + { + if(Settings.Enabled) + { + GestureMatcher.LeapData l_data = LeapManager.GetInstance().GetLatestData(); + + if(l_data.m_leftHand.m_present) + { + Utils.LeapToUnity(ref l_data.m_leftHand.m_position, ref l_data.m_leftHand.m_rotation, Settings.TrackingMode); + m_leapHandLeft.transform.localPosition = l_data.m_leftHand.m_position; + m_leapHandLeft.transform.localRotation = l_data.m_leftHand.m_rotation; + + Utils.LeapToUnity(ref l_data.m_leftHand.m_elbowPosition, ref ms_identityRotation, Settings.TrackingMode); + m_leapElbowLeft.transform.localPosition = l_data.m_leftHand.m_elbowPosition; + } + + if(l_data.m_rightHand.m_present) + { + Utils.LeapToUnity(ref l_data.m_rightHand.m_position, ref l_data.m_rightHand.m_rotation, Settings.TrackingMode); + m_leapHandRight.transform.localPosition = l_data.m_rightHand.m_position; + m_leapHandRight.transform.localRotation = l_data.m_rightHand.m_rotation; + + Utils.LeapToUnity(ref l_data.m_rightHand.m_elbowPosition, ref ms_identityRotation, Settings.TrackingMode); + m_leapElbowRight.transform.localPosition = l_data.m_rightHand.m_elbowPosition; + } + } + } + + public Transform GetLeftHand() => m_leapHandLeft.transform; + public Transform GetRightHand() => m_leapHandRight.transform; + public Transform GetLeftElbow() => m_leapElbowLeft.transform; + public Transform GetRightElbow() => m_leapElbowRight.transform; + + // Settings + void OnDesktopOffsetChange(Vector3 p_offset) + { + if(!Settings.HeadAttach) + { + if(!m_inVR) + this.transform.localPosition = p_offset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; + else + this.transform.localPosition = p_offset; + } + } + + void OnModelVisibilityChange(bool p_state) + { + m_leapControllerModel.SetActive(p_state); + } + + void OnTrackingModeChange(Settings.LeapTrackingMode p_mode) + { + switch(p_mode) + { + case Settings.LeapTrackingMode.Screentop: + m_leapControllerModel.transform.localRotation = Quaternion.Euler(0f, 0f, 180f); + break; + case Settings.LeapTrackingMode.Desktop: + m_leapControllerModel.transform.localRotation = Quaternion.identity; + break; + case Settings.LeapTrackingMode.HMD: + m_leapControllerModel.transform.localRotation = Quaternion.Euler(270f, 180f, 0f); + break; + } + } + + void OnRootAngleChange(Vector3 p_angle) + { + this.transform.localRotation = Quaternion.Euler(p_angle); + } + + void OnHeadAttachChange(bool p_state) + { + if(p_state) + { + if(!m_inVR) + { + this.transform.parent = PlayerSetup.Instance.desktopCamera.transform; + this.transform.localPosition = Settings.HeadOffset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; + this.transform.localScale = PlayerSetup.Instance.vrCameraRig.transform.localScale; + } + else + { + this.transform.parent = PlayerSetup.Instance.vrCamera.transform; + this.transform.localPosition = Settings.HeadOffset; + this.transform.localScale = Vector3.one; + } + } + else + { + if(!m_inVR) + { + this.transform.parent = PlayerSetup.Instance.desktopCameraRig.transform; + this.transform.localPosition = Settings.DesktopOffset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; + this.transform.localScale = PlayerSetup.Instance.vrCameraRig.transform.localScale; + } + else + { + this.transform.parent = PlayerSetup.Instance.vrCameraRig.transform; + this.transform.localPosition = Settings.DesktopOffset; + this.transform.localScale = Vector3.one; + } + } + + this.transform.localRotation = Quaternion.Euler(Settings.RootAngle); + } + + void OnHeadOffsetChange(Vector3 p_offset) + { + if(Settings.HeadAttach) + { + if(!m_inVR) + this.transform.localPosition = p_offset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; + else + this.transform.localPosition = p_offset; + } + } + + // Game events + internal void OnAvatarSetup() + { + m_inVR = Utils.IsInVR(); + OnHeadAttachChange(Settings.HeadAttach); + } + } +} diff --git a/ml_lme/Main.cs b/ml_lme/Main.cs index b441b9d..c520251 100644 --- a/ml_lme/Main.cs +++ b/ml_lme/Main.cs @@ -1,6 +1,6 @@ using ABI_RC.Core.Player; -using ABI_RC.Core.UI; using ABI_RC.Systems.IK.SubSystems; +using System.Collections; using System.Reflection; using UnityEngine; @@ -11,16 +11,7 @@ namespace ml_lme { static LeapMotionExtension ms_instance = null; - Leap.Controller m_leapController = null; - GestureMatcher.GesturesData m_gesturesData = null; - - GameObject m_leapTrackingRoot = null; - GameObject[] m_leapHands = null; - GameObject[] m_leapElbows = null; - GameObject m_leapControllerModel = null; - LeapTracked m_leapTracked = null; - - bool m_isInVR = false; + LeapManager m_leapManager = null; public override void OnInitializeMelon() { @@ -28,26 +19,8 @@ namespace ml_lme ms_instance = this; DependenciesHandler.ExtractDependencies(); - Settings.Init(); - Settings.EnabledChange += this.OnEnableChange; - Settings.DesktopOffsetChange += this.OnDesktopOffsetChange; - Settings.ModelVisibilityChange += this.OnModelVisibilityChange; - Settings.TrackingModeChange += this.OnTrackingModeChange; - Settings.RootAngleChange += this.OnRootAngleChange; - Settings.HeadAttachChange += this.OnHeadAttachChange; - Settings.HeadOffsetChange += this.OnHeadOffsetChange; - - m_leapController = new Leap.Controller(); - m_leapController.Device += this.OnLeapDeviceInitialized; - m_leapController.DeviceFailure += this.OnLeapDeviceFailure; - m_leapController.DeviceLost += this.OnLeapDeviceLost; - m_leapController.Connect += this.OnLeapServiceConnect; - m_leapController.Disconnect += this.OnLeapServiceDisconnect; - - m_gesturesData = new GestureMatcher.GesturesData(); - m_leapHands = new GameObject[GestureMatcher.GesturesData.ms_handsCount]; - m_leapElbows = new GameObject[GestureMatcher.GesturesData.ms_handsCount]; + AssetsHandler.Load(); // Patches HarmonyInstance.Patch( @@ -65,280 +38,27 @@ namespace ml_lme null, new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnCalibrate_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); + HarmonyInstance.Patch( + typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetControllerRayScale)), + null, + new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnRayScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + ); - MelonLoader.MelonCoroutines.Start(CreateTrackingObjects()); - } - - System.Collections.IEnumerator CreateTrackingObjects() - { - AssetsHandler.Load(); - - while(PlayerSetup.Instance == null) - yield return null; - while(PlayerSetup.Instance.desktopCameraRig == null) - yield return null; - while(PlayerSetup.Instance.desktopCamera == null) - yield return null; - while(PlayerSetup.Instance.vrCameraRig == null) - yield return null; - while(PlayerSetup.Instance.vrCamera == null) - yield return null; - - m_isInVR = Utils.IsInVR(); - - m_leapTrackingRoot = new GameObject("[LeapRoot]"); - - for(int i = 0; i < GestureMatcher.GesturesData.ms_handsCount; i++) - { - m_leapHands[i] = new GameObject("LeapHand" + i); - m_leapHands[i].transform.parent = m_leapTrackingRoot.transform; - m_leapHands[i].transform.localPosition = Vector3.zero; - m_leapHands[i].transform.localRotation = Quaternion.identity; - - m_leapElbows[i] = new GameObject("LeapElbow" + i); - m_leapElbows[i].transform.parent = m_leapTrackingRoot.transform; - m_leapElbows[i].transform.localPosition = Vector3.zero; - m_leapElbows[i].transform.localRotation = Quaternion.identity; - } - - m_leapControllerModel = AssetsHandler.GetAsset("assets/models/leapmotion/leap_motion_1_0.obj"); - if(m_leapControllerModel != null) - { - m_leapControllerModel.name = "LeapModel"; - m_leapControllerModel.transform.parent = m_leapTrackingRoot.transform; - m_leapControllerModel.transform.localPosition = Vector3.zero; - m_leapControllerModel.transform.localRotation = Quaternion.identity; - } - - // Player setup - m_leapTracked = PlayerSetup.Instance.gameObject.AddComponent(); - m_leapTracked.SetTransforms(m_leapHands[0].transform, m_leapHands[1].transform, m_leapElbows[0].transform, m_leapElbows[1].transform); - m_leapTracked.SetEnabled(Settings.Enabled); - m_leapTracked.SetTrackElbows(Settings.TrackElbows); - m_leapTracked.SetFingersOnly(Settings.FingersOnly); - - OnEnableChange(Settings.Enabled); - OnModelVisibilityChange(Settings.ModelVisibility); - OnTrackingModeChange(Settings.TrackingMode); - OnHeadAttachChange(Settings.HeadAttach); // Includes offsets and parenting + MelonLoader.MelonCoroutines.Start(WaitForRootLogic()); } public override void OnDeinitializeMelon() { if(ms_instance == this) ms_instance = null; - - m_leapController?.StopConnection(); - m_leapController?.Dispose(); - m_leapController = null; - - m_gesturesData = null; } - public override void OnUpdate() + IEnumerator WaitForRootLogic() { - if(Settings.Enabled) - { - for(int i = 0; i < GestureMatcher.GesturesData.ms_handsCount; i++) - m_gesturesData.m_handsPresenses[i] = false; + while(ABI_RC.Core.RootLogic.Instance == null) + yield return null; - if((m_leapController != null) && m_leapController.IsConnected) - { - Leap.Frame l_frame = m_leapController.Frame(); - if(l_frame != null) - { - GestureMatcher.GetGestures(l_frame, ref m_gesturesData); - - for(int i = 0; i < GestureMatcher.GesturesData.ms_handsCount; i++) - { - if((m_leapHands[i] != null) && m_gesturesData.m_handsPresenses[i]) - { - Vector3 l_pos = m_gesturesData.m_handsPositons[i]; - Quaternion l_rot = m_gesturesData.m_handsRotations[i]; - Utils.LeapToUnity(ref l_pos, ref l_rot, Settings.TrackingMode); - m_leapHands[i].transform.localPosition = l_pos; - m_leapHands[i].transform.localRotation = l_rot; - - l_pos = m_gesturesData.m_elbowsPositions[i]; - Utils.LeapToUnity(ref l_pos, ref l_rot, Settings.TrackingMode); - m_leapElbows[i].transform.localPosition = l_pos; - } - } - } - } - - if(m_leapTracked != null) - m_leapTracked.UpdateTracking(m_gesturesData); - } - } - - public override void OnLateUpdate() - { - if(Settings.Enabled && !m_isInVR && (m_leapTracked != null)) - m_leapTracked.UpdateTrackingLate(m_gesturesData); - } - - // Settings changes - void OnEnableChange(bool p_state) - { - if(p_state) - { - m_leapController?.StartConnection(); - UpdateDeviceTrackingMode(); - } - else - m_leapController?.StopConnection(); - } - - void OnDesktopOffsetChange(Vector3 p_offset) - { - if((m_leapTrackingRoot != null) && !Settings.HeadAttach) - { - if(!m_isInVR) - m_leapTrackingRoot.transform.localPosition = p_offset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; - else - m_leapTrackingRoot.transform.localPosition = p_offset; - } - } - - void OnModelVisibilityChange(bool p_state) - { - if(m_leapControllerModel != null) - m_leapControllerModel.SetActive(p_state); - } - - void OnTrackingModeChange(Settings.LeapTrackingMode p_mode) - { - if(Settings.Enabled) - UpdateDeviceTrackingMode(); - - if(m_leapControllerModel != null) - { - switch(p_mode) - { - case Settings.LeapTrackingMode.Screentop: - m_leapControllerModel.transform.localRotation = Quaternion.Euler(0f, 0f, 180f); - break; - case Settings.LeapTrackingMode.Desktop: - m_leapControllerModel.transform.localRotation = Quaternion.identity; - break; - case Settings.LeapTrackingMode.HMD: - m_leapControllerModel.transform.localRotation = Quaternion.Euler(270f, 180f, 0f); - break; - } - } - } - - void OnRootAngleChange(Vector3 p_angle) - { - if(m_leapTrackingRoot != null) - m_leapTrackingRoot.transform.localRotation = Quaternion.Euler(p_angle); - } - - void OnHeadAttachChange(bool p_state) - { - if(m_leapTrackingRoot != null) - { - if(p_state) - { - if(!m_isInVR) - { - m_leapTrackingRoot.transform.parent = PlayerSetup.Instance.desktopCamera.transform; - m_leapTrackingRoot.transform.localPosition = Settings.HeadOffset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; - m_leapTrackingRoot.transform.localScale = PlayerSetup.Instance.vrCameraRig.transform.localScale; - } - else - { - m_leapTrackingRoot.transform.parent = PlayerSetup.Instance.vrCamera.transform; - m_leapTrackingRoot.transform.localPosition = Settings.HeadOffset; - m_leapTrackingRoot.transform.localScale = Vector3.one; - } - } - else - { - if(!m_isInVR) - { - m_leapTrackingRoot.transform.parent = PlayerSetup.Instance.desktopCameraRig.transform; - m_leapTrackingRoot.transform.localPosition = Settings.DesktopOffset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; - m_leapTrackingRoot.transform.localScale = PlayerSetup.Instance.vrCameraRig.transform.localScale; - } - else - { - m_leapTrackingRoot.transform.parent = PlayerSetup.Instance.vrCameraRig.transform; - m_leapTrackingRoot.transform.localPosition = Settings.DesktopOffset; - m_leapTrackingRoot.transform.localScale = Vector3.one; - } - } - - m_leapTrackingRoot.transform.localRotation = Quaternion.Euler(Settings.RootAngle); - } - } - - void OnHeadOffsetChange(Vector3 p_offset) - { - if((m_leapTrackingRoot != null) && Settings.HeadAttach) - { - if(!m_isInVR) - m_leapTrackingRoot.transform.localPosition = p_offset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; - else - m_leapTrackingRoot.transform.localPosition = p_offset; - } - } - - // Internal utility - void UpdateDeviceTrackingMode() - { - m_leapController?.ClearPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_SCREENTOP, null); - m_leapController?.ClearPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_HMD, null); - - switch(Settings.TrackingMode) - { - case Settings.LeapTrackingMode.Screentop: - m_leapController?.SetPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_SCREENTOP, null); - break; - case Settings.LeapTrackingMode.HMD: - m_leapController?.SetPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_HMD, null); - break; - } - } - - // Leap events - void OnLeapDeviceInitialized(object p_sender, Leap.DeviceEventArgs p_args) - { - if(Settings.Enabled) - { - m_leapController?.SubscribeToDeviceEvents(p_args.Device); - UpdateDeviceTrackingMode(); - } - - if(CohtmlHud.Instance != null) - CohtmlHud.Instance.ViewDropText("Leap Motion Extension", "Device initialized"); - } - - void OnLeapDeviceFailure(object p_sender, Leap.DeviceFailureEventArgs p_args) - { - if(CohtmlHud.Instance != null) - CohtmlHud.Instance.ViewDropText("Leap Motion Extension", "Device failure, code " + p_args.ErrorCode + ": " + p_args.ErrorMessage); - } - - void OnLeapDeviceLost(object p_sender, Leap.DeviceEventArgs p_args) - { - m_leapController?.UnsubscribeFromDeviceEvents(p_args.Device); - - if(CohtmlHud.Instance != null) - CohtmlHud.Instance.ViewDropText("Leap Motion Extension", "Device lost"); - } - - void OnLeapServiceConnect(object p_sender, Leap.ConnectionEventArgs p_args) - { - if(CohtmlHud.Instance != null) - CohtmlHud.Instance.ViewDropText("Leap Motion Extension", "Service connected"); - } - - void OnLeapServiceDisconnect(object p_sender, Leap.ConnectionLostEventArgs p_args) - { - if(CohtmlHud.Instance != null) - CohtmlHud.Instance.ViewDropText("Leap Motion Extension", "Service disconnected"); + m_leapManager = new GameObject("LeapMotionManager").AddComponent(); } // Patches @@ -347,8 +67,8 @@ namespace ml_lme { try { - if(m_leapTracked != null) - m_leapTracked.OnAvatarClear(); + if(m_leapManager != null) + m_leapManager.OnAvatarClear(); } catch(System.Exception e) { @@ -361,12 +81,8 @@ namespace ml_lme { try { - m_isInVR = Utils.IsInVR(); - - if(m_leapTracked != null) - m_leapTracked.OnSetupAvatar(); - - OnHeadAttachChange(Settings.HeadAttach); + if(m_leapManager != null) + m_leapManager.OnAvatarSetup(); } catch(System.Exception e) { @@ -379,8 +95,22 @@ namespace ml_lme { try { - if(m_leapTracked != null) - m_leapTracked.OnCalibrate(); + if(m_leapManager != null) + m_leapManager.OnCalibrate(); + } + catch(System.Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } + + static void OnRayScale_Postfix(float __0) => ms_instance?.OnRayScale(__0); + void OnRayScale(float p_scale) + { + try + { + if(m_leapManager != null) + m_leapManager.OnRayScale(p_scale); } catch(System.Exception e) { diff --git a/ml_lme/Properties/AssemblyInfo.cs b/ml_lme/Properties/AssemblyInfo.cs index ea10aad..095d7d8 100644 --- a/ml_lme/Properties/AssemblyInfo.cs +++ b/ml_lme/Properties/AssemblyInfo.cs @@ -1,10 +1,10 @@ using System.Reflection; [assembly: AssemblyTitle("LeapMotionExtension")] -[assembly: AssemblyVersion("1.2.9")] -[assembly: AssemblyFileVersion("1.2.9")] +[assembly: AssemblyVersion("1.3.0")] +[assembly: AssemblyFileVersion("1.3.0")] -[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.2.9", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.3.0", "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)] diff --git a/ml_lme/README.md b/ml_lme/README.md index f843f95..355b1f3 100644 --- a/ml_lme/README.md +++ b/ml_lme/README.md @@ -1,5 +1,5 @@ # Leap Motion Extension -This mod allows you to use your Leap Motion controller for hands and fingers visual tracking. +This mod allows you to use your Leap Motion controller for hands and fingers tracking. [![](.github/img_01.png)](https://youtu.be/nak1C8uibgc) @@ -21,3 +21,6 @@ Available mod's settings in `Settings - Implementation - Leap Motion Tracking`: * **Track elbows:** elbows tracking, works best in `Screentop` and `HMD` tracking modes, `true` by default. * **Fingers tracking only:** apply only fingers tracking, disabled by default. * **Model visibility:** show Leap Motion controller model, useful for tracking visualizing, disabled by default. +* **Interaction input:** enables in-game interactions (props, menu and etc.); `true` by default. + ** Note: Suggested to use with disabled `Settings - Input & Key-Bindings - Use grip to grab`. +* **Hold/Release gesture threadhold:** limits for interaction/grip activation based on hand gesture; 50 by default. diff --git a/ml_lme/Settings.cs b/ml_lme/Settings.cs index aa5fd79..a28f0a2 100644 --- a/ml_lme/Settings.cs +++ b/ml_lme/Settings.cs @@ -31,7 +31,10 @@ namespace ml_lme HeadX, HeadY, HeadZ, - TrackElbows + TrackElbows, + Input, + HoldThreadhold, + ReleaseThreadhold }; static bool ms_enabled = false; @@ -43,6 +46,9 @@ namespace ml_lme static bool ms_headAttach = false; static Vector3 ms_headOffset = new Vector3(0f, -0.3f, 0.15f); static bool ms_trackElbows = true; + static bool ms_input = true; + static float ms_holdThreadhold = 0.5f; + static float ms_releaseThreadhold = 0.5f; static MelonLoader.MelonPreferences_Category ms_category = null; static List ms_entries = null; @@ -56,27 +62,35 @@ namespace ml_lme static public event Action HeadAttachChange; static public event Action HeadOffsetChange; static public event Action TrackElbowsChange; + static public event Action InputChange; + static public event Action HoldThreadholdChange; + static public event Action ReleaseThreadholdChange; - public static void Init() + internal static void Init() { ms_category = MelonLoader.MelonPreferences.CreateCategory("LME"); - ms_entries = new List(); - ms_entries.Add(ms_category.CreateEntry(ModSetting.Enabled.ToString(), ms_enabled)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.DesktopX.ToString(), 0)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.DesktopY.ToString(), -45)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.DesktopZ.ToString(), 30)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.FingersOnly.ToString(), ms_modelVisibility)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.Model.ToString(), ms_modelVisibility)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.Mode.ToString(), (int)ms_trackingMode)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.AngleX.ToString(), 0)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.AngleY.ToString(), 0)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.AngleZ.ToString(), 0)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.Head.ToString(), ms_headAttach)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.HeadX.ToString(), 0)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.HeadY.ToString(), -30)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.HeadZ.ToString(), 15)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.TrackElbows.ToString(), true)); + ms_entries = new List() + { + ms_category.CreateEntry(ModSetting.Enabled.ToString(), ms_enabled), + ms_category.CreateEntry(ModSetting.DesktopX.ToString(), 0), + ms_category.CreateEntry(ModSetting.DesktopY.ToString(), -45), + ms_category.CreateEntry(ModSetting.DesktopZ.ToString(), 30), + ms_category.CreateEntry(ModSetting.FingersOnly.ToString(), ms_modelVisibility), + ms_category.CreateEntry(ModSetting.Model.ToString(), ms_modelVisibility), + ms_category.CreateEntry(ModSetting.Mode.ToString(), (int)ms_trackingMode), + ms_category.CreateEntry(ModSetting.AngleX.ToString(), 0), + ms_category.CreateEntry(ModSetting.AngleY.ToString(), 0), + ms_category.CreateEntry(ModSetting.AngleZ.ToString(), 0), + ms_category.CreateEntry(ModSetting.Head.ToString(), ms_headAttach), + ms_category.CreateEntry(ModSetting.HeadX.ToString(), 0), + ms_category.CreateEntry(ModSetting.HeadY.ToString(), -30), + ms_category.CreateEntry(ModSetting.HeadZ.ToString(), 15), + ms_category.CreateEntry(ModSetting.TrackElbows.ToString(), true), + ms_category.CreateEntry(ModSetting.Input.ToString(), true), + ms_category.CreateEntry(ModSetting.HoldThreadhold.ToString(), 50), + ms_category.CreateEntry(ModSetting.ReleaseThreadhold.ToString(), 50), + }; Load(); @@ -129,6 +143,9 @@ namespace ml_lme (int)ms_entries[(int)ModSetting.HeadZ].BoxedValue ) * 0.01f; ms_trackElbows = (bool)ms_entries[(int)ModSetting.TrackElbows].BoxedValue; + ms_input = (bool)ms_entries[(int)ModSetting.Input].BoxedValue; + ms_holdThreadhold = (int)ms_entries[(int)ModSetting.HoldThreadhold].BoxedValue * 0.01f; + ms_releaseThreadhold = (int)ms_entries[(int)ModSetting.ReleaseThreadhold].BoxedValue * 0.01f; } static void OnToggleUpdate(string p_name, string p_value) @@ -171,6 +188,13 @@ namespace ml_lme TrackElbowsChange?.Invoke(ms_trackElbows); } break; + + case ModSetting.Input: + { + ms_input = bool.Parse(p_value); + InputChange?.Invoke(ms_input); + } + break; } ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); @@ -241,6 +265,18 @@ namespace ml_lme HeadOffsetChange?.Invoke(ms_headOffset); } break; + case ModSetting.HoldThreadhold: + { + ms_holdThreadhold = int.Parse(p_value) * 0.01f; + HoldThreadholdChange?.Invoke(ms_holdThreadhold); + } + break; + case ModSetting.ReleaseThreadhold: + { + ms_releaseThreadhold = int.Parse(p_value) * 0.01f; + ReleaseThreadholdChange?.Invoke(ms_releaseThreadhold); + } + break; } ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); @@ -301,5 +337,17 @@ namespace ml_lme { get => ms_trackElbows; } + public static bool Input + { + get => ms_input; + } + public static float HoldThreadhold + { + get => ms_holdThreadhold; + } + public static float ReleaseThreadhold + { + get => ms_releaseThreadhold; + } } } diff --git a/ml_lme/Utils.cs b/ml_lme/Utils.cs index bf493a4..1a05cef 100644 --- a/ml_lme/Utils.cs +++ b/ml_lme/Utils.cs @@ -1,4 +1,5 @@ using ABI_RC.Core.Player; +using ABI_RC.Core.UI; using System.Linq; using UnityEngine; @@ -8,7 +9,7 @@ namespace ml_lme { static readonly Quaternion ms_hmdRotationFix = new Quaternion(0f, 0.7071068f, 0.7071068f, 0f); static readonly Quaternion ms_screentopRotationFix = new Quaternion(0f, 0f, -1f, 0f); - + public static bool AreKnucklesInUse() => PlayerSetup.Instance._trackerManager.trackerNames.Contains("knuckles"); public static bool IsInVR() => ((ABI_RC.Core.Savior.CheckVR.Instance != null) && ABI_RC.Core.Savior.CheckVR.Instance.hasVrDeviceLoaded); @@ -17,7 +18,18 @@ namespace ml_lme { return Matrix4x4.TRS(p_pos ? p_transform.position : Vector3.zero, p_rot ? p_transform.rotation : Quaternion.identity, p_scl ? p_transform.lossyScale : Vector3.one); } - + + public static void ShowHUDNotification(string p_title, string p_message, string p_small = "", bool p_immediate = false) + { + if(CohtmlHud.Instance != null) + { + if(p_immediate) + CohtmlHud.Instance.ViewDropTextImmediate(p_title, p_message, p_small); + else + CohtmlHud.Instance.ViewDropText(p_title, p_message, p_small); + } + } + public static void LeapToUnity(ref Vector3 p_pos, ref Quaternion p_rot, Settings.LeapTrackingMode p_mode) { p_pos *= 0.001f; diff --git a/ml_lme/ml_lme.csproj b/ml_lme/ml_lme.csproj index d1fba4a..25fb3c8 100644 --- a/ml_lme/ml_lme.csproj +++ b/ml_lme/ml_lme.csproj @@ -84,7 +84,10 @@ + + + diff --git a/ml_lme/resources/menu.js b/ml_lme/resources/menu.js index bc1fb73..8b8cd52 100644 --- a/ml_lme/resources/menu.js +++ b/ml_lme/resources/menu.js @@ -384,6 +384,27 @@ function inp_dropdown_mod_lme(_obj, _callbackName) {
+ +
+
Interaction input:
+
+
+
+
+ +
+
Hold gesture threadhold:
+
+
+
+
+ +
+
Release gesture threadhold:
+
+
+
+
`; document.getElementById('settings-implementation').appendChild(l_block); diff --git a/ml_pam/ArmMover.cs b/ml_pam/ArmMover.cs index 3e1e584..d2fd112 100644 --- a/ml_pam/ArmMover.cs +++ b/ml_pam/ArmMover.cs @@ -4,6 +4,7 @@ using UnityEngine; namespace ml_pam { + [DisallowMultipleComponent] class ArmMover : MonoBehaviour { static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f); From fbad3fdf8e10256cc9788addd285c48a1612e559 Mon Sep 17 00:00:00 2001 From: SDraw Date: Sat, 28 Jan 2023 14:26:06 +0000 Subject: [PATCH 21/32] Update README.md --- ml_lme/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ml_lme/README.md b/ml_lme/README.md index 355b1f3..8b9f656 100644 --- a/ml_lme/README.md +++ b/ml_lme/README.md @@ -22,5 +22,5 @@ Available mod's settings in `Settings - Implementation - Leap Motion Tracking`: * **Fingers tracking only:** apply only fingers tracking, disabled by default. * **Model visibility:** show Leap Motion controller model, useful for tracking visualizing, disabled by default. * **Interaction input:** enables in-game interactions (props, menu and etc.); `true` by default. - ** Note: Suggested to use with disabled `Settings - Input & Key-Bindings - Use grip to grab`. + * Note: Suggested to use with disabled `Settings - Input & Key-Bindings - Use grip to grab`. * **Hold/Release gesture threadhold:** limits for interaction/grip activation based on hand gesture; 50 by default. From 6bc448d41da841c2a5e7c54b20316eba8013e247 Mon Sep 17 00:00:00 2001 From: SDraw Date: Sun, 29 Jan 2023 19:55:22 +0300 Subject: [PATCH 22/32] Rays layer fix Desktop tracking scale fix More notifications --- README.md | 2 +- ml_egn/Main.cs | 57 +++++++++++++++++++++++++++++ ml_egn/Properties/AssemblyInfo.cs | 6 +-- ml_egn/README.md | 6 ++- ml_lme/LeapInput.cs | 4 +- ml_lme/LeapManager.cs | 8 ++++ ml_lme/LeapTracking.cs | 61 +++++++++++-------------------- ml_lme/Main.cs | 19 ++++++++++ 8 files changed, 118 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 2d62003..0d7ed85 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Merged set of MelonLoader mods for ChilloutVR. | Avatar Motion Tweaker | ml_amt | 1.2.2 | Yes | Working | | Desktop Head Tracking | ml_dht | 1.1.1 | Yes | Working | | Desktop Reticle Switch | ml_drs | 1.0.0 | Yes | Working | -| Extended Game Notifications | ml_egn | 1.0.0 | Yes | Working +| Extended Game Notifications | ml_egn | 1.0.1 | Yes, update review | Working | Four Point Tracking | ml_fpt | 1.0.9 | Retired | Deprecated | In-game feature since 2022r170 update | Leap Motion Extension | ml_lme | 1.3.0 | Yes, update review | Working | | Pickup Arm Movement | ml_pam | 1.0.0 | Yes | Working | diff --git a/ml_egn/Main.cs b/ml_egn/Main.cs index 7b90b53..c77bf82 100644 --- a/ml_egn/Main.cs +++ b/ml_egn/Main.cs @@ -1,5 +1,6 @@ using ABI_RC.Core.EventSystem; using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.IO; using ABI_RC.Core.Networking; using ABI_RC.Core.Util; using DarkRift.Client; @@ -28,6 +29,24 @@ namespace ml_egn null, new HarmonyLib.HarmonyMethod(typeof(ExtendedGameNotifications).GetMethod(nameof(OnGameNetworkConnectionClosed), BindingFlags.NonPublic | BindingFlags.Static)) ); + + HarmonyInstance.Patch( + typeof(CVRCamImageSaver).GetMethod(nameof(CVRCamImageSaver.SavePicture), BindingFlags.Public | BindingFlags.Static), + null, + new HarmonyLib.HarmonyMethod(typeof(ExtendedGameNotifications).GetMethod(nameof(OnPictureSave), BindingFlags.NonPublic | BindingFlags.Static)) + ); + + HarmonyInstance.Patch( + typeof(CVRSyncHelper).GetMethod(nameof(CVRSyncHelper.DeleteAllProps), BindingFlags.Public | BindingFlags.Static), + null, + new HarmonyLib.HarmonyMethod(typeof(ExtendedGameNotifications).GetMethod(nameof(OnAllPropsDelete), BindingFlags.NonPublic | BindingFlags.Static)) + ); + + HarmonyInstance.Patch( + typeof(CVRSyncHelper).GetMethod(nameof(CVRSyncHelper.DeleteMyProps), BindingFlags.Public | BindingFlags.Static), + null, + new HarmonyLib.HarmonyMethod(typeof(ExtendedGameNotifications).GetMethod(nameof(OnOwnPropsDelete), BindingFlags.NonPublic | BindingFlags.Static)) + ); } static void OnLocalAvatarLoad() @@ -82,5 +101,43 @@ namespace ml_egn MelonLoader.MelonLogger.Error(e); } } + + static void OnPictureSave() + { + try + { + Utils.ShowHUDNotification("(Local) Client", "Screenshot saved"); + } + catch(System.Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } + + static void OnAllPropsDelete() + { + try + { + if(Utils.IsMenuOpened()) + Utils.ShowMenuNotification("Props are removed"); + } + catch(System.Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } + + static void OnOwnPropsDelete() + { + try + { + if(Utils.IsMenuOpened()) + Utils.ShowMenuNotification("Own props are removed"); + } + catch(System.Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } } } diff --git a/ml_egn/Properties/AssemblyInfo.cs b/ml_egn/Properties/AssemblyInfo.cs index de777d8..f1610b5 100644 --- a/ml_egn/Properties/AssemblyInfo.cs +++ b/ml_egn/Properties/AssemblyInfo.cs @@ -1,10 +1,10 @@ using System.Reflection; [assembly: AssemblyTitle("ExtendedGameNotifications")] -[assembly: AssemblyVersion("1.0.0")] -[assembly: AssemblyFileVersion("1.0.0")] +[assembly: AssemblyVersion("1.0.1")] +[assembly: AssemblyFileVersion("1.0.1")] -[assembly: MelonLoader.MelonInfo(typeof(ml_egn.ExtendedGameNotifications), "ExtendedGameNotifications", "1.0.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_egn.ExtendedGameNotifications), "ExtendedGameNotifications", "1.0.1", "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_egn/README.md b/ml_egn/README.md index 7103d28..15d5fe7 100644 --- a/ml_egn/README.md +++ b/ml_egn/README.md @@ -1,5 +1,9 @@ # Extended Game Notifications -This mod shows main menu notifications and HUD popups upon avatar changing, prop spawning and server connection loss. +This mod shows main menu notifications and HUD popups upon: +* Avatar changing +* Prop spawning/deletion +* Server connection loss +* Screenshot saving Basically, merged previous `Avatar Change Info` and `Server Connection Info` mods in one. # Installation diff --git a/ml_lme/LeapInput.cs b/ml_lme/LeapInput.cs index b71875e..d81d943 100644 --- a/ml_lme/LeapInput.cs +++ b/ml_lme/LeapInput.cs @@ -31,7 +31,7 @@ namespace ml_lme base.Start(); m_inputManager = CVRInputManager.Instance; // _inputManager is stripped out, cool beans - m_steamVrModule = this.GetComponent(); + m_steamVrModule = m_inputManager.GetComponent(); m_inVR = Utils.IsInVR(); m_handRayLeft = LeapTracking.GetInstance().GetLeftHand().gameObject.AddComponent(); @@ -91,7 +91,9 @@ namespace ml_lme yield return null; m_lineLeft.material = PlayerSetup.Instance.leftRay.lineRenderer.material; + m_lineLeft.gameObject.layer = PlayerSetup.Instance.leftRay.gameObject.layer; m_lineRight.material = PlayerSetup.Instance.leftRay.lineRenderer.material; + m_lineRight.gameObject.layer = PlayerSetup.Instance.leftRay.gameObject.layer; } void OnDestroy() diff --git a/ml_lme/LeapManager.cs b/ml_lme/LeapManager.cs index 33aa249..1edaa21 100644 --- a/ml_lme/LeapManager.cs +++ b/ml_lme/LeapManager.cs @@ -158,6 +158,8 @@ namespace ml_lme // Game events internal void OnAvatarClear() { + if(m_leapTracking != null) + m_leapTracking.OnAvatarClear(); if(m_leapTracked != null) m_leapTracked.OnAvatarClear(); } @@ -184,6 +186,12 @@ namespace ml_lme m_leapInput.OnRayScale(p_scale); } + internal void OnPlayspaceScale(float p_relation) + { + if(m_leapTracking != null) + m_leapTracking.OnPlayspaceScale(p_relation); + } + // Arbitrary void UpdateDeviceTrackingMode() { diff --git a/ml_lme/LeapTracking.cs b/ml_lme/LeapTracking.cs index bc71ac5..251b9cd 100644 --- a/ml_lme/LeapTracking.cs +++ b/ml_lme/LeapTracking.cs @@ -18,6 +18,8 @@ namespace ml_lme GameObject m_leapElbowRight = null; GameObject m_leapControllerModel = null; + float m_scaleRelation = 1f; + public static LeapTracking GetInstance() => ms_instance; void Start() @@ -75,9 +77,7 @@ namespace ml_lme while(PlayerSetup.Instance == null) yield return null; - OnDesktopOffsetChange(Settings.DesktopOffset); OnHeadAttachChange(Settings.HeadAttach); - OnHeadOffsetChange(Settings.HeadOffset); } void OnDestroy() @@ -130,12 +130,7 @@ namespace ml_lme void OnDesktopOffsetChange(Vector3 p_offset) { if(!Settings.HeadAttach) - { - if(!m_inVR) - this.transform.localPosition = p_offset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; - else - this.transform.localPosition = p_offset; - } + this.transform.localPosition = p_offset * (!m_inVR ? m_scaleRelation : 1f); } void OnModelVisibilityChange(bool p_state) @@ -166,56 +161,44 @@ namespace ml_lme void OnHeadAttachChange(bool p_state) { - if(p_state) + if(!m_inVR) { - if(!m_inVR) - { - this.transform.parent = PlayerSetup.Instance.desktopCamera.transform; - this.transform.localPosition = Settings.HeadOffset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; - this.transform.localScale = PlayerSetup.Instance.vrCameraRig.transform.localScale; - } - else - { - this.transform.parent = PlayerSetup.Instance.vrCamera.transform; - this.transform.localPosition = Settings.HeadOffset; - this.transform.localScale = Vector3.one; - } + this.transform.parent = (p_state ? PlayerSetup.Instance.desktopCamera.transform : PlayerSetup.Instance.desktopCameraRig.transform); + this.transform.localPosition = (p_state ? Settings.HeadOffset : Settings.DesktopOffset) * m_scaleRelation; } else { - if(!m_inVR) - { - this.transform.parent = PlayerSetup.Instance.desktopCameraRig.transform; - this.transform.localPosition = Settings.DesktopOffset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; - this.transform.localScale = PlayerSetup.Instance.vrCameraRig.transform.localScale; - } - else - { - this.transform.parent = PlayerSetup.Instance.vrCameraRig.transform; - this.transform.localPosition = Settings.DesktopOffset; - this.transform.localScale = Vector3.one; - } + this.transform.parent = (p_state ? PlayerSetup.Instance.vrCamera.transform : PlayerSetup.Instance.vrCameraRig.transform); + this.transform.localPosition = (p_state ? Settings.HeadOffset : Settings.DesktopOffset); } + this.transform.localScale = Vector3.one * (!m_inVR ? m_scaleRelation : 1f); this.transform.localRotation = Quaternion.Euler(Settings.RootAngle); } void OnHeadOffsetChange(Vector3 p_offset) { if(Settings.HeadAttach) - { - if(!m_inVR) - this.transform.localPosition = p_offset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; - else - this.transform.localPosition = p_offset; - } + this.transform.localPosition = p_offset * (!m_inVR ? m_scaleRelation : 1f); } // Game events + internal void OnAvatarClear() + { + m_scaleRelation = 1f; + OnHeadAttachChange(Settings.HeadAttach); + } + internal void OnAvatarSetup() { m_inVR = Utils.IsInVR(); OnHeadAttachChange(Settings.HeadAttach); } + + internal void OnPlayspaceScale(float p_relation) + { + m_scaleRelation = p_relation; + OnHeadAttachChange(Settings.HeadAttach); + } } } diff --git a/ml_lme/Main.cs b/ml_lme/Main.cs index c520251..2bfb331 100644 --- a/ml_lme/Main.cs +++ b/ml_lme/Main.cs @@ -43,6 +43,11 @@ namespace ml_lme null, new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnRayScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); + HarmonyInstance.Patch( + typeof(PlayerSetup).GetMethod("SetPlaySpaceScale", BindingFlags.NonPublic | BindingFlags.Instance), + null, + new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnPlayspaceScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + ); MelonLoader.MelonCoroutines.Start(WaitForRootLogic()); } @@ -117,5 +122,19 @@ namespace ml_lme MelonLoader.MelonLogger.Error(e); } } + + static void OnPlayspaceScale_Postfix(float ____avatarScaleRelation) => ms_instance?.OnPlayspaceScale(____avatarScaleRelation); + void OnPlayspaceScale(float p_relation) + { + try + { + if(m_leapManager != null) + m_leapManager.OnPlayspaceScale(p_relation); + } + catch(System.Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } } } From 783c343d11c79310214bdfbc43e76a8c486a974f Mon Sep 17 00:00:00 2001 From: SDraw Date: Sun, 29 Jan 2023 23:18:16 +0300 Subject: [PATCH 23/32] Oh no, again --- ml_lme/LeapInput.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ml_lme/LeapInput.cs b/ml_lme/LeapInput.cs index d81d943..80fc915 100644 --- a/ml_lme/LeapInput.cs +++ b/ml_lme/LeapInput.cs @@ -131,14 +131,14 @@ namespace ml_lme if(m_interactLeft != (l_strength > Settings.HoldThreadhold)) { m_interactLeft = (l_strength > Settings.HoldThreadhold); - m_inputManager.interactLeftUp |= m_interactLeft; + m_inputManager.interactLeftUp |= !m_interactLeft; m_inputManager.interactLeftDown |= m_interactLeft; } m_inputManager.gripLeftValue = 1f - l_strength; // Inversed if(m_gripLeft != (l_strength < Settings.ReleaseThreadhold)) { m_gripLeft = (l_strength < Settings.ReleaseThreadhold); - m_inputManager.gripLeftUp |= m_gripLeft; + m_inputManager.gripLeftUp |= !m_gripLeft; m_inputManager.gripLeftDown |= m_gripLeft; } } @@ -150,14 +150,14 @@ namespace ml_lme if(m_interactRight != (l_strength > Settings.HoldThreadhold)) { m_interactRight = (l_strength > Settings.HoldThreadhold); - m_inputManager.interactRightUp |= m_interactRight; + m_inputManager.interactRightUp |= !m_interactRight; m_inputManager.interactRightDown |= m_interactRight; } m_inputManager.gripRightValue = 1f - l_strength; if(m_gripRight != (l_strength < Settings.HoldThreadhold)) { m_gripRight = (l_strength < Settings.HoldThreadhold); - m_inputManager.gripRightUp |= m_gripRight; + m_inputManager.gripRightUp |= !m_gripRight; m_inputManager.gripRightDown |= m_gripRight; } } From d8c79ed15c378e11496a291552f927699b8f56d0 Mon Sep 17 00:00:00 2001 From: SDraw Date: Sun, 29 Jan 2023 23:47:06 +0300 Subject: [PATCH 24/32] Hjelp --- ml_lme/LeapInput.cs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/ml_lme/LeapInput.cs b/ml_lme/LeapInput.cs index 80fc915..882c00a 100644 --- a/ml_lme/LeapInput.cs +++ b/ml_lme/LeapInput.cs @@ -127,39 +127,53 @@ namespace ml_lme if(l_data.m_leftHand.m_present && (!m_inVR || (VRTrackerManager.Instance.leftHand == null) || !VRTrackerManager.Instance.leftHand.active || !Settings.FingersOnly)) { float l_strength = l_data.m_leftHand.m_grabStrength; - m_inputManager.interactLeftValue = l_strength; if(m_interactLeft != (l_strength > Settings.HoldThreadhold)) { m_interactLeft = (l_strength > Settings.HoldThreadhold); m_inputManager.interactLeftUp |= !m_interactLeft; m_inputManager.interactLeftDown |= m_interactLeft; } - m_inputManager.gripLeftValue = 1f - l_strength; // Inversed + if(m_interactLeft) + m_inputManager.interactLeftValue = Mathf.InverseLerp(Settings.HoldThreadhold, 1f, l_strength); + else + m_inputManager.interactLeftValue = Mathf.Max(0f, m_inputManager.interactLeftValue); + if(m_gripLeft != (l_strength < Settings.ReleaseThreadhold)) { m_gripLeft = (l_strength < Settings.ReleaseThreadhold); m_inputManager.gripLeftUp |= !m_gripLeft; m_inputManager.gripLeftDown |= m_gripLeft; } + if(m_gripLeft) + m_inputManager.gripLeftValue = Mathf.InverseLerp(Settings.ReleaseThreadhold, 0f, l_strength); + else + m_inputManager.gripLeftValue = Mathf.Max(0f, m_inputManager.gripLeftValue); } if(l_data.m_rightHand.m_present && (!m_inVR || (VRTrackerManager.Instance.rightHand == null) || !VRTrackerManager.Instance.rightHand.active || !Settings.FingersOnly)) { float l_strength = l_data.m_rightHand.m_grabStrength; - m_inputManager.interactRightValue = l_strength; if(m_interactRight != (l_strength > Settings.HoldThreadhold)) { m_interactRight = (l_strength > Settings.HoldThreadhold); m_inputManager.interactRightUp |= !m_interactRight; m_inputManager.interactRightDown |= m_interactRight; } - m_inputManager.gripRightValue = 1f - l_strength; + if(m_interactRight) + m_inputManager.interactRightValue = Mathf.InverseLerp(Settings.HoldThreadhold, 1f, l_strength); + else + m_inputManager.interactRightValue = Mathf.Max(0f, m_inputManager.interactRightValue); + if(m_gripRight != (l_strength < Settings.HoldThreadhold)) { m_gripRight = (l_strength < Settings.HoldThreadhold); m_inputManager.gripRightUp |= !m_gripRight; m_inputManager.gripRightDown |= m_gripRight; } + if(m_gripRight) + m_inputManager.gripRightValue = Mathf.InverseLerp(Settings.ReleaseThreadhold, 0f, l_strength); + else + m_inputManager.gripRightValue = Mathf.Max(0f, m_inputManager.gripRightValue); } } } From d48944a039954cfb1277ae8190df3e62f84d987d Mon Sep 17 00:00:00 2001 From: SDraw Date: Mon, 30 Jan 2023 19:52:08 +0300 Subject: [PATCH 25/32] Finally, good input --- ml_amt/MotionTweaker.cs | 10 ++-- ml_dht/HeadTracked.cs | 2 +- ml_lme/LeapInput.cs | 111 +++++++++++++++++++++++---------------- ml_lme/README.md | 3 +- ml_lme/Settings.cs | 40 +++++++------- ml_lme/Utils.cs | 5 +- ml_lme/resources/menu.js | 8 +-- 7 files changed, 102 insertions(+), 77 deletions(-) diff --git a/ml_amt/MotionTweaker.cs b/ml_amt/MotionTweaker.cs index c9077cd..c21e6cf 100644 --- a/ml_amt/MotionTweaker.cs +++ b/ml_amt/MotionTweaker.cs @@ -114,7 +114,7 @@ namespace ml_amt float l_currentHeight = Mathf.Clamp((l_hmdMatrix * ms_pointVector).y, 0f, float.MaxValue); float l_avatarScale = (m_avatarScale > 0f) ? (PlayerSetup.Instance._avatar.transform.localScale.y / m_avatarScale) : 0f; float l_avatarViewHeight = Mathf.Clamp(m_viewPointHeight * l_avatarScale, 0f, float.MaxValue); - m_upright = Mathf.Clamp(((l_avatarViewHeight > 0f) ? (l_currentHeight / l_avatarViewHeight) : 0f), 0f, 1f); + m_upright = Mathf.Clamp01((l_avatarViewHeight > 0f) ? (l_currentHeight / l_avatarViewHeight) : 0f); m_poseState = (m_upright <= Mathf.Min(m_proneLimit, m_crouchLimit)) ? PoseState.Proning : ((m_upright <= Mathf.Max(m_proneLimit, m_crouchLimit)) ? PoseState.Crouching : PoseState.Standing); if(m_avatarHips != null) @@ -216,11 +216,11 @@ namespace ml_amt Transform l_customTransform = PlayerSetup.Instance._avatar.transform.Find("CrouchLimit"); m_customCrouchLimit = (l_customTransform != null); - m_crouchLimit = m_customCrouchLimit ? Mathf.Clamp(l_customTransform.localPosition.y, 0f, 1f) : Settings.CrouchLimit; + m_crouchLimit = m_customCrouchLimit ? Mathf.Clamp01(l_customTransform.localPosition.y) : Settings.CrouchLimit; l_customTransform = PlayerSetup.Instance._avatar.transform.Find("ProneLimit"); m_customProneLimit = (l_customTransform != null); - m_proneLimit = m_customProneLimit ? Mathf.Clamp(l_customTransform.localPosition.y, 0f, 1f) : Settings.ProneLimit; + m_proneLimit = m_customProneLimit ? Mathf.Clamp01(l_customTransform.localPosition.y) : Settings.ProneLimit; l_customTransform = PlayerSetup.Instance._avatar.transform.Find("LocomotionOffset"); m_customLocomotionOffset = (l_customTransform != null); @@ -305,7 +305,7 @@ namespace ml_amt public void SetCrouchLimit(float p_value) { if(!m_customCrouchLimit) - m_crouchLimit = Mathf.Clamp(p_value, 0f, 1f); + m_crouchLimit = Mathf.Clamp01(p_value); } public void SetIKOverrideProne(bool p_state) { @@ -314,7 +314,7 @@ namespace ml_amt public void SetProneLimit(float p_value) { if(!m_customProneLimit) - m_proneLimit = Mathf.Clamp(p_value, 0f, 1f); + m_proneLimit = Mathf.Clamp01(p_value); } public void SetPoseTransitions(bool p_state) { diff --git a/ml_dht/HeadTracked.cs b/ml_dht/HeadTracked.cs index 7282ed3..a7ac529 100644 --- a/ml_dht/HeadTracked.cs +++ b/ml_dht/HeadTracked.cs @@ -106,7 +106,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; + float l_weight = Mathf.Clamp01(Mathf.InverseLerp(0.25f, 1f, Mathf.Abs(m_mouthShapes.y))) * 100f; p_component.BlendShapeValues[(int)LipShape_v2.Jaw_Open] = m_mouthShapes.x * 100f; p_component.BlendShapeValues[(int)LipShape_v2.Mouth_Pout] = ((m_mouthShapes.y > 0f) ? l_weight : 0f); diff --git a/ml_lme/LeapInput.cs b/ml_lme/LeapInput.cs index 882c00a..697d95e 100644 --- a/ml_lme/LeapInput.cs +++ b/ml_lme/LeapInput.cs @@ -16,6 +16,7 @@ namespace ml_lme CVRInputManager m_inputManager = null; InputModuleSteamVR m_steamVrModule = null; bool m_inVR = false; + bool m_gripToGrab = true; ControllerRay m_handRayLeft = null; ControllerRay m_handRayRight = null; @@ -78,9 +79,21 @@ namespace ml_lme OnEnableChange(Settings.Enabled); OnInputChange(Settings.Input); + MelonLoader.MelonCoroutines.Start(WaitForSettings()); MelonLoader.MelonCoroutines.Start(WaitForMaterial()); } + IEnumerator WaitForSettings() + { + while(MetaPort.Instance == null) + yield return null; + while(MetaPort.Instance.settings == null) + yield return null; + + m_gripToGrab = MetaPort.Instance.settings.GetSettingsBool("ControlUseGripToGrab", true); + MetaPort.Instance.settings.settingBoolChanged.AddListener(this.OnGameSettingBoolChange); + } + IEnumerator WaitForMaterial() { while(PlayerSetup.Instance == null) @@ -114,8 +127,8 @@ namespace ml_lme SetFingersInput(l_data.m_rightHand, false); } - m_handRayLeft.enabled = (l_data.m_leftHand.m_present && (!m_inVR || (VRTrackerManager.Instance.leftHand == null) || !VRTrackerManager.Instance.leftHand.active || !Settings.FingersOnly)); - m_handRayRight.enabled = (l_data.m_rightHand.m_present && (!m_inVR || (VRTrackerManager.Instance.rightHand == null) || !VRTrackerManager.Instance.rightHand.active || !Settings.FingersOnly)); + m_handRayLeft.enabled = (l_data.m_leftHand.m_present && (!m_inVR || !Utils.IsLeftHandTracked() || !Settings.FingersOnly)); + m_handRayRight.enabled = (l_data.m_rightHand.m_present && (!m_inVR || !Utils.IsRightHandTracked() || !Settings.FingersOnly)); } public override void UpdateInput() @@ -124,56 +137,60 @@ namespace ml_lme { GestureMatcher.LeapData l_data = LeapManager.GetInstance().GetLatestData(); - if(l_data.m_leftHand.m_present && (!m_inVR || (VRTrackerManager.Instance.leftHand == null) || !VRTrackerManager.Instance.leftHand.active || !Settings.FingersOnly)) + if(l_data.m_leftHand.m_present && (!m_inVR || !Utils.IsLeftHandTracked() || !Settings.FingersOnly)) { float l_strength = l_data.m_leftHand.m_grabStrength; - if(m_interactLeft != (l_strength > Settings.HoldThreadhold)) - { - m_interactLeft = (l_strength > Settings.HoldThreadhold); - m_inputManager.interactLeftUp |= !m_interactLeft; - m_inputManager.interactLeftDown |= m_interactLeft; - } - if(m_interactLeft) - m_inputManager.interactLeftValue = Mathf.InverseLerp(Settings.HoldThreadhold, 1f, l_strength); - else - m_inputManager.interactLeftValue = Mathf.Max(0f, m_inputManager.interactLeftValue); - if(m_gripLeft != (l_strength < Settings.ReleaseThreadhold)) - { - m_gripLeft = (l_strength < Settings.ReleaseThreadhold); - m_inputManager.gripLeftUp |= !m_gripLeft; - m_inputManager.gripLeftDown |= m_gripLeft; - } - if(m_gripLeft) - m_inputManager.gripLeftValue = Mathf.InverseLerp(Settings.ReleaseThreadhold, 0f, l_strength); + float l_interactValue = 0f; + if(m_gripToGrab) + l_interactValue = Mathf.Clamp01(Mathf.InverseLerp(Mathf.Min(Settings.GripThreadhold, Settings.InteractThreadhold), Mathf.Max(Settings.GripThreadhold, Settings.InteractThreadhold), l_strength)); else - m_inputManager.gripLeftValue = Mathf.Max(0f, m_inputManager.gripLeftValue); + l_interactValue = Mathf.Clamp01(Mathf.InverseLerp(0f, Settings.InteractThreadhold, l_strength)); + m_inputManager.interactLeftValue = Mathf.Max(l_interactValue, m_inputManager.interactLeftValue); + + if(m_interactLeft != (l_strength > Settings.InteractThreadhold)) + { + m_interactLeft = (l_strength > Settings.InteractThreadhold); + m_inputManager.interactLeftDown |= m_interactLeft; + m_inputManager.interactLeftUp |= !m_interactLeft; + } + + float l_gripValue = Mathf.Clamp01(Mathf.InverseLerp(0f, Settings.GripThreadhold, l_strength)); + m_inputManager.gripLeftValue = Mathf.Max(l_gripValue, m_inputManager.gripLeftValue); + if(m_gripLeft != (l_strength > Settings.GripThreadhold)) + { + m_gripLeft = (l_strength > Settings.GripThreadhold); + m_inputManager.gripLeftDown |= m_gripLeft; + m_inputManager.gripLeftUp |= !m_gripLeft; + } } - if(l_data.m_rightHand.m_present && (!m_inVR || (VRTrackerManager.Instance.rightHand == null) || !VRTrackerManager.Instance.rightHand.active || !Settings.FingersOnly)) + if(l_data.m_rightHand.m_present && (!m_inVR || !Utils.IsRightHandTracked() || !Settings.FingersOnly)) { float l_strength = l_data.m_rightHand.m_grabStrength; - if(m_interactRight != (l_strength > Settings.HoldThreadhold)) - { - m_interactRight = (l_strength > Settings.HoldThreadhold); - m_inputManager.interactRightUp |= !m_interactRight; - m_inputManager.interactRightDown |= m_interactRight; - } - if(m_interactRight) - m_inputManager.interactRightValue = Mathf.InverseLerp(Settings.HoldThreadhold, 1f, l_strength); - else - m_inputManager.interactRightValue = Mathf.Max(0f, m_inputManager.interactRightValue); - if(m_gripRight != (l_strength < Settings.HoldThreadhold)) - { - m_gripRight = (l_strength < Settings.HoldThreadhold); - m_inputManager.gripRightUp |= !m_gripRight; - m_inputManager.gripRightDown |= m_gripRight; - } - if(m_gripRight) - m_inputManager.gripRightValue = Mathf.InverseLerp(Settings.ReleaseThreadhold, 0f, l_strength); + float l_interactValue = 0f; + if(m_gripToGrab) + l_interactValue = Mathf.Clamp01(Mathf.InverseLerp(Mathf.Min(Settings.GripThreadhold, Settings.InteractThreadhold), Mathf.Max(Settings.GripThreadhold, Settings.InteractThreadhold), l_strength)); else - m_inputManager.gripRightValue = Mathf.Max(0f, m_inputManager.gripRightValue); + l_interactValue = Mathf.Clamp01(Mathf.InverseLerp(0f, Settings.InteractThreadhold, l_strength)); + m_inputManager.interactRightValue = Mathf.Max(l_interactValue, m_inputManager.interactRightValue); + + if(m_interactRight != (l_strength > Settings.InteractThreadhold)) + { + m_interactRight = (l_strength > Settings.InteractThreadhold); + m_inputManager.interactRightDown |= m_interactRight; + m_inputManager.interactRightUp |= !m_interactRight; + } + + float l_gripValue = Mathf.Clamp01(Mathf.InverseLerp(0f, Settings.GripThreadhold, l_strength)); + m_inputManager.gripRightValue = Mathf.Max(l_gripValue, m_inputManager.gripRightValue); + if(m_gripRight != (l_strength > Settings.GripThreadhold)) + { + m_gripRight = (l_strength > Settings.GripThreadhold); + m_inputManager.gripRightDown |= m_gripRight; + m_inputManager.gripRightUp |= !m_gripRight; + } } } } @@ -187,8 +204,8 @@ namespace ml_lme void OnInputChange(bool p_state) { - (m_handRayLeft as MonoBehaviour).enabled = (p_state && Settings.Enabled); - (m_handRayRight as MonoBehaviour).enabled = (p_state && Settings.Enabled); + ((MonoBehaviour)m_handRayLeft).enabled = (p_state && Settings.Enabled); + ((MonoBehaviour)m_handRayRight).enabled = (p_state && Settings.Enabled); m_lineLeft.enabled = (p_state && Settings.Enabled); m_lineRight.enabled = (p_state && Settings.Enabled); @@ -259,5 +276,11 @@ namespace ml_lme IKSystem.Instance.FingerSystem.rightPinkyCurl = p_hand.m_bends[4]; } } + + void OnGameSettingBoolChange(string p_name, bool p_state) + { + if(p_name == "ControlUseGripToGrab") + m_gripToGrab = p_state; + } } } diff --git a/ml_lme/README.md b/ml_lme/README.md index 8b9f656..b9c5322 100644 --- a/ml_lme/README.md +++ b/ml_lme/README.md @@ -23,4 +23,5 @@ Available mod's settings in `Settings - Implementation - Leap Motion Tracking`: * **Model visibility:** show Leap Motion controller model, useful for tracking visualizing, disabled by default. * **Interaction input:** enables in-game interactions (props, menu and etc.); `true` by default. * Note: Suggested to use with disabled `Settings - Input & Key-Bindings - Use grip to grab`. -* **Hold/Release gesture threadhold:** limits for interaction/grip activation based on hand gesture; 50 by default. +* **Interact gesture threadhold:** activation limit for interaction based on hand gesture; 80 by default. +* **Grip gesture threadhold:** activation limit for grip based on hand gesture; 40 by default. diff --git a/ml_lme/Settings.cs b/ml_lme/Settings.cs index a28f0a2..0015b43 100644 --- a/ml_lme/Settings.cs +++ b/ml_lme/Settings.cs @@ -33,8 +33,8 @@ namespace ml_lme HeadZ, TrackElbows, Input, - HoldThreadhold, - ReleaseThreadhold + InteractThreadhold, + GripThreadhold }; static bool ms_enabled = false; @@ -47,8 +47,8 @@ namespace ml_lme static Vector3 ms_headOffset = new Vector3(0f, -0.3f, 0.15f); static bool ms_trackElbows = true; static bool ms_input = true; - static float ms_holdThreadhold = 0.5f; - static float ms_releaseThreadhold = 0.5f; + static float ms_interactThreadhold = 0.8f; + static float ms_gripThreadhold = 0.4f; static MelonLoader.MelonPreferences_Category ms_category = null; static List ms_entries = null; @@ -63,8 +63,8 @@ namespace ml_lme static public event Action HeadOffsetChange; static public event Action TrackElbowsChange; static public event Action InputChange; - static public event Action HoldThreadholdChange; - static public event Action ReleaseThreadholdChange; + static public event Action InteractThreadholdChange; + static public event Action GripThreadholdChange; internal static void Init() { @@ -88,8 +88,8 @@ namespace ml_lme ms_category.CreateEntry(ModSetting.HeadZ.ToString(), 15), ms_category.CreateEntry(ModSetting.TrackElbows.ToString(), true), ms_category.CreateEntry(ModSetting.Input.ToString(), true), - ms_category.CreateEntry(ModSetting.HoldThreadhold.ToString(), 50), - ms_category.CreateEntry(ModSetting.ReleaseThreadhold.ToString(), 50), + ms_category.CreateEntry(ModSetting.InteractThreadhold.ToString(), 80), + ms_category.CreateEntry(ModSetting.GripThreadhold.ToString(), 40), }; Load(); @@ -144,8 +144,8 @@ namespace ml_lme ) * 0.01f; ms_trackElbows = (bool)ms_entries[(int)ModSetting.TrackElbows].BoxedValue; ms_input = (bool)ms_entries[(int)ModSetting.Input].BoxedValue; - ms_holdThreadhold = (int)ms_entries[(int)ModSetting.HoldThreadhold].BoxedValue * 0.01f; - ms_releaseThreadhold = (int)ms_entries[(int)ModSetting.ReleaseThreadhold].BoxedValue * 0.01f; + ms_interactThreadhold = (int)ms_entries[(int)ModSetting.InteractThreadhold].BoxedValue * 0.01f; + ms_gripThreadhold = (int)ms_entries[(int)ModSetting.GripThreadhold].BoxedValue * 0.01f; } static void OnToggleUpdate(string p_name, string p_value) @@ -265,16 +265,16 @@ namespace ml_lme HeadOffsetChange?.Invoke(ms_headOffset); } break; - case ModSetting.HoldThreadhold: + case ModSetting.InteractThreadhold: { - ms_holdThreadhold = int.Parse(p_value) * 0.01f; - HoldThreadholdChange?.Invoke(ms_holdThreadhold); + ms_interactThreadhold = int.Parse(p_value) * 0.01f; + InteractThreadholdChange?.Invoke(ms_interactThreadhold); } break; - case ModSetting.ReleaseThreadhold: + case ModSetting.GripThreadhold: { - ms_releaseThreadhold = int.Parse(p_value) * 0.01f; - ReleaseThreadholdChange?.Invoke(ms_releaseThreadhold); + ms_gripThreadhold = int.Parse(p_value) * 0.01f; + GripThreadholdChange?.Invoke(ms_gripThreadhold); } break; } @@ -341,13 +341,13 @@ namespace ml_lme { get => ms_input; } - public static float HoldThreadhold + public static float InteractThreadhold { - get => ms_holdThreadhold; + get => ms_interactThreadhold; } - public static float ReleaseThreadhold + public static float GripThreadhold { - get => ms_releaseThreadhold; + get => ms_gripThreadhold; } } } diff --git a/ml_lme/Utils.cs b/ml_lme/Utils.cs index 1a05cef..a113e64 100644 --- a/ml_lme/Utils.cs +++ b/ml_lme/Utils.cs @@ -10,9 +10,10 @@ namespace ml_lme static readonly Quaternion ms_hmdRotationFix = new Quaternion(0f, 0.7071068f, 0.7071068f, 0f); static readonly Quaternion ms_screentopRotationFix = new Quaternion(0f, 0f, -1f, 0f); - public static bool AreKnucklesInUse() => PlayerSetup.Instance._trackerManager.trackerNames.Contains("knuckles"); - public static bool IsInVR() => ((ABI_RC.Core.Savior.CheckVR.Instance != null) && ABI_RC.Core.Savior.CheckVR.Instance.hasVrDeviceLoaded); + public static bool AreKnucklesInUse() => PlayerSetup.Instance._trackerManager.trackerNames.Contains("knuckles"); + public static bool IsLeftHandTracked() => ((VRTrackerManager.Instance.leftHand != null) && VRTrackerManager.Instance.leftHand.active); + public static bool IsRightHandTracked() => ((VRTrackerManager.Instance.rightHand != null) && VRTrackerManager.Instance.rightHand.active); public static Matrix4x4 GetMatrix(this Transform p_transform, bool p_pos = true, bool p_rot = true, bool p_scl = false) { diff --git a/ml_lme/resources/menu.js b/ml_lme/resources/menu.js index 8b8cd52..3a54314 100644 --- a/ml_lme/resources/menu.js +++ b/ml_lme/resources/menu.js @@ -393,16 +393,16 @@ function inp_dropdown_mod_lme(_obj, _callbackName) {
-
Hold gesture threadhold:
+
Interact gesture threadhold:
-
+
-
Release gesture threadhold:
+
Grip gesture threadhold:
-
+
`; From 77b5362a128ed634fccb1588d112fb2c9d45b295 Mon Sep 17 00:00:00 2001 From: SDraw Date: Wed, 1 Feb 2023 09:50:37 +0000 Subject: [PATCH 26/32] Update README.md --- ml_lme/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/ml_lme/README.md b/ml_lme/README.md index b9c5322..00f797c 100644 --- a/ml_lme/README.md +++ b/ml_lme/README.md @@ -22,6 +22,5 @@ Available mod's settings in `Settings - Implementation - Leap Motion Tracking`: * **Fingers tracking only:** apply only fingers tracking, disabled by default. * **Model visibility:** show Leap Motion controller model, useful for tracking visualizing, disabled by default. * **Interaction input:** enables in-game interactions (props, menu and etc.); `true` by default. - * Note: Suggested to use with disabled `Settings - Input & Key-Bindings - Use grip to grab`. * **Interact gesture threadhold:** activation limit for interaction based on hand gesture; 80 by default. * **Grip gesture threadhold:** activation limit for grip based on hand gesture; 40 by default. From 0a0da79eaa0f9514f00d160ff798113598f2d812 Mon Sep 17 00:00:00 2001 From: SDraw Date: Mon, 6 Feb 2023 22:49:23 +0000 Subject: [PATCH 27/32] Update LeapTracked.cs --- ml_lme/LeapTracked.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ml_lme/LeapTracked.cs b/ml_lme/LeapTracked.cs index 167ba6d..d7a70fe 100644 --- a/ml_lme/LeapTracked.cs +++ b/ml_lme/LeapTracked.cs @@ -275,11 +275,11 @@ namespace ml_lme Transform l_hand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand); if(l_hand != null) - m_leftHandTarget.localRotation = ((m_vrIK != null) ? ms_offsetLeft : ms_offsetLeftDesktop) * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_hand.GetMatrix()).rotation; + m_leftHandTarget.localRotation = (m_inVR ? ms_offsetLeft : ms_offsetLeftDesktop) * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_hand.GetMatrix()).rotation; l_hand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand); if(l_hand != null) - m_rightHandTarget.localRotation = ((m_vrIK != null) ? ms_offsetRight : ms_offsetRightDesktop) * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_hand.GetMatrix()).rotation; + m_rightHandTarget.localRotation = (m_inVR ? ms_offsetRight : ms_offsetRightDesktop) * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_hand.GetMatrix()).rotation; if(m_vrIK == null) { From afe64721bff61861dd9a6135e5405db410e09104 Mon Sep 17 00:00:00 2001 From: SDraw Date: Wed, 8 Feb 2023 00:34:20 +0300 Subject: [PATCH 28/32] Original targets caching --- ml_lme/GestureMatcher.cs | 1 - ml_lme/LeapTracked.cs | 108 +++++++++++++++++++++------------------ 2 files changed, 59 insertions(+), 50 deletions(-) diff --git a/ml_lme/GestureMatcher.cs b/ml_lme/GestureMatcher.cs index 550af8f..9b93c24 100644 --- a/ml_lme/GestureMatcher.cs +++ b/ml_lme/GestureMatcher.cs @@ -4,7 +4,6 @@ namespace ml_lme { static class GestureMatcher { - readonly static Vector2[] ms_fingerLimits = { new Vector2(-50f, 0f), diff --git a/ml_lme/LeapTracked.cs b/ml_lme/LeapTracked.cs index d7a70fe..443e51f 100644 --- a/ml_lme/LeapTracked.cs +++ b/ml_lme/LeapTracked.cs @@ -18,16 +18,18 @@ namespace ml_lme VRIK m_vrIK = null; Vector2 m_armsWeights = Vector2.zero; bool m_inVR = false; - Transform m_origElbowLeft = null; - Transform m_origElbowRight = null; Transform m_hips = null; + Transform m_origLeftHand = null; + Transform m_origRightHand = null; + Transform m_origLeftElbow = null; + Transform m_origRightElbow = null; bool m_enabled = true; bool m_fingersOnly = false; bool m_trackElbows = true; - ArmIK m_leftIK = null; - ArmIK m_rightIK = null; + ArmIK m_leftArmIK = null; + ArmIK m_rightArmIK = null; HumanPoseHandler m_poseHandler = null; HumanPose m_pose; Transform m_leftHandTarget = null; @@ -87,10 +89,10 @@ namespace ml_lme { m_trackElbows = p_state; - if((m_leftIK != null) && (m_rightIK != null)) + if((m_leftArmIK != null) && (m_rightArmIK != null)) { - m_leftIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f); - m_rightIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f); + m_leftArmIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f); + m_rightArmIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f); } RestoreVRIK(); @@ -102,17 +104,17 @@ namespace ml_lme { GestureMatcher.LeapData l_data = LeapManager.GetInstance().GetLatestData(); - if((m_leftIK != null) && (m_rightIK != null)) + if((m_leftArmIK != null) && (m_rightArmIK != null)) { - m_leftIK.solver.IKPositionWeight = Mathf.Lerp(m_leftIK.solver.IKPositionWeight, (l_data.m_leftHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); - m_leftIK.solver.IKRotationWeight = Mathf.Lerp(m_leftIK.solver.IKRotationWeight, (l_data.m_leftHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_leftArmIK.solver.IKPositionWeight = Mathf.Lerp(m_leftArmIK.solver.IKPositionWeight, (l_data.m_leftHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_leftArmIK.solver.IKRotationWeight = Mathf.Lerp(m_leftArmIK.solver.IKRotationWeight, (l_data.m_leftHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); if(m_trackElbows) - m_leftIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_leftIK.solver.arm.bendGoalWeight, (l_data.m_leftHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_leftArmIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_leftArmIK.solver.arm.bendGoalWeight, (l_data.m_leftHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); - m_rightIK.solver.IKPositionWeight = Mathf.Lerp(m_rightIK.solver.IKPositionWeight, (l_data.m_rightHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); - m_rightIK.solver.IKRotationWeight = Mathf.Lerp(m_rightIK.solver.IKRotationWeight, (l_data.m_rightHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_rightArmIK.solver.IKPositionWeight = Mathf.Lerp(m_rightArmIK.solver.IKPositionWeight, (l_data.m_rightHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_rightArmIK.solver.IKRotationWeight = Mathf.Lerp(m_rightArmIK.solver.IKRotationWeight, (l_data.m_rightHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); if(m_trackElbows) - m_rightIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_rightIK.solver.arm.bendGoalWeight, (l_data.m_rightHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_rightArmIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_rightArmIK.solver.arm.bendGoalWeight, (l_data.m_rightHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); } if((m_vrIK != null) && !m_fingersOnly) @@ -126,9 +128,9 @@ namespace ml_lme } if(!l_data.m_leftHand.m_present && m_leftTargetActive) { - m_vrIK.solver.leftArm.target = (m_inVR ? IKSystem.Instance.leftHandAnchor : null); - m_vrIK.solver.leftArm.bendGoal = m_origElbowLeft; - m_vrIK.solver.leftArm.bendGoalWeight = ((m_origElbowLeft != null) ? 1f : 0f); + m_vrIK.solver.leftArm.target = m_origLeftHand; + m_vrIK.solver.leftArm.bendGoal = m_origLeftElbow; + m_vrIK.solver.leftArm.bendGoalWeight = ((m_origLeftElbow != null) ? 1f : 0f); m_leftTargetActive = false; } @@ -141,9 +143,9 @@ namespace ml_lme } if(!l_data.m_rightHand.m_present && m_rightTargetActive) { - m_vrIK.solver.rightArm.target = (m_inVR ? IKSystem.Instance.rightHandAnchor : null); - m_vrIK.solver.rightArm.bendGoal = m_origElbowRight; - m_vrIK.solver.rightArm.bendGoalWeight = ((m_origElbowRight != null) ? 1f : 0f); + m_vrIK.solver.rightArm.target = m_origRightHand; + m_vrIK.solver.rightArm.bendGoal = m_origRightElbow; + m_vrIK.solver.rightArm.bendGoalWeight = ((m_origRightElbow != null) ? 1f : 0f); m_rightTargetActive = false; } } @@ -228,12 +230,14 @@ namespace ml_lme internal void OnAvatarClear() { m_vrIK = null; - m_origElbowLeft = null; - m_origElbowRight = null; + m_origLeftHand = null; + m_origRightHand = null; + m_origLeftElbow = null; + m_origRightElbow = null; m_hips = null; m_armsWeights = Vector2.zero; - m_leftIK = null; - m_rightIK = null; + m_leftArmIK = null; + m_rightArmIK = null; m_leftTargetActive = false; m_rightTargetActive = false; @@ -289,9 +293,9 @@ namespace ml_lme if(l_chest == null) l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Spine); - m_leftIK = PlayerSetup.Instance._avatar.AddComponent(); - m_leftIK.solver.isLeft = true; - m_leftIK.solver.SetChain( + m_leftArmIK = PlayerSetup.Instance._avatar.AddComponent(); + m_leftArmIK.solver.isLeft = true; + m_leftArmIK.solver.SetChain( l_chest, PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftShoulder), PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftUpperArm), @@ -299,14 +303,14 @@ namespace ml_lme PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand), PlayerSetup.Instance._animator.transform ); - m_leftIK.solver.arm.target = m_leftHandTarget; - m_leftIK.solver.arm.bendGoal = LeapTracking.GetInstance().GetLeftElbow(); - m_leftIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f); - m_leftIK.enabled = (m_enabled && !m_fingersOnly); + m_leftArmIK.solver.arm.target = m_leftHandTarget; + m_leftArmIK.solver.arm.bendGoal = LeapTracking.GetInstance().GetLeftElbow(); + m_leftArmIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f); + m_leftArmIK.enabled = (m_enabled && !m_fingersOnly); - m_rightIK = PlayerSetup.Instance._avatar.AddComponent(); - m_rightIK.solver.isLeft = false; - m_rightIK.solver.SetChain( + m_rightArmIK = PlayerSetup.Instance._avatar.AddComponent(); + m_rightArmIK.solver.isLeft = false; + m_rightArmIK.solver.SetChain( l_chest, PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightShoulder), PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightUpperArm), @@ -314,15 +318,19 @@ namespace ml_lme PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand), PlayerSetup.Instance._animator.transform ); - m_rightIK.solver.arm.target = m_rightHandTarget; - m_rightIK.solver.arm.bendGoal = LeapTracking.GetInstance().GetRightElbow(); - m_rightIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f); - m_rightIK.enabled = (m_enabled && !m_fingersOnly); + m_rightArmIK.solver.arm.target = m_rightHandTarget; + m_rightArmIK.solver.arm.bendGoal = LeapTracking.GetInstance().GetRightElbow(); + m_rightArmIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f); + m_rightArmIK.enabled = (m_enabled && !m_fingersOnly); m_poseHandler?.SetHumanPose(ref m_pose); } else { + m_origLeftHand = m_vrIK.solver.leftArm.target; + m_origRightHand = m_vrIK.solver.rightArm.target; + m_origLeftElbow = m_vrIK.solver.leftArm.bendGoal; + m_origRightElbow = m_vrIK.solver.rightArm.bendGoal; m_vrIK.solver.OnPreUpdate += this.OnIKPreUpdate; m_vrIK.solver.OnPostUpdate += this.OnIKPostUpdate; } @@ -333,8 +341,10 @@ namespace ml_lme { if(m_vrIK != null) { - m_origElbowLeft = m_vrIK.solver.leftArm.bendGoal; - m_origElbowRight = m_vrIK.solver.rightArm.bendGoal; + m_origLeftHand = m_vrIK.solver.leftArm.target; + m_origRightHand = m_vrIK.solver.rightArm.target; + m_origLeftElbow = m_vrIK.solver.leftArm.bendGoal; + m_origRightElbow = m_vrIK.solver.rightArm.bendGoal; } } @@ -368,16 +378,16 @@ namespace ml_lme { if(m_leftTargetActive) { - m_vrIK.solver.leftArm.target = (m_inVR ? IKSystem.Instance.leftHandAnchor : null); - m_vrIK.solver.leftArm.bendGoal = m_origElbowLeft; - m_vrIK.solver.leftArm.bendGoalWeight = ((m_origElbowLeft != null) ? 1f : 0f); + m_vrIK.solver.leftArm.target = m_origLeftHand; + m_vrIK.solver.leftArm.bendGoal = m_origLeftElbow; + m_vrIK.solver.leftArm.bendGoalWeight = ((m_origLeftElbow != null) ? 1f : 0f); m_leftTargetActive = false; } if(m_rightTargetActive) { - m_vrIK.solver.rightArm.target = (m_inVR ? IKSystem.Instance.rightHandAnchor : null); - m_vrIK.solver.rightArm.bendGoal = m_origElbowRight; - m_vrIK.solver.rightArm.bendGoalWeight = ((m_origElbowRight != null) ? 1f : 0f); + m_vrIK.solver.rightArm.target = m_origRightHand; + m_vrIK.solver.rightArm.bendGoal = m_origRightElbow; + m_vrIK.solver.rightArm.bendGoalWeight = ((m_origRightElbow != null) ? 1f : 0f); m_rightTargetActive = false; } } @@ -385,10 +395,10 @@ namespace ml_lme void RefreshArmIK() { - if((m_leftIK != null) && (m_rightIK != null)) + if((m_leftArmIK != null) && (m_rightArmIK != null)) { - m_leftIK.enabled = (m_enabled && !m_fingersOnly); - m_rightIK.enabled = (m_enabled && !m_fingersOnly); + m_leftArmIK.enabled = (m_enabled && !m_fingersOnly); + m_rightArmIK.enabled = (m_enabled && !m_fingersOnly); } } From ed6cfa06bc674790284f49260f1548ac6f2b1aab Mon Sep 17 00:00:00 2001 From: SDraw Date: Wed, 8 Feb 2023 00:36:06 +0300 Subject: [PATCH 29/32] "Fix" of chairs and AAS avatars --- ml_amt/Main.cs | 25 ++++++++++++++++++++++++- ml_amt/Properties/AssemblyInfo.cs | 6 +++--- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/ml_amt/Main.cs b/ml_amt/Main.cs index 450a028..9c2d33d 100644 --- a/ml_amt/Main.cs +++ b/ml_amt/Main.cs @@ -1,10 +1,11 @@ using ABI.CCK.Components; +using ABI_RC.Core; using ABI_RC.Core.Player; using ABI_RC.Systems.IK.SubSystems; using ABI_RC.Systems.MovementSystem; +using System.Collections; using System.Reflection; using UnityEngine; -using System.Collections; namespace ml_amt { @@ -69,6 +70,18 @@ namespace ml_amt null ); + // AAS overriding "fix" + HarmonyInstance.Patch( + typeof(CVRAnimatorManager).GetMethod(nameof(CVRAnimatorManager.SetOverrideAnimation), BindingFlags.Instance), + new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnAnimationOverride_Prefix), BindingFlags.Static | BindingFlags.NonPublic)), + null + ); + HarmonyInstance.Patch( + typeof(CVRAnimatorManager).GetMethod(nameof(CVRAnimatorManager.RestoreOverrideAnimation)), + new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnAnimationOverrideRestore_Prefix), BindingFlags.Static | BindingFlags.NonPublic)), + null + ); + MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); } @@ -223,5 +236,15 @@ namespace ml_amt return false; } + + static bool OnAnimationOverride_Prefix() + { + return false; + } + + static bool OnAnimationOverrideRestore_Prefix() + { + return false; + } } } diff --git a/ml_amt/Properties/AssemblyInfo.cs b/ml_amt/Properties/AssemblyInfo.cs index b79799e..1bbc069 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.2.2")] -[assembly: AssemblyFileVersion("1.2.2")] +[assembly: AssemblyVersion("1.2.3")] +[assembly: AssemblyFileVersion("1.2.3")] -[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.2.2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.2.3", "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 From f2b63303ebbe71c01555f9e6b94d8e1021f884f2 Mon Sep 17 00:00:00 2001 From: SDraw Date: Wed, 8 Feb 2023 12:08:15 +0300 Subject: [PATCH 30/32] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0d7ed85..87c9637 100644 --- a/README.md +++ b/README.md @@ -10,5 +10,5 @@ Merged set of MelonLoader mods for ChilloutVR. | Extended Game Notifications | ml_egn | 1.0.1 | Yes, update review | Working | Four Point Tracking | ml_fpt | 1.0.9 | Retired | Deprecated | In-game feature since 2022r170 update | Leap Motion Extension | ml_lme | 1.3.0 | Yes, update review | Working | -| Pickup Arm Movement | ml_pam | 1.0.0 | Yes | Working | +| Pickup Arm Movement | ml_pam | 1.0.0 | Retired | Retired | No desire for development | Server Connection Info | ml_sci | 1.0.2 | Retired | Retired | Superseded by `Extended Game Notifications` From cb26ab1e6cc2745d0659c537cca29983fc0fd987 Mon Sep 17 00:00:00 2001 From: SDraw Date: Sat, 11 Feb 2023 13:49:50 +0300 Subject: [PATCH 31/32] Automatic locomotion mass center Animated bend normal while jumping/flying Arm weights fix Mod remake --- README.md | 8 +- ml_amt/MotionTweaker.cs | 75 +++++--- ml_amt/README.md | 7 +- ml_amt/Settings.cs | 19 +- ml_amt/resources/menu.js | 7 + ml_lme/LeapTracked.cs | 20 ++- ml_lme/Properties/AssemblyInfo.cs | 6 +- ml_lme/README.md | 10 +- ml_pam/ArmMover.cs | 279 ++++++++++++++++++++++++++---- ml_pam/Main.cs | 61 +++++-- ml_pam/Properties/AssemblyInfo.cs | 7 +- ml_pam/README.md | 7 +- ml_pam/Scripts.cs | 26 +++ ml_pam/Settings.cs | 113 ++++++++++++ ml_pam/ml_pam.csproj | 15 ++ ml_pam/resources/menu.js | 209 ++++++++++++++++++++++ 16 files changed, 773 insertions(+), 96 deletions(-) create mode 100644 ml_pam/Scripts.cs create mode 100644 ml_pam/Settings.cs create mode 100644 ml_pam/resources/menu.js diff --git a/README.md b/README.md index 87c9637..9e1ab38 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,11 @@ 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.3 | Retired | Retired | Superseded by `Extended Game Notifications` -| Avatar Motion Tweaker | ml_amt | 1.2.2 | Yes | Working | +| Avatar Motion Tweaker | ml_amt | 1.2.3 | Yes, update review | Working | | Desktop Head Tracking | ml_dht | 1.1.1 | Yes | Working | | Desktop Reticle Switch | ml_drs | 1.0.0 | Yes | Working | -| Extended Game Notifications | ml_egn | 1.0.1 | Yes, update review | Working +| Extended Game Notifications | ml_egn | 1.0.1 | Yes | Working | Four Point Tracking | ml_fpt | 1.0.9 | Retired | Deprecated | In-game feature since 2022r170 update -| Leap Motion Extension | ml_lme | 1.3.0 | Yes, update review | Working | -| Pickup Arm Movement | ml_pam | 1.0.0 | Retired | Retired | No desire for development +| Leap Motion Extension | ml_lme | 1.3.1 | Yes, update review | Working | +| Pickup Arm Movement | ml_pam | 1.0.1 | Retired, update review | Working | | Server Connection Info | ml_sci | 1.0.2 | Retired | Retired | Superseded by `Extended Game Notifications` diff --git a/ml_amt/MotionTweaker.cs b/ml_amt/MotionTweaker.cs index c21e6cf..6d45664 100644 --- a/ml_amt/MotionTweaker.cs +++ b/ml_amt/MotionTweaker.cs @@ -11,8 +11,10 @@ namespace ml_amt [DisallowMultipleComponent] class MotionTweaker : MonoBehaviour { + static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f); static readonly FieldInfo ms_grounded = typeof(MovementSystem).GetField("_isGrounded", BindingFlags.NonPublic | BindingFlags.Instance); static readonly FieldInfo ms_groundedRaw = typeof(MovementSystem).GetField("_isGroundedRaw", BindingFlags.NonPublic | BindingFlags.Instance); + static readonly FieldInfo ms_hasToes = typeof(IKSolverVR).GetField("hasToes", BindingFlags.NonPublic | BindingFlags.Instance); static readonly int ms_emoteHash = Animator.StringToHash("Emote"); enum PoseState @@ -22,17 +24,18 @@ namespace ml_amt Proning } - 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 bool m_plantFeet = false; // Original plant feet float m_avatarScale = 1f; // Instantiated scale + Vector3 m_locomotionOffset = Vector3.zero; // Original locomotion offset + bool m_bendNormalLeft = false; + bool m_bendNormalRight = false; Transform m_avatarHips = null; float m_viewPointHeight = 1f; - bool m_isInVR = false; + bool m_inVR = false; bool m_avatarReady = false; bool m_compatibleAvatar = false; @@ -55,15 +58,14 @@ namespace ml_amt bool m_ikOverrideFly = true; bool m_ikOverrideJump = true; - bool m_customLocomotionOffset = false; - Vector3 m_locomotionOffset = Vector3.zero; - bool m_detectEmotes = true; bool m_emoteActive = false; bool m_followHips = true; Vector3 m_hipsToPlayer = Vector3.zero; + Vector3 m_massCenter = Vector3.zero; + readonly List m_parameters = null; internal MotionTweaker() @@ -73,7 +75,7 @@ namespace ml_amt void Start() { - m_isInVR = Utils.IsInVR(); + m_inVR = Utils.IsInVR(); Settings.IKOverrideCrouchChange += this.SetIKOverrideCrouch; Settings.CrouchLimitChange += this.SetCrouchLimit; @@ -85,6 +87,7 @@ namespace ml_amt Settings.IKOverrideJumpChange += this.SetIKOverrideJump; Settings.DetectEmotesChange += this.SetDetectEmotes; Settings.FollowHipsChange += this.SetFollowHips; + Settings.MassCenterChange += this.SetMassCenter; } void OnDestroy() @@ -99,6 +102,7 @@ namespace ml_amt Settings.IKOverrideJumpChange -= this.SetIKOverrideJump; Settings.DetectEmotesChange -= this.SetDetectEmotes; Settings.FollowHipsChange -= this.SetFollowHips; + Settings.MassCenterChange -= this.SetMassCenter; } void Update() @@ -110,7 +114,7 @@ namespace ml_amt m_moving = !Mathf.Approximately(MovementSystem.Instance.movementVector.magnitude, 0f); // Update upright - Matrix4x4 l_hmdMatrix = PlayerSetup.Instance.transform.GetMatrix().inverse * (m_isInVR ? PlayerSetup.Instance.vrHeadTracker.transform.GetMatrix() : PlayerSetup.Instance.desktopCameraRig.transform.GetMatrix()); + Matrix4x4 l_hmdMatrix = PlayerSetup.Instance.transform.GetMatrix().inverse * (m_inVR ? PlayerSetup.Instance.vrHeadTracker.transform.GetMatrix() : PlayerSetup.Instance.desktopCameraRig.transform.GetMatrix()); float l_currentHeight = Mathf.Clamp((l_hmdMatrix * ms_pointVector).y, 0f, float.MaxValue); float l_avatarScale = (m_avatarScale > 0f) ? (PlayerSetup.Instance._avatar.transform.localScale.y / m_avatarScale) : 0f; float l_avatarViewHeight = Mathf.Clamp(m_viewPointHeight * l_avatarScale, 0f, float.MaxValue); @@ -123,7 +127,7 @@ namespace ml_amt m_hipsToPlayer.Set(l_hipsToPoint.x, 0f, l_hipsToPoint.z); } - if(m_isInVR && (m_vrIk != null) && m_vrIk.enabled) + if(m_inVR && (m_vrIk != null) && m_vrIk.enabled) { if(m_adjustedMovement) { @@ -170,20 +174,20 @@ namespace ml_amt m_poseState = PoseState.Standing; m_customCrouchLimit = false; m_customProneLimit = false; - m_customLocomotionOffset = false; - m_locomotionOffset = Vector3.zero; m_avatarScale = 1f; + m_locomotionOffset = Vector3.zero; m_emoteActive = false; m_moving = false; m_hipsToPlayer = Vector3.zero; m_avatarHips = null; m_viewPointHeight = 1f; + m_massCenter = Vector3.zero; m_parameters.Clear(); } internal void OnSetupAvatar() { - m_isInVR = Utils.IsInVR(); + m_inVR = Utils.IsInVR(); m_vrIk = PlayerSetup.Instance._avatar.GetComponent(); m_locomotionLayer = PlayerSetup.Instance._animator.GetLayerIndex("Locomotion/Emotes"); m_avatarHips = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Hips); @@ -222,15 +226,31 @@ namespace ml_amt m_customProneLimit = (l_customTransform != null); m_proneLimit = m_customProneLimit ? Mathf.Clamp01(l_customTransform.localPosition.y) : Settings.ProneLimit; - l_customTransform = PlayerSetup.Instance._avatar.transform.Find("LocomotionOffset"); - m_customLocomotionOffset = (l_customTransform != null); - m_locomotionOffset = m_customLocomotionOffset ? l_customTransform.localPosition : Vector3.zero; - // Apply VRIK tweaks if(m_vrIk != null) { - if(m_customLocomotionOffset) - m_vrIk.solver.locomotion.offset = m_locomotionOffset; + m_locomotionOffset = m_vrIk.solver.locomotion.offset; + m_massCenter = m_locomotionOffset; + + if((bool)ms_hasToes.GetValue(m_vrIk.solver)) + { + Transform l_foot = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftFoot); + if(l_foot == null) + l_foot = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightFoot); + + Transform l_toe = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftToes); + if(l_toe == null) + l_toe = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightToes); + + if((l_foot != null) && (l_toe != null)) + { + Vector3 l_footPos = (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_foot.GetMatrix()) * ms_pointVector; + Vector3 l_toePos = (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_toe.GetMatrix()) * ms_pointVector; + m_massCenter = new Vector3(0f, 0f, l_toePos.z - l_footPos.z); + } + } + + m_vrIk.solver.locomotion.offset = (Settings.MassCenter ? m_massCenter : m_locomotionOffset); m_vrIk.onPreSolverUpdate.AddListener(this.OnIKPreUpdate); m_vrIk.onPostSolverUpdate.AddListener(this.OnIKPostUpdate); @@ -260,6 +280,8 @@ namespace ml_amt m_ikWeight = m_vrIk.solver.IKPositionWeight; m_locomotionWeight = m_vrIk.solver.locomotion.weight; m_plantFeet = m_vrIk.solver.plantFeet; + m_bendNormalLeft = m_vrIk.solver.leftLeg.useAnimatedBendNormal; + m_bendNormalRight = m_vrIk.solver.rightLeg.useAnimatedBendNormal; if(m_detectEmotes && m_emoteActive) m_vrIk.solver.IKPositionWeight = 0f; @@ -272,18 +294,22 @@ namespace ml_amt if(m_ikOverrideFly && MovementSystem.Instance.flying) { m_vrIk.solver.locomotion.weight = 0f; + m_vrIk.solver.leftLeg.useAnimatedBendNormal = true; + m_vrIk.solver.rightLeg.useAnimatedBendNormal = true; l_legsOverride = true; } if(m_ikOverrideJump && !m_grounded && !MovementSystem.Instance.flying) { m_vrIk.solver.locomotion.weight = 0f; + m_vrIk.solver.leftLeg.useAnimatedBendNormal = true; + m_vrIk.solver.rightLeg.useAnimatedBendNormal = true; l_legsOverride = true; } bool l_solverActive = !Mathf.Approximately(m_vrIk.solver.IKPositionWeight, 0f); - if(l_legsOverride && l_solverActive && m_followHips && (!m_moving || (m_poseState == PoseState.Proning)) && m_isInVR && !BodySystem.isCalibratedAsFullBody) + if(l_legsOverride && l_solverActive && m_followHips && (!m_moving || (m_poseState == PoseState.Proning)) && m_inVR && !BodySystem.isCalibratedAsFullBody) { m_vrIk.solver.plantFeet = false; ABI_RC.Systems.IK.IKSystem.VrikRootController.enabled = false; @@ -296,6 +322,8 @@ namespace ml_amt m_vrIk.solver.IKPositionWeight = m_ikWeight; m_vrIk.solver.locomotion.weight = m_locomotionWeight; m_vrIk.solver.plantFeet = m_plantFeet; + m_vrIk.solver.leftLeg.useAnimatedBendNormal = m_bendNormalLeft; + m_vrIk.solver.rightLeg.useAnimatedBendNormal = m_bendNormalRight; } public void SetIKOverrideCrouch(bool p_state) @@ -320,7 +348,7 @@ namespace ml_amt { m_poseTransitions = p_state; - if(!m_poseTransitions && m_avatarReady && m_isInVR) + if(!m_poseTransitions && m_avatarReady && m_inVR) { PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Crouching", false); PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Prone", false); @@ -330,7 +358,7 @@ namespace ml_amt { m_adjustedMovement = p_state; - if(!m_adjustedMovement && m_avatarReady && m_isInVR) + if(!m_adjustedMovement && m_avatarReady && m_inVR) { MovementSystem.Instance.ChangeCrouch(false); MovementSystem.Instance.ChangeProne(false); @@ -352,6 +380,11 @@ namespace ml_amt { m_followHips = p_state; } + public void SetMassCenter(bool p_state) + { + if(m_vrIk != null) + m_vrIk.solver.locomotion.offset = (Settings.MassCenter ? m_massCenter : m_locomotionOffset); + } public float GetUpright() => m_upright; public bool GetGroundedRaw() => m_groundedRaw; diff --git a/ml_amt/README.md b/ml_amt/README.md index 0489c8c..6e5482a 100644 --- a/ml_amt/README.md +++ b/ml_amt/README.md @@ -18,7 +18,7 @@ Available mod's settings in `Settings - IK - Avatar Motion Tweaker`: * Note: Can be overrided by avatar. For this avatar has to have child gameobject with name `ProneLimit`, its Y-axis location will be used as limit, should be in range [0.0, 1.0]. * **IK override while flying:** disables legs locomotion/autostep in fly mode; default value - `true`. * **IK override while jumping:** disables legs locomotion/autostep in jump; default value - `true`. -* **Follow hips on IK override:** adjust avatar position to overcome animation snapping on IK override; default value - `true`. +* **Follow hips on IK override:** adjusts avatar position to overcome animation snapping on IK override; default value - `true`. * Note: Works best with animations that have root transform position (XZ) based on center of mass. * Note: Made for four point tracking (head, hands, hips) in mind. * **Pose transitions:** allows regular avatars animator to transit in crouch/prone states; default value - `true`. @@ -26,6 +26,8 @@ Available mod's settings in `Settings - IK - Avatar Motion Tweaker`: * **Adjusted pose movement speed:** scales movement speed upon crouching/proning; default value - `true`. * **Detect animations emote tag:** disables avatar's IK entirely if current animator state has `Emote` tag; default value - `true`. * Note: Created as example for [propoused game feature](https://feedback.abinteractive.net/p/disabling-vr-ik-for-emotes-via-animator-state-tag-7b80d963-053a-41c0-86ac-e3d53c61c1e2). +* **Adjusted locomotion mass center:** automatically changes IK locomotion center if avatar has toe bones; default value - `true`. + * Note: Compatible with [DesktopVRIK](https://github.com/NotAKidOnSteam/DesktopVRIK) and [FuckToes](https://github.com/NotAKidOnSteam/FuckToes). * **Alternative avatar collider scale:** applies slightly different approach to avatar collider size change; default value - `true` Available additional parameters for AAS animator: @@ -38,8 +40,5 @@ Available additional parameters for AAS animator: * **`Moving`:** defines movement state of player * Note: Can be set as local-only (not synced) if starts with `#` character. -Additional avatars tweaks: -* If avatar has child object with name `LocomotionOffset` its local position will be used for offsetting VRIK locomotion mass center. - Additional mod's behaviour: * Overrides FBT behaviour in 4PT mode (head, hands, hips). Be sure to disable legs and knees tracking in `Settings - IK tab`. diff --git a/ml_amt/Settings.cs b/ml_amt/Settings.cs index ed548c0..12d0d83 100644 --- a/ml_amt/Settings.cs +++ b/ml_amt/Settings.cs @@ -19,7 +19,8 @@ namespace ml_amt IKOverrideJump, DetectEmotes, FollowHips, - CollisionScale + CollisionScale, + MassCenter }; static bool ms_ikOverrideCrouch = true; @@ -33,6 +34,7 @@ namespace ml_amt static bool ms_detectEmotes = true; static bool ms_followHips = true; static bool ms_collisionScale = true; + static bool ms_massCenter = true; static MelonLoader.MelonPreferences_Category ms_category = null; static List ms_entries = null; @@ -48,6 +50,7 @@ namespace ml_amt static public event Action DetectEmotesChange; static public event Action FollowHipsChange; static public event Action CollisionScaleChange; + static public event Action MassCenterChange; internal static void Init() { @@ -65,7 +68,8 @@ namespace ml_amt ms_category.CreateEntry(ModSetting.IKOverrideJump.ToString(), true), ms_category.CreateEntry(ModSetting.DetectEmotes.ToString(), true), ms_category.CreateEntry(ModSetting.FollowHips.ToString(), true), - ms_category.CreateEntry(ModSetting.CollisionScale.ToString(), true) + ms_category.CreateEntry(ModSetting.CollisionScale.ToString(), true), + ms_category.CreateEntry(ModSetting.MassCenter.ToString(), true) }; Load(); @@ -108,6 +112,7 @@ namespace ml_amt ms_detectEmotes = (bool)ms_entries[(int)ModSetting.DetectEmotes].BoxedValue; ms_followHips = (bool)ms_entries[(int)ModSetting.FollowHips].BoxedValue; ms_collisionScale = (bool)ms_entries[(int)ModSetting.CollisionScale].BoxedValue; + ms_massCenter = (bool)ms_entries[(int)ModSetting.MassCenter].BoxedValue; } static void OnSliderUpdate(string p_name, string p_value) @@ -203,6 +208,12 @@ namespace ml_amt CollisionScaleChange?.Invoke(ms_collisionScale); } break; + + case ModSetting.MassCenter: + { + ms_massCenter = bool.Parse(p_value); + MassCenterChange?.Invoke(ms_massCenter); + } break; } ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); @@ -253,5 +264,9 @@ namespace ml_amt { get => ms_collisionScale; } + public static bool MassCenter + { + get => ms_massCenter; + } } } diff --git a/ml_amt/resources/menu.js b/ml_amt/resources/menu.js index 1b6ebaa..72c85c1 100644 --- a/ml_amt/resources/menu.js +++ b/ml_amt/resources/menu.js @@ -249,6 +249,13 @@ function inp_toggle_mod_amt(_obj, _callbackName) {
+ +
+
Adjusted locomotion mass center:
+
+
+
+
Alternative avatar collider scale:
diff --git a/ml_lme/LeapTracked.cs b/ml_lme/LeapTracked.cs index 443e51f..4725404 100644 --- a/ml_lme/LeapTracked.cs +++ b/ml_lme/LeapTracked.cs @@ -16,7 +16,7 @@ namespace ml_lme static readonly Quaternion ms_offsetRightDesktop = Quaternion.Euler(0f, 270f, 0f); VRIK m_vrIK = null; - Vector2 m_armsWeights = Vector2.zero; + Vector4 m_armsWeights = Vector2.zero; bool m_inVR = false; Transform m_hips = null; Transform m_origLeftHand = null; @@ -350,14 +350,19 @@ namespace ml_lme void OnIKPreUpdate() { - m_armsWeights.Set(m_vrIK.solver.leftArm.positionWeight, m_vrIK.solver.rightArm.positionWeight); + m_armsWeights.Set( + m_vrIK.solver.leftArm.positionWeight, + m_vrIK.solver.leftArm.rotationWeight, + m_vrIK.solver.rightArm.positionWeight, + m_vrIK.solver.rightArm.rotationWeight + ); - if(m_leftTargetActive && Mathf.Approximately(m_armsWeights.x, 0f)) + if(m_leftTargetActive && (Mathf.Approximately(m_armsWeights.x, 0f) || Mathf.Approximately(m_armsWeights.y, 0f))) { m_vrIK.solver.leftArm.positionWeight = 1f; m_vrIK.solver.leftArm.rotationWeight = 1f; } - if(m_rightTargetActive && Mathf.Approximately(m_armsWeights.y, 0f)) + if(m_rightTargetActive && (Mathf.Approximately(m_armsWeights.z, 0f) || Mathf.Approximately(m_armsWeights.w, 0f))) { m_vrIK.solver.rightArm.positionWeight = 1f; m_vrIK.solver.rightArm.rotationWeight = 1f; @@ -366,10 +371,9 @@ namespace ml_lme void OnIKPostUpdate() { m_vrIK.solver.leftArm.positionWeight = m_armsWeights.x; - m_vrIK.solver.leftArm.rotationWeight = m_armsWeights.x; - - m_vrIK.solver.rightArm.positionWeight = m_armsWeights.y; - m_vrIK.solver.rightArm.rotationWeight = m_armsWeights.y; + m_vrIK.solver.leftArm.rotationWeight = m_armsWeights.y; + m_vrIK.solver.rightArm.positionWeight = m_armsWeights.z; + m_vrIK.solver.rightArm.rotationWeight = m_armsWeights.w; } void RestoreVRIK() diff --git a/ml_lme/Properties/AssemblyInfo.cs b/ml_lme/Properties/AssemblyInfo.cs index 095d7d8..c404034 100644 --- a/ml_lme/Properties/AssemblyInfo.cs +++ b/ml_lme/Properties/AssemblyInfo.cs @@ -1,10 +1,10 @@ using System.Reflection; [assembly: AssemblyTitle("LeapMotionExtension")] -[assembly: AssemblyVersion("1.3.0")] -[assembly: AssemblyFileVersion("1.3.0")] +[assembly: AssemblyVersion("1.3.1")] +[assembly: AssemblyFileVersion("1.3.1")] -[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.3.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.3.1", "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)] diff --git a/ml_lme/README.md b/ml_lme/README.md index 00f797c..663a96e 100644 --- a/ml_lme/README.md +++ b/ml_lme/README.md @@ -12,15 +12,15 @@ This mod allows you to use your Leap Motion controller for hands and fingers tra # Usage ## Settings Available mod's settings in `Settings - Implementation - Leap Motion Tracking`: -* **Enable tracking:** enable hands tracking from Leap Motion data, disabled by default. -* **Tracking mode:** set Leap Motion tracking mode, available values: `Screentop`, `Desktop` (by default), `HMD`. +* **Enable tracking:** enables/disables hands tracking from Leap Motion data, disabled by default. +* **Tracking mode:** sets Leap Motion tracking mode, available values: `Screentop`, `Desktop` (by default), `HMD`. * **Desktop offset X/Y/Z:** offset position for body attachment, (0, -45, 30) by default. -* **Attach to head:** attach hands transformation to head instead of body, disabled by default. +* **Attach to head:** attaches hands transformation to head instead of body, disabled by default. * **Head offset X/Y/Z:** offset position for head attachment (`Attach to head` is **`true`**), (0, -30, 15) by default. * **Offset angle X/Y/X:** rotation around specific axis, useful for neck mounts, 0 by default. * **Track elbows:** elbows tracking, works best in `Screentop` and `HMD` tracking modes, `true` by default. -* **Fingers tracking only:** apply only fingers tracking, disabled by default. -* **Model visibility:** show Leap Motion controller model, useful for tracking visualizing, disabled by default. +* **Fingers tracking only:** applies only fingers tracking, disabled by default. +* **Model visibility:** shows Leap Motion controller model, useful for tracking visualizing, disabled by default. * **Interaction input:** enables in-game interactions (props, menu and etc.); `true` by default. * **Interact gesture threadhold:** activation limit for interaction based on hand gesture; 80 by default. * **Grip gesture threadhold:** activation limit for grip based on hand gesture; 40 by default. diff --git a/ml_pam/ArmMover.cs b/ml_pam/ArmMover.cs index d2fd112..01db46d 100644 --- a/ml_pam/ArmMover.cs +++ b/ml_pam/ArmMover.cs @@ -1,5 +1,8 @@ using ABI.CCK.Components; +using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.Player; +using RootMotion.FinalIK; +using System.Reflection; using UnityEngine; namespace ml_pam @@ -7,57 +10,275 @@ namespace ml_pam [DisallowMultipleComponent] class ArmMover : MonoBehaviour { + const float c_offsetLimit = 0.5f; + + static readonly float[] ms_tposeMuscles = typeof(ABI_RC.Systems.IK.SubSystems.BodySystem).GetField("TPoseMuscles", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null) as float[]; static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f); - static readonly Quaternion ms_rotationOffset = Quaternion.Euler(0f, 0f, -90f); + static readonly Quaternion ms_offsetRight = Quaternion.Euler(0f, 0f, 90f); + static readonly Quaternion ms_offsetRightDesktop = Quaternion.Euler(0f, 270f, 0f); + static readonly Quaternion ms_palmToLeft = Quaternion.Euler(0f, 0f, -90f); - Animator m_animator = null; + bool m_inVR = false; + VRIK m_vrIK = null; + Vector2 m_armWeight = Vector2.zero; + Transform m_origRightHand = null; + float m_playspaceScale = 1f; - int m_mainLayer = -1; - CVRPickupObject m_target = null; + bool m_enabled = true; + ArmIK m_armIK = null; + Transform m_target = null; + Transform m_rotationTarget = null; + CVRPickupObject m_pickup = null; Matrix4x4 m_offset = Matrix4x4.identity; + bool m_targetActive = false; void Start() { - m_animator = PlayerSetup.Instance._animator; - m_mainLayer = m_animator.GetLayerIndex("Locomotion/Emotes"); + m_inVR = Utils.IsInVR(); + + m_target = new GameObject("ArmPickupTarget").transform; + m_target.parent = PlayerSetup.Instance.GetActiveCamera().transform; + m_target.localPosition = Vector3.zero; + m_target.localRotation = Quaternion.identity; + + m_rotationTarget = new GameObject("RotationTarget").transform; + m_rotationTarget.parent = m_target; + m_rotationTarget.localPosition = new Vector3(c_offsetLimit * Settings.GrabOffset, 0f, 0f); + m_rotationTarget.localRotation = Quaternion.identity; + + m_enabled = Settings.Enabled; + + Settings.EnabledChange += this.SetEnabled; + Settings.GrabOffsetChange += this.SetGrabOffset; } - void OnAnimatorIK(int p_layerIndex) + void OnDestroy() { - if((p_layerIndex == m_mainLayer) && (m_target != null)) // Only main Locomotion/Emotes layer + Settings.EnabledChange -= this.SetEnabled; + Settings.GrabOffsetChange -= this.SetGrabOffset; + } + + void Update() + { + if(m_enabled && (m_pickup != null)) { - Transform l_camera = PlayerSetup.Instance.GetActiveCamera().transform; + Matrix4x4 l_result = m_pickup.transform.GetMatrix() * m_offset; + m_target.position = l_result * ms_pointVector; + } + } - m_animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 1f); - m_animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 1f); + void OnIKPreUpdate() + { + m_armWeight.Set(m_vrIK.solver.rightArm.positionWeight, m_vrIK.solver.rightArm.rotationWeight); - switch(m_target.gripType) + if(m_targetActive && (Mathf.Approximately(m_armWeight.x, 0f) || Mathf.Approximately(m_armWeight.y, 0f))) + { + m_vrIK.solver.rightArm.positionWeight = 1f; + m_vrIK.solver.rightArm.rotationWeight = 1f; + } + } + void OnIKPostUpdate() + { + m_vrIK.solver.rightArm.positionWeight = m_armWeight.x; + m_vrIK.solver.rightArm.rotationWeight = m_armWeight.y; + } + + // Settings + void SetEnabled(bool p_state) + { + m_enabled = p_state; + + RefreshArmIK(); + if(m_enabled) + RestorePickup(); + else + RestoreVRIK(); + } + + void SetGrabOffset(float p_value) + { + if(m_rotationTarget != null) + m_rotationTarget.localPosition = new Vector3(c_offsetLimit * m_playspaceScale * p_value, 0f, 0f); + } + + // Game events + internal void OnAvatarClear() + { + m_vrIK = null; + m_origRightHand = null; + m_armIK = null; + m_targetActive = false; + } + + internal void OnAvatarSetup() + { + // Recheck if user could switch to VR + if(m_inVR != Utils.IsInVR()) + { + m_target.parent = PlayerSetup.Instance.GetActiveCamera().transform; + m_target.localPosition = Vector3.zero; + m_target.localRotation = Quaternion.identity; + } + + m_inVR = Utils.IsInVR(); + m_vrIK = PlayerSetup.Instance._animator.GetComponent(); + + if(PlayerSetup.Instance._animator.isHuman) + { + HumanPose l_currentPose = new HumanPose(); + HumanPoseHandler l_poseHandler = null; + + if(!m_inVR) { - case CVRPickupObject.GripType.Origin: - { - if(m_target.gripOrigin != null) - { - m_animator.SetIKPosition(AvatarIKGoal.RightHand, m_target.gripOrigin.position); - m_animator.SetIKRotation(AvatarIKGoal.RightHand, l_camera.rotation * ms_rotationOffset); - } - } - break; + l_poseHandler = new HumanPoseHandler(PlayerSetup.Instance._animator.avatar, PlayerSetup.Instance._avatar.transform); + l_poseHandler.GetHumanPose(ref l_currentPose); - case CVRPickupObject.GripType.Free: + HumanPose l_tPose = new HumanPose { - Matrix4x4 l_result = m_target.transform.GetMatrix() * m_offset; - m_animator.SetIKPosition(AvatarIKGoal.RightHand, l_result * ms_pointVector); - m_animator.SetIKRotation(AvatarIKGoal.RightHand, l_camera.rotation * ms_rotationOffset); + bodyPosition = l_currentPose.bodyPosition, + bodyRotation = l_currentPose.bodyRotation, + muscles = new float[l_currentPose.muscles.Length] + }; + for(int i = 0; i < l_tPose.muscles.Length; i++) + l_tPose.muscles[i] = ms_tposeMuscles[i]; + + l_poseHandler.SetHumanPose(ref l_tPose); + } + + Transform l_hand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand); + if(l_hand != null) + m_rotationTarget.localRotation = (ms_palmToLeft * (m_inVR ? ms_offsetRight : ms_offsetRightDesktop)) * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_hand.GetMatrix()).rotation; + + if(m_vrIK == null) + { + Transform l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.UpperChest); + if(l_chest == null) + l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Chest); + if(l_chest == null) + l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Spine); + + m_armIK = PlayerSetup.Instance._avatar.AddComponent(); + m_armIK.solver.isLeft = false; + m_armIK.solver.SetChain( + l_chest, + PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightShoulder), + PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightUpperArm), + PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightLowerArm), + l_hand, + PlayerSetup.Instance._animator.transform + ); + m_armIK.solver.arm.target = m_rotationTarget; + m_armIK.solver.arm.positionWeight = 1f; + m_armIK.solver.arm.rotationWeight = 1f; + m_armIK.solver.IKPositionWeight = 0f; + m_armIK.solver.IKRotationWeight = 0f; + m_armIK.enabled = m_enabled; + } + else + { + m_origRightHand = m_vrIK.solver.rightArm.target; + m_vrIK.solver.OnPreUpdate += this.OnIKPreUpdate; + m_vrIK.solver.OnPostUpdate += this.OnIKPostUpdate; + } + + l_poseHandler?.SetHumanPose(ref l_currentPose); + l_poseHandler?.Dispose(); + } + + if(m_enabled) + RestorePickup(); + } + + internal void OnPickupGrab(CVRPickupObject p_pickup, ControllerRay p_ray, Vector3 p_hit) + { + if(p_ray == ViewManager.Instance.desktopControllerRay) + { + m_pickup = p_pickup; + + // Set offsets + if(m_pickup.gripType == CVRPickupObject.GripType.Origin) + { + if(m_pickup.ikReference != null) + m_offset = (m_pickup.transform.GetMatrix().inverse * m_pickup.ikReference.GetMatrix()); + else + { + if(m_pickup.gripOrigin != null) + m_offset = m_pickup.transform.GetMatrix().inverse * m_pickup.gripOrigin.GetMatrix(); + } + } + else + m_offset = m_pickup.transform.GetMatrix().inverse * Matrix4x4.Translate(p_hit); + + if(m_enabled) + { + if((m_vrIK != null) && !m_targetActive) + { + m_vrIK.solver.rightArm.target = m_rotationTarget; + m_targetActive = true; + } + + if(m_armIK != null) + { + m_armIK.solver.IKPositionWeight = 1f; + m_armIK.solver.IKRotationWeight = 1f; } - break; } } } - public void SetTarget(CVRPickupObject p_target, Vector3 p_hit) + internal void OnPickupDrop(CVRPickupObject p_pickup) { - m_target = p_target; - m_offset = (m_target != null) ? (p_target.transform.GetMatrix().inverse * Matrix4x4.Translate(p_hit)): Matrix4x4.identity; + if(m_pickup == p_pickup) + { + m_pickup = null; + + if(m_enabled) + { + RestoreVRIK(); + + if(m_armIK != null) + { + m_armIK.solver.IKPositionWeight = 0f; + m_armIK.solver.IKRotationWeight = 0f; + } + } + } + } + + internal void OnPlayspaceScale(float p_relation) + { + m_playspaceScale = p_relation; + SetGrabOffset(Settings.GrabOffset); + } + + // Arbitrary + void RestorePickup() + { + if((m_vrIK != null) && (m_pickup != null)) + { + m_vrIK.solver.rightArm.target = m_rotationTarget; + m_targetActive = true; + } + if((m_armIK != null) && (m_pickup != null)) + { + m_armIK.solver.IKPositionWeight = 1f; + m_armIK.solver.IKRotationWeight = 1f; + } + } + + void RestoreVRIK() + { + if((m_vrIK != null) && m_targetActive) + { + m_vrIK.solver.rightArm.target = m_origRightHand; + m_targetActive = false; + } + } + + void RefreshArmIK() + { + if(m_armIK != null) + m_armIK.enabled = m_enabled; } } } diff --git a/ml_pam/Main.cs b/ml_pam/Main.cs index 3f808c9..728e91b 100644 --- a/ml_pam/Main.cs +++ b/ml_pam/Main.cs @@ -1,4 +1,5 @@ using ABI.CCK.Components; +using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.Player; using System; using System.Reflection; @@ -10,13 +11,15 @@ namespace ml_pam { static PickupArmMovement ms_instance = null; - ArmMover m_localPuller = null; + ArmMover m_localMover = null; public override void OnInitializeMelon() { if(ms_instance == null) ms_instance = this; + Settings.Init(); + HarmonyInstance.Patch( typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)), null, @@ -37,6 +40,21 @@ namespace ml_pam null, new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnCVRPickupObjectDrop_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); + HarmonyInstance.Patch( + typeof(PlayerSetup).GetMethod("SetPlaySpaceScale", BindingFlags.NonPublic | BindingFlags.Instance), + null, + new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnPlayspaceScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + ); + + MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); + } + + System.Collections.IEnumerator WaitForLocalPlayer() + { + while(PlayerSetup.Instance == null) + yield return null; + + m_localMover = PlayerSetup.Instance.gameObject.AddComponent(); } public override void OnDeinitializeMelon() @@ -50,7 +68,8 @@ namespace ml_pam { try { - m_localPuller = null; + if(m_localMover != null) + m_localMover.OnAvatarClear(); } catch(Exception e) { @@ -63,8 +82,8 @@ namespace ml_pam { try { - if(!Utils.IsInVR()) - m_localPuller = PlayerSetup.Instance._avatar.AddComponent(); + if(m_localMover != null) + m_localMover.OnAvatarSetup(); } catch(Exception e) { @@ -72,15 +91,13 @@ namespace ml_pam } } - static void OnCVRPickupObjectGrab_Postfix(ref CVRPickupObject __instance, Vector3 __2) => ms_instance?.OnCVRPickupObjectGrab(__instance, __2); - void OnCVRPickupObjectGrab(CVRPickupObject p_pickup, Vector3 p_hit) + static void OnCVRPickupObjectGrab_Postfix(ref CVRPickupObject __instance, ControllerRay __1, Vector3 __2) => ms_instance?.OnCVRPickupObjectGrab(__instance, __1, __2); + void OnCVRPickupObjectGrab(CVRPickupObject p_pickup, ControllerRay p_ray, Vector3 p_hit) { try { - if(p_pickup.IsGrabbedByMe() && (m_localPuller != null)) - { - m_localPuller.SetTarget(p_pickup, p_hit); - } + if(p_pickup.IsGrabbedByMe() && (m_localMover != null)) + m_localMover.OnPickupGrab(p_pickup, p_ray, p_hit); } catch(Exception e) { @@ -88,15 +105,27 @@ namespace ml_pam } } - static void OnCVRPickupObjectDrop_Postfix() => ms_instance?.OnCVRPickupObjectDrop(); - void OnCVRPickupObjectDrop() + static void OnCVRPickupObjectDrop_Postfix(ref CVRPickupObject __instance) => ms_instance?.OnCVRPickupObjectDrop(__instance); + void OnCVRPickupObjectDrop(CVRPickupObject p_pickup) { try { - if(m_localPuller != null) - { - m_localPuller.SetTarget(null, Vector3.zero); - } + if(m_localMover != null) + m_localMover.OnPickupDrop(p_pickup); + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } + + static void OnPlayspaceScale_Postfix(float ____avatarScaleRelation) => ms_instance?.OnPlayspaceScale(____avatarScaleRelation); + void OnPlayspaceScale(float p_relation) + { + try + { + if(m_localMover != null) + m_localMover.OnPlayspaceScale(p_relation); } catch(Exception e) { diff --git a/ml_pam/Properties/AssemblyInfo.cs b/ml_pam/Properties/AssemblyInfo.cs index a0e0b87..9a229fb 100644 --- a/ml_pam/Properties/AssemblyInfo.cs +++ b/ml_pam/Properties/AssemblyInfo.cs @@ -1,10 +1,11 @@ using System.Reflection; [assembly: AssemblyTitle("PickupArmMovement")] -[assembly: AssemblyVersion("1.0.0")] -[assembly: AssemblyFileVersion("1.0.0")] +[assembly: AssemblyVersion("1.0.1")] +[assembly: AssemblyFileVersion("1.0.1")] -[assembly: MelonLoader.MelonInfo(typeof(ml_pam.PickupArmMovement), "PickupArmMovement", "1.0.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_pam.PickupArmMovement), "PickupArmMovement", "1.0.1", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")] +[assembly: MelonLoader.MelonPriority(1)] [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_pam/README.md b/ml_pam/README.md index dceb34e..e2fe1c9 100644 --- a/ml_pam/README.md +++ b/ml_pam/README.md @@ -1,7 +1,12 @@ # Pickup Arm Movement -This mod adds arm tracking upon holding pickup. +This mod adds arm tracking upon holding pickup in desktop mode. # Installation * Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader) * Get [latest release DLL](../../../releases/latest): * Put `ml_pam.dll` in `Mods` folder of game + +# Usage +Available mod's settings in `Settings - Interactions`: +* **Enable hand movement:** enables/disables arm tracking; default value - `true`. +* **Grab offset:** offset from pickup grab point; defalut value - `25`. diff --git a/ml_pam/Scripts.cs b/ml_pam/Scripts.cs new file mode 100644 index 0000000..5509d9e --- /dev/null +++ b/ml_pam/Scripts.cs @@ -0,0 +1,26 @@ +using System; +using System.IO; +using System.Reflection; + +namespace ml_pam +{ + static class Scripts + { + public static string GetEmbeddedScript(string p_name) + { + string l_result = ""; + Assembly l_assembly = Assembly.GetExecutingAssembly(); + string l_assemblyName = l_assembly.GetName().Name; + + try + { + Stream l_libraryStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name); + StreamReader l_streadReader = new StreamReader(l_libraryStream); + l_result = l_streadReader.ReadToEnd(); + } + catch(Exception) { } + + return l_result; + } + } +} diff --git a/ml_pam/Settings.cs b/ml_pam/Settings.cs new file mode 100644 index 0000000..c3fc659 --- /dev/null +++ b/ml_pam/Settings.cs @@ -0,0 +1,113 @@ +using ABI_RC.Core.InteractionSystem; +using cohtml; +using System; +using System.Collections.Generic; + +namespace ml_pam +{ + static class Settings + { + public enum ModSetting + { + Enabled = 0, + GrabOffset + } + + static bool ms_enabled = true; + static float ms_grabOffset = 0.25f; + + static MelonLoader.MelonPreferences_Category ms_category = null; + static List ms_entries = null; + + static public event Action EnabledChange; + static public event Action GrabOffsetChange; + + internal static void Init() + { + ms_category = MelonLoader.MelonPreferences.CreateCategory("PAM"); + + ms_entries = new List() + { + ms_category.CreateEntry(ModSetting.Enabled.ToString(), ms_enabled), + ms_category.CreateEntry(ModSetting.GrabOffset.ToString(), 25), + }; + + Load(); + + MelonLoader.MelonCoroutines.Start(WaitMainMenuUi()); + } + + static System.Collections.IEnumerator WaitMainMenuUi() + { + while(ViewManager.Instance == null) + yield return null; + while(ViewManager.Instance.gameMenuView == null) + yield return null; + while(ViewManager.Instance.gameMenuView.Listener == null) + yield return null; + + ViewManager.Instance.gameMenuView.Listener.ReadyForBindings += () => + { + ViewManager.Instance.gameMenuView.View.BindCall("MelonMod_PAM_Call_InpToggle", new Action(OnToggleUpdate)); + ViewManager.Instance.gameMenuView.View.BindCall("MelonMod_PAM_Call_InpSlider", new Action(OnSliderUpdate)); + }; + ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) => + { + ViewManager.Instance.gameMenuView.View.ExecuteScript(Scripts.GetEmbeddedScript("menu.js")); + foreach(var l_entry in ms_entries) + ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSettingPAM", l_entry.DisplayName, l_entry.GetValueAsString()); + }; + } + + static void Load() + { + ms_enabled = (bool)ms_entries[(int)ModSetting.Enabled].BoxedValue; + ms_grabOffset = (int)ms_entries[(int)ModSetting.GrabOffset].BoxedValue * 0.01f; + } + + static void OnToggleUpdate(string p_name, string p_value) + { + if(Enum.TryParse(p_name, out ModSetting l_setting)) + { + switch(l_setting) + { + case ModSetting.Enabled: + { + ms_enabled = bool.Parse(p_value); + EnabledChange?.Invoke(ms_enabled); + } + break; + } + + ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); + } + } + + static void OnSliderUpdate(string p_name, string p_value) + { + if(Enum.TryParse(p_name, out ModSetting l_setting)) + { + switch(l_setting) + { + case ModSetting.GrabOffset: + { + ms_grabOffset = int.Parse(p_value) * 0.01f; + GrabOffsetChange?.Invoke(ms_grabOffset); + } + break; + } + + ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); + } + } + + public static bool Enabled + { + get => ms_enabled; + } + public static float GrabOffset + { + get => ms_grabOffset; + } + } +} diff --git a/ml_pam/ml_pam.csproj b/ml_pam/ml_pam.csproj index 23e1b5b..7250d1e 100644 --- a/ml_pam/ml_pam.csproj +++ b/ml_pam/ml_pam.csproj @@ -42,6 +42,16 @@ D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll False + + False + False + + + False + + + False + False D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\MelonLoader.dll @@ -66,8 +76,13 @@ + + + + + copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\" diff --git a/ml_pam/resources/menu.js b/ml_pam/resources/menu.js new file mode 100644 index 0000000..c4b41b2 --- /dev/null +++ b/ml_pam/resources/menu.js @@ -0,0 +1,209 @@ +// Add settings +var g_modSettingsPAM = []; + +engine.on('updateModSettingPAM', function (_name, _value) { + for (var i = 0; i < g_modSettingsPAM.length; i++) { + if (g_modSettingsPAM[i].name == _name) { + g_modSettingsPAM[i].updateValue(_value); + break; + } + } +}); + +// Modified from original `inp` types, because I have no js knowledge to hook stuff +function inp_toggle_mod_pam(_obj, _callbackName) { + this.obj = _obj; + this.callbackName = _callbackName; + this.value = _obj.getAttribute('data-current'); + this.name = _obj.id; + this.type = _obj.getAttribute('data-type'); + + var self = this; + + this.mouseDown = function (_e) { + self.value = self.value == "True" ? "False" : "True"; + self.updateState(); + } + + this.updateState = function () { + self.obj.classList.remove("checked"); + if (self.value == "True") { + self.obj.classList.add("checked"); + } + + engine.call(self.callbackName, self.name, self.value); + } + + _obj.addEventListener('mousedown', this.mouseDown); + + this.getValue = function () { + return self.value; + } + + this.updateValue = function (value) { + self.value = value; + + self.obj.classList.remove("checked"); + if (self.value == "True") { + self.obj.classList.add("checked"); + } + } + + this.updateValue(this.value); + + return { + name: this.name, + value: this.getValue, + updateValue: this.updateValue + } +} + +function inp_slider_mod_pam(_obj, _callbackName) { + this.obj = _obj; + this.callbackName = _callbackName; + this.minValue = parseFloat(_obj.getAttribute('data-min')); + this.maxValue = parseFloat(_obj.getAttribute('data-max')); + this.percent = 0; + this.value = parseFloat(_obj.getAttribute('data-current')); + this.dragActive = false; + this.name = _obj.id; + this.type = _obj.getAttribute('data-type'); + this.stepSize = _obj.getAttribute('data-stepSize') || 0; + this.format = _obj.getAttribute('data-format') || '{value}'; + + var self = this; + + if (this.stepSize != 0) + this.value = Math.round(this.value / this.stepSize) * this.stepSize; + else + this.value = Math.round(this.value); + + this.valueLabelBackground = document.createElement('div'); + this.valueLabelBackground.className = 'valueLabel background'; + this.valueLabelBackground.innerHTML = this.format.replace('{value}', this.value); + this.obj.appendChild(this.valueLabelBackground); + + this.valueBar = document.createElement('div'); + this.valueBar.className = 'valueBar'; + this.valueBar.setAttribute('style', 'width: ' + (((this.value - this.minValue) / (this.maxValue - this.minValue)) * 100) + '%;'); + this.obj.appendChild(this.valueBar); + + this.valueLabelForeground = document.createElement('div'); + this.valueLabelForeground.className = 'valueLabel foreground'; + this.valueLabelForeground.innerHTML = this.format.replace('{value}', this.value); + this.valueLabelForeground.setAttribute('style', 'width: ' + (1.0 / ((this.value - this.minValue) / (this.maxValue - this.minValue)) * 100) + '%;'); + this.valueBar.appendChild(this.valueLabelForeground); + + this.mouseDown = function (_e) { + self.dragActive = true; + self.mouseMove(_e, false); + } + + this.mouseMove = function (_e, _write) { + if (self.dragActive) { + var rect = _obj.getBoundingClientRect(); + var start = rect.left; + var end = rect.right; + self.percent = Math.min(Math.max((_e.clientX - start) / rect.width, 0), 1); + var value = self.percent; + value *= (self.maxValue - self.minValue); + value += self.minValue; + if (self.stepSize != 0) { + value = Math.round(value / self.stepSize); + self.value = value * self.stepSize; + self.percent = (self.value - self.minValue) / (self.maxValue - self.minValue); + } + else + self.value = Math.round(value); + + self.valueBar.setAttribute('style', 'width: ' + (self.percent * 100) + '%;'); + self.valueLabelForeground.setAttribute('style', 'width: ' + (1.0 / self.percent * 100) + '%;'); + self.valueLabelBackground.innerHTML = self.valueLabelForeground.innerHTML = self.format.replace('{value}', self.value); + + engine.call(self.callbackName, self.name, "" + self.value); + self.displayImperial(); + } + } + + this.mouseUp = function (_e) { + self.mouseMove(_e, true); + self.dragActive = false; + } + + _obj.addEventListener('mousedown', this.mouseDown); + document.addEventListener('mousemove', this.mouseMove); + document.addEventListener('mouseup', this.mouseUp); + + this.getValue = function () { + return self.value; + } + + this.updateValue = function (value) { + if (self.stepSize != 0) + self.value = Math.round(value * self.stepSize) / self.stepSize; + else + self.value = Math.round(value); + self.percent = (self.value - self.minValue) / (self.maxValue - self.minValue); + self.valueBar.setAttribute('style', 'width: ' + (self.percent * 100) + '%;'); + self.valueLabelForeground.setAttribute('style', 'width: ' + (1.0 / self.percent * 100) + '%;'); + self.valueLabelBackground.innerHTML = self.valueLabelForeground.innerHTML = self.format.replace('{value}', self.value); + self.displayImperial(); + } + + this.displayImperial = function () { + var displays = document.querySelectorAll('.imperialDisplay'); + for (var i = 0; i < displays.length; i++) { + var binding = displays[i].getAttribute('data-binding'); + if (binding == self.name) { + var realFeet = ((self.value * 0.393700) / 12); + var feet = Math.floor(realFeet); + var inches = Math.floor((realFeet - feet) * 12); + displays[i].innerHTML = feet + "'" + inches + ''''; + } + } + } + + return { + name: this.name, + value: this.getValue, + updateValue: this.updateValue + } +} + +// Add own menu +{ + let l_block = document.createElement('div'); + l_block.innerHTML = ` +
+
Pickup Arm Mover
+
+
+ +
+
Enable hand movement:
+
+
+
+
+ +
+
Grab offset:
+
+
+
+
+ `; + document.getElementById('settings-interaction').appendChild(l_block); + + // Update toggles in new menu block + let l_toggles = l_block.querySelectorAll('.inp_toggle'); + for (var i = 0; i < l_toggles.length; i++) { + g_modSettingsPAM[g_modSettingsPAM.length] = new inp_toggle_mod_pam(l_toggles[i], 'MelonMod_PAM_Call_InpToggle'); + } + + // Update sliders in new menu block + let l_sliders = l_block.querySelectorAll('.inp_slider'); + for (var i = 0; i < l_sliders.length; i++) { + g_modSettingsPAM[g_modSettingsPAM.length] = new inp_slider_mod_pam(l_sliders[i], 'MelonMod_PAM_Call_InpSlider'); + } +} From 24699622e5e4e51af48b84ec9846cfa4330a2dcc Mon Sep 17 00:00:00 2001 From: SDraw Date: Mon, 13 Feb 2023 11:47:53 +0300 Subject: [PATCH 32/32] Override prevention option --- ml_amt/Main.cs | 4 ++-- ml_amt/README.md | 2 ++ ml_amt/Settings.cs | 23 ++++++++++++++++++++--- ml_amt/resources/menu.js | 7 +++++++ 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/ml_amt/Main.cs b/ml_amt/Main.cs index 9c2d33d..c6aeae2 100644 --- a/ml_amt/Main.cs +++ b/ml_amt/Main.cs @@ -239,12 +239,12 @@ namespace ml_amt static bool OnAnimationOverride_Prefix() { - return false; + return !Settings.OverrideFix; } static bool OnAnimationOverrideRestore_Prefix() { - return false; + return !Settings.OverrideFix; } } } diff --git a/ml_amt/README.md b/ml_amt/README.md index 6e5482a..c49dd7d 100644 --- a/ml_amt/README.md +++ b/ml_amt/README.md @@ -29,6 +29,8 @@ Available mod's settings in `Settings - IK - Avatar Motion Tweaker`: * **Adjusted locomotion mass center:** automatically changes IK locomotion center if avatar has toe bones; default value - `true`. * Note: Compatible with [DesktopVRIK](https://github.com/NotAKidOnSteam/DesktopVRIK) and [FuckToes](https://github.com/NotAKidOnSteam/FuckToes). * **Alternative avatar collider scale:** applies slightly different approach to avatar collider size change; default value - `true` +* **Prevent Unity animation override:** disables overriding of animations at runtime for avatars with AAS; default value - `false`. + * Note: This options is made for "fix" of [broken animator issues with chairs and combat worlds](https://feedback.abinteractive.net/p/gestures-getting-stuck-locally-upon-entering-vehicles-chairs). Available additional parameters for AAS animator: * **`Upright`:** defines linear coefficient between current viewpoint height and avatar's viewpoint height; float, range - [0.0, 1.0]. diff --git a/ml_amt/Settings.cs b/ml_amt/Settings.cs index 12d0d83..c01f273 100644 --- a/ml_amt/Settings.cs +++ b/ml_amt/Settings.cs @@ -20,7 +20,8 @@ namespace ml_amt DetectEmotes, FollowHips, CollisionScale, - MassCenter + MassCenter, + OverrideFix }; static bool ms_ikOverrideCrouch = true; @@ -35,6 +36,7 @@ namespace ml_amt static bool ms_followHips = true; static bool ms_collisionScale = true; static bool ms_massCenter = true; + static bool ms_overrideFix = false; static MelonLoader.MelonPreferences_Category ms_category = null; static List ms_entries = null; @@ -51,6 +53,7 @@ namespace ml_amt static public event Action FollowHipsChange; static public event Action CollisionScaleChange; static public event Action MassCenterChange; + static public event Action OverrideFixChange; internal static void Init() { @@ -69,7 +72,8 @@ namespace ml_amt ms_category.CreateEntry(ModSetting.DetectEmotes.ToString(), true), ms_category.CreateEntry(ModSetting.FollowHips.ToString(), true), ms_category.CreateEntry(ModSetting.CollisionScale.ToString(), true), - ms_category.CreateEntry(ModSetting.MassCenter.ToString(), true) + ms_category.CreateEntry(ModSetting.MassCenter.ToString(), true), + ms_category.CreateEntry(ModSetting.OverrideFix.ToString(), false) }; Load(); @@ -113,6 +117,7 @@ namespace ml_amt ms_followHips = (bool)ms_entries[(int)ModSetting.FollowHips].BoxedValue; ms_collisionScale = (bool)ms_entries[(int)ModSetting.CollisionScale].BoxedValue; ms_massCenter = (bool)ms_entries[(int)ModSetting.MassCenter].BoxedValue; + ms_overrideFix = (bool)ms_entries[(int)ModSetting.OverrideFix].BoxedValue; } static void OnSliderUpdate(string p_name, string p_value) @@ -213,7 +218,15 @@ namespace ml_amt { ms_massCenter = bool.Parse(p_value); MassCenterChange?.Invoke(ms_massCenter); - } break; + } + break; + + case ModSetting.OverrideFix: + { + ms_overrideFix = bool.Parse(p_value); + OverrideFixChange?.Invoke(ms_overrideFix); + } + break; } ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); @@ -268,5 +281,9 @@ namespace ml_amt { get => ms_massCenter; } + public static bool OverrideFix + { + get => ms_overrideFix; + } } } diff --git a/ml_amt/resources/menu.js b/ml_amt/resources/menu.js index 72c85c1..8e1e71c 100644 --- a/ml_amt/resources/menu.js +++ b/ml_amt/resources/menu.js @@ -263,6 +263,13 @@ function inp_toggle_mod_amt(_obj, _callbackName) {
+ +
+
Prevent Unity animation override (chairs, etc.):
+
+
+
+
`; document.getElementById('settings-ik').appendChild(l_block);