Moved PlayerRagdollMod and DesktopHeadTracking to archived

Fixed for r173 game build
This commit is contained in:
SDraw 2023-11-10 02:12:12 +03:00
parent a232c2ce13
commit 9886bdc154
No known key found for this signature in database
GPG key ID: BB95B4DAB2BB8BB5
43 changed files with 3490 additions and 3600 deletions

View file

@ -1,43 +0,0 @@
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);
}
}
}
}

View file

@ -1,216 +0,0 @@
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.ChangeFlight)),
null,
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnChangeFlight_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 OnChangeFlight_Postfix() => ms_instance?.OnChangeFlight();
void OnChangeFlight()
{
try
{
if(m_localController != null)
m_localController.OnChangeFlight();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
}
}

View file

@ -1,198 +0,0 @@
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);
}
}
}

View file

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

View file

@ -1,68 +0,0 @@
# Player Ragdoll Mod
This mod turns player's avatar into ragdoll puppet.
# Installation
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
* Get [latest release DLL](../../../releases/latest):
* Put `ml_prm.dll` in `Mods` folder of game
# Usage
* Press `R` to turn into ragdoll and back.
Optional mod's settings page with [BTKUILib](https://github.com/BTK-Development/BTKUILib):
* **Switch ragdoll:** turns into ragdoll state and back, made for VR usage primarily.
* **Use hotkey:** enables/disables ragdoll state switch with `R` key; `true` by default.
* **Use gravity:** enables/disables gravity for ragdoll; `true` by default.
* Note: Forcibly enabled in worlds that don't allow flight.
* **Pointers reaction:** enables ragdoll state when player collides with trigger colliders and particle systems with CVRPointer component of `ragdoll` type (avatars, props and world included); `true` by default.
* **Ignore local pointers:** enables/disables ignoring of CVRPointer components of `ragdoll` type on local player's avatar; `true` by default.
* **Combat reaction:** enables ragdoll state upon death in worlds with combat system; `true` by default.
* **Auto recover:** enables automatic recovering after specific time delay; `false` by default.
* **Slipperiness:** enables/disable low friction of ragdoll; `false` by default.
* Note: Forcibly disabled in worlds that don't allow flight.
* **Bounciness:** enables/disable bounce force of ragdoll; `false` by default.
* Note: Forcibly disabled in worlds that don't allow flight.
* **View direction velocity:** apply velocity to camera view direction instead of player movement direction; `false` by default.
* Note: Forcibly disabled in worlds that don't allow flight.
* **Jump recover:** enables recovering from ragdoll state by jumping; `false` by default.
* **Velocity multiplier:** velocity force multiplier based on player's movement direction; `2.0` by default.
* Note: Limited according to world's fly multiplier.
* Note: Forcibly set to `1.0` in worlds that don't allow flight.
* **Movement drag:** movement resistance; `2.0` by default.
* Note: Forcibly set to `1.0` in worlds that don't allow flight.
* **Angular movement drag:** angular movement resistance; `2.0` by default.
* **Recover delay:** time delay for enabled `Auto recover` in seconds; `3.0` by default.
* **Reset settings:** resets mod settings to default.
Optional mod's settings in [UIExpansionKit](https://github.com/ddakebono/ChilloutMods):
* **Hotkey:** system key that is used to switch ragdoll state; `R` by default.
Available additional parameters for AAS animator:
* **`Ragdolled`:** defines current ragdoll state; boolean.
* Note: Can be set as local-only (not synced) if starts with `#` character.
# Unity Editor Script
You can also trigger the ragdoll via animations on your avatar. To do this you need:
* Download and import the `ml_prm_editor_script.unitypackage` into your unity project
* Add the component `Ragdoll Toggle` anywhere inside of your avatar's hierarchy.
Now you can animate both parameters available:
- **Should Override:** whether the animation should override the toggled state of the ragdoll.
- **Is On:** whether the ragdoll state is On or Off (only works if `Should Override` is also On).
![](.github/img_01.png)
Note: In order to work the game object needs to be active and the component enabled.
# Mods Integration
You can use this mod's functions within your mod. To do this you need:
* Add mod's dll as reference in your project
* Access ragdoll controller with `ml_prm.RagdollController.Instance`
Available methods:
* ```bool IsRagdolled()```
* ```void SwitchRagdoll()```
# Notes
* If ragdoll state is enabled during emote, remote players see whole emote playing while local player sees ragdolling. It's tied to how game handles remote players, currently can be prevented with (choose one):
* Renaming avatar emote animations to not have default name or containing `Emote` substring.
* Holding any movement key right after activating ragdoll state.

View file

@ -1,570 +0,0 @@
using ABI.CCK.Components;
using ABI_RC.Core.InteractionSystem;
using ABI_RC.Core.Player;
using ABI_RC.Core.Savior;
using ABI_RC.Systems.IK.SubSystems;
using ABI_RC.Systems.InputManagement;
using ABI_RC.Systems.MovementSystem;
using RootMotion.Dynamics;
using RootMotion.FinalIK;
using System.Collections.Generic;
using UnityEngine;
namespace ml_prm
{
[DisallowMultipleComponent]
public class RagdollController : MonoBehaviour
{
const float c_defaultFriction = 0.6f;
public static RagdollController Instance { get; private set; } = null;
VRIK m_vrIK = null;
float m_vrIkWeight = 1f;
bool m_inVr = false;
bool m_enabled = false;
readonly List<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 = c_defaultFriction;
m_physicsMaterial.staticFriction = c_defaultFriction;
m_physicsMaterial.frictionCombine = PhysicMaterialCombine.Average;
m_physicsMaterial.bounciness = 0f;
m_physicsMaterial.bounceCombine = PhysicMaterialCombine.Average;
}
~RagdollController()
{
if(Instance == this)
Instance = null;
}
// Unity events
void Start()
{
m_inVr = Utils.IsInVR();
m_puppetRoot = new GameObject("[PlayerAvatarPuppet]").transform;
m_puppetRoot.parent = PlayerSetup.Instance.transform;
m_puppetRoot.localPosition = Vector3.zero;
m_puppetRoot.localRotation = Quaternion.identity;
m_customTrigger = MovementSystem.Instance.proxyCollider.gameObject.AddComponent<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(Settings.HotkeyKey) && !ViewManager.Instance.isGameMenuOpen())
SwitchRagdoll();
if(m_avatarReady && m_enabled && CVRInputManager.Instance.jump && Settings.JumpRecover)
SwitchRagdoll();
}
void LateUpdate()
{
if(m_avatarReady)
{
if(m_enabled)
{
if(!BodySystem.isCalibrating)
{
BodySystem.TrackingPositionWeight = 0f;
foreach(var l_link in m_boneLinks)
l_link.Item1.CopyGlobal(l_link.Item2);
}
}
else
{
foreach(var l_link in m_boneLinks)
l_link.Item2.CopyGlobal(l_link.Item1);
}
}
}
// Game events
internal void OnAvatarClear()
{
if(m_enabled && (MovementSystem.Instance != null))
MovementSystem.Instance.SetImmobilized(false);
if(m_puppet != null)
Object.Destroy(m_puppet.gameObject);
m_puppet = null;
m_vrIK = null;
m_enabled = false;
m_avatarReady = false;
m_avatarRagdollToggle = null;
m_ragdolledParameter = null;
m_rigidBodies.Clear();
m_colliders.Clear();
m_puppetReferences = new BipedRagdollReferences();
m_boneLinks.Clear();
m_jointAnchors.Clear();
m_reachedGround = true;
m_groundedTime = 0f;
m_downTime = float.MinValue;
m_puppetRoot.localScale = Vector3.one;
}
internal void OnAvatarSetup()
{
m_inVr = Utils.IsInVR();
if(PlayerSetup.Instance._animator.isHuman)
{
BipedRagdollReferences l_avatarReferences = BipedRagdollReferences.FromAvatar(PlayerSetup.Instance._animator);
m_puppet = new GameObject("Root").transform;
m_puppet.parent = m_puppetRoot;
m_puppet.localPosition = Vector3.zero;
m_puppet.localRotation = Quaternion.identity;
m_puppetReferences.root = m_puppet;
m_puppetReferences.hips = CloneTransform(l_avatarReferences.hips, m_puppetReferences.root, "Hips");
m_puppetReferences.spine = CloneTransform(l_avatarReferences.spine, m_puppetReferences.hips, "Spine");
if(l_avatarReferences.chest != null)
m_puppetReferences.chest = CloneTransform(l_avatarReferences.chest, m_puppetReferences.spine, "Chest");
m_puppetReferences.head = CloneTransform(l_avatarReferences.head, (m_puppetReferences.chest != null) ? m_puppetReferences.chest : m_puppetReferences.spine, "Head");
m_puppetReferences.leftUpperArm = CloneTransform(l_avatarReferences.leftUpperArm, (m_puppetReferences.chest != null) ? m_puppetReferences.chest : m_puppetReferences.spine, "LeftUpperArm");
m_puppetReferences.leftLowerArm = CloneTransform(l_avatarReferences.leftLowerArm, m_puppetReferences.leftUpperArm, "LeftLowerArm");
m_puppetReferences.leftHand = CloneTransform(l_avatarReferences.leftHand, m_puppetReferences.leftLowerArm, "LeftHand");
m_puppetReferences.rightUpperArm = CloneTransform(l_avatarReferences.rightUpperArm, (m_puppetReferences.chest != null) ? m_puppetReferences.chest : m_puppetReferences.spine, "RightUpperArm");
m_puppetReferences.rightLowerArm = CloneTransform(l_avatarReferences.rightLowerArm, m_puppetReferences.rightUpperArm, "RightLowerArm");
m_puppetReferences.rightHand = CloneTransform(l_avatarReferences.rightHand, m_puppetReferences.rightLowerArm, "RightHand");
m_puppetReferences.leftUpperLeg = CloneTransform(l_avatarReferences.leftUpperLeg, m_puppetReferences.hips, "LeftUpperLeg");
m_puppetReferences.leftLowerLeg = CloneTransform(l_avatarReferences.leftLowerLeg, m_puppetReferences.leftUpperLeg, "LeftLowerLeg");
m_puppetReferences.leftFoot = CloneTransform(l_avatarReferences.leftFoot, m_puppetReferences.leftLowerLeg, "LeftFoot");
m_puppetReferences.rightUpperLeg = CloneTransform(l_avatarReferences.rightUpperLeg, m_puppetReferences.hips, "RightUpperLeg");
m_puppetReferences.rightLowerLeg = CloneTransform(l_avatarReferences.rightLowerLeg, m_puppetReferences.rightUpperLeg, "RightLowerLeg");
m_puppetReferences.rightFoot = CloneTransform(l_avatarReferences.rightFoot, m_puppetReferences.rightLowerLeg, "RightFoot");
// Move to world origin to overcome possible issues, maybe?
m_puppetRoot.position = Vector3.zero;
m_puppetRoot.rotation = Quaternion.identity;
BipedRagdollCreator.Options l_options = BipedRagdollCreator.AutodetectOptions(m_puppetReferences);
l_options.joints = RagdollCreator.JointType.Character;
BipedRagdollCreator.Create(m_puppetReferences, l_options);
Transform[] l_puppetTransforms = m_puppetReferences.GetRagdollTransforms();
Transform[] l_avatarTransforms = l_avatarReferences.GetRagdollTransforms();
for(int i = 0; i < l_puppetTransforms.Length; i++)
{
if(l_puppetTransforms[i] != null)
{
Rigidbody l_body = l_puppetTransforms[i].GetComponent<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;
l_body.gameObject.layer = LayerMask.NameToLayer("PlayerLocal");
}
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 OnChangeFlight()
{
if(m_avatarReady && m_enabled && MovementSystem.Instance.flying)
SwitchRagdoll();
}
// IK updates
void OnIKPreUpdate()
{
if(m_enabled)
{
m_vrIkWeight = m_vrIK.solver.IKPositionWeight;
m_vrIK.solver.IKPositionWeight = 0f;
}
}
void OnIKPostUpdate()
{
if(m_enabled)
m_vrIK.solver.IKPositionWeight = m_vrIkWeight;
else
{
foreach(var l_link in m_boneLinks)
l_link.Item2.CopyGlobal(l_link.Item1);
}
}
// Settings
void OnMovementDragChange(float p_value)
{
if(m_avatarReady)
{
float l_drag = (Utils.IsWorldSafe() ? p_value : 1f);
foreach(Rigidbody l_body in m_rigidBodies)
{
l_body.drag = l_drag;
if(m_enabled)
l_body.WakeUp();
}
}
}
void OnAngularDragChange(float p_value)
{
if(m_avatarReady)
{
foreach(Rigidbody l_body in m_rigidBodies)
{
l_body.angularDrag = p_value;
if(m_enabled)
l_body.WakeUp();
}
}
}
void OnGravityChange(bool p_state)
{
if(m_avatarReady)
{
bool l_gravity = (!Utils.IsWorldSafe() || p_state);
foreach(Rigidbody l_body in m_rigidBodies)
l_body.useGravity = l_gravity;
}
}
void OnPhysicsMaterialChange(bool p_state)
{
if(m_physicsMaterial != null)
{
bool l_slipperiness = (Settings.Slipperiness && Utils.IsWorldSafe());
bool l_bounciness = (Settings.Bounciness && Utils.IsWorldSafe());
m_physicsMaterial.dynamicFriction = (l_slipperiness ? 0f : c_defaultFriction);
m_physicsMaterial.staticFriction = (l_slipperiness ? 0f : c_defaultFriction);
m_physicsMaterial.frictionCombine = (l_slipperiness ? PhysicMaterialCombine.Minimum : PhysicMaterialCombine.Average);
m_physicsMaterial.bounciness = (l_bounciness ? 1f : 0f);
m_physicsMaterial.bounceCombine = (l_bounciness ? PhysicMaterialCombine.Maximum : PhysicMaterialCombine.Average);
}
}
// Arbitrary
public void SwitchRagdoll()
{
if(m_avatarReady)
{
if(!m_enabled)
{
if(IsSafeToRagdoll() && m_reachedGround)
{
// Eject player from seat
if(MovementSystem.Instance.lastSeat != null)
{
Vector3 l_pos = PlayerSetup.Instance.transform.position;
Quaternion l_rot = PlayerSetup.Instance.transform.rotation;
if(MetaPort.Instance.isUsingVr)
{
MetaPort.Instance.isUsingVr = false;
MovementSystem.Instance.lastSeat.ExitSeat();
MetaPort.Instance.isUsingVr = true;
}
else
MovementSystem.Instance.lastSeat.ExitSeat();
PlayerSetup.Instance.transform.position = l_pos;
PlayerSetup.Instance.transform.rotation = Quaternion.Euler(0f, l_rot.eulerAngles.y, 0f);
}
if(MovementSystem.Instance.flying)
MovementSystem.Instance.ChangeFlight(false);
bool l_crouch = MovementSystem.Instance.crouching;
bool l_prone = MovementSystem.Instance.prone;
MovementSystem.Instance.SetImmobilized(true);
MovementSystem.Instance.ChangeCrouch(l_crouch);
MovementSystem.Instance.ChangeProne(l_prone);
PlayerSetup.Instance.animatorManager.SetAnimatorParameterTrigger("CancelEmote");
m_ragdolledParameter.SetValue(true);
if(!BodySystem.isCalibrating)
BodySystem.TrackingPositionWeight = 0f;
if(!Utils.IsWorldSafe())
{
m_reachedGround = false; // Force player to unragdoll and reach ground first
m_groundedTime = 0f;
}
m_puppetRoot.gameObject.SetActive(true);
foreach(Rigidbody l_body in m_rigidBodies)
l_body.isKinematic = false;
Vector3 l_velocity = Vector3.ClampMagnitude(m_velocity * (Utils.IsWorldSafe() ? Settings.VelocityMultiplier : 1f), Utils.GetWorldMovementLimit());
if(Settings.ViewVelocity && Utils.IsWorldSafe())
{
float l_mag = l_velocity.magnitude;
l_velocity = PlayerSetup.Instance.GetActiveCamera().transform.forward * l_mag;
}
foreach(Rigidbody l_body in m_rigidBodies)
{
l_body.velocity = l_velocity;
l_body.angularVelocity = Vector3.zero;
}
foreach(Collider l_collider in m_colliders)
l_collider.enabled = true;
m_ragdollLastPos = m_puppetReferences.hips.position;
m_downTime = 0f;
m_enabled = true;
}
}
else
{
if(IsSafeToUnragdoll())
{
MovementSystem.Instance.SetImmobilized(false);
if(!Utils.IsWorldSafe())
{
Vector3 l_vec = MovementSystem.Instance.GetAppliedGravity();
l_vec.y = Mathf.Clamp(l_vec.y, float.MinValue, 0f);
MovementSystem.Instance.SetAppliedGravity(l_vec);
}
m_ragdolledParameter.SetValue(false);
if(!BodySystem.isCalibrating)
BodySystem.TrackingPositionWeight = 1f;
m_puppetRoot.gameObject.SetActive(false);
foreach(Rigidbody l_body in m_rigidBodies)
l_body.isKinematic = true;
PlayerSetup.Instance.transform.position = m_puppetReferences.hips.position;
if(m_inVr)
PlayerSetup.Instance.transform.position -= (PlayerSetup.Instance.transform.rotation * PlayerSetup.Instance._avatar.transform.localPosition);
foreach(Collider l_collider in m_colliders)
l_collider.enabled = false;
if(m_vrIK != null)
m_vrIK.solver.Reset();
m_lastPosition = PlayerSetup.Instance.transform.position;
m_velocity = Vector3.zero;
m_downTime = float.MinValue;
m_enabled = false;
}
}
}
}
public bool IsRagdolled() => (m_avatarReady && m_enabled);
static Transform CloneTransform(Transform p_source, Transform p_parent, string p_name)
{
Transform l_target = new GameObject(p_name).transform;
l_target.parent = p_parent;
p_source.CopyGlobal(l_target);
return l_target;
}
static bool IsSafeToRagdoll()
{
bool l_result = true;
l_result &= !BodySystem.isCalibrating; // Not calibrating
l_result &= ((CombatSystem.Instance == null) || !CombatSystem.Instance.isDown); // Non-combat world or not dead
return l_result;
}
static bool IsSafeToUnragdoll()
{
bool l_result = true;
l_result &= ((CombatSystem.Instance == null) || !CombatSystem.Instance.isDown); // Non-combat world or not dead
return l_result;
}
}
}

View file

@ -1,12 +0,0 @@
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;
}
}

View file

@ -1,103 +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()
{
CVRParticlePointerManager.RemoveTrigger(m_collider);
}
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

@ -1,223 +0,0 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace ml_prm
{
static class Settings
{
public enum ModSetting
{
Hotkey = 0,
HotkeyKey,
VelocityMultiplier,
MovementDrag,
AngularDrag,
Gravity,
PointersReaction,
IgnoreLocal,
CombatReaction,
AutoRecover,
RecoverDelay,
Slipperiness,
Bounciness,
ViewVelocity,
JumpRecover
}
public static bool Hotkey { get; private set; } = true;
public static KeyCode HotkeyKey { get; private set; } = KeyCode.R;
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<KeyCode> HotkeyKeyChange;
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", "Player Ragdoll Mod");
ms_entries = new List<MelonLoader.MelonPreferences_Entry>()
{
ms_category.CreateEntry(ModSetting.Hotkey.ToString(), Hotkey, null, null, true),
ms_category.CreateEntry(ModSetting.HotkeyKey.ToString(), HotkeyKey, "Hotkey"),
ms_category.CreateEntry(ModSetting.VelocityMultiplier.ToString(), VelocityMultiplier, null, null, true),
ms_category.CreateEntry(ModSetting.MovementDrag.ToString(), MovementDrag, null, null, true),
ms_category.CreateEntry(ModSetting.AngularDrag.ToString(), AngularDrag, null, null, true),
ms_category.CreateEntry(ModSetting.Gravity.ToString(), Gravity, null, null, true),
ms_category.CreateEntry(ModSetting.PointersReaction.ToString(), PointersReaction, null, null, true),
ms_category.CreateEntry(ModSetting.IgnoreLocal.ToString(), IgnoreLocal, null, null, true),
ms_category.CreateEntry(ModSetting.CombatReaction.ToString(), CombatReaction, null, null, true),
ms_category.CreateEntry(ModSetting.AutoRecover.ToString(), AutoRecover, null, null, true),
ms_category.CreateEntry(ModSetting.RecoverDelay.ToString(), RecoverDelay, null, null, true),
ms_category.CreateEntry(ModSetting.Slipperiness.ToString(), Slipperiness, null, null, true),
ms_category.CreateEntry(ModSetting.Bounciness.ToString(), Bounciness, null, null, true),
ms_category.CreateEntry(ModSetting.ViewVelocity.ToString(), ViewVelocity, null, null, true),
ms_category.CreateEntry(ModSetting.JumpRecover.ToString(), JumpRecover, null, null, true)
};
ms_entries[(int)ModSetting.HotkeyKey].OnEntryValueChangedUntyped.Subscribe(OnMelonSettingSave_HotkeyKey);
Hotkey = (bool)ms_entries[(int)ModSetting.Hotkey].BoxedValue;
HotkeyKey = (KeyCode)ms_entries[(int)ModSetting.HotkeyKey].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;
}
static void OnMelonSettingSave_HotkeyKey(object p_oldValue, object p_newValue)
{
if(p_newValue is KeyCode)
{
HotkeyKey = (KeyCode)p_newValue;
HotkeyKeyChange?.Invoke(HotkeyKey);
}
}
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;
}
}
}

View file

@ -1,39 +0,0 @@
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;
}
}
}

View file

@ -1,78 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<Platforms>x64</Platforms>
<PackageId>PlayerRagdollMod</PackageId>
<Version>1.0.11</Version>
<Authors>SDraw</Authors>
<Company>None</Company>
<Product>PlayerRagdollMod</Product>
</PropertyGroup>
<ItemGroup>
<None Remove="PlayerRagdollMod.json" />
<None Remove="resources\person.png" />
<None Remove="vendor\RootMotion\info.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="resources\person.png" />
</ItemGroup>
<ItemGroup>
<Reference Include="0Harmony">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\0Harmony.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="Assembly-CSharp">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="Assembly-CSharp-firstpass">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="BTKUILib">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\Mods\BTKUILib.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="MelonLoader">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\MelonLoader.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="UnityEngine">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="UnityEngine.AnimationModule">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="UnityEngine.ClothModule">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.ClothModule.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="UnityEngine.CoreModule">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="UnityEngine.InputLegacyModule">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.InputLegacyModule.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="UnityEngine.PhysicsModule">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="UnityEngine.ParticleSystemModule">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.ParticleSystemModule.dll</HintPath>
<Private>false</Private>
</Reference>
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="copy /y &quot;$(TargetPath)&quot; &quot;D:\Games\Steam\steamapps\common\ChilloutVR\Mods\&quot;" />
</Target>
</Project>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

View file

@ -1 +0,0 @@
Put `PuppetMaster` and `RagdollMaster` folders from [PuppetMaster asset](https://assetstore.unity.com/packages/tools/physics/puppetmaster-48977) here.

View file

@ -1 +0,0 @@
https://assetstore.unity.com/packages/tools/physics/puppetmaster-48977