diff --git a/ml_prm/Main.cs b/ml_prm/Main.cs index a8abb8f..cb01968 100644 --- a/ml_prm/Main.cs +++ b/ml_prm/Main.cs @@ -1,13 +1,14 @@ -using ABI_RC.Core; +using ABI.CCK.Components; +using ABI_RC.Core; using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.Player; +using ABI_RC.Core.Util.AssetFiltering; using ABI_RC.Systems.IK.SubSystems; +using ABI_RC.Systems.MovementSystem; using System; using System.Collections.Generic; -using System.Reflection; -using ABI_RC.Core.Util.AssetFiltering; -using ABI.CCK.Components; using System.Linq; +using System.Reflection; namespace ml_prm { @@ -54,6 +55,11 @@ namespace ml_prm new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnCombatDown_Prefix), BindingFlags.Static | BindingFlags.NonPublic)), null ); + HarmonyInstance.Patch( + typeof(MovementSystem).GetMethod(nameof(MovementSystem.ToggleFlight)), + null, + new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnToggleFlight_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + ); // Whitelist the toggle script (typeof(SharedFilter).GetField("_localComponentWhitelist", BindingFlags.NonPublic | BindingFlags.Static)?.GetValue(null) as HashSet)?.Add(typeof(RagdollToggle)); @@ -77,6 +83,7 @@ namespace ml_prm m_localController = PlayerSetup.Instance.gameObject.AddComponent(); } + // Patches static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear(); void OnAvatarClear() { @@ -164,5 +171,19 @@ namespace ml_prm MelonLoader.MelonLogger.Error(e); } } + + static void OnToggleFlight_Postfix() => ms_instance?.OnToggleFlight(); + void OnToggleFlight() + { + try + { + if(m_localController != null) + m_localController.OnToggleFlight(); + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } } } diff --git a/ml_prm/README.md b/ml_prm/README.md index 992788b..c81013e 100644 --- a/ml_prm/README.md +++ b/ml_prm/README.md @@ -58,7 +58,6 @@ Available methods: * ```void SwitchRagdoll()``` # Notes -* Not suggested to activate fly mode with enabled ragdoll state. * If ragdoll state is enabled during emote, remote players see whole emote playing while local player sees ragdolling. It's tied to how game handles remote players, currently can be prevented with (choose one): * Renaming avatar emote animations to not have default name or containing `Emote` substring. * Holding any movement key right after activating ragdoll state. diff --git a/ml_prm/RagdollController.cs b/ml_prm/RagdollController.cs index 602e56e..52231d3 100644 --- a/ml_prm/RagdollController.cs +++ b/ml_prm/RagdollController.cs @@ -102,7 +102,7 @@ namespace ml_prm void Update() { - if(m_enabled && m_avatarReady) + if(m_avatarReady && m_enabled) { Vector3 l_dif = m_puppetReferences.hips.position - m_ragdollLastPos; PlayerSetup.Instance.transform.position += l_dif; @@ -110,17 +110,17 @@ namespace ml_prm m_ragdollLastPos = m_puppetReferences.hips.position; } - if(!m_enabled && m_avatarReady) + if(m_avatarReady && !m_enabled) { Vector3 l_pos = PlayerSetup.Instance.transform.position; m_velocity = (m_velocity + (l_pos - m_lastPosition) / Time.deltaTime) * 0.5f; m_lastPosition = l_pos; } - if(m_avatarReady && !m_reachedGround && MovementSystem.Instance.IsGrounded()) - m_reachedGround = true; + if(m_avatarReady && !m_reachedGround) + m_reachedGround = MovementSystem.Instance.IsGrounded(); - if(m_enabled && m_avatarReady && BodySystem.isCalibratedAsFullBody) + if(m_avatarReady && m_enabled && BodySystem.isCalibratedAsFullBody && !BodySystem.isCalibrating) BodySystem.TrackingPositionWeight = 0f; if(m_avatarReady && m_enabled && Settings.AutoRecover) @@ -139,20 +139,26 @@ namespace ml_prm if((m_avatarRagdollToggle != null) && m_avatarRagdollToggle.isActiveAndEnabled && m_avatarRagdollToggle.shouldOverride && (m_enabled != m_avatarRagdollToggle.isOn)) SwitchRagdoll(); - if((m_customTrigger != null) && m_customTrigger.GetStateWithReset() && !m_enabled && m_avatarReady && Settings.PointersReaction) + if((m_customTrigger != null) && m_customTrigger.GetStateWithReset() && m_avatarReady && !m_enabled && Settings.PointersReaction) SwitchRagdoll(); } void LateUpdate() { - if(m_enabled && m_avatarReady) + if(m_avatarReady && m_enabled) { - if(BodySystem.isCalibratedAsFullBody) + if(BodySystem.isCalibratedAsFullBody && !BodySystem.isCalibrating) BodySystem.TrackingPositionWeight = 0f; foreach(var l_link in m_boneLinks) l_link.Item1.CopyGlobal(l_link.Item2); } + + if(m_avatarReady && !m_enabled && (m_vrIK != null)) + { + foreach(var l_link in m_boneLinks) + l_link.Item2.CopyGlobal(l_link.Item1); + } } // Game events @@ -285,19 +291,19 @@ namespace ml_prm internal void OnSeatSitDown(CVRSeat p_seat) { - if(m_enabled && m_avatarReady && !p_seat.occupied) + if(m_avatarReady && m_enabled && !p_seat.occupied) SwitchRagdoll(); } internal void OnStartCalibration() { - if(m_enabled && m_avatarReady) + if(m_avatarReady && m_enabled) SwitchRagdoll(); } internal void OnWorldSpawn() { - if(m_enabled && m_avatarReady) + if(m_avatarReady && m_enabled) SwitchRagdoll(); OnGravityChange(Settings.Gravity); @@ -306,7 +312,13 @@ namespace ml_prm internal void OnCombatDown() { - if(!m_enabled && m_avatarReady && Settings.CombatReaction) + if(m_avatarReady && !m_enabled && Settings.CombatReaction) + SwitchRagdoll(); + } + + internal void OnToggleFlight() + { + if(m_avatarReady && m_enabled && MovementSystem.Instance.flying) SwitchRagdoll(); } @@ -354,8 +366,9 @@ namespace ml_prm { if(m_avatarReady) { + bool l_gravity = (!Utils.IsWorldSafe() || p_state); foreach(Rigidbody l_body in m_rigidBodies) - l_body.useGravity = (!Utils.IsWorldSafe() || p_state); + l_body.useGravity = l_gravity; } } void OnPhysicsMaterialChange(bool p_state) @@ -400,6 +413,9 @@ namespace ml_prm PlayerSetup.Instance.transform.rotation = Quaternion.Euler(0f, l_rot.eulerAngles.y, 0f); } + if(MovementSystem.Instance.flying) + MovementSystem.Instance.ChangeFlight(false); + MovementSystem.Instance.SetImmobilized(true); PlayerSetup.Instance.animatorManager.SetAnimatorParameterTrigger("CancelEmote"); m_ragdolledParameter.SetValue(true); @@ -410,8 +426,11 @@ namespace ml_prm m_reachedGround = false; // Force player to unragdoll and reach ground first // Copy before set to non-kinematic to reduce stacked forces - foreach(var l_link in m_boneLinks) - l_link.Item2.CopyGlobal(l_link.Item1); + if(m_vrIK == null) + { + foreach(var l_link in m_boneLinks) + l_link.Item2.CopyGlobal(l_link.Item1); + } foreach(Rigidbody l_body in m_rigidBodies) l_body.isKinematic = false; @@ -451,7 +470,8 @@ namespace ml_prm l_body.isKinematic = true; PlayerSetup.Instance.transform.position = m_puppetReferences.hips.position; - PlayerSetup.Instance.transform.position -= (PlayerSetup.Instance.transform.rotation * PlayerSetup.Instance._avatar.transform.localPosition); + if(m_inVr) + PlayerSetup.Instance.transform.position -= (PlayerSetup.Instance.transform.rotation * PlayerSetup.Instance._avatar.transform.localPosition); foreach(Collider l_collider in m_colliders) l_collider.enabled = false; @@ -466,7 +486,7 @@ namespace ml_prm } } - public bool IsRagdolled() => (m_enabled && m_avatarReady); + public bool IsRagdolled() => (m_avatarReady && m_enabled); static Transform CloneTransform(Transform p_source, Transform p_parent, string p_name) {