Instance set changes

Additional animator parameters
Reworked rigidbodies
Update to latest LeapC and LeapCSharp
This commit is contained in:
SDraw 2024-07-20 11:13:51 +03:00
parent 1f0b518761
commit 075ff67304
No known key found for this signature in database
GPG key ID: BB95B4DAB2BB8BB5
38 changed files with 8310 additions and 8646 deletions

View file

@ -1,253 +1,253 @@
using ABI.CCK.Components;
using ABI_RC.Core;
using ABI_RC.Core.InteractionSystem;
using ABI_RC.Core.Player;
using ABI_RC.Systems.IK;
using ABI_RC.Systems.IK.SubSystems;
using ABI_RC.Systems.Movement;
using System;
using System.Linq;
using System.Reflection;
namespace ml_prm
{
static class GameEvents
{
internal class EventResult
{
public bool m_result = false;
}
internal class GameEvent
{
event Action m_action;
public void AddHandler(Action p_listener) => m_action += p_listener;
public void RemoveHandler(Action p_listener) => m_action -= p_listener;
public void Invoke() => m_action?.Invoke();
}
internal class GameEvent<T1>
{
event Action<T1> m_action;
public void AddHandler(Action<T1> p_listener) => m_action += p_listener;
public void RemoveHandler(Action<T1> p_listener) => m_action -= p_listener;
public void Invoke(T1 p_obj) => m_action?.Invoke(p_obj);
}
public static readonly GameEvent OnAvatarSetup = new GameEvent();
public static readonly GameEvent OnAvatarClear = new GameEvent();
public static readonly GameEvent OnAvatarPreReuse = new GameEvent();
public static readonly GameEvent OnAvatarPostReuse = new GameEvent();
public static readonly GameEvent<float> OnIKScaling = new GameEvent<float>();
public static readonly GameEvent<CVRSeat> OnSeatPreSit = new GameEvent<CVRSeat>();
public static readonly GameEvent OnCalibrationStart = new GameEvent();
public static readonly GameEvent OnWorldPreSpawn = new GameEvent();
public static readonly GameEvent OnCombatPreDown = new GameEvent();
public static readonly GameEvent OnFlightChange = new GameEvent();
public static readonly GameEvent<EventResult> OnIKOffsetUpdate = new GameEvent<EventResult>();
static readonly EventResult ms_result = new EventResult();
internal static void Init(HarmonyLib.Harmony p_instance)
{
try
{
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
);
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch(
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarReinitialize_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch(
typeof(PlayerSetup).GetMethod("SetupIKScaling", BindingFlags.NonPublic | BindingFlags.Instance),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupIKScaling_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch(
typeof(CVRSeat).GetMethod(nameof(CVRSeat.SitDown)),
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnCVRSeatSitDown_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
null
);
p_instance.Patch(
typeof(BodySystem).GetMethod(nameof(BodySystem.StartCalibration)),
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnStartCalibration_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
null
);
p_instance.Patch(
typeof(RootLogic).GetMethod(nameof(RootLogic.SpawnOnWorldInstance)),
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnWorldSpawn_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
null
);
p_instance.Patch(
typeof(CombatSystem).GetMethods().First(m => (!m.IsGenericMethod && m.Name == nameof(CombatSystem.Down))),
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnCombatDown_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
null
);
p_instance.Patch(
typeof(BetterBetterCharacterController).GetMethod(nameof(BetterBetterCharacterController.ChangeFlight)),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnChangeFlight_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch(
typeof(IKSystem).GetMethod("OnPreSolverUpdateActiveOffset", BindingFlags.Instance | BindingFlags.NonPublic),
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnOffsetUpdate_Prefix), BindingFlags.Static | BindingFlags.NonPublic))
);
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnAvatarClear_Postfix()
{
try
{
OnAvatarClear.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnSetupAvatar_Postfix()
{
try
{
OnAvatarSetup.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnAvatarReinitialize_Prefix()
{
try
{
OnAvatarPreReuse.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnAvatarReinitialize_Postfix()
{
try
{
OnAvatarPostReuse.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnSetupIKScaling_Postfix(ref UnityEngine.Vector3 ___scaleDifference)
{
try
{
OnIKScaling.Invoke(1f + ___scaleDifference.y);
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnCVRSeatSitDown_Prefix(ref CVRSeat __instance)
{
try
{
OnSeatPreSit.Invoke(__instance);
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnStartCalibration_Prefix()
{
try
{
OnCalibrationStart.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnWorldSpawn_Prefix()
{
try
{
OnWorldPreSpawn.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnCombatDown_Prefix()
{
try
{
OnCombatPreDown.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnChangeFlight_Postfix()
{
try
{
OnFlightChange.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static bool OnOffsetUpdate_Prefix()
{
try
{
ms_result.m_result = false;
OnIKOffsetUpdate.Invoke(ms_result);
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
return !ms_result.m_result;
}
}
}
using ABI.CCK.Components;
using ABI_RC.Core;
using ABI_RC.Core.InteractionSystem;
using ABI_RC.Core.Player;
using ABI_RC.Systems.IK;
using ABI_RC.Systems.IK.SubSystems;
using ABI_RC.Systems.Movement;
using System;
using System.Linq;
using System.Reflection;
namespace ml_prm
{
static class GameEvents
{
internal class EventResult
{
public bool m_result = false;
}
internal class GameEvent
{
event Action m_action;
public void AddHandler(Action p_listener) => m_action += p_listener;
public void RemoveHandler(Action p_listener) => m_action -= p_listener;
public void Invoke() => m_action?.Invoke();
}
internal class GameEvent<T1>
{
event Action<T1> m_action;
public void AddHandler(Action<T1> p_listener) => m_action += p_listener;
public void RemoveHandler(Action<T1> p_listener) => m_action -= p_listener;
public void Invoke(T1 p_obj) => m_action?.Invoke(p_obj);
}
public static readonly GameEvent OnAvatarSetup = new GameEvent();
public static readonly GameEvent OnAvatarClear = new GameEvent();
public static readonly GameEvent OnAvatarPreReuse = new GameEvent();
public static readonly GameEvent OnAvatarPostReuse = new GameEvent();
public static readonly GameEvent<float> OnIKScaling = new GameEvent<float>();
public static readonly GameEvent<CVRSeat> OnSeatPreSit = new GameEvent<CVRSeat>();
public static readonly GameEvent OnCalibrationStart = new GameEvent();
public static readonly GameEvent OnWorldPreSpawn = new GameEvent();
public static readonly GameEvent OnCombatPreDown = new GameEvent();
public static readonly GameEvent OnFlightChange = new GameEvent();
public static readonly GameEvent<EventResult> OnIKOffsetUpdate = new GameEvent<EventResult>();
static readonly EventResult ms_result = new EventResult();
internal static void Init(HarmonyLib.Harmony p_instance)
{
try
{
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
);
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch(
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarReinitialize_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch(
typeof(PlayerSetup).GetMethod("SetupIKScaling", BindingFlags.NonPublic | BindingFlags.Instance),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupIKScaling_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch(
typeof(CVRSeat).GetMethod(nameof(CVRSeat.SitDown)),
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnCVRSeatSitDown_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
null
);
p_instance.Patch(
typeof(BodySystem).GetMethod(nameof(BodySystem.StartCalibration)),
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnStartCalibration_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
null
);
p_instance.Patch(
typeof(RootLogic).GetMethod(nameof(RootLogic.SpawnOnWorldInstance)),
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnWorldSpawn_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
null
);
p_instance.Patch(
typeof(CombatSystem).GetMethods().First(m => (!m.IsGenericMethod && m.Name == nameof(CombatSystem.Down))),
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnCombatDown_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
null
);
p_instance.Patch(
typeof(BetterBetterCharacterController).GetMethod(nameof(BetterBetterCharacterController.ChangeFlight)),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnChangeFlight_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch(
typeof(IKSystem).GetMethod("OnPreSolverUpdateActiveOffset", BindingFlags.Instance | BindingFlags.NonPublic),
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnOffsetUpdate_Prefix), BindingFlags.Static | BindingFlags.NonPublic))
);
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnAvatarClear_Postfix()
{
try
{
OnAvatarClear.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnSetupAvatar_Postfix()
{
try
{
OnAvatarSetup.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnAvatarReinitialize_Prefix()
{
try
{
OnAvatarPreReuse.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnAvatarReinitialize_Postfix()
{
try
{
OnAvatarPostReuse.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnSetupIKScaling_Postfix(ref UnityEngine.Vector3 ___scaleDifference)
{
try
{
OnIKScaling.Invoke(1f + ___scaleDifference.y);
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnCVRSeatSitDown_Prefix(ref CVRSeat __instance)
{
try
{
OnSeatPreSit.Invoke(__instance);
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnStartCalibration_Prefix()
{
try
{
OnCalibrationStart.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnWorldSpawn_Prefix()
{
try
{
OnWorldPreSpawn.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnCombatDown_Prefix()
{
try
{
OnCombatPreDown.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnChangeFlight_Postfix()
{
try
{
OnFlightChange.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static bool OnOffsetUpdate_Prefix()
{
try
{
ms_result.m_result = false;
OnIKOffsetUpdate.Invoke(ms_result);
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
return !ms_result.m_result;
}
}
}

View file

@ -1,29 +0,0 @@
using ABI.CCK.Components;
using ABI_RC.Systems.Movement;
using UnityEngine;
namespace ml_prm
{
[DisallowMultipleComponent]
class GravityInfluencer : MonoBehaviour
{
Rigidbody m_rigidBody = null;
PhysicsInfluencer m_physicsInfluencer = null;
bool m_activeGravity = true;
void Start()
{
m_rigidBody = this.GetComponent<Rigidbody>();
m_physicsInfluencer = this.GetComponent<PhysicsInfluencer>();
}
void FixedUpdate()
{
m_rigidBody.useGravity = false;
if(m_activeGravity && ((m_physicsInfluencer == null) || !m_physicsInfluencer.enableInfluence || !m_physicsInfluencer.GetSubmerged()))
m_rigidBody.AddForce(BetterBetterCharacterController.Instance.GravityResult.AppliedGravity * m_rigidBody.mass);
}
public void SetActiveGravity(bool p_state) => m_activeGravity = p_state;
}
}

View file

@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using BTKUILib.UIObjects;
using BTKUILib.UIObjects.Components;
namespace ml_prm
{
@ -37,83 +37,103 @@ namespace ml_prm
FallLimit
}
const string c_ragdollKeyTooltip = "Switch ragdoll mode with '{0}' key";
const string c_fallLimitTooltip = "Fall limit based on impact velocity<p>Current value corresponds to drop from {0} units with default gravity</p>";
internal static readonly UiEvent OnSwitchChanged = new UiEvent();
static List<object> ms_uiElements = null;
static Page ms_page = null;
static Category ms_category = null;
static Button ms_ragdollButton = null;
static ToggleButton ms_hotkeyToggle = null;
static ToggleButton ms_gravityToggle = null;
static ToggleButton ms_pointersToggle = null;
static ToggleButton ms_ignoreLocalToggle = null;
static ToggleButton ms_combatToggle = null;
static ToggleButton ms_recoveryToggle = null;
static ToggleButton ms_slipperinessToggle = null;
static ToggleButton ms_bouncinessToggle = null;
static ToggleButton ms_viewDirectionToggle = null;
static ToggleButton ms_jumpRecoverToggle = null;
static ToggleButton ms_buoyancyToggle = null;
static ToggleButton ms_fallDamageToggle = null;
static SliderFloat ms_velocityMultiplierSlider = null;
static SliderFloat ms_movementDragSlider = null;
static SliderFloat ms_angularMovementDragSlider = null;
static SliderFloat ms_recoverDelaySlider = null;
static SliderFloat ms_fallLimitSlider = null;
static Button ms_resetButton = null;
internal static void Init()
{
ms_uiElements = new List<object>();
if(MelonLoader.MelonMod.RegisteredMelons.FirstOrDefault(m => m.Info.Name == "BTKUILib") != null)
CreateUi();
}
// Separated method, otherwise exception is thrown, funny CSharp and optional references, smh
static void CreateUi()
{
BTKUILib.QuickMenuAPI.PrepareIcon("PlayerRagdollMod", "PRM-Person", GetIconStream("person.png"));
var l_modRoot = new BTKUILib.UIObjects.Page("PlayerRagdollMod", "MainPage", true, "PRM-Person");
l_modRoot.MenuTitle = "Player Ragdoll Mod";
l_modRoot.MenuSubtitle = "Become a ragdoll and change various settings for people amusement";
ms_page = new Page("PlayerRagdollMod", "MainPage", true, "PRM-Person");
ms_page.MenuTitle = "Player Ragdoll Mod";
ms_page.MenuSubtitle = "Become a ragdoll and change various settings for people amusement";
var l_modCategory = l_modRoot.AddCategory("Settings");
ms_category = ms_page.AddCategory("Settings");
l_modCategory.AddButton("Switch ragdoll", "PRM-Person", "Switch between normal and ragdoll state.").OnPress += OnSwitch;
ms_ragdollButton = ms_category.AddButton("Switch ragdoll", "PRM-Person", "Switch between normal and ragdoll state");
ms_ragdollButton.OnPress += OnSwitch;
ms_hotkeyToggle = ms_category.AddToggle("Use hotkey", "Switch ragdoll mode with 'R' key", Settings.Hotkey);
ms_hotkeyToggle.ToggleTooltip = string.Format(c_ragdollKeyTooltip, Settings.HotkeyKey);
ms_hotkeyToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Hotkey, state);
Settings.OnHotkeyKeyChanged.AddHandler(OnHotkeyKeyChanged);
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);
ms_gravityToggle = ms_category.AddToggle("Use gravity", "Apply gravity to ragdoll", Settings.Gravity);
ms_gravityToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Gravity, state);
ms_uiElements.Add(l_modCategory.AddToggle("Use gravity", "Apply gravity to ragdoll", Settings.Gravity));
(ms_uiElements[(int)UiIndex.Gravity] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Gravity, state);
ms_pointersToggle = ms_category.AddToggle("Pointers reaction", "React to trigger colliders with CVRPointer component of 'ragdoll' type", Settings.PointersReaction);
ms_pointersToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.PointersReaction, state);
ms_uiElements.Add(l_modCategory.AddToggle("Pointers reaction", "React to trigger colliders with CVRPointer component of 'ragdoll' type", Settings.PointersReaction));
(ms_uiElements[(int)UiIndex.PointersReaction] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.PointersReaction, state);
ms_ignoreLocalToggle = ms_category.AddToggle("Ignore local pointers", "Ignore local avatar's CVRPointer components of 'ragdoll' type", Settings.IgnoreLocal);
ms_ignoreLocalToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.IgnoreLocal, state);
ms_uiElements.Add(l_modCategory.AddToggle("Ignore local pointers", "Ignore local avatar's CVRPointer components of 'ragdoll' type", Settings.IgnoreLocal));
(ms_uiElements[(int)UiIndex.IgnoreLocal] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.IgnoreLocal, state);
ms_combatToggle = ms_category.AddToggle("Combat reaction", "Ragdoll upon combat system death", Settings.CombatReaction);
ms_combatToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.CombatReaction, state);
ms_uiElements.Add(l_modCategory.AddToggle("Combat reaction", "Ragdoll upon combat system death", Settings.CombatReaction));
(ms_uiElements[(int)UiIndex.CombatReaction] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.CombatReaction, state);
ms_recoveryToggle = ms_category.AddToggle("Auto recover", "Automatically unragdoll after set recover delay", Settings.AutoRecover);
ms_recoveryToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.AutoRecover, state);
ms_uiElements.Add(l_modCategory.AddToggle("Auto recover", "Automatically unragdoll after set recover delay", Settings.AutoRecover));
(ms_uiElements[(int)UiIndex.AutoRecover] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.AutoRecover, state);
ms_slipperinessToggle = ms_category.AddToggle("Slipperiness", "Enables/disables friction of ragdoll", Settings.Slipperiness);
ms_slipperinessToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Slipperiness, state);
ms_uiElements.Add(l_modCategory.AddToggle("Slipperiness", "Enables/disables friction of ragdoll", Settings.Slipperiness));
(ms_uiElements[(int)UiIndex.Slipperiness] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Slipperiness, state);
ms_bouncinessToggle = ms_category.AddToggle("Bounciness", "Enables/disables bounciness of ragdoll", Settings.Bounciness);
ms_bouncinessToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Bounciness, state);
ms_uiElements.Add(l_modCategory.AddToggle("Bounciness", "Enables/disables bounciness of ragdoll", Settings.Bounciness));
(ms_uiElements[(int)UiIndex.Bounciness] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Bounciness, state);
ms_viewDirectionToggle = ms_category.AddToggle("View direction velocity", "Apply velocity to camera view direction", Settings.ViewVelocity);
ms_viewDirectionToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.ViewVelocity, state);
ms_uiElements.Add(l_modCategory.AddToggle("View direction velocity", "Apply velocity to camera view direction", Settings.ViewVelocity));
(ms_uiElements[(int)UiIndex.ViewVelocity] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.ViewVelocity, state);
ms_jumpRecoverToggle = ms_category.AddToggle("Jump recover", "Recover from ragdoll state by jumping", Settings.JumpRecover);
ms_jumpRecoverToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.JumpRecover, state);
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_buoyancyToggle = ms_category.AddToggle("Buoyancy", "Enable buoyancy in fluid volumes<p>Warning: constantly changes movement and air drag of hips, spine and chest</p>", Settings.Buoyancy);
ms_buoyancyToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Buoyancy, 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_fallDamageToggle = ms_category.AddToggle("Fall damage", "Enable ragdoll when falling from height", Settings.FallDamage);
ms_fallDamageToggle.OnValueUpdated += (state) => OnToggleUpdate(UiIndex.FallDamage, state);
ms_uiElements.Add(l_modCategory.AddToggle("Fall damage", "Enable ragdoll when falling from height", Settings.FallDamage));
(ms_uiElements[(int)UiIndex.FallDamage] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.FallDamage, state);
ms_velocityMultiplierSlider = ms_category.AddSlider("Velocity multiplier", "Velocity multiplier upon entering ragdoll state", Settings.VelocityMultiplier, 1f, 50f);
ms_velocityMultiplierSlider.OnValueUpdated += (value) => OnSliderUpdate(UiIndex.VelocityMultiplier, value);
ms_uiElements.Add(l_modCategory.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);
ms_movementDragSlider = ms_category.AddSlider("Movement drag", "Movement resistance", Settings.MovementDrag, 0f, 50f);
ms_movementDragSlider.OnValueUpdated += (value) => OnSliderUpdate(UiIndex.MovementDrag, value);
ms_uiElements.Add(l_modCategory.AddSlider("Movement drag", "Movement resistance", Settings.MovementDrag, 0f, 50f));
(ms_uiElements[(int)UiIndex.MovementDrag] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(UiIndex.MovementDrag, value);
ms_angularMovementDragSlider = ms_category.AddSlider("Angular movement drag", "Rotation movement resistance", Settings.AngularDrag, 0f, 50f);
ms_angularMovementDragSlider.OnValueUpdated += (value) => OnSliderUpdate(UiIndex.AngularDrag, value);
ms_uiElements.Add(l_modCategory.AddSlider("Angular movement drag", "Rotation movement resistance", Settings.AngularDrag, 0f, 50f));
(ms_uiElements[(int)UiIndex.AngularDrag] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(UiIndex.AngularDrag, value);
ms_recoverDelaySlider = ms_category.AddSlider("Recover delay (seconds)", "Recover delay for automatic recover", Settings.RecoverDelay, 1f, 10f);
ms_recoverDelaySlider.OnValueUpdated += (value) => OnSliderUpdate(UiIndex.RecoverDelay, value);
ms_uiElements.Add(l_modCategory.AddSlider("Recover delay (seconds)", "Recover delay for automatic recover", Settings.RecoverDelay, 1f, 10f));
(ms_uiElements[(int)UiIndex.RecoverDelay] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(UiIndex.RecoverDelay, value);
ms_fallLimitSlider = ms_category.AddSlider("Fall limit", "", Settings.FallLimit, 4.5f, 44.5f);
ms_fallLimitSlider.SliderTooltip = string.Format(c_fallLimitTooltip, GetDropHeight(Settings.FallLimit));
ms_fallLimitSlider.OnValueUpdated += (value) => OnSliderUpdate(UiIndex.FallLimit, value);
ms_uiElements.Add(l_modCategory.AddSlider("Fall limit", "Height limit for fall damage", Settings.FallLimit, 0f, 100f));
(ms_uiElements[(int)UiIndex.FallLimit] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(UiIndex.FallLimit, value);
l_modCategory.AddButton("Reset settings", "", "Reset mod settings to default").OnPress += Reset;
ms_resetButton = ms_category.AddButton("Reset settings", "", "Reset mod settings to default");
ms_resetButton.OnPress += Reset;
}
static void OnSwitch()
@ -128,7 +148,7 @@ namespace ml_prm
}
}
static void OnToggleUpdate(UiIndex p_index, bool p_state, bool p_force = false)
static void OnToggleUpdate(UiIndex p_index, bool p_state)
{
try
{
@ -182,9 +202,6 @@ namespace ml_prm
Settings.SetSetting(Settings.ModSetting.FallDamage, p_state);
break;
}
if(p_force)
(ms_uiElements[(int)p_index] as BTKUILib.UIObjects.Components.ToggleButton).ToggleValue = p_state;
}
catch(Exception e)
{
@ -192,7 +209,7 @@ namespace ml_prm
}
}
static void OnSliderUpdate(UiIndex p_index, float p_value, bool p_force = false)
static void OnSliderUpdate(UiIndex p_index, float p_value)
{
try
{
@ -215,12 +232,12 @@ namespace ml_prm
break;
case UiIndex.FallLimit:
{
Settings.SetSetting(Settings.ModSetting.FallLimit, p_value);
break;
ms_fallLimitSlider.SliderTooltip = string.Format(c_fallLimitTooltip, GetDropHeight(p_value));
}
break;
}
if(p_force)
(ms_uiElements[(int)p_index] as BTKUILib.UIObjects.Components.SliderFloat).SetSliderValue(p_value);
}
catch(Exception e)
{
@ -230,23 +247,62 @@ namespace ml_prm
static void Reset()
{
OnToggleUpdate(UiIndex.Hotkey, true, true);
OnToggleUpdate(UiIndex.Gravity, true, true);
OnToggleUpdate(UiIndex.PointersReaction, true, true);
OnToggleUpdate(UiIndex.IgnoreLocal, true, true);
OnToggleUpdate(UiIndex.CombatReaction, true, true);
OnToggleUpdate(UiIndex.AutoRecover, false, true);
OnToggleUpdate(UiIndex.Slipperiness, false, true);
OnToggleUpdate(UiIndex.Bounciness, false, true);
OnToggleUpdate(UiIndex.ViewVelocity, false, true);
OnToggleUpdate(UiIndex.JumpRecover, false, true);
OnToggleUpdate(UiIndex.Buoyancy, true, true);
OnToggleUpdate(UiIndex.FallDamage, true, true);
OnSliderUpdate(UiIndex.VelocityMultiplier, 2f, true);
OnSliderUpdate(UiIndex.MovementDrag, 1f, true);
OnSliderUpdate(UiIndex.AngularDrag, 1f, true);
OnSliderUpdate(UiIndex.RecoverDelay, 3f, true);
OnSliderUpdate(UiIndex.FallLimit, 5f, true);
OnToggleUpdate(UiIndex.Hotkey, true);
ms_hotkeyToggle.ToggleValue = true;
OnToggleUpdate(UiIndex.Gravity, true);
ms_gravityToggle.ToggleValue = true;
OnToggleUpdate(UiIndex.PointersReaction, true);
ms_pointersToggle.ToggleValue = true;
OnToggleUpdate(UiIndex.IgnoreLocal, true);
ms_ignoreLocalToggle.ToggleValue = true;
OnToggleUpdate(UiIndex.CombatReaction, true);
ms_combatToggle.ToggleValue = true;
OnToggleUpdate(UiIndex.AutoRecover, false);
ms_recoveryToggle.ToggleValue = false;
OnToggleUpdate(UiIndex.Slipperiness, false);
ms_slipperinessToggle.ToggleValue = false;
OnToggleUpdate(UiIndex.Bounciness, false);
ms_bouncinessToggle.ToggleValue = false;
OnToggleUpdate(UiIndex.ViewVelocity, false);
ms_viewDirectionToggle.ToggleValue = false;
OnToggleUpdate(UiIndex.JumpRecover, false);
ms_jumpRecoverToggle.ToggleValue = false;
OnToggleUpdate(UiIndex.Buoyancy, true);
ms_buoyancyToggle.ToggleValue = true;
OnToggleUpdate(UiIndex.FallDamage, true);
ms_fallDamageToggle.ToggleValue = true;
OnSliderUpdate(UiIndex.VelocityMultiplier, 2f);
ms_velocityMultiplierSlider.SetSliderValue(2f);
OnSliderUpdate(UiIndex.MovementDrag, 1f);
ms_movementDragSlider.SetSliderValue(1f);
OnSliderUpdate(UiIndex.AngularDrag, 1f);
ms_angularMovementDragSlider.SetSliderValue(1f);
OnSliderUpdate(UiIndex.RecoverDelay, 3f);
ms_recoverDelaySlider.SetSliderValue(3f);
OnSliderUpdate(UiIndex.FallLimit, 9.899494f);
ms_fallLimitSlider.SetSliderValue(9.899494f);
}
static void OnHotkeyKeyChanged(UnityEngine.KeyCode p_keyCode)
{
if(ms_ragdollButton != null)
ms_hotkeyToggle.ToggleTooltip = string.Format(c_ragdollKeyTooltip, p_keyCode);
}
static Stream GetIconStream(string p_name)
@ -255,5 +311,10 @@ namespace ml_prm
string l_assemblyName = l_assembly.GetName().Name;
return l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name);
}
static float GetDropHeight(float p_speed, float p_gravity = 9.8f)
{
return MathF.Pow(p_speed, 2f) / (p_gravity * 2f);
}
}
}

View file

@ -1,7 +1,7 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.1.7", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.1.8", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
[assembly: MelonLoader.MelonPriority(2)]
[assembly: MelonLoader.MelonOptionalDependencies("BTKUILib")]
[assembly: MelonLoader.MelonAdditionalDependencies("BTKUILib")]
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
[assembly: MelonLoader.MelonAdditionalCredits("kafeijao, NotAKidOnSteam")]

View file

@ -0,0 +1,192 @@
using ABI.CCK.Components;
using ABI_RC.Core.Player;
using ABI_RC.Core.Savior;
using ABI_RC.Systems.Movement;
using UnityEngine;
namespace ml_prm
{
[DisallowMultipleComponent]
class RagdollBodypartHandler : MonoBehaviour, CVRTriggerVolume
{
const string c_ragdollPointerType = "ragdoll";
Rigidbody m_rigidBody = null;
public Collider collider { get; set; } = null;
PhysicsInfluencer m_physicsInfluencer = null;
bool m_shouldHaveInfluencer = false;
bool m_activeGravity = true;
// Unity events
void Awake()
{
this.gameObject.layer = LayerMask.NameToLayer("PlayerLocal");
collider = this.GetComponent<Collider>();
m_rigidBody = this.GetComponent<Rigidbody>();
if(m_rigidBody != null)
{
m_rigidBody.isKinematic = false;
m_rigidBody.detectCollisions = true;
m_rigidBody.useGravity = false;
m_rigidBody.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
}
if(collider != null)
{
Physics.IgnoreCollision(collider, BetterBetterCharacterController.Instance.Collider, true);
Physics.IgnoreCollision(collider, BetterBetterCharacterController.Instance.KinematicTriggerProxy.Collider, true);
Physics.IgnoreCollision(collider, BetterBetterCharacterController.Instance.NonKinematicProxy.Collider, true);
Physics.IgnoreCollision(collider, BetterBetterCharacterController.Instance.SphereProxy.Collider, true);
BetterBetterCharacterController.Instance.IgnoreCollision(collider, true);
}
}
void Start()
{
if(m_shouldHaveInfluencer && (m_rigidBody != null) && (collider != null))
{
m_physicsInfluencer = this.gameObject.AddComponent<PhysicsInfluencer>();
m_physicsInfluencer.fluidDrag = 3f;
m_physicsInfluencer.fluidAngularDrag = 1f;
m_physicsInfluencer.enableBuoyancy = true;
m_physicsInfluencer.enableInfluence = false;
m_physicsInfluencer.forceAlignUpright = false;
float mass = m_rigidBody.mass;
m_physicsInfluencer.UpdateDensity();
m_rigidBody.mass = mass;
m_physicsInfluencer.volume = mass * 0.005f;
m_physicsInfluencer.enableLocalGravity = true;
}
if(collider != null)
{
CVRParticlePointerManager.volumes.Add(this);
CVRParticlePointerManager.UpdateParticleSystems();
}
}
void OnDestroy()
{
if(collider != null)
CVRParticlePointerManager.RemoveTrigger(collider);
}
void FixedUpdate()
{
if(m_rigidBody != null)
{
m_rigidBody.useGravity = false;
if(m_activeGravity && ((m_physicsInfluencer == null) || !m_physicsInfluencer.enableInfluence || !m_physicsInfluencer.GetSubmerged()))
m_rigidBody.AddForce(BetterBetterCharacterController.Instance.GravityResult.AppliedGravity * m_rigidBody.mass);
}
}
void OnTriggerEnter(Collider p_col)
{
if(Settings.PointersReaction && (RagdollController.Instance != null))
{
CVRPointer l_pointer = p_col.GetComponent<CVRPointer>();
if((l_pointer != null) && (l_pointer.type == c_ragdollPointerType) && !IsIgnored(l_pointer.transform) && !RagdollController.Instance.IsRagdolled())
RagdollController.Instance.SwitchRagdoll();
}
}
// Arbitrary
public bool IsReady() => ((m_rigidBody != null) && (collider != null) && (!m_shouldHaveInfluencer || ((m_physicsInfluencer != null) && m_physicsInfluencer.IsReady())));
public void SetInfuencerUsage(bool p_state) => m_shouldHaveInfluencer = p_state;
public void SetColliderMaterial(PhysicMaterial p_material)
{
if(collider != null)
{
collider.sharedMaterial = p_material;
collider.material = p_material;
}
}
public void SetAsKinematic(bool p_state)
{
if(collider != null)
collider.isTrigger = p_state;
if(m_rigidBody != null)
{
m_rigidBody.isKinematic = p_state;
m_rigidBody.collisionDetectionMode = (p_state ? CollisionDetectionMode.Discrete : CollisionDetectionMode.ContinuousDynamic);
}
}
public void SetVelocity(Vector3 p_vec)
{
if(m_rigidBody != null)
m_rigidBody.velocity = p_vec;
}
public void SetAngularVelocity(Vector3 p_vec)
{
if(m_rigidBody != null)
m_rigidBody.angularVelocity = p_vec;
}
public void SetActiveGravity(bool p_state)
{
m_activeGravity = p_state;
if(m_physicsInfluencer != null)
m_physicsInfluencer.enabled = m_activeGravity;
}
public void SetDrag(float p_value)
{
if(m_rigidBody != null)
{
m_rigidBody.drag = p_value;
m_rigidBody.WakeUp();
}
if(m_physicsInfluencer != null)
m_physicsInfluencer.airDrag = p_value;
}
public void SetAngularDrag(float p_value)
{
if(m_rigidBody != null)
{
m_rigidBody.angularDrag = p_value;
m_rigidBody.WakeUp();
}
if(m_physicsInfluencer != null)
m_physicsInfluencer.airAngularDrag = p_value;
}
public void SetBuoyancy(bool p_state)
{
if(m_physicsInfluencer != null)
m_physicsInfluencer.enableInfluence = p_state;
}
public void ClearFluidVolumes()
{
if(m_physicsInfluencer != null)
m_physicsInfluencer.ClearFluidVolumes();
}
static bool IsIgnored(Transform p_transform)
{
return (Settings.IgnoreLocal && (p_transform.root == PlayerSetup.Instance.transform));
}
// CVRTriggerVolume
public void TriggerEnter(CVRPointer pointer)
{
if(Settings.PointersReaction && (RagdollController.Instance != null))
{
if((pointer != null) && (pointer.type == c_ragdollPointerType) && !IsIgnored(pointer.transform) && !RagdollController.Instance.IsRagdolled())
RagdollController.Instance.SwitchRagdoll();
}
}
public void TriggerExit(CVRPointer pointer) { }
}
}

View file

@ -27,15 +27,12 @@ namespace ml_prm
bool m_enabled = false;
bool m_forcedSwitch = false;
readonly List<Rigidbody> m_rigidBodies = null;
readonly List<Collider> m_colliders = null;
Transform m_puppetRoot = null;
Transform m_puppet = null;
BipedRagdollReferences m_puppetReferences;
readonly List<RagdollBodypartHandler> m_ragdollBodyHandlers = null;
readonly List<System.Tuple<Transform, Transform>> m_boneLinks = null;
readonly List<System.Tuple<CharacterJoint, Vector3>> m_jointAnchors = null;
readonly List<PhysicsInfluencer> m_physicsInfluencers = null;
readonly List<GravityInfluencer> m_gravityInfluencers = null;
bool m_avatarReady = false;
Coroutine m_initCoroutine = null;
@ -44,8 +41,7 @@ namespace ml_prm
Vector3 m_ragdollLastPos = Vector3.zero;
bool m_wasSwimming = false;
RagdollToggle m_avatarRagdollToggle = null;
RagdollTrigger m_ragdollTrigger = null;
RagdollToggle m_avatarRagdollToggle = null; // Custom component available for editor
AvatarBoolParameter m_ragdolledParameter = null;
PhysicMaterial m_physicsMaterial = null;
@ -54,24 +50,25 @@ namespace ml_prm
float m_downTime = float.MinValue;
bool m_inAir = false;
float m_inAirDistance = 0f;
internal RagdollController()
{
m_rigidBodies = new List<Rigidbody>();
m_colliders = new List<Collider>();
m_ragdollBodyHandlers = new List<RagdollBodypartHandler>();
m_boneLinks = new List<System.Tuple<Transform, Transform>>();
m_jointAnchors = new List<System.Tuple<CharacterJoint, Vector3>>();
m_physicsInfluencers = new List<PhysicsInfluencer>();
m_gravityInfluencers = new List<GravityInfluencer>();
}
// Unity events
void Awake()
{
if((Instance != null) && (Instance != this))
Object.Destroy(this);
else
Instance = this;
}
void Start()
{
if(Instance == null)
Instance = this;
m_physicsMaterial = new PhysicMaterial("Ragdoll");
m_physicsMaterial.dynamicFriction = c_defaultFriction;
m_physicsMaterial.staticFriction = c_defaultFriction;
@ -84,9 +81,6 @@ namespace ml_prm
m_puppetRoot.localPosition = Vector3.zero;
m_puppetRoot.localRotation = Quaternion.identity;
m_ragdollTrigger = BetterBetterCharacterController.Instance.NonKinematicProxy.gameObject.AddComponent<RagdollTrigger>();
m_ragdollTrigger.enabled = false;
Settings.OnMovementDragChanged.AddHandler(this.OnMovementDragChanged);
Settings.OnAngularDragChanged.AddHandler(this.OnAngularDragChanged);
Settings.OnGravityChanged.AddHandler(this.OnGravityChanged);
@ -125,17 +119,11 @@ namespace ml_prm
m_puppetRoot = null;
m_puppet = null;
m_rigidBodies.Clear();
m_colliders.Clear();
m_ragdollBodyHandlers.Clear();
m_boneLinks.Clear();
m_jointAnchors.Clear();
m_physicsInfluencers.Clear();
m_avatarRagdollToggle = null;
if(m_ragdollTrigger != null)
Object.Destroy(m_ragdollTrigger);
m_ragdollTrigger = null;
if(m_physicsMaterial != null)
Object.Destroy(m_physicsMaterial);
m_physicsMaterial = null;
@ -170,33 +158,23 @@ namespace ml_prm
{
bool l_grounded = BetterBetterCharacterController.Instance.IsGrounded();
bool l_inWater = BetterBetterCharacterController.Instance.IsInWater();
if(m_inAir && l_grounded && !l_inWater && (m_inAirDistance > Settings.FallLimit))
{
m_inAirDistance = 0f;
if(m_inAir && l_grounded && !l_inWater && (m_velocity.magnitude >= Settings.FallLimit))
SwitchRagdoll();
}
m_inAir = !(l_grounded || l_inWater);
if(!m_inAir)
m_inAirDistance = 0f;
}
if(m_avatarReady && m_enabled)
{
m_inAirDistance = 0f;
BodySystem.TrackingPositionWeight = 0f;
BetterBetterCharacterController.Instance.PauseGroundConstraint();
BetterBetterCharacterController.Instance.ResetAllForces();
}
if(m_avatarReady && !m_enabled)
{
Vector3 l_pos = PlayerSetup.Instance.transform.position;
m_velocity = (m_velocity + (l_pos - m_lastPosition) / Time.deltaTime) * 0.5f;
if(m_inAir)
{
m_inAirDistance += (Quaternion.Inverse(PlayerSetup.Instance.transform.rotation) * (m_lastPosition - l_pos)).y;
m_inAirDistance = Mathf.Clamp(m_inAirDistance, 0f, float.MaxValue);
}
m_lastPosition = l_pos;
if(!m_reachedGround && BetterBetterCharacterController.Instance.IsOnGround())
@ -220,9 +198,6 @@ namespace ml_prm
if((m_avatarRagdollToggle != null) && m_avatarRagdollToggle.isActiveAndEnabled && m_avatarRagdollToggle.shouldOverride && (m_enabled != m_avatarRagdollToggle.isOn))
SwitchRagdoll();
if((m_ragdollTrigger != null) && m_ragdollTrigger.GetStateWithReset() && m_avatarReady && !m_enabled && Settings.PointersReaction)
SwitchRagdoll();
if(Settings.Hotkey && Input.GetKeyDown(Settings.HotkeyKey) && !ViewManager.Instance.IsAnyMenuOpen)
SwitchRagdoll();
@ -277,31 +252,21 @@ namespace ml_prm
Object.Destroy(m_puppet.gameObject);
m_puppet = null;
if(m_ragdollTrigger != null)
{
m_ragdollTrigger.GetStateWithReset();
m_ragdollTrigger.enabled = false;
}
m_vrIK = null;
m_applyHipsPosition = false;
m_enabled = false;
m_avatarReady = false;
m_avatarRagdollToggle = null;
m_ragdolledParameter = null;
m_rigidBodies.Clear();
m_colliders.Clear();
m_puppetReferences = new BipedRagdollReferences();
m_ragdollBodyHandlers.Clear();
m_boneLinks.Clear();
m_jointAnchors.Clear();
m_physicsInfluencers.Clear();
m_gravityInfluencers.Clear();
m_reachedGround = true;
m_groundedTime = 0f;
m_downTime = float.MinValue;
m_puppetRoot.localScale = Vector3.one;
m_inAir = false;
m_inAirDistance = 0f;
m_wasSwimming = false;
}
@ -353,26 +318,11 @@ namespace ml_prm
Transform[] l_puppetTransforms = m_puppetReferences.GetRagdollTransforms();
Transform[] l_avatarTransforms = l_avatarReferences.GetRagdollTransforms();
Transform[] l_influencedTransforms = new Transform[] { m_puppetReferences.hips, m_puppetReferences.spine, m_puppetReferences.chest };
for(int i = 0; i < l_puppetTransforms.Length; i++)
{
if(l_puppetTransforms[i] != null)
{
Rigidbody l_body = l_puppetTransforms[i].GetComponent<Rigidbody>();
if(l_body != null)
{
m_rigidBodies.Add(l_body);
l_body.isKinematic = true;
l_body.angularDrag = Settings.AngularDrag;
l_body.drag = (WorldHandler.IsSafeWorld() ? Settings.MovementDrag : 1f);
l_body.useGravity = false;
l_body.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
l_body.gameObject.layer = LayerMask.NameToLayer("PlayerLocal");
GravityInfluencer l_gravInfluencer = l_body.gameObject.AddComponent<GravityInfluencer>();
l_gravInfluencer.SetActiveGravity((!WorldHandler.IsSafeWorld() || Settings.Gravity));
m_gravityInfluencers.Add(l_gravInfluencer);
}
CharacterJoint l_joint = l_puppetTransforms[i].GetComponent<CharacterJoint>();
if(l_joint != null)
{
@ -381,37 +331,13 @@ namespace ml_prm
m_jointAnchors.Add(System.Tuple.Create(l_joint, l_joint.connectedAnchor));
}
Rigidbody l_body = l_puppetTransforms[i].GetComponent<Rigidbody>();
Collider l_collider = l_puppetTransforms[i].GetComponent<Collider>();
if(l_collider != null)
if((l_body != null) && (l_collider != null))
{
Physics.IgnoreCollision(l_collider, BetterBetterCharacterController.Instance.Collider, true);
Physics.IgnoreCollision(l_collider, BetterBetterCharacterController.Instance.KinematicTriggerProxy.Collider, true);
Physics.IgnoreCollision(l_collider, BetterBetterCharacterController.Instance.NonKinematicProxy.Collider, true);
Physics.IgnoreCollision(l_collider, BetterBetterCharacterController.Instance.SphereProxy.Collider, true);
BetterBetterCharacterController.Instance.IgnoreCollision(l_collider, true);
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 = (WorldHandler.IsSafeWorld() ? Settings.MovementDrag : 1f);
l_physicsInfluencer.airAngularDrag = Settings.AngularDrag;
l_physicsInfluencer.fluidDrag = 3f;
l_physicsInfluencer.fluidAngularDrag = 1f;
l_physicsInfluencer.enableBuoyancy = true;
l_physicsInfluencer.enableInfluence = false;
l_physicsInfluencer.forceAlignUpright = 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);
RagdollBodypartHandler l_handler = l_puppetTransforms[i].gameObject.AddComponent<RagdollBodypartHandler>();
l_handler.SetInfuencerUsage(Utils.IsInEnumeration(l_puppetTransforms[i], l_influencedTransforms));
m_ragdollBodyHandlers.Add(l_handler);
}
if(l_avatarTransforms[i] != null)
@ -422,7 +348,6 @@ namespace ml_prm
// And return back
m_puppetRoot.localPosition = Vector3.zero;
m_puppetRoot.localRotation = Quaternion.identity;
m_puppetRoot.gameObject.SetActive(true);
m_vrIK = PlayerSetup.Instance._avatar.GetComponent<VRIK>();
if(m_vrIK != null)
@ -431,25 +356,28 @@ namespace ml_prm
m_avatarRagdollToggle = PlayerSetup.Instance._avatar.GetComponentInChildren<RagdollToggle>(true);
m_ragdolledParameter = new AvatarBoolParameter("Ragdolled", PlayerSetup.Instance.animatorManager);
m_initCoroutine = StartCoroutine(WaitForPhysicsInfluencers());
m_initCoroutine = StartCoroutine(WaitForBodyHandlers());
}
}
IEnumerator WaitForPhysicsInfluencers()
IEnumerator WaitForBodyHandlers()
{
while(!m_physicsInfluencers.TrueForAll(p => p.IsReady()))
while(!m_ragdollBodyHandlers.TrueForAll(p => p.IsReady()))
yield return null;
m_puppetRoot.gameObject.SetActive(false);
foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
{
l_handler.SetAsKinematic(true);
l_handler.SetColliderMaterial(m_physicsMaterial);
}
m_ragdollTrigger.enabled = true;
m_avatarReady = true;
m_initCoroutine = null;
OnGravityChanged(Settings.Gravity);
OnBuoyancyChanged(Settings.Buoyancy);
OnMovementDragChanged(Settings.MovementDrag);
OnAngularDragChanged(Settings.AngularDrag);
OnGravityChanged(Settings.Gravity);
OnBuoyancyChanged(Settings.Buoyancy);
}
void OnAvatarPreReuse()
@ -573,28 +501,16 @@ namespace ml_prm
if(m_avatarReady)
{
float l_drag = (WorldHandler.IsSafeWorld() ? p_value : 1f);
foreach(Rigidbody l_body in m_rigidBodies)
{
l_body.drag = l_drag;
if(m_enabled)
l_body.WakeUp();
}
foreach(PhysicsInfluencer l_influencer in m_physicsInfluencers)
l_influencer.airDrag = l_drag;
foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
l_handler.SetDrag(l_drag);
}
}
void OnAngularDragChanged(float p_value)
{
if(m_avatarReady)
{
foreach(Rigidbody l_body in m_rigidBodies)
{
l_body.angularDrag = p_value;
if(m_enabled)
l_body.WakeUp();
}
foreach(PhysicsInfluencer l_influencer in m_physicsInfluencers)
l_influencer.airAngularDrag = p_value;
foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
l_handler.SetAngularDrag(p_value);
}
}
void OnGravityChanged(bool p_state)
@ -602,10 +518,8 @@ namespace ml_prm
if(m_avatarReady)
{
bool l_gravity = (!WorldHandler.IsSafeWorld() || p_state);
foreach(PhysicsInfluencer l_influencer in m_physicsInfluencers)
l_influencer.enabled = l_gravity;
foreach(GravityInfluencer l_influencer in m_gravityInfluencers)
l_influencer.SetActiveGravity(l_gravity);
foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
l_handler.SetActiveGravity(l_gravity);
if(!l_gravity)
{
@ -632,8 +546,8 @@ namespace ml_prm
if(m_avatarReady)
{
bool l_buoyancy = (!WorldHandler.IsSafeWorld() || p_state);
foreach(PhysicsInfluencer l_influencer in m_physicsInfluencers)
l_influencer.enableInfluence = l_buoyancy;
foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
l_handler.SetBuoyancy(l_buoyancy);
if(!l_buoyancy)
{
@ -645,7 +559,6 @@ namespace ml_prm
void OnFallDamageChanged(bool p_state)
{
m_inAir = false;
m_inAirDistance = 0f;
}
// Arbitrary
@ -663,6 +576,8 @@ namespace ml_prm
BetterBetterCharacterController.Instance.ChangeFlight(false, true);
BetterBetterCharacterController.Instance.SetImmobilized(true);
BetterBetterCharacterController.Instance.ClearFluidVolumes();
BetterBetterCharacterController.Instance.ResetAllForces();
BetterBetterCharacterController.Instance.PauseGroundConstraint();
BodySystem.TrackingPositionWeight = 0f;
m_applyHipsPosition = IKSystem.Instance.applyOriginalHipPosition;
IKSystem.Instance.applyOriginalHipPosition = true;
@ -678,10 +593,11 @@ namespace ml_prm
m_groundedTime = 0f;
}
m_puppetRoot.gameObject.SetActive(true);
foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
l_handler.SetAsKinematic(false);
foreach(Rigidbody l_body in m_rigidBodies)
l_body.isKinematic = false;
m_puppetRoot.gameObject.SetActive(false); //
m_puppetRoot.gameObject.SetActive(true); // Resets rigidbodies and joints inner physics states
Vector3 l_velocity = Vector3.ClampMagnitude(m_velocity * (WorldHandler.IsSafeWorld() ? Settings.VelocityMultiplier : 1f), WorldHandler.GetMovementLimit());
if(Settings.ViewVelocity && WorldHandler.IsSafeWorld())
@ -690,10 +606,10 @@ namespace ml_prm
l_velocity = PlayerSetup.Instance.GetActiveCamera().transform.forward * l_mag;
}
foreach(Rigidbody l_body in m_rigidBodies)
foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
{
l_body.velocity = l_velocity;
l_body.angularVelocity = Vector3.zero;
l_handler.SetVelocity(l_velocity);
l_handler.SetAngularVelocity(Vector3.zero);
}
m_ragdollLastPos = m_puppetReferences.hips.position;
@ -723,15 +639,14 @@ namespace ml_prm
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;
foreach(PhysicsInfluencer l_physicsInfluencer in m_physicsInfluencers)
l_physicsInfluencer.ClearFluidVolumes();
foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
{
l_handler.SetAsKinematic(true);
l_handler.ClearFluidVolumes();
}
m_lastPosition = PlayerSetup.Instance.transform.position;
m_velocity = Vector3.zero;
@ -762,7 +677,6 @@ namespace ml_prm
}
m_inAir = false;
m_inAirDistance = 0f;
}
static Transform CloneTransform(Transform p_source, Transform p_parent, string p_name)

View file

@ -1,108 +0,0 @@
using ABI.CCK.Components;
using ABI_RC.Core.Player;
using ABI_RC.Core.Savior;
using UnityEngine;
namespace ml_prm
{
[DisallowMultipleComponent]
class RagdollTrigger : MonoBehaviour
{
const string c_ragdollPointerType = "ragdoll";
Collider m_collider = null;
Collider m_lastColliderTrigger = null;
ParticleSystem m_lastParticleSystemTrigger = null;
bool m_triggered = false;
void Start()
{
m_collider = this.GetComponent<Collider>();
CVRParticlePointerManager.volumes.Add(new RagdollTriggerVolume(m_collider, this));
CVRParticlePointerManager.UpdateParticleSystems();
}
void OnDestroy()
{
if(m_collider != null)
CVRParticlePointerManager.RemoveTrigger(m_collider);
m_collider = null;
m_lastColliderTrigger = null;
m_lastParticleSystemTrigger = null;
}
void Update()
{
if(!ReferenceEquals(m_lastColliderTrigger, null))
{
if(m_lastColliderTrigger != null)
{
if(!m_collider.bounds.Intersects(m_lastColliderTrigger.bounds))
m_lastColliderTrigger = null;
}
else
m_lastColliderTrigger = null;
}
if(!ReferenceEquals(m_lastParticleSystemTrigger, null))
{
if(m_lastParticleSystemTrigger != null)
{
if(m_lastParticleSystemTrigger.particleCount == 0)
m_lastParticleSystemTrigger = null;
}
else
m_lastParticleSystemTrigger = null;
}
}
void OnTriggerEnter(Collider p_other)
{
CVRPointer l_pointer = p_other.GetComponent<CVRPointer>();
if((l_pointer != null) && (l_pointer.type == c_ragdollPointerType) && !IsIgnored(l_pointer.transform) && (m_lastColliderTrigger != p_other))
{
m_lastColliderTrigger = p_other;
m_triggered = true;
}
}
void OnTriggerExit(Collider p_other)
{
if(m_lastColliderTrigger == p_other)
m_lastColliderTrigger = null;
}
public void OnPointerParticleEnter(CVRPointer p_pointer)
{
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;
}
}
public void OnPointerParticleExit(CVRPointer p_pointer)
{
// This seems to be very unreliable, and it's causing weird behavior
// if (!gameObject.activeInHierarchy) return;
// if(m_lastParticleSystemTrigger == p_pointer.particleSystem)
// m_lastParticleSystemTrigger = null;
}
public bool GetStateWithReset()
{
bool l_state = m_triggered;
m_triggered = false;
return l_state;
}
static bool IsIgnored(Transform p_transform)
{
return (Settings.IgnoreLocal && (p_transform.root == PlayerSetup.Instance.transform));
}
}
}

View file

@ -1,22 +0,0 @@
using ABI_RC.Core.Savior;
using ABI.CCK.Components;
using UnityEngine;
namespace ml_prm
{
class RagdollTriggerVolume : CVRTriggerVolume
{
readonly RagdollTrigger m_trigger = null;
public Collider collider { get; set; }
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);
}
}

View file

@ -53,7 +53,7 @@ namespace ml_prm
public static bool JumpRecover { get; private set; } = false;
public static bool Buoyancy { get; private set; } = true;
public static bool FallDamage { get; private set; } = true;
public static float FallLimit { get; private set; } = 5f;
public static float FallLimit { get; private set; } = 9.899494f;
public static readonly SettingEvent<bool> OnHotkeyChanged = new SettingEvent<bool>();
public static readonly SettingEvent<KeyCode> OnHotkeyKeyChanged = new SettingEvent<KeyCode>();
@ -122,7 +122,7 @@ namespace ml_prm
JumpRecover = (bool)ms_entries[(int)ModSetting.JumpRecover].BoxedValue;
Buoyancy = (bool)ms_entries[(int)ModSetting.Buoyancy].BoxedValue;
FallDamage = (bool)ms_entries[(int)ModSetting.FallDamage].BoxedValue;
FallLimit = Mathf.Clamp((float)ms_entries[(int)ModSetting.FallLimit].BoxedValue, 0f, 100f);
FallLimit = Mathf.Clamp((float)ms_entries[(int)ModSetting.FallLimit].BoxedValue, 4.5f, 44.5f);
}
static void OnMelonSettingSave_HotkeyKey(object p_oldValue, object p_newValue)

View file

@ -6,6 +6,7 @@ using ABI_RC.Systems.Movement;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using System.Linq;
namespace ml_prm
{
@ -40,5 +41,7 @@ namespace ml_prm
PlayerSetup.Instance._avatar.transform.localPosition = Vector3.zero;
PlayerSetup.Instance._avatar.transform.localRotation = Quaternion.identity;
}
public static bool IsInEnumeration(object p_obj, object[] p_enumeration) => p_enumeration.Contains(p_obj);
}
}

View file

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