From c7556b3bfe59f5a7dcec029e6b2492ed6e301ae1 Mon Sep 17 00:00:00 2001 From: SDraw Date: Sun, 11 Dec 2022 16:39:43 +0300 Subject: [PATCH] IK shenanigans --- README.md | 4 +-- ml_amt/Main.cs | 49 +++++++++++++++++++++++++++++++ ml_amt/MotionTweaker.cs | 36 ++++++++++++++++++----- ml_amt/Properties/AssemblyInfo.cs | 2 +- ml_amt/README.md | 3 ++ 5 files changed, 84 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 6625a0b..a33c7d6 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,6 @@ Testing branch for experimental version of ChilloutVR. **Build 2022r170ex3:** | Full name | Short name | Latest version | Current Status | Notes | |-----------|------------|----------------|----------------|-------| -| Avatar Motion Tweaker | ml_amt | 1.1.9-experimental | Partially working | FBT behaviour problems +| Avatar Motion Tweaker | ml_amt | 1.1.9-ex2 | Working | | Four Point Tracking | ml_fpt | 1.0.9 | Deprecated | In-game feature | -| Leap Motion Extension | ml_lme | 1.2.8-ex2 | Yes | Working | +| Leap Motion Extension | ml_lme | 1.2.8-ex2 | Working | diff --git a/ml_amt/Main.cs b/ml_amt/Main.cs index ea622e4..652e17b 100644 --- a/ml_amt/Main.cs +++ b/ml_amt/Main.cs @@ -9,6 +9,8 @@ public class AvatarMotionTweaker : MelonLoader.MelonMod MotionTweaker m_localTweaker = null; + static int ms_calibrationCounts = 0; + public override void OnInitializeMelon() { if(ms_instance == null) @@ -26,6 +28,21 @@ public override void OnInitializeMelon() null, new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); + HarmonyInstance.Patch( + typeof(ABI_RC.Systems.IK.SubSystems.BodySystem).GetMethod(nameof(ABI_RC.Systems.IK.SubSystems.BodySystem.Calibrate)), + null, + new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnCalibrate_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + ); + HarmonyInstance.Patch( + typeof(ABI_RC.Systems.IK.SubSystems.BodySystem).GetMethod(nameof(ABI_RC.Systems.IK.SubSystems.BodySystem.FBTAvailable)), + new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnFBTAvailable_Prefix), BindingFlags.Static | BindingFlags.NonPublic)), + null + ); + HarmonyInstance.Patch( + typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ReCalibrateAvatar)), + new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnReCalibrateAvatar_Prefix), BindingFlags.Static | BindingFlags.NonPublic)), + null + ); MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); } @@ -75,6 +92,8 @@ void OnSetupAvatar() { try { + ms_calibrationCounts = 0; + if(m_localTweaker != null) m_localTweaker.OnSetupAvatar(); } @@ -83,5 +102,35 @@ void OnSetupAvatar() 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); + } + } + + static void OnReCalibrateAvatar_Prefix() + { + MotionTweaker.ms_fptActive = false; + ms_calibrationCounts++; + } + + static bool OnFBTAvailable_Prefix(ref bool __result) + { + if(MotionTweaker.ms_fptActive || (ms_calibrationCounts == 0)) + { + __result = false; + return false; + } + return true; + } } } diff --git a/ml_amt/MotionTweaker.cs b/ml_amt/MotionTweaker.cs index 2afdce3..0a6fa2a 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; @@ -53,6 +54,7 @@ enum PoseState Transform m_avatarHips = null; float m_viewPointHeight = 1f; bool m_isInVR = false; + public static bool ms_fptActive = false; bool m_avatarReady = false; bool m_compatibleAvatar = false; @@ -137,10 +139,10 @@ void Update() 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(m_isInVR && (m_vrIk != null) && m_vrIk.enabled) @@ -255,6 +257,7 @@ public void OnAvatarClear() m_avatarHips = null; m_viewPointHeight = 1f; m_parameters.Clear(); + ms_fptActive = false; } public void OnSetupAvatar() @@ -310,13 +313,30 @@ public void OnSetupAvatar() if(m_customLocomotionOffset) m_vrIk.solver.locomotion.offset = m_locomotionOffset; - m_vrIk.solver.OnPreUpdate += this.OnIKPreUpdate; - m_vrIk.solver.OnPostUpdate += this.OnIKPostUpdate; + // Place our pre-solver listener first + m_vrIk.onPreSolverUpdate.AddListener(this.OnIKPreUpdate); + m_vrIk.onPostSolverUpdate.AddListener(this.OnIKPostUpdate); } m_avatarReady = true; } + public void OnCalibrate() + { + if(m_avatarReady && 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! + + ms_fptActive = true; + } + } + void OnIKPreUpdate() { bool l_legsOverride = false; @@ -327,7 +347,6 @@ void OnIKPreUpdate() if(m_detectEmotes && m_emoteActive) m_vrIk.solver.IKPositionWeight = 0f; - // Game doesn't manages VRIK for desktop itself anymore if((m_ikOverrideCrouch && (m_poseState != PoseState.Standing)) || (m_ikOverrideProne && (m_poseState == PoseState.Proning))) { m_vrIk.solver.locomotion.weight = 0f; @@ -347,8 +366,11 @@ void OnIKPreUpdate() 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) + 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() diff --git a/ml_amt/Properties/AssemblyInfo.cs b/ml_amt/Properties/AssemblyInfo.cs index 8d2d09b..00e0f71 100644 --- a/ml_amt/Properties/AssemblyInfo.cs +++ b/ml_amt/Properties/AssemblyInfo.cs @@ -4,7 +4,7 @@ [assembly: AssemblyVersion("1.1.9")] [assembly: AssemblyFileVersion("1.1.9")] -[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.1.9-experimental", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.1.9-ex2", "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..5f1a624 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: +* Disables FBT state in 4PT mode (head, hands, hips). Be sure to enable only hips tracking in `Settings - IK` tab.