Unarchived and fixed PlayerRagdollMod

This commit is contained in:
SDraw 2023-11-12 21:30:15 +03:00
parent dacde8975b
commit 7d087bd8fe
No known key found for this signature in database
GPG key ID: BB95B4DAB2BB8BB5
16 changed files with 307 additions and 155 deletions

View file

@ -3,10 +3,11 @@ Merged set of MelonLoader mods for ChilloutVR.
**Table for game build 2023r173:**
| 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.4 [:arrow_down:](../../releases/latest/download/ml_amt.dll)| ✔ Yes<br>:hourglass_flowing_sand: Update review |
| [Leap Motion Extension](/ml_lme/README.md)| ml_lme | 1.4.4 [:arrow_down:](../../releases/latest/download/ml_lme.dll)| ✔ Yes<br>:hourglass_flowing_sand: Update review |
| [Avatar Motion Tweaker](/ml_amt/README.md) | ml_amt | 1.3.4 [:arrow_down:](../../releases/latest/download/ml_amt.dll)| ✔ Yes |
| [Leap Motion Extension](/ml_lme/README.md)| ml_lme | 1.4.4 [: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.1.0 | ✔ Yes<br>: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:**
@ -18,5 +19,4 @@ Merged set of MelonLoader mods for ChilloutVR.
| Extended Game Notifications | ml_egn | In-game feature sine 2023r172 update |
| Four Point Tracking | ml_fpt | In-game feature since 2022r170 update |
| Game Main Fixes | ml_gmf | In-game feature sine 2023r172 update |
| Player Ragdoll Mod | ml_prm | Unable to fix offset problems |
| Server Connection Info | ml_sci | Superseded by `Extended Game Notifications`

View file

@ -1,56 +1,54 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.33214.272
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_amt", "ml_amt\ml_amt.csproj", "{714806A3-E6FC-46F6-9D1D-89C77FEBAF06}"
ProjectSection(ProjectDependencies) = postProject
{D27B6D36-884F-4A49-9A25-B9C121E7B65F} = {D27B6D36-884F-4A49-9A25-B9C121E7B65F}
{118675AA-9AC7-4B0C-BFB1-FA1691619502} = {118675AA-9AC7-4B0C-BFB1-FA1691619502}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_dht", "ml_dht\ml_dht.csproj", "{D805BA67-067E-4B79-87FC-6B08973F13EE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_lme", "ml_lme\ml_lme.csproj", "{77EA76B1-3709-4FC5-BDBD-8F77160E6DA3}"
ProjectSection(ProjectDependencies) = postProject
{118675AA-9AC7-4B0C-BFB1-FA1691619502} = {118675AA-9AC7-4B0C-BFB1-FA1691619502}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_pam", "ml_pam\ml_pam.csproj", "{5B614459-234A-443D-B06D-34FF81ADA67E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_prm", "ml_prm\ml_prm.csproj", "{D27B6D36-884F-4A49-9A25-B9C121E7B65F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_pmc", "ml_pmc\ml_pmc.csproj", "{118675AA-9AC7-4B0C-BFB1-FA1691619502}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{714806A3-E6FC-46F6-9D1D-89C77FEBAF06}.Debug|x64.ActiveCfg = Debug|x64
{714806A3-E6FC-46F6-9D1D-89C77FEBAF06}.Release|x64.ActiveCfg = Release|x64
{714806A3-E6FC-46F6-9D1D-89C77FEBAF06}.Release|x64.Build.0 = Release|x64
{D805BA67-067E-4B79-87FC-6B08973F13EE}.Debug|x64.ActiveCfg = Debug|x64
{D805BA67-067E-4B79-87FC-6B08973F13EE}.Release|x64.ActiveCfg = Release|x64
{D805BA67-067E-4B79-87FC-6B08973F13EE}.Release|x64.Build.0 = Release|x64
{77EA76B1-3709-4FC5-BDBD-8F77160E6DA3}.Debug|x64.ActiveCfg = Debug|x64
{77EA76B1-3709-4FC5-BDBD-8F77160E6DA3}.Release|x64.ActiveCfg = Release|x64
{77EA76B1-3709-4FC5-BDBD-8F77160E6DA3}.Release|x64.Build.0 = Release|x64
{5B614459-234A-443D-B06D-34FF81ADA67E}.Debug|x64.ActiveCfg = Debug|x64
{5B614459-234A-443D-B06D-34FF81ADA67E}.Release|x64.ActiveCfg = Release|x64
{5B614459-234A-443D-B06D-34FF81ADA67E}.Release|x64.Build.0 = Release|x64
{D27B6D36-884F-4A49-9A25-B9C121E7B65F}.Debug|x64.ActiveCfg = Debug|x64
{D27B6D36-884F-4A49-9A25-B9C121E7B65F}.Release|x64.ActiveCfg = Release|x64
{D27B6D36-884F-4A49-9A25-B9C121E7B65F}.Release|x64.Build.0 = Release|x64
{118675AA-9AC7-4B0C-BFB1-FA1691619502}.Debug|x64.ActiveCfg = Debug|x64
{118675AA-9AC7-4B0C-BFB1-FA1691619502}.Release|x64.ActiveCfg = Release|x64
{118675AA-9AC7-4B0C-BFB1-FA1691619502}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C7C6398E-220C-40C3-AE95-5690C9B2B3C3}
EndGlobalSection
EndGlobal

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.33214.272
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_amt", "ml_amt\ml_amt.csproj", "{714806A3-E6FC-46F6-9D1D-89C77FEBAF06}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_lme", "ml_lme\ml_lme.csproj", "{77EA76B1-3709-4FC5-BDBD-8F77160E6DA3}"
ProjectSection(ProjectDependencies) = postProject
{118675AA-9AC7-4B0C-BFB1-FA1691619502} = {118675AA-9AC7-4B0C-BFB1-FA1691619502}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_pam", "ml_pam\ml_pam.csproj", "{5B614459-234A-443D-B06D-34FF81ADA67E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_pmc", "ml_pmc\ml_pmc.csproj", "{118675AA-9AC7-4B0C-BFB1-FA1691619502}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_vei", "ml_vei\ml_vei.csproj", "{608CDBD6-8E29-43B7-BCBF-7E3967430A24}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_prm", "ml_prm\ml_prm.csproj", "{C4C3F080-379F-49DB-ADC6-6328BE884AE3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{714806A3-E6FC-46F6-9D1D-89C77FEBAF06}.Debug|x64.ActiveCfg = Debug|x64
{714806A3-E6FC-46F6-9D1D-89C77FEBAF06}.Release|x64.ActiveCfg = Release|x64
{714806A3-E6FC-46F6-9D1D-89C77FEBAF06}.Release|x64.Build.0 = Release|x64
{77EA76B1-3709-4FC5-BDBD-8F77160E6DA3}.Debug|x64.ActiveCfg = Debug|x64
{77EA76B1-3709-4FC5-BDBD-8F77160E6DA3}.Release|x64.ActiveCfg = Release|x64
{77EA76B1-3709-4FC5-BDBD-8F77160E6DA3}.Release|x64.Build.0 = Release|x64
{5B614459-234A-443D-B06D-34FF81ADA67E}.Debug|x64.ActiveCfg = Debug|x64
{5B614459-234A-443D-B06D-34FF81ADA67E}.Release|x64.ActiveCfg = Release|x64
{5B614459-234A-443D-B06D-34FF81ADA67E}.Release|x64.Build.0 = Release|x64
{118675AA-9AC7-4B0C-BFB1-FA1691619502}.Debug|x64.ActiveCfg = Debug|x64
{118675AA-9AC7-4B0C-BFB1-FA1691619502}.Release|x64.ActiveCfg = Release|x64
{118675AA-9AC7-4B0C-BFB1-FA1691619502}.Release|x64.Build.0 = Release|x64
{608CDBD6-8E29-43B7-BCBF-7E3967430A24}.Debug|x64.ActiveCfg = Debug|x64
{608CDBD6-8E29-43B7-BCBF-7E3967430A24}.Debug|x64.Build.0 = Debug|x64
{608CDBD6-8E29-43B7-BCBF-7E3967430A24}.Release|x64.ActiveCfg = Release|x64
{608CDBD6-8E29-43B7-BCBF-7E3967430A24}.Release|x64.Build.0 = Release|x64
{C4C3F080-379F-49DB-ADC6-6328BE884AE3}.Debug|x64.ActiveCfg = Debug|x64
{C4C3F080-379F-49DB-ADC6-6328BE884AE3}.Debug|x64.Build.0 = Debug|x64
{C4C3F080-379F-49DB-ADC6-6328BE884AE3}.Release|x64.ActiveCfg = Release|x64
{C4C3F080-379F-49DB-ADC6-6328BE884AE3}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C7C6398E-220C-40C3-AE95-5690C9B2B3C3}
EndGlobalSection
EndGlobal

View file

@ -22,8 +22,8 @@ namespace ml_prm
if(l_regex.IsMatch(l_param.name) && (l_param.type == AnimatorControllerParameterType.Bool))
{
m_name = l_param.name;
m_sync = l_param.name.StartsWith('#');
m_hash = l_param.nameHash;
m_sync = (l_param.name[0] != '#');
break;
}
}

View file

@ -3,6 +3,7 @@ using ABI_RC.Core;
using ABI_RC.Core.InteractionSystem;
using ABI_RC.Core.Player;
using ABI_RC.Core.Util.AssetFiltering;
using ABI_RC.Systems.Camera.VisualMods;
using ABI_RC.Systems.IK.SubSystems;
using ABI_RC.Systems.MovementSystem;
using System;
@ -66,6 +67,16 @@ namespace ml_prm
null,
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnChangeFlight_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
HarmonyInstance.Patch(
typeof(MovementSystem).GetMethod(nameof(MovementSystem.TeleportToPosRot)),
null,
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnPlayerTeleport_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
HarmonyInstance.Patch(
typeof(DroneMode).GetMethod(nameof(DroneMode.Disable)),
null,
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnDroneModeDisable_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
// Whitelist the toggle script
(typeof(SharedFilter).GetField("_localComponentWhitelist", BindingFlags.NonPublic | BindingFlags.Static)?.GetValue(null) as HashSet<Type>)?.Add(typeof(RagdollToggle));
@ -212,5 +223,33 @@ namespace ml_prm
MelonLoader.MelonLogger.Error(e);
}
}
static void OnPlayerTeleport_Postfix() => ms_instance?.OnPlayerTeleport();
void OnPlayerTeleport()
{
try
{
if(m_localController != null)
m_localController.OnPlayerTeleport();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnDroneModeDisable_Postfix() => ms_instance?.OnDroneModeDisable();
void OnDroneModeDisable()
{
try
{
if(m_localController != null)
m_localController.OnDroneModeDisable();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
}
}

View file

@ -20,6 +20,7 @@ namespace ml_prm
Bounciness,
ViewVelocity,
JumpRecover,
Buoyancy,
VelocityMultiplier,
MovementDrag,
AngularDrag,
@ -49,7 +50,7 @@ namespace ml_prm
var l_modCategory = l_modRoot.AddCategory("Settings");
l_modCategory.AddButton("Switch ragdoll", "PRM-Person", "Switch between normal and ragdoll state").OnPress += () => SwitchChange?.Invoke();
l_modCategory.AddButton("Switch ragdoll", "PRM-Person", "Switch between normal and ragdoll state.").OnPress += () => SwitchChange?.Invoke();
ms_uiElements.Add(l_modCategory.AddToggle("Use hotkey", "Switch ragdoll mode with 'R' key", Settings.Hotkey));
(ms_uiElements[(int)UiIndex.Hotkey] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Hotkey, state);
@ -81,6 +82,9 @@ namespace ml_prm
ms_uiElements.Add(l_modCategory.AddToggle("Jump recover", "Recover from ragdoll state by jumping", Settings.JumpRecover));
(ms_uiElements[(int)UiIndex.JumpRecover] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.JumpRecover, state);
ms_uiElements.Add(l_modCategory.AddToggle("Buoyancy", "Enable buoyancy in fluid volumes. Warning: constantly changes movement and air drag of hips, spine and chest.", Settings.Buoyancy));
(ms_uiElements[(int)UiIndex.Buoyancy] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Buoyancy, state);
ms_uiElements.Add(l_modRoot.AddSlider("Velocity multiplier", "Velocity multiplier upon entering ragdoll state", Settings.VelocityMultiplier, 1f, 50f));
(ms_uiElements[(int)UiIndex.VelocityMultiplier] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(UiIndex.VelocityMultiplier, value);
@ -139,6 +143,10 @@ namespace ml_prm
case UiIndex.JumpRecover:
Settings.SetSetting(Settings.ModSetting.JumpRecover, p_state);
break;
case UiIndex.Buoyancy:
Settings.SetSetting(Settings.ModSetting.Buoyancy, p_state);
break;
}
if(p_force)
@ -182,9 +190,10 @@ namespace ml_prm
OnToggleUpdate(UiIndex.Bounciness, false, true);
OnToggleUpdate(UiIndex.ViewVelocity, false, true);
OnToggleUpdate(UiIndex.JumpRecover, false, true);
OnToggleUpdate(UiIndex.Buoyancy, true, true);
OnSliderUpdate(UiIndex.VelocityMultiplier, 2f, true);
OnSliderUpdate(UiIndex.MovementDrag, 2f, true);
OnSliderUpdate(UiIndex.AngularDrag, 2f, true);
OnSliderUpdate(UiIndex.MovementDrag, 1f, true);
OnSliderUpdate(UiIndex.AngularDrag, 1f, true);
OnSliderUpdate(UiIndex.RecoverDelay, 3f, true);
}

View file

@ -1,4 +1,4 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.0.11", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.1.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
[assembly: MelonLoader.MelonPriority(2)]
[assembly: MelonLoader.MelonOptionalDependencies("BTKUILib")]

View file

@ -11,6 +11,7 @@ This mod turns player's avatar into ragdoll puppet.
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.
* Note: You can't ragdoll in chairs.
* **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.
@ -25,6 +26,8 @@ Optional mod's settings page with [BTKUILib](https://github.com/BTK-Development/
* **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.
* **Buoyancy:** enabled floating in fluid volumes; `true` by default.
* Note: Forcibly enabled in worlds that don't allow flight.
* **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.

View file

@ -2,11 +2,14 @@
using ABI_RC.Core.InteractionSystem;
using ABI_RC.Core.Player;
using ABI_RC.Core.Savior;
using ABI_RC.Systems.Camera;
using ABI_RC.Systems.IK;
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;
using System.Collections.Generic;
using UnityEngine;
@ -19,11 +22,12 @@ namespace ml_prm
public static RagdollController Instance { get; private set; } = null;
VRIK m_vrIK = null;
float m_vrIkWeight = 1f;
bool m_inVr = false;
VRIK m_vrIK = null;
bool m_applyHipsPosition = false;
bool m_enabled = false;
bool m_forcedSwitch = false;
readonly List<Rigidbody> m_rigidBodies = null;
readonly List<Collider> m_colliders = null;
@ -32,8 +36,10 @@ namespace ml_prm
BipedRagdollReferences m_puppetReferences;
readonly List<System.Tuple<Transform, Transform>> m_boneLinks = null;
readonly List<System.Tuple<CharacterJoint, Vector3>> m_jointAnchors = null;
readonly List<PhysicsInfluencer> m_physicsInfluencers = null;
bool m_avatarReady = false;
Coroutine m_initCoroutine = null;
Vector3 m_lastPosition = Vector3.zero;
Vector3 m_velocity = Vector3.zero;
Vector3 m_ragdollLastPos = Vector3.zero;
@ -56,6 +62,7 @@ namespace ml_prm
m_colliders = new List<Collider>();
m_boneLinks = new List<System.Tuple<Transform, Transform>>();
m_jointAnchors = new List<System.Tuple<CharacterJoint, Vector3>>();
m_physicsInfluencers = new List<PhysicsInfluencer>();
m_physicsMaterial = new PhysicMaterial("Ragdoll");
m_physicsMaterial.dynamicFriction = c_defaultFriction;
@ -81,12 +88,14 @@ namespace ml_prm
m_puppetRoot.localRotation = Quaternion.identity;
m_customTrigger = MovementSystem.Instance.proxyCollider.gameObject.AddComponent<RagdollTrigger>();
m_customTrigger.enabled = false;
Settings.MovementDragChange += this.OnMovementDragChange;
Settings.AngularDragChange += this.OnAngularDragChange;
Settings.GravityChange += this.OnGravityChange;
Settings.SlipperinessChange += this.OnPhysicsMaterialChange;
Settings.BouncinessChange += this.OnPhysicsMaterialChange;
Settings.BuoyancyChange += this.OnBuoyancyChange;
}
void OnDestroy()
@ -112,6 +121,8 @@ namespace ml_prm
PlayerSetup.Instance.transform.position += l_dif;
m_puppetReferences.hips.position -= l_dif;
m_ragdollLastPos = m_puppetReferences.hips.position;
BodySystem.TrackingPositionWeight = 0f;
}
if(m_avatarReady && !m_enabled)
@ -128,9 +139,6 @@ namespace ml_prm
}
}
if(m_avatarReady && m_enabled && !BodySystem.isCalibrating)
BodySystem.TrackingPositionWeight = 0f;
if(m_avatarReady && m_enabled && Settings.AutoRecover)
{
m_downTime += Time.deltaTime;
@ -160,13 +168,8 @@ namespace ml_prm
{
if(m_enabled)
{
if(!BodySystem.isCalibrating)
{
BodySystem.TrackingPositionWeight = 0f;
foreach(var l_link in m_boneLinks)
l_link.Item1.CopyGlobal(l_link.Item2);
}
foreach(var l_link in m_boneLinks)
l_link.Item1.CopyGlobal(l_link.Item2);
}
else
{
@ -179,14 +182,30 @@ namespace ml_prm
// Game events
internal void OnAvatarClear()
{
if(m_enabled && (MovementSystem.Instance != null))
MovementSystem.Instance.SetImmobilized(false);
if(m_initCoroutine != null)
{
StopCoroutine(m_initCoroutine);
m_initCoroutine = null;
}
if(m_enabled)
{
TryRestoreMovement();
BodySystem.TrackingPositionWeight = 1f;
}
if(m_puppet != null)
Object.Destroy(m_puppet.gameObject);
m_puppet = null;
if(m_customTrigger != null)
{
m_customTrigger.GetStateWithReset();
m_customTrigger.enabled = false;
}
m_vrIK = null;
m_applyHipsPosition = false;
m_enabled = false;
m_avatarReady = false;
m_avatarRagdollToggle = null;
@ -196,6 +215,7 @@ namespace ml_prm
m_puppetReferences = new BipedRagdollReferences();
m_boneLinks.Clear();
m_jointAnchors.Clear();
m_physicsInfluencers.Clear();
m_reachedGround = true;
m_groundedTime = 0f;
m_downTime = float.MinValue;
@ -277,15 +297,32 @@ namespace ml_prm
Collider l_collider = l_puppetTransforms[i].GetComponent<Collider>();
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.proxyCollider, 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_body != null) && (l_collider != null) && (l_puppetTransforms[i] == m_puppetReferences.hips || l_puppetTransforms[i] == m_puppetReferences.spine || l_puppetTransforms[i] == m_puppetReferences.chest))
{
PhysicsInfluencer l_physicsInfluencer = l_puppetTransforms[i].gameObject.AddComponent<PhysicsInfluencer>();
l_physicsInfluencer.airDrag = (Utils.IsWorldSafe() ? Settings.MovementDrag : 1f);
l_physicsInfluencer.airAngularDrag = Settings.AngularDrag;
l_physicsInfluencer.fluidDrag = 3f;
l_physicsInfluencer.fluidAngularDrag = 1f;
l_physicsInfluencer.enableBuoyancy = true;
l_physicsInfluencer.enableInfluence = false;
float mass = l_body.mass;
l_physicsInfluencer.UpdateDensity();
l_body.mass = mass;
l_physicsInfluencer.volume = mass * 0.005f;
l_physicsInfluencer.enableLocalGravity = true;
m_physicsInfluencers.Add(l_physicsInfluencer);
}
if(l_avatarTransforms[i] != null)
m_boneLinks.Add(System.Tuple.Create(l_puppetTransforms[i], l_avatarTransforms[i]));
}
@ -294,22 +331,36 @@ namespace ml_prm
// And return back
m_puppetRoot.localPosition = Vector3.zero;
m_puppetRoot.localRotation = Quaternion.identity;
m_puppetRoot.gameObject.SetActive(false);
m_puppetRoot.gameObject.SetActive(true);
m_vrIK = PlayerSetup.Instance._avatar.GetComponent<VRIK>();
if(m_vrIK != null)
{
m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreUpdate);
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate);
}
m_avatarRagdollToggle = PlayerSetup.Instance._avatar.GetComponentInChildren<RagdollToggle>(true);
m_ragdolledParameter = new AvatarBoolParameter("Ragdolled", PlayerSetup.Instance.animatorManager);
m_avatarReady = true;
m_initCoroutine = StartCoroutine(WaitForPhysicsInfluencers());
}
}
IEnumerator WaitForPhysicsInfluencers()
{
while(!m_physicsInfluencers.TrueForAll(p => p.IsReady()))
yield return null;
m_puppetRoot.gameObject.SetActive(false);
m_customTrigger.enabled = true;
m_avatarReady = true;
m_initCoroutine = null;
OnGravityChange(Settings.Gravity);
OnBuoyancyChange(Settings.Buoyancy);
OnMovementDragChange(Settings.MovementDrag);
OnAngularDragChange(Settings.AngularDrag);
}
internal void OnAvatarScaling(float p_scaleDifference)
{
if(m_avatarReady)
@ -323,13 +374,21 @@ namespace ml_prm
internal void OnSeatSitDown(CVRSeat p_seat)
{
if(m_avatarReady && m_enabled && !p_seat.occupied)
{
m_forcedSwitch = true;
SwitchRagdoll();
m_forcedSwitch = false;
}
}
internal void OnStartCalibration()
{
if(m_avatarReady && m_enabled)
{
m_forcedSwitch = true;
SwitchRagdoll();
m_forcedSwitch = false;
}
}
internal void OnWorldSpawn()
@ -340,6 +399,7 @@ namespace ml_prm
OnGravityChange(Settings.Gravity);
OnPhysicsMaterialChange(true);
OnMovementDragChange(Settings.MovementDrag);
OnBuoyancyChange(Settings.Buoyancy);
}
internal void OnCombatDown()
@ -347,30 +407,38 @@ namespace ml_prm
if(m_avatarReady && !m_enabled && Settings.CombatReaction)
{
m_reachedGround = true;
m_forcedSwitch = true;
SwitchRagdoll();
m_forcedSwitch = false;
}
}
internal void OnChangeFlight()
{
if(m_avatarReady && m_enabled && MovementSystem.Instance.flying)
{
m_forcedSwitch = true;
SwitchRagdoll();
m_forcedSwitch = false;
}
}
internal void OnPlayerTeleport()
{
if(m_avatarReady && m_enabled)
m_ragdollLastPos = m_puppetReferences.hips.position;
}
internal void OnDroneModeDisable()
{
if(m_avatarReady && m_enabled)
MovementSystem.Instance.canRot = false;
}
// 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
if(!m_enabled)
{
foreach(var l_link in m_boneLinks)
l_link.Item2.CopyGlobal(l_link.Item1);
@ -389,6 +457,8 @@ namespace ml_prm
if(m_enabled)
l_body.WakeUp();
}
foreach(PhysicsInfluencer l_influencer in m_physicsInfluencers)
l_influencer.airDrag = l_drag;
}
}
void OnAngularDragChange(float p_value)
@ -401,6 +471,8 @@ namespace ml_prm
if(m_enabled)
l_body.WakeUp();
}
foreach(PhysicsInfluencer l_influencer in m_physicsInfluencers)
l_influencer.airAngularDrag = p_value;
}
}
void OnGravityChange(bool p_state)
@ -410,6 +482,14 @@ namespace ml_prm
bool l_gravity = (!Utils.IsWorldSafe() || p_state);
foreach(Rigidbody l_body in m_rigidBodies)
l_body.useGravity = l_gravity;
foreach(PhysicsInfluencer l_influencer in m_physicsInfluencers)
l_influencer.enabled = l_gravity;
if(!l_gravity)
{
OnMovementDragChange(Settings.MovementDrag);
OnAngularDragChange(Settings.AngularDrag);
}
}
}
void OnPhysicsMaterialChange(bool p_state)
@ -425,6 +505,21 @@ namespace ml_prm
m_physicsMaterial.bounceCombine = (l_bounciness ? PhysicMaterialCombine.Maximum : PhysicMaterialCombine.Average);
}
}
void OnBuoyancyChange(bool p_state)
{
if(m_avatarReady)
{
bool l_buoyancy = (!Utils.IsWorldSafe() || p_state);
foreach(PhysicsInfluencer l_influencer in m_physicsInfluencers)
l_influencer.enableInfluence = l_buoyancy;
if(!l_buoyancy)
{
OnMovementDragChange(Settings.MovementDrag);
OnAngularDragChange(Settings.AngularDrag);
}
}
}
// Arbitrary
public void SwitchRagdoll()
@ -433,40 +528,17 @@ namespace ml_prm
{
if(!m_enabled)
{
if(IsSafeToRagdoll() && m_reachedGround)
if(CanRagdoll())
{
// 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);
BodySystem.TrackingPositionWeight = 0f;
m_applyHipsPosition = IKSystem.Instance.applyOriginalHipPosition;
IKSystem.Instance.applyOriginalHipPosition = true;
PlayerSetup.Instance.animatorManager.SetAnimatorParameterTrigger("CancelEmote");
m_ragdolledParameter.SetValue(true);
if(!BodySystem.isCalibrating)
BodySystem.TrackingPositionWeight = 0f;
if(!Utils.IsWorldSafe())
{
@ -492,9 +564,6 @@ namespace ml_prm
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;
@ -503,39 +572,39 @@ namespace ml_prm
}
else
{
if(IsSafeToUnragdoll())
if(CanUnragdoll())
{
MovementSystem.Instance.SetImmobilized(false);
MovementSystem.Instance.TeleportTo(m_puppetReferences.hips.position, new Vector3(0f, PlayerSetup.Instance.GetActiveCamera().transform.rotation.eulerAngles.y, 0f));
TryRestoreMovement();
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;
BodySystem.TrackingPositionWeight = 1f;
IKSystem.Instance.applyOriginalHipPosition = m_applyHipsPosition;
if(m_vrIK != null)
m_vrIK.solver.Reset();
m_ragdolledParameter.SetValue(false);
m_puppetRoot.gameObject.SetActive(false);
m_puppetRoot.localPosition = Vector3.zero;
m_puppetRoot.localRotation = Quaternion.identity;
foreach(Rigidbody l_body in m_rigidBodies)
l_body.isKinematic = true;
m_lastPosition = PlayerSetup.Instance.transform.position;
m_velocity = Vector3.zero;
m_downTime = float.MinValue;
// Restore rigidbody properties that could be affected by buoyancy
OnMovementDragChange(Settings.MovementDrag);
OnAngularDragChange(Settings.AngularDrag);
m_enabled = false;
}
}
@ -552,19 +621,34 @@ namespace ml_prm
return l_target;
}
static bool IsSafeToRagdoll()
bool CanRagdoll()
{
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;
bool l_result = m_reachedGround;
l_result &= !BodySystem.isCalibrating;
l_result &= (MovementSystem.Instance.lastSeat == null);
l_result &= ((CombatSystem.Instance == null) || !CombatSystem.Instance.isDown);
return (l_result || m_forcedSwitch);
}
static bool IsSafeToUnragdoll()
bool CanUnragdoll()
{
bool l_result = true;
l_result &= ((CombatSystem.Instance == null) || !CombatSystem.Instance.isDown); // Non-combat world or not dead
return l_result;
l_result &= ((CombatSystem.Instance == null) || !CombatSystem.Instance.isDown);
return (l_result || m_forcedSwitch);
}
static void TryRestoreMovement()
{
bool l_state = true;
l_state &= ((CombatSystem.Instance == null) || !CombatSystem.Instance.isDown);
l_state &= (MovementSystem.Instance.lastSeat == null);
if(l_state)
{
MovementSystem.Instance.SetImmobilized(false);
if(PortableCamera.Instance.CheckModActive(typeof(ABI_RC.Systems.Camera.VisualMods.DroneMode)))
MovementSystem.Instance.canRot = false;
}
}
}
}

View file

@ -22,7 +22,8 @@ namespace ml_prm
Slipperiness,
Bounciness,
ViewVelocity,
JumpRecover
JumpRecover,
Buoyancy
}
public static bool Hotkey { get; private set; } = true;
@ -40,6 +41,7 @@ namespace ml_prm
public static bool Bounciness { get; private set; } = false;
public static bool ViewVelocity { get; private set; } = false;
public static bool JumpRecover { get; private set; } = false;
public static bool Buoyancy { get; private set; } = true;
static public event Action<bool> HotkeyChange;
static public event Action<KeyCode> HotkeyKeyChange;
@ -56,6 +58,7 @@ namespace ml_prm
static public event Action<bool> BouncinessChange;
static public event Action<bool> ViewVelocityChange;
static public event Action<bool> JumpRecoverChange;
static public event Action<bool> BuoyancyChange;
static MelonLoader.MelonPreferences_Category ms_category = null;
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
@ -80,7 +83,8 @@ namespace ml_prm
ms_category.CreateEntry(ModSetting.Slipperiness.ToString(), Slipperiness, null, null, true),
ms_category.CreateEntry(ModSetting.Bounciness.ToString(), Bounciness, null, null, true),
ms_category.CreateEntry(ModSetting.ViewVelocity.ToString(), ViewVelocity, null, null, true),
ms_category.CreateEntry(ModSetting.JumpRecover.ToString(), JumpRecover, null, null, true)
ms_category.CreateEntry(ModSetting.JumpRecover.ToString(), JumpRecover, null, null, true),
ms_category.CreateEntry(ModSetting.Buoyancy.ToString(), Buoyancy, null, null, true),
};
ms_entries[(int)ModSetting.HotkeyKey].OnEntryValueChangedUntyped.Subscribe(OnMelonSettingSave_HotkeyKey);
@ -100,6 +104,7 @@ namespace ml_prm
Bounciness = (bool)ms_entries[(int)ModSetting.Bounciness].BoxedValue;
ViewVelocity = (bool)ms_entries[(int)ModSetting.ViewVelocity].BoxedValue;
JumpRecover = (bool)ms_entries[(int)ModSetting.JumpRecover].BoxedValue;
Buoyancy = (bool)ms_entries[(int)ModSetting.Buoyancy].BoxedValue;
}
static void OnMelonSettingSave_HotkeyKey(object p_oldValue, object p_newValue)
@ -186,6 +191,13 @@ namespace ml_prm
}
break;
case ModSetting.Buoyancy:
{
Buoyancy = (bool)p_value;
BuoyancyChange?.Invoke((bool)p_value);
}
break;
// Floats
case ModSetting.VelocityMultiplier:
{

View file

@ -1,6 +1,7 @@
using ABI.CCK.Components;
using ABI_RC.Core.Savior;
using ABI_RC.Systems.MovementSystem;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
@ -10,6 +11,7 @@ namespace ml_prm
{
static readonly FieldInfo ms_groundedRaw = typeof(MovementSystem).GetField("_isGroundedRaw", BindingFlags.NonPublic | BindingFlags.Instance);
static readonly FieldInfo ms_appliedGravity = typeof(MovementSystem).GetField("_appliedGravity", BindingFlags.NonPublic | BindingFlags.Instance);
static readonly FieldInfo ms_referencePoints = typeof(PhysicsInfluencer).GetField("_referencePoints", BindingFlags.NonPublic | BindingFlags.Instance);
public static bool IsInVR() => ((CheckVR.Instance != null) && CheckVR.Instance.hasVrDeviceLoaded);
public static bool IsWorldSafe() => ((CVRWorld.Instance != null) && CVRWorld.Instance.allowFlying);
@ -35,5 +37,10 @@ namespace ml_prm
p_target.position = p_source.position;
p_target.rotation = p_source.rotation;
}
public static bool IsReady(this PhysicsInfluencer p_instance)
{
return ((ms_referencePoints.GetValue(p_instance) as List<Vector3>).Count > 0);
}
}
}

View file

@ -4,7 +4,7 @@
<TargetFramework>netstandard2.1</TargetFramework>
<Platforms>x64</Platforms>
<PackageId>PlayerRagdollMod</PackageId>
<Version>1.0.11</Version>
<Version>1.1.0</Version>
<Authors>SDraw</Authors>
<Company>None</Company>
<Product>PlayerRagdollMod</Product>

View file

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Before After
Before After