mirror of
https://github.com/hanetzer/sdraw_mods_cvr.git
synced 2025-09-04 02:49:23 +00:00
Update to build 2023r171ex7p2
This commit is contained in:
parent
6f8fa13c94
commit
d210ed4636
76 changed files with 3349 additions and 1220 deletions
43
ml_prm/AvatarBoolParameter.cs
Normal file
43
ml_prm/AvatarBoolParameter.cs
Normal file
|
@ -0,0 +1,43 @@
|
|||
using ABI_RC.Core;
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_prm
|
||||
{
|
||||
class AvatarBoolParameter
|
||||
{
|
||||
public readonly string m_name;
|
||||
public readonly int m_hash = 0;
|
||||
public readonly bool m_sync;
|
||||
readonly CVRAnimatorManager m_manager = null;
|
||||
|
||||
public AvatarBoolParameter(string p_name, CVRAnimatorManager p_manager)
|
||||
{
|
||||
m_name = p_name;
|
||||
m_manager = p_manager;
|
||||
|
||||
Regex l_regex = new Regex("^#?" + p_name + '$');
|
||||
foreach(var l_param in m_manager.animator.parameters)
|
||||
{
|
||||
if(l_regex.IsMatch(l_param.name) && (l_param.type == AnimatorControllerParameterType.Bool))
|
||||
{
|
||||
m_name = l_param.name;
|
||||
m_hash = l_param.nameHash;
|
||||
m_sync = (l_param.name[0] != '#');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetValue(bool p_value)
|
||||
{
|
||||
if(m_hash != 0)
|
||||
{
|
||||
if(m_sync)
|
||||
m_manager.SetAnimatorParameterBool(m_name, p_value);
|
||||
else
|
||||
m_manager.animator.SetBool(m_hash, p_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
216
ml_prm/Main.cs
Normal file
216
ml_prm/Main.cs
Normal file
|
@ -0,0 +1,216 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core;
|
||||
using ABI_RC.Core.InteractionSystem;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Util.AssetFiltering;
|
||||
using ABI_RC.Systems.IK.SubSystems;
|
||||
using ABI_RC.Systems.MovementSystem;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ml_prm
|
||||
{
|
||||
public class PlayerRagdollMod : MelonLoader.MelonMod
|
||||
{
|
||||
static PlayerRagdollMod ms_instance = null;
|
||||
|
||||
RagdollController m_localController = null;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
if(ms_instance == null)
|
||||
ms_instance = this;
|
||||
|
||||
Settings.Init();
|
||||
ModUi.Init();
|
||||
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod("SetupIKScaling", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnSetupIKScaling_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRSeat).GetMethod(nameof(CVRSeat.SitDown)),
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnCVRSeatSitDown_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
|
||||
null
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(BodySystem).GetMethod(nameof(BodySystem.StartCalibration)),
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnStartCalibration_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
|
||||
null
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(RootLogic).GetMethod(nameof(RootLogic.SpawnOnWorldInstance)),
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnWorldSpawn_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
|
||||
null
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CombatSystem).GetMethods().First(m => (!m.IsGenericMethod && m.Name == nameof(CombatSystem.Down))),
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnCombatDown_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
|
||||
null
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(MovementSystem).GetMethod(nameof(MovementSystem.ToggleFlight)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnToggleFlight_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
// Whitelist the toggle script
|
||||
(typeof(SharedFilter).GetField("_localComponentWhitelist", BindingFlags.NonPublic | BindingFlags.Static)?.GetValue(null) as HashSet<Type>)?.Add(typeof(RagdollToggle));
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
|
||||
}
|
||||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
m_localController = null;
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator WaitForLocalPlayer()
|
||||
{
|
||||
while(PlayerSetup.Instance == null)
|
||||
yield return null;
|
||||
|
||||
m_localController = PlayerSetup.Instance.gameObject.AddComponent<RagdollController>();
|
||||
ModUi.SwitchChange += this.OnSwitchActivation;
|
||||
}
|
||||
|
||||
void OnSwitchActivation()
|
||||
{
|
||||
if(m_localController != null)
|
||||
m_localController.SwitchRagdoll();
|
||||
}
|
||||
|
||||
// Patches
|
||||
static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear();
|
||||
void OnAvatarClear()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localController != null)
|
||||
m_localController.OnAvatarClear();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar();
|
||||
void OnSetupAvatar()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localController != null)
|
||||
m_localController.OnAvatarSetup();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupIKScaling_Postfix(ref UnityEngine.Vector3 ___scaleDifference) => ms_instance?.OnSetupIKScaling(___scaleDifference.y);
|
||||
void OnSetupIKScaling(float p_scaleDifference)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localController != null)
|
||||
m_localController.OnAvatarScaling(1f + p_scaleDifference);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCVRSeatSitDown_Prefix(ref CVRSeat __instance) => ms_instance?.OnCVRSeatSitDown(__instance);
|
||||
void OnCVRSeatSitDown(CVRSeat p_seat)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localController != null)
|
||||
m_localController.OnSeatSitDown(p_seat);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnStartCalibration_Prefix() => ms_instance?.OnStartCalibration();
|
||||
void OnStartCalibration()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localController != null)
|
||||
m_localController.OnStartCalibration();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnWorldSpawn_Prefix() => ms_instance?.OnWorldSpawn();
|
||||
void OnWorldSpawn()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localController != null)
|
||||
m_localController.OnWorldSpawn();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCombatDown_Prefix(ref CombatSystem __instance)
|
||||
{
|
||||
if((__instance == CombatSystem.Instance) && !__instance.isDown)
|
||||
ms_instance?.OnCombatDown();
|
||||
}
|
||||
void OnCombatDown()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localController != null)
|
||||
m_localController.OnCombatDown();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnToggleFlight_Postfix() => ms_instance?.OnToggleFlight();
|
||||
void OnToggleFlight()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localController != null)
|
||||
m_localController.OnToggleFlight();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
198
ml_prm/ModUi.cs
Normal file
198
ml_prm/ModUi.cs
Normal file
|
@ -0,0 +1,198 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ml_prm
|
||||
{
|
||||
static class ModUi
|
||||
{
|
||||
enum UiIndex
|
||||
{
|
||||
Hotkey = 0,
|
||||
Gravity,
|
||||
PointersReaction,
|
||||
IgnoreLocal,
|
||||
CombatReaction,
|
||||
AutoRecover,
|
||||
Slipperiness,
|
||||
Bounciness,
|
||||
ViewVelocity,
|
||||
JumpRecover,
|
||||
VelocityMultiplier,
|
||||
MovementDrag,
|
||||
AngularDrag,
|
||||
RecoverDelay
|
||||
}
|
||||
|
||||
static public event Action SwitchChange;
|
||||
|
||||
static List<object> ms_uiElements = 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";
|
||||
|
||||
var l_modCategory = l_modRoot.AddCategory("Settings");
|
||||
|
||||
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);
|
||||
|
||||
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_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_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_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_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_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_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_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_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_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);
|
||||
|
||||
ms_uiElements.Add(l_modRoot.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_uiElements.Add(l_modRoot.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_uiElements.Add(l_modRoot.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);
|
||||
|
||||
l_modCategory.AddButton("Reset settings", "", "Reset mod settings to default").OnPress += Reset;
|
||||
}
|
||||
|
||||
static void OnToggleUpdate(UiIndex p_index, bool p_state, bool p_force = false)
|
||||
{
|
||||
switch(p_index)
|
||||
{
|
||||
case UiIndex.Hotkey:
|
||||
Settings.SetSetting(Settings.ModSetting.Hotkey, p_state);
|
||||
break;
|
||||
|
||||
case UiIndex.Gravity:
|
||||
Settings.SetSetting(Settings.ModSetting.Gravity, p_state);
|
||||
break;
|
||||
|
||||
case UiIndex.PointersReaction:
|
||||
Settings.SetSetting(Settings.ModSetting.PointersReaction, p_state);
|
||||
break;
|
||||
|
||||
case UiIndex.IgnoreLocal:
|
||||
Settings.SetSetting(Settings.ModSetting.IgnoreLocal, p_state);
|
||||
break;
|
||||
|
||||
case UiIndex.CombatReaction:
|
||||
Settings.SetSetting(Settings.ModSetting.CombatReaction, p_state);
|
||||
break;
|
||||
|
||||
case UiIndex.AutoRecover:
|
||||
Settings.SetSetting(Settings.ModSetting.AutoRecover, p_state);
|
||||
break;
|
||||
|
||||
case UiIndex.Slipperiness:
|
||||
Settings.SetSetting(Settings.ModSetting.Slipperiness, p_state);
|
||||
break;
|
||||
|
||||
case UiIndex.Bounciness:
|
||||
Settings.SetSetting(Settings.ModSetting.Bounciness, p_state);
|
||||
break;
|
||||
|
||||
case UiIndex.ViewVelocity:
|
||||
Settings.SetSetting(Settings.ModSetting.ViewVelocity, p_state);
|
||||
break;
|
||||
|
||||
case UiIndex.JumpRecover:
|
||||
Settings.SetSetting(Settings.ModSetting.JumpRecover, p_state);
|
||||
break;
|
||||
}
|
||||
|
||||
if(p_force)
|
||||
(ms_uiElements[(int)p_index] as BTKUILib.UIObjects.Components.ToggleButton).ToggleValue = p_state;
|
||||
}
|
||||
|
||||
static void OnSliderUpdate(UiIndex p_index, float p_value, bool p_force = false)
|
||||
{
|
||||
switch(p_index)
|
||||
{
|
||||
case UiIndex.VelocityMultiplier:
|
||||
Settings.SetSetting(Settings.ModSetting.VelocityMultiplier, p_value);
|
||||
break;
|
||||
|
||||
case UiIndex.MovementDrag:
|
||||
Settings.SetSetting(Settings.ModSetting.MovementDrag, p_value);
|
||||
break;
|
||||
|
||||
case UiIndex.AngularDrag:
|
||||
Settings.SetSetting(Settings.ModSetting.AngularDrag, p_value);
|
||||
break;
|
||||
|
||||
case UiIndex.RecoverDelay:
|
||||
Settings.SetSetting(Settings.ModSetting.RecoverDelay, p_value);
|
||||
break;
|
||||
}
|
||||
|
||||
if(p_force)
|
||||
(ms_uiElements[(int)p_index] as BTKUILib.UIObjects.Components.SliderFloat).SetSliderValue(p_value);
|
||||
}
|
||||
|
||||
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);
|
||||
OnSliderUpdate(UiIndex.VelocityMultiplier, 2f, true);
|
||||
OnSliderUpdate(UiIndex.MovementDrag, 2f, true);
|
||||
OnSliderUpdate(UiIndex.AngularDrag, 2f, true);
|
||||
OnSliderUpdate(UiIndex.RecoverDelay, 3f, true);
|
||||
}
|
||||
|
||||
static Stream GetIconStream(string p_name)
|
||||
{
|
||||
Assembly l_assembly = Assembly.GetExecutingAssembly();
|
||||
string l_assemblyName = l_assembly.GetName().Name;
|
||||
return l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name);
|
||||
}
|
||||
}
|
||||
}
|
8
ml_prm/Properties/AssemblyInfo.cs
Normal file
8
ml_prm/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
using System.Reflection;
|
||||
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.0.5", "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)]
|
562
ml_prm/RagdollController.cs
Normal file
562
ml_prm/RagdollController.cs
Normal file
|
@ -0,0 +1,562 @@
|
|||
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
|
||||
{
|
||||
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<Rigidbody> m_rigidBodies = null;
|
||||
readonly List<Collider> m_colliders = null;
|
||||
Transform m_puppetRoot = null;
|
||||
Transform m_puppet = null;
|
||||
BipedRagdollReferences m_puppetReferences;
|
||||
readonly List<System.Tuple<Transform, Transform>> m_boneLinks = null;
|
||||
readonly List<System.Tuple<CharacterJoint, Vector3>> 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<Rigidbody>();
|
||||
m_colliders = new List<Collider>();
|
||||
m_boneLinks = new List<System.Tuple<Transform, Transform>>();
|
||||
m_jointAnchors = new List<System.Tuple<CharacterJoint, Vector3>>();
|
||||
|
||||
m_physicsMaterial = new PhysicMaterial("Ragdoll");
|
||||
m_physicsMaterial.dynamicFriction = 0.5f;
|
||||
m_physicsMaterial.staticFriction = 0.5f;
|
||||
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<RagdollTrigger>();
|
||||
|
||||
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(KeyCode.R) && !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<Rigidbody>();
|
||||
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;
|
||||
}
|
||||
|
||||
CharacterJoint l_joint = l_puppetTransforms[i].GetComponent<CharacterJoint>();
|
||||
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<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.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<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;
|
||||
}
|
||||
}
|
||||
|
||||
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 OnToggleFlight()
|
||||
{
|
||||
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 : 0.5f);
|
||||
m_physicsMaterial.staticFriction = (l_slipperiness ? 0f : 0.5f);
|
||||
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);
|
||||
|
||||
MovementSystem.Instance.SetImmobilized(true);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
12
ml_prm/RagdollToggle.cs
Normal file
12
ml_prm/RagdollToggle.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using UnityEngine;
|
||||
|
||||
namespace ml_prm
|
||||
{
|
||||
public class RagdollToggle : MonoBehaviour
|
||||
{
|
||||
[Tooltip("Whether or not is should use the isOn property to override the current Ragdoll State of the Avatar.")]
|
||||
[SerializeField] public bool shouldOverride;
|
||||
[Tooltip("Whether Ragdoll State is active or not on the Avatar. Requires shouldOverride to be true to work.")]
|
||||
[SerializeField] public bool isOn;
|
||||
}
|
||||
}
|
61
ml_prm/RagdollTrigger.cs
Normal file
61
ml_prm/RagdollTrigger.cs
Normal file
|
@ -0,0 +1,61 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.Player;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_prm
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
class RagdollTrigger : MonoBehaviour
|
||||
{
|
||||
Collider m_collider = null;
|
||||
Collider m_lastTrigger = null;
|
||||
bool m_triggered = false;
|
||||
|
||||
void Start()
|
||||
{
|
||||
m_collider = this.GetComponent<Collider>();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if(!ReferenceEquals(m_lastTrigger, null))
|
||||
{
|
||||
if(m_lastTrigger != null)
|
||||
{
|
||||
if(!m_collider.bounds.Intersects(m_lastTrigger.bounds))
|
||||
m_lastTrigger = null;
|
||||
}
|
||||
else
|
||||
m_lastTrigger = null;
|
||||
}
|
||||
}
|
||||
|
||||
void OnTriggerEnter(Collider p_other)
|
||||
{
|
||||
CVRPointer l_pointer = p_other.GetComponent<CVRPointer>();
|
||||
if((l_pointer != null) && (l_pointer.type == "ragdoll") && !IsIgnored(l_pointer.transform) && (m_lastTrigger != p_other))
|
||||
{
|
||||
m_lastTrigger = p_other;
|
||||
m_triggered = true;
|
||||
}
|
||||
}
|
||||
|
||||
void OnTriggerExit(Collider p_other)
|
||||
{
|
||||
if(m_lastTrigger == p_other)
|
||||
m_lastTrigger = 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));
|
||||
}
|
||||
}
|
||||
}
|
207
ml_prm/Settings.cs
Normal file
207
ml_prm/Settings.cs
Normal file
|
@ -0,0 +1,207 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_prm
|
||||
{
|
||||
static class Settings
|
||||
{
|
||||
public enum ModSetting
|
||||
{
|
||||
Hotkey = 0,
|
||||
VelocityMultiplier,
|
||||
MovementDrag,
|
||||
AngularDrag,
|
||||
Gravity,
|
||||
PointersReaction,
|
||||
IgnoreLocal,
|
||||
CombatReaction,
|
||||
AutoRecover,
|
||||
RecoverDelay,
|
||||
Slipperiness,
|
||||
Bounciness,
|
||||
ViewVelocity,
|
||||
JumpRecover
|
||||
}
|
||||
|
||||
public static bool Hotkey { get; private set; } = true;
|
||||
public static float VelocityMultiplier { get; private set; } = 2f;
|
||||
public static float MovementDrag { get; private set; } = 2f;
|
||||
public static float AngularDrag { get; private set; } = 2f;
|
||||
public static bool Gravity { get; private set; } = true;
|
||||
public static bool PointersReaction { get; private set; } = true;
|
||||
public static bool IgnoreLocal { get; private set; } = true;
|
||||
public static bool CombatReaction { get; private set; } = true;
|
||||
public static bool AutoRecover { get; private set; } = false;
|
||||
public static float RecoverDelay { get; private set; } = 3f;
|
||||
public static bool Slipperiness { get; private set; } = false;
|
||||
public static bool Bounciness { get; private set; } = false;
|
||||
public static bool ViewVelocity { get; private set; } = false;
|
||||
public static bool JumpRecover { get; private set; } = false;
|
||||
|
||||
static public event Action<bool> HotkeyChange;
|
||||
static public event Action<float> VelocityMultiplierChange;
|
||||
static public event Action<float> MovementDragChange;
|
||||
static public event Action<float> AngularDragChange;
|
||||
static public event Action<bool> GravityChange;
|
||||
static public event Action<bool> PointersReactionChange;
|
||||
static public event Action<bool> IgnoreLocalChange;
|
||||
static public event Action<bool> CombatReactionChange;
|
||||
static public event Action<bool> AutoRecoverChange;
|
||||
static public event Action<float> RecoverDelayChange;
|
||||
static public event Action<bool> SlipperinessChange;
|
||||
static public event Action<bool> BouncinessChange;
|
||||
static public event Action<bool> ViewVelocityChange;
|
||||
static public event Action<bool> JumpRecoverChange;
|
||||
|
||||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
ms_category = MelonLoader.MelonPreferences.CreateCategory("PRM", null, true);
|
||||
ms_entries = new List<MelonLoader.MelonPreferences_Entry>()
|
||||
{
|
||||
ms_category.CreateEntry(ModSetting.Hotkey.ToString(), Hotkey),
|
||||
ms_category.CreateEntry(ModSetting.VelocityMultiplier.ToString(), VelocityMultiplier),
|
||||
ms_category.CreateEntry(ModSetting.MovementDrag.ToString(), MovementDrag),
|
||||
ms_category.CreateEntry(ModSetting.AngularDrag.ToString(), AngularDrag),
|
||||
ms_category.CreateEntry(ModSetting.Gravity.ToString(), Gravity),
|
||||
ms_category.CreateEntry(ModSetting.PointersReaction.ToString(), PointersReaction),
|
||||
ms_category.CreateEntry(ModSetting.IgnoreLocal.ToString(), IgnoreLocal),
|
||||
ms_category.CreateEntry(ModSetting.CombatReaction.ToString(), CombatReaction),
|
||||
ms_category.CreateEntry(ModSetting.AutoRecover.ToString(), AutoRecover),
|
||||
ms_category.CreateEntry(ModSetting.RecoverDelay.ToString(), RecoverDelay),
|
||||
ms_category.CreateEntry(ModSetting.Slipperiness.ToString(), Slipperiness),
|
||||
ms_category.CreateEntry(ModSetting.Bounciness.ToString(), Bounciness),
|
||||
ms_category.CreateEntry(ModSetting.ViewVelocity.ToString(), ViewVelocity),
|
||||
ms_category.CreateEntry(ModSetting.JumpRecover.ToString(), JumpRecover)
|
||||
};
|
||||
|
||||
Hotkey = (bool)ms_entries[(int)ModSetting.Hotkey].BoxedValue;
|
||||
VelocityMultiplier = Mathf.Clamp((float)ms_entries[(int)ModSetting.VelocityMultiplier].BoxedValue, 1f, 50f);
|
||||
MovementDrag = Mathf.Clamp((float)ms_entries[(int)ModSetting.MovementDrag].BoxedValue, 0f, 50f);
|
||||
AngularDrag = Mathf.Clamp((float)ms_entries[(int)ModSetting.AngularDrag].BoxedValue, 0f, 50f);
|
||||
Gravity = (bool)ms_entries[(int)ModSetting.Gravity].BoxedValue;
|
||||
PointersReaction = (bool)ms_entries[(int)ModSetting.PointersReaction].BoxedValue;
|
||||
IgnoreLocal = (bool)ms_entries[(int)ModSetting.IgnoreLocal].BoxedValue;
|
||||
CombatReaction = (bool)ms_entries[(int)ModSetting.CombatReaction].BoxedValue;
|
||||
AutoRecover = (bool)ms_entries[(int)ModSetting.AutoRecover].BoxedValue;
|
||||
RecoverDelay = Mathf.Clamp((float)ms_entries[(int)ModSetting.RecoverDelay].BoxedValue, 1f, 10f);
|
||||
Slipperiness = (bool)ms_entries[(int)ModSetting.Slipperiness].BoxedValue;
|
||||
Bounciness = (bool)ms_entries[(int)ModSetting.Bounciness].BoxedValue;
|
||||
ViewVelocity = (bool)ms_entries[(int)ModSetting.ViewVelocity].BoxedValue;
|
||||
JumpRecover = (bool)ms_entries[(int)ModSetting.JumpRecover].BoxedValue;
|
||||
}
|
||||
|
||||
public static void SetSetting(ModSetting p_settings, object p_value)
|
||||
{
|
||||
switch(p_settings)
|
||||
{
|
||||
// Booleans
|
||||
case ModSetting.Hotkey:
|
||||
{
|
||||
Hotkey = (bool)p_value;
|
||||
HotkeyChange?.Invoke((bool)p_value);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.Gravity:
|
||||
{
|
||||
Gravity = (bool)p_value;
|
||||
GravityChange?.Invoke((bool)p_value);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.PointersReaction:
|
||||
{
|
||||
PointersReaction = (bool)p_value;
|
||||
PointersReactionChange?.Invoke((bool)p_value);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.IgnoreLocal:
|
||||
{
|
||||
IgnoreLocal = (bool)p_value;
|
||||
IgnoreLocalChange?.Invoke((bool)p_value);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.CombatReaction:
|
||||
{
|
||||
CombatReaction = (bool)p_value;
|
||||
CombatReactionChange?.Invoke((bool)p_value);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.AutoRecover:
|
||||
{
|
||||
AutoRecover = (bool)p_value;
|
||||
AutoRecoverChange?.Invoke((bool)p_value);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.Slipperiness:
|
||||
{
|
||||
Slipperiness = (bool)p_value;
|
||||
SlipperinessChange?.Invoke((bool)p_value);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.Bounciness:
|
||||
{
|
||||
Bounciness = (bool)p_value;
|
||||
BouncinessChange?.Invoke((bool)p_value);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.ViewVelocity:
|
||||
{
|
||||
ViewVelocity = (bool)p_value;
|
||||
ViewVelocityChange?.Invoke((bool)p_value);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.JumpRecover:
|
||||
{
|
||||
JumpRecover = (bool)p_value;
|
||||
JumpRecoverChange?.Invoke((bool)p_value);
|
||||
}
|
||||
break;
|
||||
|
||||
// Floats
|
||||
case ModSetting.VelocityMultiplier:
|
||||
{
|
||||
VelocityMultiplier = (float)p_value;
|
||||
VelocityMultiplierChange?.Invoke((float)p_value);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.MovementDrag:
|
||||
{
|
||||
MovementDrag = (float)p_value;
|
||||
MovementDragChange?.Invoke((float)p_value);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.AngularDrag:
|
||||
{
|
||||
AngularDrag = (float)p_value;
|
||||
AngularDragChange?.Invoke((float)p_value);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.RecoverDelay:
|
||||
{
|
||||
RecoverDelay = (float)p_value;
|
||||
RecoverDelayChange?.Invoke((float)p_value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(ms_entries != null)
|
||||
ms_entries[(int)p_settings].BoxedValue = p_value;
|
||||
}
|
||||
}
|
||||
}
|
39
ml_prm/Utils.cs
Normal file
39
ml_prm/Utils.cs
Normal file
|
@ -0,0 +1,39 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.Savior;
|
||||
using ABI_RC.Systems.MovementSystem;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_prm
|
||||
{
|
||||
static class Utils
|
||||
{
|
||||
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);
|
||||
|
||||
public static bool IsInVR() => ((CheckVR.Instance != null) && CheckVR.Instance.hasVrDeviceLoaded);
|
||||
public static bool IsWorldSafe() => ((CVRWorld.Instance != null) && CVRWorld.Instance.allowFlying);
|
||||
public static float GetWorldMovementLimit()
|
||||
{
|
||||
float l_result = 1f;
|
||||
if(CVRWorld.Instance != null)
|
||||
{
|
||||
l_result = CVRWorld.Instance.baseMovementSpeed;
|
||||
l_result *= CVRWorld.Instance.sprintMultiplier;
|
||||
l_result *= CVRWorld.Instance.inAirMovementMultiplier;
|
||||
l_result *= CVRWorld.Instance.flyMultiplier;
|
||||
}
|
||||
return l_result;
|
||||
}
|
||||
|
||||
public static bool IsGrounded(this MovementSystem p_instance) => (bool)ms_groundedRaw.GetValue(p_instance);
|
||||
public static Vector3 GetAppliedGravity(this MovementSystem p_instance) => (Vector3)ms_appliedGravity.GetValue(p_instance);
|
||||
public static void SetAppliedGravity(this MovementSystem p_instance, Vector3 p_vec) => ms_appliedGravity.SetValue(p_instance, p_vec);
|
||||
|
||||
public static void CopyGlobal(this Transform p_source, Transform p_target)
|
||||
{
|
||||
p_target.position = p_source.position;
|
||||
p_target.rotation = p_source.rotation;
|
||||
}
|
||||
}
|
||||
}
|
58
ml_prm/ml_prm.csproj
Normal file
58
ml_prm/ml_prm.csproj
Normal file
|
@ -0,0 +1,58 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
<PackageId>PlayerRagdollMod</PackageId>
|
||||
<Version>1.0.5</Version>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>PlayerRagdollMod</Product>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="PlayerRagdollMod.json" />
|
||||
<None Remove="vendor\RootMotion\info.txt" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\0Harmony.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp-firstpass">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="BTKUILib">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\Mods\[broken]\BTKUILib.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MelonLoader">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\MelonLoader.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.AnimationModule">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.ClothModule">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.ClothModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.InputLegacyModule">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.InputLegacyModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.PhysicsModule">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\"" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
BIN
ml_prm/resources/person.png
Normal file
BIN
ml_prm/resources/person.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.9 KiB |
1
ml_prm/vendor/RootMotion/info.txt
vendored
Normal file
1
ml_prm/vendor/RootMotion/info.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
https://assetstore.unity.com/packages/tools/physics/puppetmaster-48977
|
Loading…
Add table
Add a link
Reference in a new issue