diff --git a/README.md b/README.md
index 64e1b04..e35fe14 100644
--- a/README.md
+++ b/README.md
@@ -3,13 +3,13 @@ Merged set of MelonLoader mods for ChilloutVR.
**Table for game build 2023r172p1:**
| Full name | Short name | Latest version | Available in [CVRMA](https://github.com/knah/CVRMelonAssistant) |
|:---------:|:----------:|:--------------:| :----------------------------------------------------------------|
-| [Avatar Motion Tweaker](/ml_amt/README.md) | ml_amt | 1.3.3 [:arrow_down:](../../releases/latest/download/ml_amt.dll)| ✔ Yes
:hourglass_flowing_sand: Update review |
+| [Avatar Motion Tweaker](/ml_amt/README.md) | ml_amt | 1.3.3 [:arrow_down:](../../releases/latest/download/ml_amt.dll)| ✔ Yes |
| [Desktop Head Tracking](/ml_dht/README.md)| ml_dht | - | ✔ Yes
:warning:Broken |
-| [Leap Motion Extension](/ml_lme/README.md)| ml_lme | 1.4.3 [:arrow_down:](../../releases/latest/download/ml_lme.dll)| ✔ Yes
:hourglass_flowing_sand: Update review |
-| [Pickup Arm Movement](/ml_pam/README.md)| ml_pam | 1.0.8 [:arrow_down:](../../releases/latest/download/ml_pam.dll)| ✔ Yes
:hourglass_flowing_sand: Update review |
+| [Leap Motion Extension](/ml_lme/README.md)| ml_lme | 1.4.3 [:arrow_down:](../../releases/latest/download/ml_lme.dll)| ✔ Yes |
+| [Pickup Arm Movement](/ml_pam/README.md)| ml_pam | 1.0.8 [:arrow_down:](../../releases/latest/download/ml_pam.dll)| ✔ Yes |
| [Player Movement Copycat](/ml_pmc/README.md)| ml_pmc | 1.0.3 [:arrow_down:](../../releases/latest/download/ml_pmc.dll)| ✔ Yes |
-| [Player Ragdoll Mod](/ml_prm/README.md)| ml_prm | 1.0.10 [:arrow_down:](../../releases/latest/download/ml_prm.dll)| ✔ Yes
:hourglass_flowing_sand: Update review |
-| [Vive Extended Input](/ml_vei/README.md) | ml_vei | 1.0.0 [:arrow_down:](../../releases/latest/download/ml_vei.dll)| :hourglass_flowing_sand: On review |
+| [Player Ragdoll Mod](/ml_prm/README.md)| ml_prm | 1.0.11 [:arrow_down:](../../releases/latest/download/ml_prm.dll)| ✔ Yes
:hourglass_flowing_sand: Update review |
+| [Vive Extended Input](/ml_vei/README.md) | ml_vei | 1.0.0 [:arrow_down:](../../releases/latest/download/ml_vei.dll)| ✔ Yes |
**Archived mods:**
| Full name | Short name | Notes |
diff --git a/ml_prm/Properties/AssemblyInfo.cs b/ml_prm/Properties/AssemblyInfo.cs
index abd9de2..aae800c 100644
--- a/ml_prm/Properties/AssemblyInfo.cs
+++ b/ml_prm/Properties/AssemblyInfo.cs
@@ -1,7 +1,7 @@
-[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.0.10", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
-[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
-[assembly: MelonLoader.MelonPriority(2)]
-[assembly: MelonLoader.MelonOptionalDependencies("BTKUILib")]
-[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
-[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
-[assembly: MelonLoader.MelonAdditionalCredits("kafeijao, NotAKidOnSteam")]
+[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.0.11", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
+[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
+[assembly: MelonLoader.MelonPriority(2)]
+[assembly: MelonLoader.MelonOptionalDependencies("BTKUILib")]
+[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
+[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
+[assembly: MelonLoader.MelonAdditionalCredits("kafeijao, NotAKidOnSteam")]
diff --git a/ml_prm/README.md b/ml_prm/README.md
index 96c6aa3..e45baa6 100644
--- a/ml_prm/README.md
+++ b/ml_prm/README.md
@@ -1,68 +1,68 @@
-# Player Ragdoll Mod
-This mod turns player's avatar into ragdoll puppet.
-
-# Installation
-* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
-* Get [latest release DLL](../../../releases/latest):
- * Put `ml_prm.dll` in `Mods` folder of game
-
-# Usage
-* Press `R` to turn into ragdoll and back.
-
-Optional mod's settings page with [BTKUILib](https://github.com/BTK-Development/BTKUILib):
-* **Switch ragdoll:** turns into ragdoll state and back, made for VR usage primarily.
-* **Use hotkey:** enables/disables ragdoll state switch with `R` key; `true` by default.
-* **Use gravity:** enables/disables gravity for ragdoll; `true` by default.
- * Note: Forcibly enabled in worlds that don't allow flight.
-* **Pointers reaction:** enables ragdoll state when player collides with trigger colliders with CVRPointer component of `ragdoll` type (avatars, props and world included); `true` by default.
-* **Ignore local pointers:** enables/disables ignoring of CVRPointer components of `ragdoll` type on local player's avatar; `true` by default.
-* **Combat reaction:** enables ragdoll state upon death in worlds with combat system; `true` by default.
-* **Auto recover:** enables automatic recovering after specific time delay; `false` by default.
-* **Slipperiness:** enables/disable low friction of ragdoll; `false` by default.
- * Note: Forcibly disabled in worlds that don't allow flight.
-* **Bounciness:** enables/disable bounce force of ragdoll; `false` by default.
- * Note: Forcibly disabled in worlds that don't allow flight.
-* **View direction velocity:** apply velocity to camera view direction instead of player movement direction; `false` by default.
- * Note: Forcibly disabled in worlds that don't allow flight.
-* **Jump recover:** enables recovering from ragdoll state by jumping; `false` by default.
-* **Velocity multiplier:** velocity force multiplier based on player's movement direction; `2.0` by default.
- * Note: Limited according to world's fly multiplier.
- * Note: Forcibly set to `1.0` in worlds that don't allow flight.
-* **Movement drag:** movement resistance; `2.0` by default.
- * Note: Forcibly set to `1.0` in worlds that don't allow flight.
-* **Angular movement drag:** angular movement resistance; `2.0` by default.
-* **Recover delay:** time delay for enabled `Auto recover` in seconds; `3.0` by default.
-* **Reset settings:** resets mod settings to default.
-
-Optional mod's settings in [UIExpansionKit](https://github.com/ddakebono/ChilloutMods):
-* **Hotkey:** system key that is used to switch ragdoll state; `R` by default.
-
-Available additional parameters for AAS animator:
-* **`Ragdolled`:** defines current ragdoll state; boolean.
- * Note: Can be set as local-only (not synced) if starts with `#` character.
-
-# Unity Editor Script
-You can also trigger the ragdoll via animations on your avatar. To do this you need:
-* Download and import the `ml_prm_editor_script.unitypackage` into your unity project
-* Add the component `Ragdoll Toggle` anywhere inside of your avatar's hierarchy.
-
-Now you can animate both parameters available:
-- **Should Override:** whether the animation should override the toggled state of the ragdoll.
-- **Is On:** whether the ragdoll state is On or Off (only works if `Should Override` is also On).
-
-
-Note: In order to work the game object needs to be active and the component enabled.
-
-# Mods Integration
-You can use this mod's functions within your mod. To do this you need:
-* Add mod's dll as reference in your project
-* Access ragdoll controller with `ml_prm.RagdollController.Instance`
-
-Available methods:
-* ```bool IsRagdolled()```
-* ```void SwitchRagdoll()```
-
-# Notes
-* 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.
+# Player Ragdoll Mod
+This mod turns player's avatar into ragdoll puppet.
+
+# Installation
+* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
+* Get [latest release DLL](../../../releases/latest):
+ * Put `ml_prm.dll` in `Mods` folder of game
+
+# Usage
+* Press `R` to turn into ragdoll and back.
+
+Optional mod's settings page with [BTKUILib](https://github.com/BTK-Development/BTKUILib):
+* **Switch ragdoll:** turns into ragdoll state and back, made for VR usage primarily.
+* **Use hotkey:** enables/disables ragdoll state switch with `R` key; `true` by default.
+* **Use gravity:** enables/disables gravity for ragdoll; `true` by default.
+ * Note: Forcibly enabled in worlds that don't allow flight.
+* **Pointers reaction:** enables ragdoll state when player collides with trigger colliders and particle systems with CVRPointer component of `ragdoll` type (avatars, props and world included); `true` by default.
+* **Ignore local pointers:** enables/disables ignoring of CVRPointer components of `ragdoll` type on local player's avatar; `true` by default.
+* **Combat reaction:** enables ragdoll state upon death in worlds with combat system; `true` by default.
+* **Auto recover:** enables automatic recovering after specific time delay; `false` by default.
+* **Slipperiness:** enables/disable low friction of ragdoll; `false` by default.
+ * Note: Forcibly disabled in worlds that don't allow flight.
+* **Bounciness:** enables/disable bounce force of ragdoll; `false` by default.
+ * Note: Forcibly disabled in worlds that don't allow flight.
+* **View direction velocity:** apply velocity to camera view direction instead of player movement direction; `false` by default.
+ * Note: Forcibly disabled in worlds that don't allow flight.
+* **Jump recover:** enables recovering from ragdoll state by jumping; `false` by default.
+* **Velocity multiplier:** velocity force multiplier based on player's movement direction; `2.0` by default.
+ * Note: Limited according to world's fly multiplier.
+ * Note: Forcibly set to `1.0` in worlds that don't allow flight.
+* **Movement drag:** movement resistance; `2.0` by default.
+ * Note: Forcibly set to `1.0` in worlds that don't allow flight.
+* **Angular movement drag:** angular movement resistance; `2.0` by default.
+* **Recover delay:** time delay for enabled `Auto recover` in seconds; `3.0` by default.
+* **Reset settings:** resets mod settings to default.
+
+Optional mod's settings in [UIExpansionKit](https://github.com/ddakebono/ChilloutMods):
+* **Hotkey:** system key that is used to switch ragdoll state; `R` by default.
+
+Available additional parameters for AAS animator:
+* **`Ragdolled`:** defines current ragdoll state; boolean.
+ * Note: Can be set as local-only (not synced) if starts with `#` character.
+
+# Unity Editor Script
+You can also trigger the ragdoll via animations on your avatar. To do this you need:
+* Download and import the `ml_prm_editor_script.unitypackage` into your unity project
+* Add the component `Ragdoll Toggle` anywhere inside of your avatar's hierarchy.
+
+Now you can animate both parameters available:
+- **Should Override:** whether the animation should override the toggled state of the ragdoll.
+- **Is On:** whether the ragdoll state is On or Off (only works if `Should Override` is also On).
+
+
+Note: In order to work the game object needs to be active and the component enabled.
+
+# Mods Integration
+You can use this mod's functions within your mod. To do this you need:
+* Add mod's dll as reference in your project
+* Access ragdoll controller with `ml_prm.RagdollController.Instance`
+
+Available methods:
+* ```bool IsRagdolled()```
+* ```void SwitchRagdoll()```
+
+# Notes
+* 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 4defe7a..194a0ad 100644
--- a/ml_prm/RagdollController.cs
+++ b/ml_prm/RagdollController.cs
@@ -1,570 +1,570 @@
-using ABI.CCK.Components;
-using ABI_RC.Core.InteractionSystem;
-using ABI_RC.Core.Player;
-using ABI_RC.Core.Savior;
-using ABI_RC.Systems.IK.SubSystems;
-using ABI_RC.Systems.InputManagement;
-using ABI_RC.Systems.MovementSystem;
-using RootMotion.Dynamics;
-using RootMotion.FinalIK;
-using System.Collections.Generic;
-using UnityEngine;
-
-namespace ml_prm
-{
- [DisallowMultipleComponent]
- public class RagdollController : MonoBehaviour
- {
- const float c_defaultFriction = 0.6f;
-
- public static RagdollController Instance { get; private set; } = null;
-
- VRIK m_vrIK = null;
- float m_vrIkWeight = 1f;
- bool m_inVr = false;
-
- bool m_enabled = false;
-
- readonly List m_rigidBodies = null;
- readonly List m_colliders = null;
- Transform m_puppetRoot = null;
- Transform m_puppet = null;
- BipedRagdollReferences m_puppetReferences;
- readonly List> m_boneLinks = null;
- readonly List> m_jointAnchors = null;
-
- bool m_avatarReady = false;
- Vector3 m_lastPosition = Vector3.zero;
- Vector3 m_velocity = Vector3.zero;
- Vector3 m_ragdollLastPos = Vector3.zero;
-
- RagdollToggle m_avatarRagdollToggle = null;
- RagdollTrigger m_customTrigger = null;
- AvatarBoolParameter m_ragdolledParameter = null;
- readonly PhysicMaterial m_physicsMaterial = null;
-
- bool m_reachedGround = true;
- float m_groundedTime = 0f;
- float m_downTime = float.MinValue;
-
- internal RagdollController()
- {
- if(Instance == null)
- Instance = this;
-
- m_rigidBodies = new List();
- m_colliders = new List();
- m_boneLinks = new List>();
- m_jointAnchors = new List>();
-
- m_physicsMaterial = new PhysicMaterial("Ragdoll");
- m_physicsMaterial.dynamicFriction = c_defaultFriction;
- m_physicsMaterial.staticFriction = c_defaultFriction;
- m_physicsMaterial.frictionCombine = PhysicMaterialCombine.Average;
- m_physicsMaterial.bounciness = 0f;
- m_physicsMaterial.bounceCombine = PhysicMaterialCombine.Average;
- }
- ~RagdollController()
- {
- if(Instance == this)
- Instance = null;
- }
-
- // Unity events
- void Start()
- {
- m_inVr = Utils.IsInVR();
-
- m_puppetRoot = new GameObject("[PlayerAvatarPuppet]").transform;
- m_puppetRoot.parent = PlayerSetup.Instance.transform;
- m_puppetRoot.localPosition = Vector3.zero;
- m_puppetRoot.localRotation = Quaternion.identity;
-
- m_customTrigger = MovementSystem.Instance.proxyCollider.gameObject.AddComponent();
-
- Settings.MovementDragChange += this.OnMovementDragChange;
- Settings.AngularDragChange += this.OnAngularDragChange;
- Settings.GravityChange += this.OnGravityChange;
- Settings.SlipperinessChange += this.OnPhysicsMaterialChange;
- Settings.BouncinessChange += this.OnPhysicsMaterialChange;
- }
-
- void OnDestroy()
- {
- if(m_customTrigger != null)
- {
- Object.Destroy(m_customTrigger);
- m_customTrigger = null;
- }
-
- Settings.MovementDragChange -= this.OnMovementDragChange;
- Settings.AngularDragChange -= this.OnAngularDragChange;
- Settings.GravityChange -= this.OnGravityChange;
- Settings.SlipperinessChange -= this.OnPhysicsMaterialChange;
- Settings.BouncinessChange -= this.OnPhysicsMaterialChange;
- }
-
- void Update()
- {
- if(m_avatarReady && m_enabled)
- {
- Vector3 l_dif = m_puppetReferences.hips.position - m_ragdollLastPos;
- PlayerSetup.Instance.transform.position += l_dif;
- m_puppetReferences.hips.position -= l_dif;
- m_ragdollLastPos = m_puppetReferences.hips.position;
- }
-
- 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_reachedGround && MovementSystem.Instance.IsGrounded())
- {
- m_groundedTime += Time.deltaTime;
- if(m_groundedTime >= 0.25f)
- m_reachedGround = true;
- }
- }
-
- if(m_avatarReady && m_enabled && !BodySystem.isCalibrating)
- BodySystem.TrackingPositionWeight = 0f;
-
- if(m_avatarReady && m_enabled && Settings.AutoRecover)
- {
- m_downTime += Time.deltaTime;
- if(m_downTime >= Settings.RecoverDelay)
- {
- SwitchRagdoll();
- m_downTime = float.MinValue; // One attepmt to recover
- }
- }
-
- if((m_avatarRagdollToggle != null) && m_avatarRagdollToggle.isActiveAndEnabled && m_avatarRagdollToggle.shouldOverride && (m_enabled != m_avatarRagdollToggle.isOn))
- SwitchRagdoll();
-
- if((m_customTrigger != null) && m_customTrigger.GetStateWithReset() && m_avatarReady && !m_enabled && Settings.PointersReaction)
- SwitchRagdoll();
-
- if(Settings.Hotkey && Input.GetKeyDown(Settings.HotkeyKey) && !ViewManager.Instance.isGameMenuOpen())
- SwitchRagdoll();
-
- if(m_avatarReady && m_enabled && CVRInputManager.Instance.jump && Settings.JumpRecover)
- SwitchRagdoll();
- }
-
- void LateUpdate()
- {
- if(m_avatarReady)
- {
- if(m_enabled)
- {
- if(!BodySystem.isCalibrating)
- {
- BodySystem.TrackingPositionWeight = 0f;
-
- foreach(var l_link in m_boneLinks)
- l_link.Item1.CopyGlobal(l_link.Item2);
- }
- }
- else
- {
- foreach(var l_link in m_boneLinks)
- l_link.Item2.CopyGlobal(l_link.Item1);
- }
- }
- }
-
- // Game events
- internal void OnAvatarClear()
- {
- if(m_enabled && (MovementSystem.Instance != null))
- MovementSystem.Instance.SetImmobilized(false);
-
- if(m_puppet != null)
- Object.Destroy(m_puppet.gameObject);
- m_puppet = null;
-
- m_vrIK = null;
- m_enabled = false;
- m_avatarReady = false;
- m_avatarRagdollToggle = null;
- m_ragdolledParameter = null;
- m_rigidBodies.Clear();
- m_colliders.Clear();
- m_puppetReferences = new BipedRagdollReferences();
- m_boneLinks.Clear();
- m_jointAnchors.Clear();
- m_reachedGround = true;
- m_groundedTime = 0f;
- m_downTime = float.MinValue;
- m_puppetRoot.localScale = Vector3.one;
- }
-
- internal void OnAvatarSetup()
- {
- m_inVr = Utils.IsInVR();
-
- if(PlayerSetup.Instance._animator.isHuman)
- {
- BipedRagdollReferences l_avatarReferences = BipedRagdollReferences.FromAvatar(PlayerSetup.Instance._animator);
-
- m_puppet = new GameObject("Root").transform;
- m_puppet.parent = m_puppetRoot;
- m_puppet.localPosition = Vector3.zero;
- m_puppet.localRotation = Quaternion.identity;
-
- m_puppetReferences.root = m_puppet;
- m_puppetReferences.hips = CloneTransform(l_avatarReferences.hips, m_puppetReferences.root, "Hips");
- m_puppetReferences.spine = CloneTransform(l_avatarReferences.spine, m_puppetReferences.hips, "Spine");
-
- if(l_avatarReferences.chest != null)
- m_puppetReferences.chest = CloneTransform(l_avatarReferences.chest, m_puppetReferences.spine, "Chest");
-
- m_puppetReferences.head = CloneTransform(l_avatarReferences.head, (m_puppetReferences.chest != null) ? m_puppetReferences.chest : m_puppetReferences.spine, "Head");
-
- m_puppetReferences.leftUpperArm = CloneTransform(l_avatarReferences.leftUpperArm, (m_puppetReferences.chest != null) ? m_puppetReferences.chest : m_puppetReferences.spine, "LeftUpperArm");
- m_puppetReferences.leftLowerArm = CloneTransform(l_avatarReferences.leftLowerArm, m_puppetReferences.leftUpperArm, "LeftLowerArm");
- m_puppetReferences.leftHand = CloneTransform(l_avatarReferences.leftHand, m_puppetReferences.leftLowerArm, "LeftHand");
-
- m_puppetReferences.rightUpperArm = CloneTransform(l_avatarReferences.rightUpperArm, (m_puppetReferences.chest != null) ? m_puppetReferences.chest : m_puppetReferences.spine, "RightUpperArm");
- m_puppetReferences.rightLowerArm = CloneTransform(l_avatarReferences.rightLowerArm, m_puppetReferences.rightUpperArm, "RightLowerArm");
- m_puppetReferences.rightHand = CloneTransform(l_avatarReferences.rightHand, m_puppetReferences.rightLowerArm, "RightHand");
-
- m_puppetReferences.leftUpperLeg = CloneTransform(l_avatarReferences.leftUpperLeg, m_puppetReferences.hips, "LeftUpperLeg");
- m_puppetReferences.leftLowerLeg = CloneTransform(l_avatarReferences.leftLowerLeg, m_puppetReferences.leftUpperLeg, "LeftLowerLeg");
- m_puppetReferences.leftFoot = CloneTransform(l_avatarReferences.leftFoot, m_puppetReferences.leftLowerLeg, "LeftFoot");
-
- m_puppetReferences.rightUpperLeg = CloneTransform(l_avatarReferences.rightUpperLeg, m_puppetReferences.hips, "RightUpperLeg");
- m_puppetReferences.rightLowerLeg = CloneTransform(l_avatarReferences.rightLowerLeg, m_puppetReferences.rightUpperLeg, "RightLowerLeg");
- m_puppetReferences.rightFoot = CloneTransform(l_avatarReferences.rightFoot, m_puppetReferences.rightLowerLeg, "RightFoot");
-
- // Move to world origin to overcome possible issues, maybe?
- m_puppetRoot.position = Vector3.zero;
- m_puppetRoot.rotation = Quaternion.identity;
-
- BipedRagdollCreator.Options l_options = BipedRagdollCreator.AutodetectOptions(m_puppetReferences);
- l_options.joints = RagdollCreator.JointType.Character;
- BipedRagdollCreator.Create(m_puppetReferences, l_options);
-
- Transform[] l_puppetTransforms = m_puppetReferences.GetRagdollTransforms();
- Transform[] l_avatarTransforms = l_avatarReferences.GetRagdollTransforms();
- for(int i = 0; i < l_puppetTransforms.Length; i++)
- {
- if(l_puppetTransforms[i] != null)
- {
- Rigidbody l_body = l_puppetTransforms[i].GetComponent();
- if(l_body != null)
- {
- m_rigidBodies.Add(l_body);
- l_body.isKinematic = true;
- l_body.angularDrag = Settings.AngularDrag;
- l_body.drag = (Utils.IsWorldSafe() ? Settings.MovementDrag : 1f);
- l_body.useGravity = (!Utils.IsWorldSafe() || Settings.Gravity);
- l_body.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
- l_body.gameObject.layer = LayerMask.NameToLayer("PlayerLocal");
- }
-
- CharacterJoint l_joint = l_puppetTransforms[i].GetComponent();
- if(l_joint != null)
- {
- l_joint.enablePreprocessing = false;
- l_joint.enableProjection = true;
- m_jointAnchors.Add(System.Tuple.Create(l_joint, l_joint.connectedAnchor));
- }
-
- Collider l_collider = l_puppetTransforms[i].GetComponent();
- if(l_collider != null)
- {
- Physics.IgnoreCollision(l_collider, MovementSystem.Instance.proxyCollider, true);
- Physics.IgnoreCollision(l_collider, MovementSystem.Instance.controller, true);
- Physics.IgnoreCollision(l_collider, MovementSystem.Instance.forceCollider, true);
- l_collider.enabled = false;
- l_collider.sharedMaterial = m_physicsMaterial;
- l_collider.material = m_physicsMaterial;
- m_colliders.Add(l_collider);
- }
-
- if(l_avatarTransforms[i] != null)
- m_boneLinks.Add(System.Tuple.Create(l_puppetTransforms[i], l_avatarTransforms[i]));
- }
- }
-
- // And return back
- m_puppetRoot.localPosition = Vector3.zero;
- m_puppetRoot.localRotation = Quaternion.identity;
- m_puppetRoot.gameObject.SetActive(false);
-
- m_vrIK = PlayerSetup.Instance._avatar.GetComponent();
- if(m_vrIK != null)
- {
- m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreUpdate);
- m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate);
- }
-
- m_avatarRagdollToggle = PlayerSetup.Instance._avatar.GetComponentInChildren(true);
- m_ragdolledParameter = new AvatarBoolParameter("Ragdolled", PlayerSetup.Instance.animatorManager);
-
- m_avatarReady = true;
- }
- }
-
- internal void OnAvatarScaling(float p_scaleDifference)
- {
- if(m_avatarReady)
- {
- m_puppetRoot.localScale = Vector3.one * p_scaleDifference;
- foreach(var l_pair in m_jointAnchors)
- l_pair.Item1.connectedAnchor = l_pair.Item2 * p_scaleDifference;
- }
- }
-
- internal void OnSeatSitDown(CVRSeat p_seat)
- {
- if(m_avatarReady && m_enabled && !p_seat.occupied)
- SwitchRagdoll();
- }
-
- internal void OnStartCalibration()
- {
- if(m_avatarReady && m_enabled)
- SwitchRagdoll();
- }
-
- internal void OnWorldSpawn()
- {
- if(m_avatarReady && m_enabled)
- SwitchRagdoll();
-
- OnGravityChange(Settings.Gravity);
- OnPhysicsMaterialChange(true);
- OnMovementDragChange(Settings.MovementDrag);
- }
-
- internal void OnCombatDown()
- {
- if(m_avatarReady && !m_enabled && Settings.CombatReaction)
- {
- m_reachedGround = true;
- SwitchRagdoll();
- }
- }
-
- internal void OnChangeFlight()
- {
- if(m_avatarReady && m_enabled && MovementSystem.Instance.flying)
- SwitchRagdoll();
- }
-
- // IK updates
- void OnIKPreUpdate()
- {
- if(m_enabled)
- {
- m_vrIkWeight = m_vrIK.solver.IKPositionWeight;
- m_vrIK.solver.IKPositionWeight = 0f;
- }
- }
- void OnIKPostUpdate()
- {
- if(m_enabled)
- m_vrIK.solver.IKPositionWeight = m_vrIkWeight;
- else
- {
- foreach(var l_link in m_boneLinks)
- l_link.Item2.CopyGlobal(l_link.Item1);
- }
- }
-
- // Settings
- void OnMovementDragChange(float p_value)
- {
- if(m_avatarReady)
- {
- float l_drag = (Utils.IsWorldSafe() ? p_value : 1f);
- foreach(Rigidbody l_body in m_rigidBodies)
- {
- l_body.drag = l_drag;
- if(m_enabled)
- l_body.WakeUp();
- }
- }
- }
- void OnAngularDragChange(float p_value)
- {
- if(m_avatarReady)
- {
- foreach(Rigidbody l_body in m_rigidBodies)
- {
- l_body.angularDrag = p_value;
- if(m_enabled)
- l_body.WakeUp();
- }
- }
- }
- void OnGravityChange(bool p_state)
- {
- if(m_avatarReady)
- {
- bool l_gravity = (!Utils.IsWorldSafe() || p_state);
- foreach(Rigidbody l_body in m_rigidBodies)
- l_body.useGravity = l_gravity;
- }
- }
- void OnPhysicsMaterialChange(bool p_state)
- {
- if(m_physicsMaterial != null)
- {
- bool l_slipperiness = (Settings.Slipperiness && Utils.IsWorldSafe());
- bool l_bounciness = (Settings.Bounciness && Utils.IsWorldSafe());
- m_physicsMaterial.dynamicFriction = (l_slipperiness ? 0f : c_defaultFriction);
- m_physicsMaterial.staticFriction = (l_slipperiness ? 0f : c_defaultFriction);
- m_physicsMaterial.frictionCombine = (l_slipperiness ? PhysicMaterialCombine.Minimum : PhysicMaterialCombine.Average);
- m_physicsMaterial.bounciness = (l_bounciness ? 1f : 0f);
- m_physicsMaterial.bounceCombine = (l_bounciness ? PhysicMaterialCombine.Maximum : PhysicMaterialCombine.Average);
- }
- }
-
- // Arbitrary
- public void SwitchRagdoll()
- {
- if(m_avatarReady)
- {
- if(!m_enabled)
- {
- if(IsSafeToRagdoll() && m_reachedGround)
- {
- // Eject player from seat
- if(MovementSystem.Instance.lastSeat != null)
- {
- Vector3 l_pos = PlayerSetup.Instance.transform.position;
- Quaternion l_rot = PlayerSetup.Instance.transform.rotation;
-
- if(MetaPort.Instance.isUsingVr)
- {
- MetaPort.Instance.isUsingVr = false;
- MovementSystem.Instance.lastSeat.ExitSeat();
- MetaPort.Instance.isUsingVr = true;
- }
- else
- MovementSystem.Instance.lastSeat.ExitSeat();
-
- PlayerSetup.Instance.transform.position = l_pos;
- PlayerSetup.Instance.transform.rotation = Quaternion.Euler(0f, l_rot.eulerAngles.y, 0f);
- }
-
- if(MovementSystem.Instance.flying)
- MovementSystem.Instance.ChangeFlight(false);
-
- bool l_crouch = MovementSystem.Instance.crouching;
- bool l_prone = MovementSystem.Instance.prone;
- MovementSystem.Instance.SetImmobilized(true);
- MovementSystem.Instance.ChangeCrouch(l_crouch);
- MovementSystem.Instance.ChangeProne(l_prone);
-
- PlayerSetup.Instance.animatorManager.SetAnimatorParameterTrigger("CancelEmote");
- m_ragdolledParameter.SetValue(true);
- if(!BodySystem.isCalibrating)
- BodySystem.TrackingPositionWeight = 0f;
-
- if(!Utils.IsWorldSafe())
- {
- m_reachedGround = false; // Force player to unragdoll and reach ground first
- m_groundedTime = 0f;
- }
-
- m_puppetRoot.gameObject.SetActive(true);
-
- foreach(Rigidbody l_body in m_rigidBodies)
- l_body.isKinematic = false;
-
- Vector3 l_velocity = Vector3.ClampMagnitude(m_velocity * (Utils.IsWorldSafe() ? Settings.VelocityMultiplier : 1f), Utils.GetWorldMovementLimit());
- if(Settings.ViewVelocity && Utils.IsWorldSafe())
- {
- float l_mag = l_velocity.magnitude;
- l_velocity = PlayerSetup.Instance.GetActiveCamera().transform.forward * l_mag;
- }
-
- foreach(Rigidbody l_body in m_rigidBodies)
- {
- l_body.velocity = l_velocity;
- l_body.angularVelocity = Vector3.zero;
- }
-
- foreach(Collider l_collider in m_colliders)
- l_collider.enabled = true;
-
- m_ragdollLastPos = m_puppetReferences.hips.position;
- m_downTime = 0f;
-
- m_enabled = true;
- }
- }
- else
- {
- if(IsSafeToUnragdoll())
- {
- MovementSystem.Instance.SetImmobilized(false);
- if(!Utils.IsWorldSafe())
- {
- Vector3 l_vec = MovementSystem.Instance.GetAppliedGravity();
- l_vec.y = Mathf.Clamp(l_vec.y, float.MinValue, 0f);
- MovementSystem.Instance.SetAppliedGravity(l_vec);
- }
-
- m_ragdolledParameter.SetValue(false);
- if(!BodySystem.isCalibrating)
- BodySystem.TrackingPositionWeight = 1f;
-
- m_puppetRoot.gameObject.SetActive(false);
-
- foreach(Rigidbody l_body in m_rigidBodies)
- l_body.isKinematic = true;
-
- PlayerSetup.Instance.transform.position = m_puppetReferences.hips.position;
- 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;
-
- if(m_vrIK != null)
- m_vrIK.solver.Reset();
-
- m_lastPosition = PlayerSetup.Instance.transform.position;
- m_velocity = Vector3.zero;
- m_downTime = float.MinValue;
-
- m_enabled = false;
- }
- }
- }
- }
-
- public bool IsRagdolled() => (m_avatarReady && m_enabled);
-
- static Transform CloneTransform(Transform p_source, Transform p_parent, string p_name)
- {
- Transform l_target = new GameObject(p_name).transform;
- l_target.parent = p_parent;
- p_source.CopyGlobal(l_target);
- return l_target;
- }
-
- static bool IsSafeToRagdoll()
- {
- bool l_result = true;
- l_result &= !BodySystem.isCalibrating; // Not calibrating
- l_result &= ((CombatSystem.Instance == null) || !CombatSystem.Instance.isDown); // Non-combat world or not dead
- return l_result;
- }
-
- static bool IsSafeToUnragdoll()
- {
- bool l_result = true;
- l_result &= ((CombatSystem.Instance == null) || !CombatSystem.Instance.isDown); // Non-combat world or not dead
- return l_result;
- }
- }
-}
+using ABI.CCK.Components;
+using ABI_RC.Core.InteractionSystem;
+using ABI_RC.Core.Player;
+using ABI_RC.Core.Savior;
+using ABI_RC.Systems.IK.SubSystems;
+using ABI_RC.Systems.InputManagement;
+using ABI_RC.Systems.MovementSystem;
+using RootMotion.Dynamics;
+using RootMotion.FinalIK;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace ml_prm
+{
+ [DisallowMultipleComponent]
+ public class RagdollController : MonoBehaviour
+ {
+ const float c_defaultFriction = 0.6f;
+
+ public static RagdollController Instance { get; private set; } = null;
+
+ VRIK m_vrIK = null;
+ float m_vrIkWeight = 1f;
+ bool m_inVr = false;
+
+ bool m_enabled = false;
+
+ readonly List m_rigidBodies = null;
+ readonly List m_colliders = null;
+ Transform m_puppetRoot = null;
+ Transform m_puppet = null;
+ BipedRagdollReferences m_puppetReferences;
+ readonly List> m_boneLinks = null;
+ readonly List> m_jointAnchors = null;
+
+ bool m_avatarReady = false;
+ Vector3 m_lastPosition = Vector3.zero;
+ Vector3 m_velocity = Vector3.zero;
+ Vector3 m_ragdollLastPos = Vector3.zero;
+
+ RagdollToggle m_avatarRagdollToggle = null;
+ RagdollTrigger m_customTrigger = null;
+ AvatarBoolParameter m_ragdolledParameter = null;
+ readonly PhysicMaterial m_physicsMaterial = null;
+
+ bool m_reachedGround = true;
+ float m_groundedTime = 0f;
+ float m_downTime = float.MinValue;
+
+ internal RagdollController()
+ {
+ if(Instance == null)
+ Instance = this;
+
+ m_rigidBodies = new List();
+ m_colliders = new List();
+ m_boneLinks = new List>();
+ m_jointAnchors = new List>();
+
+ m_physicsMaterial = new PhysicMaterial("Ragdoll");
+ m_physicsMaterial.dynamicFriction = c_defaultFriction;
+ m_physicsMaterial.staticFriction = c_defaultFriction;
+ m_physicsMaterial.frictionCombine = PhysicMaterialCombine.Average;
+ m_physicsMaterial.bounciness = 0f;
+ m_physicsMaterial.bounceCombine = PhysicMaterialCombine.Average;
+ }
+ ~RagdollController()
+ {
+ if(Instance == this)
+ Instance = null;
+ }
+
+ // Unity events
+ void Start()
+ {
+ m_inVr = Utils.IsInVR();
+
+ m_puppetRoot = new GameObject("[PlayerAvatarPuppet]").transform;
+ m_puppetRoot.parent = PlayerSetup.Instance.transform;
+ m_puppetRoot.localPosition = Vector3.zero;
+ m_puppetRoot.localRotation = Quaternion.identity;
+
+ m_customTrigger = MovementSystem.Instance.proxyCollider.gameObject.AddComponent();
+
+ Settings.MovementDragChange += this.OnMovementDragChange;
+ Settings.AngularDragChange += this.OnAngularDragChange;
+ Settings.GravityChange += this.OnGravityChange;
+ Settings.SlipperinessChange += this.OnPhysicsMaterialChange;
+ Settings.BouncinessChange += this.OnPhysicsMaterialChange;
+ }
+
+ void OnDestroy()
+ {
+ if(m_customTrigger != null)
+ {
+ Object.Destroy(m_customTrigger);
+ m_customTrigger = null;
+ }
+
+ Settings.MovementDragChange -= this.OnMovementDragChange;
+ Settings.AngularDragChange -= this.OnAngularDragChange;
+ Settings.GravityChange -= this.OnGravityChange;
+ Settings.SlipperinessChange -= this.OnPhysicsMaterialChange;
+ Settings.BouncinessChange -= this.OnPhysicsMaterialChange;
+ }
+
+ void Update()
+ {
+ if(m_avatarReady && m_enabled)
+ {
+ Vector3 l_dif = m_puppetReferences.hips.position - m_ragdollLastPos;
+ PlayerSetup.Instance.transform.position += l_dif;
+ m_puppetReferences.hips.position -= l_dif;
+ m_ragdollLastPos = m_puppetReferences.hips.position;
+ }
+
+ 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_reachedGround && MovementSystem.Instance.IsGrounded())
+ {
+ m_groundedTime += Time.deltaTime;
+ if(m_groundedTime >= 0.25f)
+ m_reachedGround = true;
+ }
+ }
+
+ if(m_avatarReady && m_enabled && !BodySystem.isCalibrating)
+ BodySystem.TrackingPositionWeight = 0f;
+
+ if(m_avatarReady && m_enabled && Settings.AutoRecover)
+ {
+ m_downTime += Time.deltaTime;
+ if(m_downTime >= Settings.RecoverDelay)
+ {
+ SwitchRagdoll();
+ m_downTime = float.MinValue; // One attepmt to recover
+ }
+ }
+
+ if((m_avatarRagdollToggle != null) && m_avatarRagdollToggle.isActiveAndEnabled && m_avatarRagdollToggle.shouldOverride && (m_enabled != m_avatarRagdollToggle.isOn))
+ SwitchRagdoll();
+
+ if((m_customTrigger != null) && m_customTrigger.GetStateWithReset() && m_avatarReady && !m_enabled && Settings.PointersReaction)
+ SwitchRagdoll();
+
+ if(Settings.Hotkey && Input.GetKeyDown(Settings.HotkeyKey) && !ViewManager.Instance.isGameMenuOpen())
+ SwitchRagdoll();
+
+ if(m_avatarReady && m_enabled && CVRInputManager.Instance.jump && Settings.JumpRecover)
+ SwitchRagdoll();
+ }
+
+ void LateUpdate()
+ {
+ if(m_avatarReady)
+ {
+ if(m_enabled)
+ {
+ if(!BodySystem.isCalibrating)
+ {
+ BodySystem.TrackingPositionWeight = 0f;
+
+ foreach(var l_link in m_boneLinks)
+ l_link.Item1.CopyGlobal(l_link.Item2);
+ }
+ }
+ else
+ {
+ foreach(var l_link in m_boneLinks)
+ l_link.Item2.CopyGlobal(l_link.Item1);
+ }
+ }
+ }
+
+ // Game events
+ internal void OnAvatarClear()
+ {
+ if(m_enabled && (MovementSystem.Instance != null))
+ MovementSystem.Instance.SetImmobilized(false);
+
+ if(m_puppet != null)
+ Object.Destroy(m_puppet.gameObject);
+ m_puppet = null;
+
+ m_vrIK = null;
+ m_enabled = false;
+ m_avatarReady = false;
+ m_avatarRagdollToggle = null;
+ m_ragdolledParameter = null;
+ m_rigidBodies.Clear();
+ m_colliders.Clear();
+ m_puppetReferences = new BipedRagdollReferences();
+ m_boneLinks.Clear();
+ m_jointAnchors.Clear();
+ m_reachedGround = true;
+ m_groundedTime = 0f;
+ m_downTime = float.MinValue;
+ m_puppetRoot.localScale = Vector3.one;
+ }
+
+ internal void OnAvatarSetup()
+ {
+ m_inVr = Utils.IsInVR();
+
+ if(PlayerSetup.Instance._animator.isHuman)
+ {
+ BipedRagdollReferences l_avatarReferences = BipedRagdollReferences.FromAvatar(PlayerSetup.Instance._animator);
+
+ m_puppet = new GameObject("Root").transform;
+ m_puppet.parent = m_puppetRoot;
+ m_puppet.localPosition = Vector3.zero;
+ m_puppet.localRotation = Quaternion.identity;
+
+ m_puppetReferences.root = m_puppet;
+ m_puppetReferences.hips = CloneTransform(l_avatarReferences.hips, m_puppetReferences.root, "Hips");
+ m_puppetReferences.spine = CloneTransform(l_avatarReferences.spine, m_puppetReferences.hips, "Spine");
+
+ if(l_avatarReferences.chest != null)
+ m_puppetReferences.chest = CloneTransform(l_avatarReferences.chest, m_puppetReferences.spine, "Chest");
+
+ m_puppetReferences.head = CloneTransform(l_avatarReferences.head, (m_puppetReferences.chest != null) ? m_puppetReferences.chest : m_puppetReferences.spine, "Head");
+
+ m_puppetReferences.leftUpperArm = CloneTransform(l_avatarReferences.leftUpperArm, (m_puppetReferences.chest != null) ? m_puppetReferences.chest : m_puppetReferences.spine, "LeftUpperArm");
+ m_puppetReferences.leftLowerArm = CloneTransform(l_avatarReferences.leftLowerArm, m_puppetReferences.leftUpperArm, "LeftLowerArm");
+ m_puppetReferences.leftHand = CloneTransform(l_avatarReferences.leftHand, m_puppetReferences.leftLowerArm, "LeftHand");
+
+ m_puppetReferences.rightUpperArm = CloneTransform(l_avatarReferences.rightUpperArm, (m_puppetReferences.chest != null) ? m_puppetReferences.chest : m_puppetReferences.spine, "RightUpperArm");
+ m_puppetReferences.rightLowerArm = CloneTransform(l_avatarReferences.rightLowerArm, m_puppetReferences.rightUpperArm, "RightLowerArm");
+ m_puppetReferences.rightHand = CloneTransform(l_avatarReferences.rightHand, m_puppetReferences.rightLowerArm, "RightHand");
+
+ m_puppetReferences.leftUpperLeg = CloneTransform(l_avatarReferences.leftUpperLeg, m_puppetReferences.hips, "LeftUpperLeg");
+ m_puppetReferences.leftLowerLeg = CloneTransform(l_avatarReferences.leftLowerLeg, m_puppetReferences.leftUpperLeg, "LeftLowerLeg");
+ m_puppetReferences.leftFoot = CloneTransform(l_avatarReferences.leftFoot, m_puppetReferences.leftLowerLeg, "LeftFoot");
+
+ m_puppetReferences.rightUpperLeg = CloneTransform(l_avatarReferences.rightUpperLeg, m_puppetReferences.hips, "RightUpperLeg");
+ m_puppetReferences.rightLowerLeg = CloneTransform(l_avatarReferences.rightLowerLeg, m_puppetReferences.rightUpperLeg, "RightLowerLeg");
+ m_puppetReferences.rightFoot = CloneTransform(l_avatarReferences.rightFoot, m_puppetReferences.rightLowerLeg, "RightFoot");
+
+ // Move to world origin to overcome possible issues, maybe?
+ m_puppetRoot.position = Vector3.zero;
+ m_puppetRoot.rotation = Quaternion.identity;
+
+ BipedRagdollCreator.Options l_options = BipedRagdollCreator.AutodetectOptions(m_puppetReferences);
+ l_options.joints = RagdollCreator.JointType.Character;
+ BipedRagdollCreator.Create(m_puppetReferences, l_options);
+
+ Transform[] l_puppetTransforms = m_puppetReferences.GetRagdollTransforms();
+ Transform[] l_avatarTransforms = l_avatarReferences.GetRagdollTransforms();
+ for(int i = 0; i < l_puppetTransforms.Length; i++)
+ {
+ if(l_puppetTransforms[i] != null)
+ {
+ Rigidbody l_body = l_puppetTransforms[i].GetComponent();
+ if(l_body != null)
+ {
+ m_rigidBodies.Add(l_body);
+ l_body.isKinematic = true;
+ l_body.angularDrag = Settings.AngularDrag;
+ l_body.drag = (Utils.IsWorldSafe() ? Settings.MovementDrag : 1f);
+ l_body.useGravity = (!Utils.IsWorldSafe() || Settings.Gravity);
+ l_body.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
+ l_body.gameObject.layer = LayerMask.NameToLayer("PlayerLocal");
+ }
+
+ CharacterJoint l_joint = l_puppetTransforms[i].GetComponent();
+ if(l_joint != null)
+ {
+ l_joint.enablePreprocessing = false;
+ l_joint.enableProjection = true;
+ m_jointAnchors.Add(System.Tuple.Create(l_joint, l_joint.connectedAnchor));
+ }
+
+ Collider l_collider = l_puppetTransforms[i].GetComponent();
+ if(l_collider != null)
+ {
+ Physics.IgnoreCollision(l_collider, MovementSystem.Instance.proxyCollider, true);
+ Physics.IgnoreCollision(l_collider, MovementSystem.Instance.controller, true);
+ Physics.IgnoreCollision(l_collider, MovementSystem.Instance.forceCollider, true);
+ l_collider.enabled = false;
+ l_collider.sharedMaterial = m_physicsMaterial;
+ l_collider.material = m_physicsMaterial;
+ m_colliders.Add(l_collider);
+ }
+
+ if(l_avatarTransforms[i] != null)
+ m_boneLinks.Add(System.Tuple.Create(l_puppetTransforms[i], l_avatarTransforms[i]));
+ }
+ }
+
+ // And return back
+ m_puppetRoot.localPosition = Vector3.zero;
+ m_puppetRoot.localRotation = Quaternion.identity;
+ m_puppetRoot.gameObject.SetActive(false);
+
+ m_vrIK = PlayerSetup.Instance._avatar.GetComponent();
+ if(m_vrIK != null)
+ {
+ m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreUpdate);
+ m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate);
+ }
+
+ m_avatarRagdollToggle = PlayerSetup.Instance._avatar.GetComponentInChildren(true);
+ m_ragdolledParameter = new AvatarBoolParameter("Ragdolled", PlayerSetup.Instance.animatorManager);
+
+ m_avatarReady = true;
+ }
+ }
+
+ internal void OnAvatarScaling(float p_scaleDifference)
+ {
+ if(m_avatarReady)
+ {
+ m_puppetRoot.localScale = Vector3.one * p_scaleDifference;
+ foreach(var l_pair in m_jointAnchors)
+ l_pair.Item1.connectedAnchor = l_pair.Item2 * p_scaleDifference;
+ }
+ }
+
+ internal void OnSeatSitDown(CVRSeat p_seat)
+ {
+ if(m_avatarReady && m_enabled && !p_seat.occupied)
+ SwitchRagdoll();
+ }
+
+ internal void OnStartCalibration()
+ {
+ if(m_avatarReady && m_enabled)
+ SwitchRagdoll();
+ }
+
+ internal void OnWorldSpawn()
+ {
+ if(m_avatarReady && m_enabled)
+ SwitchRagdoll();
+
+ OnGravityChange(Settings.Gravity);
+ OnPhysicsMaterialChange(true);
+ OnMovementDragChange(Settings.MovementDrag);
+ }
+
+ internal void OnCombatDown()
+ {
+ if(m_avatarReady && !m_enabled && Settings.CombatReaction)
+ {
+ m_reachedGround = true;
+ SwitchRagdoll();
+ }
+ }
+
+ internal void OnChangeFlight()
+ {
+ if(m_avatarReady && m_enabled && MovementSystem.Instance.flying)
+ SwitchRagdoll();
+ }
+
+ // IK updates
+ void OnIKPreUpdate()
+ {
+ if(m_enabled)
+ {
+ m_vrIkWeight = m_vrIK.solver.IKPositionWeight;
+ m_vrIK.solver.IKPositionWeight = 0f;
+ }
+ }
+ void OnIKPostUpdate()
+ {
+ if(m_enabled)
+ m_vrIK.solver.IKPositionWeight = m_vrIkWeight;
+ else
+ {
+ foreach(var l_link in m_boneLinks)
+ l_link.Item2.CopyGlobal(l_link.Item1);
+ }
+ }
+
+ // Settings
+ void OnMovementDragChange(float p_value)
+ {
+ if(m_avatarReady)
+ {
+ float l_drag = (Utils.IsWorldSafe() ? p_value : 1f);
+ foreach(Rigidbody l_body in m_rigidBodies)
+ {
+ l_body.drag = l_drag;
+ if(m_enabled)
+ l_body.WakeUp();
+ }
+ }
+ }
+ void OnAngularDragChange(float p_value)
+ {
+ if(m_avatarReady)
+ {
+ foreach(Rigidbody l_body in m_rigidBodies)
+ {
+ l_body.angularDrag = p_value;
+ if(m_enabled)
+ l_body.WakeUp();
+ }
+ }
+ }
+ void OnGravityChange(bool p_state)
+ {
+ if(m_avatarReady)
+ {
+ bool l_gravity = (!Utils.IsWorldSafe() || p_state);
+ foreach(Rigidbody l_body in m_rigidBodies)
+ l_body.useGravity = l_gravity;
+ }
+ }
+ void OnPhysicsMaterialChange(bool p_state)
+ {
+ if(m_physicsMaterial != null)
+ {
+ bool l_slipperiness = (Settings.Slipperiness && Utils.IsWorldSafe());
+ bool l_bounciness = (Settings.Bounciness && Utils.IsWorldSafe());
+ m_physicsMaterial.dynamicFriction = (l_slipperiness ? 0f : c_defaultFriction);
+ m_physicsMaterial.staticFriction = (l_slipperiness ? 0f : c_defaultFriction);
+ m_physicsMaterial.frictionCombine = (l_slipperiness ? PhysicMaterialCombine.Minimum : PhysicMaterialCombine.Average);
+ m_physicsMaterial.bounciness = (l_bounciness ? 1f : 0f);
+ m_physicsMaterial.bounceCombine = (l_bounciness ? PhysicMaterialCombine.Maximum : PhysicMaterialCombine.Average);
+ }
+ }
+
+ // Arbitrary
+ public void SwitchRagdoll()
+ {
+ if(m_avatarReady)
+ {
+ if(!m_enabled)
+ {
+ if(IsSafeToRagdoll() && m_reachedGround)
+ {
+ // Eject player from seat
+ if(MovementSystem.Instance.lastSeat != null)
+ {
+ Vector3 l_pos = PlayerSetup.Instance.transform.position;
+ Quaternion l_rot = PlayerSetup.Instance.transform.rotation;
+
+ if(MetaPort.Instance.isUsingVr)
+ {
+ MetaPort.Instance.isUsingVr = false;
+ MovementSystem.Instance.lastSeat.ExitSeat();
+ MetaPort.Instance.isUsingVr = true;
+ }
+ else
+ MovementSystem.Instance.lastSeat.ExitSeat();
+
+ PlayerSetup.Instance.transform.position = l_pos;
+ PlayerSetup.Instance.transform.rotation = Quaternion.Euler(0f, l_rot.eulerAngles.y, 0f);
+ }
+
+ if(MovementSystem.Instance.flying)
+ MovementSystem.Instance.ChangeFlight(false);
+
+ bool l_crouch = MovementSystem.Instance.crouching;
+ bool l_prone = MovementSystem.Instance.prone;
+ MovementSystem.Instance.SetImmobilized(true);
+ MovementSystem.Instance.ChangeCrouch(l_crouch);
+ MovementSystem.Instance.ChangeProne(l_prone);
+
+ PlayerSetup.Instance.animatorManager.SetAnimatorParameterTrigger("CancelEmote");
+ m_ragdolledParameter.SetValue(true);
+ if(!BodySystem.isCalibrating)
+ BodySystem.TrackingPositionWeight = 0f;
+
+ if(!Utils.IsWorldSafe())
+ {
+ m_reachedGround = false; // Force player to unragdoll and reach ground first
+ m_groundedTime = 0f;
+ }
+
+ m_puppetRoot.gameObject.SetActive(true);
+
+ foreach(Rigidbody l_body in m_rigidBodies)
+ l_body.isKinematic = false;
+
+ Vector3 l_velocity = Vector3.ClampMagnitude(m_velocity * (Utils.IsWorldSafe() ? Settings.VelocityMultiplier : 1f), Utils.GetWorldMovementLimit());
+ if(Settings.ViewVelocity && Utils.IsWorldSafe())
+ {
+ float l_mag = l_velocity.magnitude;
+ l_velocity = PlayerSetup.Instance.GetActiveCamera().transform.forward * l_mag;
+ }
+
+ foreach(Rigidbody l_body in m_rigidBodies)
+ {
+ l_body.velocity = l_velocity;
+ l_body.angularVelocity = Vector3.zero;
+ }
+
+ foreach(Collider l_collider in m_colliders)
+ l_collider.enabled = true;
+
+ m_ragdollLastPos = m_puppetReferences.hips.position;
+ m_downTime = 0f;
+
+ m_enabled = true;
+ }
+ }
+ else
+ {
+ if(IsSafeToUnragdoll())
+ {
+ MovementSystem.Instance.SetImmobilized(false);
+ if(!Utils.IsWorldSafe())
+ {
+ Vector3 l_vec = MovementSystem.Instance.GetAppliedGravity();
+ l_vec.y = Mathf.Clamp(l_vec.y, float.MinValue, 0f);
+ MovementSystem.Instance.SetAppliedGravity(l_vec);
+ }
+
+ m_ragdolledParameter.SetValue(false);
+ if(!BodySystem.isCalibrating)
+ BodySystem.TrackingPositionWeight = 1f;
+
+ m_puppetRoot.gameObject.SetActive(false);
+
+ foreach(Rigidbody l_body in m_rigidBodies)
+ l_body.isKinematic = true;
+
+ PlayerSetup.Instance.transform.position = m_puppetReferences.hips.position;
+ 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;
+
+ if(m_vrIK != null)
+ m_vrIK.solver.Reset();
+
+ m_lastPosition = PlayerSetup.Instance.transform.position;
+ m_velocity = Vector3.zero;
+ m_downTime = float.MinValue;
+
+ m_enabled = false;
+ }
+ }
+ }
+ }
+
+ public bool IsRagdolled() => (m_avatarReady && m_enabled);
+
+ static Transform CloneTransform(Transform p_source, Transform p_parent, string p_name)
+ {
+ Transform l_target = new GameObject(p_name).transform;
+ l_target.parent = p_parent;
+ p_source.CopyGlobal(l_target);
+ return l_target;
+ }
+
+ static bool IsSafeToRagdoll()
+ {
+ bool l_result = true;
+ l_result &= !BodySystem.isCalibrating; // Not calibrating
+ l_result &= ((CombatSystem.Instance == null) || !CombatSystem.Instance.isDown); // Non-combat world or not dead
+ return l_result;
+ }
+
+ static bool IsSafeToUnragdoll()
+ {
+ bool l_result = true;
+ l_result &= ((CombatSystem.Instance == null) || !CombatSystem.Instance.isDown); // Non-combat world or not dead
+ return l_result;
+ }
+ }
+}
diff --git a/ml_prm/RagdollTrigger.cs b/ml_prm/RagdollTrigger.cs
index 45b9d84..8afe3f7 100644
--- a/ml_prm/RagdollTrigger.cs
+++ b/ml_prm/RagdollTrigger.cs
@@ -6,7 +6,7 @@ using UnityEngine;
namespace ml_prm
{
[DisallowMultipleComponent]
- public class RagdollTrigger : MonoBehaviour
+ class RagdollTrigger : MonoBehaviour
{
const string c_ragdollPointerType = "ragdoll";
@@ -18,14 +18,13 @@ namespace ml_prm
void Start()
{
m_collider = this.GetComponent();
- CVRParticlePointerManager.volumes.Add(new RagdollTriggerVolume() {
- collider = m_collider,
- trigger = this,
- });
+
+ CVRParticlePointerManager.volumes.Add(new RagdollTriggerVolume(m_collider, this));
CVRParticlePointerManager.UpdateParticleSystems();
}
- void OnDestroy() {
+ void OnDestroy()
+ {
CVRParticlePointerManager.RemoveTrigger(m_collider);
}
@@ -45,7 +44,7 @@ namespace ml_prm
{
if(m_lastParticleSystemTrigger != null)
{
- if (m_lastParticleSystemTrigger.particleCount == 0)
+ if(m_lastParticleSystemTrigger.particleCount == 0)
m_lastParticleSystemTrigger = null;
}
else
@@ -71,8 +70,10 @@ namespace ml_prm
public void OnPointerParticleEnter(CVRPointer p_pointer)
{
- if (!gameObject.activeInHierarchy) return;
- if ((p_pointer.type == c_ragdollPointerType) && !IsIgnored(p_pointer.transform) && (m_lastParticleSystemTrigger != p_pointer.particleSystem))
+ if(!this.gameObject.activeInHierarchy)
+ return;
+
+ if((p_pointer.type == c_ragdollPointerType) && !IsIgnored(p_pointer.transform) && (m_lastParticleSystemTrigger != p_pointer.particleSystem))
{
m_lastParticleSystemTrigger = p_pointer.particleSystem;
m_triggered = true;
diff --git a/ml_prm/RagdollTriggerVolume.cs b/ml_prm/RagdollTriggerVolume.cs
index 6980708..8216728 100644
--- a/ml_prm/RagdollTriggerVolume.cs
+++ b/ml_prm/RagdollTriggerVolume.cs
@@ -2,13 +2,21 @@
using ABI.CCK.Components;
using UnityEngine;
-namespace ml_prm {
-
- public class RagdollTriggerVolume : CVRTriggerVolume
+namespace ml_prm
+{
+ class RagdollTriggerVolume : CVRTriggerVolume
{
+ readonly RagdollTrigger m_trigger = null;
+
public Collider collider { get; set; }
- public RagdollTrigger trigger { get; set; }
- public void TriggerEnter(CVRPointer pointer) => trigger.OnPointerParticleEnter(pointer);
- public void TriggerExit(CVRPointer pointer) => trigger.OnPointerParticleExit(pointer);
+
+ internal RagdollTriggerVolume(Collider p_collider, RagdollTrigger p_trigger)
+ {
+ collider = p_collider;
+ m_trigger = p_trigger;
+ }
+
+ public void TriggerEnter(CVRPointer pointer) => m_trigger.OnPointerParticleEnter(pointer);
+ public void TriggerExit(CVRPointer pointer) => m_trigger.OnPointerParticleExit(pointer);
}
}
diff --git a/ml_prm/ml_prm.csproj b/ml_prm/ml_prm.csproj
index 01c5ff4..a0d9d36 100644
--- a/ml_prm/ml_prm.csproj
+++ b/ml_prm/ml_prm.csproj
@@ -4,7 +4,7 @@
netstandard2.1
x64
PlayerRagdollMod
- 1.0.10
+ 1.0.11
SDraw
None
PlayerRagdollMod