Custom event classes for patched methods

Update to LeapCSharp 6.15.0
This commit is contained in:
SDraw 2024-04-26 23:52:25 +03:00
parent 4b879d53d5
commit 85925a7072
No known key found for this signature in database
GPG key ID: BB95B4DAB2BB8BB5
76 changed files with 3443 additions and 2187 deletions

253
ml_prm/GameEvents.cs Normal file
View file

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

View file

@ -1,5 +1,4 @@
using ABI.CCK.Components;
using ABI_RC.Systems.Gravity;
using ABI_RC.Systems.Movement;
using UnityEngine;

View file

@ -1,84 +1,20 @@
using ABI.CCK.Components;
using ABI_RC.Core;
using ABI_RC.Core.InteractionSystem;
using ABI_RC.Core.Player;
using ABI_RC.Core.Player;
using ABI_RC.Core.Util.AssetFiltering;
using ABI_RC.Systems.Camera.VisualMods;
using ABI_RC.Systems.IK;
using ABI_RC.Systems.IK.SubSystems;
using ABI_RC.Systems.Movement;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace ml_prm
{
public class PlayerRagdollMod : MelonLoader.MelonMod
{
static readonly Type[] ms_teleportTypes = { typeof(UnityEngine.Vector3), typeof(bool), typeof(bool), typeof(UnityEngine.Quaternion?) };
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(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnAvatarReinitialize_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnAvatarReinitialize_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(BetterBetterCharacterController).GetMethod(nameof(BetterBetterCharacterController.ChangeFlight)),
null,
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnChangeFlight_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
HarmonyInstance.Patch(
typeof(IKSystem).GetMethod("OnPreSolverUpdateActiveOffset", BindingFlags.Instance | BindingFlags.NonPublic),
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnOffsetUpdate_Prefix), BindingFlags.Static | BindingFlags.NonPublic))
);
GameEvents.Init(HarmonyInstance);
// Whitelist the toggle script
(typeof(SharedFilter).GetField("_localComponentWhitelist", BindingFlags.NonPublic | BindingFlags.Static)?.GetValue(null) as HashSet<Type>)?.Add(typeof(RagdollToggle));
@ -88,11 +24,6 @@ namespace ml_prm
public override void OnDeinitializeMelon()
{
if(ms_instance == this)
ms_instance = null;
ModUi.SwitchChange -= this.OnSwitchActivation;
if(m_localController != null)
UnityEngine.Object.Destroy(m_localController);
m_localController = null;
@ -104,174 +35,6 @@ namespace ml_prm
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 OnAvatarReinitialize_Prefix() => ms_instance?.OnPreAvatarReinitialize();
void OnPreAvatarReinitialize()
{
try
{
if(m_localController != null)
m_localController.OnPreAvatarReinitialize();
}
catch(System.Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnAvatarReinitialize_Postfix() => ms_instance?.OnPostAvatarReinitialize();
void OnPostAvatarReinitialize()
{
try
{
if(m_localController != null)
m_localController.OnPostAvatarReinitialize();
}
catch(System.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);
}
}
static bool OnOffsetUpdate_Prefix(ref IKSystem __instance) => ms_instance.OnOffsetUpdate(__instance);
bool OnOffsetUpdate(IKSystem p_instance)
{
bool l_result = true;
try
{
if(m_localController != null)
l_result = !m_localController.ShoudlDisableHeadOffset();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
return l_result;
}
}
}

View file

@ -8,6 +8,14 @@ namespace ml_prm
{
static class ModUi
{
internal class UiEvent
{
event Action m_action;
public void AddHandler(Action p_listener) => m_action += p_listener;
public void RemoveHandler(Action p_listener) => m_action -= p_listener;
public void Invoke() => m_action?.Invoke();
}
enum UiIndex
{
Hotkey = 0,
@ -29,7 +37,7 @@ namespace ml_prm
FallLimit
}
public static event Action SwitchChange;
internal static readonly UiEvent OnSwitchChanged = new UiEvent();
static List<object> ms_uiElements = null;
@ -52,7 +60,7 @@ namespace ml_prm
var l_modCategory = l_modRoot.AddCategory("Settings");
l_modCategory.AddButton("Switch ragdoll", "PRM-Person", "Switch between normal and ragdoll state.").OnPress += () => SwitchChange?.Invoke();
l_modCategory.AddButton("Switch ragdoll", "PRM-Person", "Switch between normal and ragdoll state.").OnPress += OnSwitch;
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);
@ -108,90 +116,116 @@ namespace ml_prm
l_modCategory.AddButton("Reset settings", "", "Reset mod settings to default").OnPress += Reset;
}
static void OnSwitch()
{
try
{
OnSwitchChanged.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnToggleUpdate(UiIndex p_index, bool p_state, bool p_force = false)
{
switch(p_index)
try
{
case UiIndex.Hotkey:
Settings.SetSetting(Settings.ModSetting.Hotkey, p_state);
break;
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.Gravity:
Settings.SetSetting(Settings.ModSetting.Gravity, p_state);
break;
case UiIndex.PointersReaction:
Settings.SetSetting(Settings.ModSetting.PointersReaction, 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.IgnoreLocal:
Settings.SetSetting(Settings.ModSetting.IgnoreLocal, p_state);
break;
case UiIndex.CombatReaction:
Settings.SetSetting(Settings.ModSetting.CombatReaction, 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.AutoRecover:
Settings.SetSetting(Settings.ModSetting.AutoRecover, p_state);
break;
case UiIndex.Slipperiness:
Settings.SetSetting(Settings.ModSetting.Slipperiness, 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.Bounciness:
Settings.SetSetting(Settings.ModSetting.Bounciness, p_state);
break;
case UiIndex.ViewVelocity:
Settings.SetSetting(Settings.ModSetting.ViewVelocity, 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;
case UiIndex.JumpRecover:
Settings.SetSetting(Settings.ModSetting.JumpRecover, p_state);
break;
case UiIndex.Buoyancy:
Settings.SetSetting(Settings.ModSetting.Buoyancy, p_state);
break;
case UiIndex.Buoyancy:
Settings.SetSetting(Settings.ModSetting.Buoyancy, p_state);
break;
case UiIndex.FallDamage:
Settings.SetSetting(Settings.ModSetting.FallDamage, p_state);
break;
case UiIndex.FallDamage:
Settings.SetSetting(Settings.ModSetting.FallDamage, p_state);
break;
}
if(p_force)
(ms_uiElements[(int)p_index] as BTKUILib.UIObjects.Components.ToggleButton).ToggleValue = p_state;
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
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)
try
{
case UiIndex.VelocityMultiplier:
Settings.SetSetting(Settings.ModSetting.VelocityMultiplier, p_value);
break;
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.MovementDrag:
Settings.SetSetting(Settings.ModSetting.MovementDrag, p_value);
break;
case UiIndex.AngularDrag:
Settings.SetSetting(Settings.ModSetting.AngularDrag, 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;
case UiIndex.RecoverDelay:
Settings.SetSetting(Settings.ModSetting.RecoverDelay, p_value);
break;
case UiIndex.FallLimit:
Settings.SetSetting(Settings.ModSetting.FallLimit, p_value);
break;
case UiIndex.FallLimit:
Settings.SetSetting(Settings.ModSetting.FallLimit, p_value);
break;
}
if(p_force)
(ms_uiElements[(int)p_index] as BTKUILib.UIObjects.Components.SliderFloat).SetSliderValue(p_value);
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
if(p_force)
(ms_uiElements[(int)p_index] as BTKUILib.UIObjects.Components.SliderFloat).SetSliderValue(p_value);
}
static void Reset()

View file

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

View file

@ -20,7 +20,6 @@ namespace ml_prm
public static RagdollController Instance { get; private set; } = null;
bool m_inVR = false;
VRIK m_vrIK = null;
bool m_applyHipsPosition = false;
bool m_applyHipsRotation = false;
@ -88,15 +87,28 @@ namespace ml_prm
m_ragdollTrigger = BetterBetterCharacterController.Instance.NonKinematicProxy.gameObject.AddComponent<RagdollTrigger>();
m_ragdollTrigger.enabled = false;
Settings.MovementDragChange += this.OnMovementDragChange;
Settings.AngularDragChange += this.OnAngularDragChange;
Settings.GravityChange += this.OnGravityChange;
Settings.SlipperinessChange += this.OnPhysicsMaterialChange;
Settings.BouncinessChange += this.OnPhysicsMaterialChange;
Settings.BuoyancyChange += this.OnBuoyancyChange;
Settings.FallDamageChange += this.OnFallDamageChange;
Settings.OnMovementDragChanged.AddHandler(this.OnMovementDragChanged);
Settings.OnAngularDragChanged.AddHandler(this.OnAngularDragChanged);
Settings.OnGravityChanged.AddHandler(this.OnGravityChanged);
Settings.OnSlipperinessChanged.AddHandler(this.OnPhysicsMaterialChanged);
Settings.OnBouncinessChanged.AddHandler(this.OnPhysicsMaterialChanged);
Settings.OnBuoyancyChanged.AddHandler(this.OnBuoyancyChanged);
Settings.OnFallDamageChanged.AddHandler(this.OnFallDamageChanged);
GameEvents.OnAvatarClear.AddHandler(this.OnAvatarClear);
GameEvents.OnAvatarSetup.AddHandler(this.OnAvatarSetup);
GameEvents.OnAvatarPreReuse.AddHandler(this.OnAvatarPreReuse);
GameEvents.OnAvatarPostReuse.AddHandler(this.OnAvatarPostReuse);
GameEvents.OnIKScaling.AddHandler(this.OnAvatarScaling);
GameEvents.OnSeatPreSit.AddHandler(this.OnSeatPreSit);
GameEvents.OnCalibrationStart.AddHandler(this.OnCalibrationStart);
GameEvents.OnWorldPreSpawn.AddHandler(this.OnWorldPreSpawn);
GameEvents.OnCombatPreDown.AddHandler(this.OnCombatPreDown);
GameEvents.OnFlightChange.AddHandler(this.OnFlightChange);
GameEvents.OnIKOffsetUpdate.AddHandler(this.OnIKOffsetUpdate);
BetterBetterCharacterController.OnTeleport.AddListener(this.OnPlayerTeleport);
ModUi.OnSwitchChanged.AddHandler(this.SwitchRagdoll);
}
void OnDestroy()
@ -128,15 +140,28 @@ namespace ml_prm
Object.Destroy(m_physicsMaterial);
m_physicsMaterial = null;
Settings.MovementDragChange -= this.OnMovementDragChange;
Settings.AngularDragChange -= this.OnAngularDragChange;
Settings.GravityChange -= this.OnGravityChange;
Settings.SlipperinessChange -= this.OnPhysicsMaterialChange;
Settings.BouncinessChange -= this.OnPhysicsMaterialChange;
Settings.BuoyancyChange -= this.OnBuoyancyChange;
Settings.FallDamageChange -= this.OnFallDamageChange;
Settings.OnMovementDragChanged.RemoveHandler(this.OnMovementDragChanged);
Settings.OnAngularDragChanged.RemoveHandler(this.OnAngularDragChanged);
Settings.OnGravityChanged.RemoveHandler(this.OnGravityChanged);
Settings.OnSlipperinessChanged.RemoveHandler(this.OnPhysicsMaterialChanged);
Settings.OnBouncinessChanged.RemoveHandler(this.OnPhysicsMaterialChanged);
Settings.OnBuoyancyChanged.RemoveHandler(this.OnBuoyancyChanged);
Settings.OnFallDamageChanged.RemoveHandler(this.OnFallDamageChanged);
GameEvents.OnAvatarClear.RemoveHandler(this.OnAvatarClear);
GameEvents.OnAvatarSetup.RemoveHandler(this.OnAvatarSetup);
GameEvents.OnAvatarPreReuse.RemoveHandler(this.OnAvatarPreReuse);
GameEvents.OnAvatarPostReuse.RemoveHandler(this.OnAvatarPostReuse);
GameEvents.OnIKScaling.RemoveHandler(this.OnAvatarScaling);
GameEvents.OnSeatPreSit.RemoveHandler(this.OnSeatPreSit);
GameEvents.OnCalibrationStart.RemoveHandler(this.OnCalibrationStart);
GameEvents.OnWorldPreSpawn.RemoveHandler(this.OnWorldPreSpawn);
GameEvents.OnCombatPreDown.RemoveHandler(this.OnCombatPreDown);
GameEvents.OnFlightChange.RemoveHandler(this.OnFlightChange);
GameEvents.OnIKOffsetUpdate.RemoveHandler(this.OnIKOffsetUpdate);
BetterBetterCharacterController.OnTeleport.RemoveListener(this.OnPlayerTeleport);
ModUi.OnSwitchChanged.RemoveHandler(this.SwitchRagdoll);
}
void Update()
@ -234,10 +259,8 @@ namespace ml_prm
}
// Game events
internal void OnAvatarClear()
void OnAvatarClear()
{
m_inVR = Utils.IsInVR();
if(m_initCoroutine != null)
{
StopCoroutine(m_initCoroutine);
@ -282,10 +305,8 @@ namespace ml_prm
m_wasSwimming = false;
}
internal void OnAvatarSetup()
void OnAvatarSetup()
{
m_inVR = Utils.IsInVR();
if(PlayerSetup.Instance._animator.isHuman)
{
Utils.SetAvatarTPose();
@ -405,7 +426,7 @@ namespace ml_prm
m_vrIK = PlayerSetup.Instance._avatar.GetComponent<VRIK>();
if(m_vrIK != null)
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate);
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostSolverUpdate);
m_avatarRagdollToggle = PlayerSetup.Instance._avatar.GetComponentInChildren<RagdollToggle>(true);
m_ragdolledParameter = new AvatarBoolParameter("Ragdolled", PlayerSetup.Instance.animatorManager);
@ -425,13 +446,13 @@ namespace ml_prm
m_avatarReady = true;
m_initCoroutine = null;
OnGravityChange(Settings.Gravity);
OnBuoyancyChange(Settings.Buoyancy);
OnMovementDragChange(Settings.MovementDrag);
OnAngularDragChange(Settings.AngularDrag);
OnGravityChanged(Settings.Gravity);
OnBuoyancyChanged(Settings.Buoyancy);
OnMovementDragChanged(Settings.MovementDrag);
OnAngularDragChanged(Settings.AngularDrag);
}
internal void OnPreAvatarReinitialize()
void OnAvatarPreReuse()
{
if(m_avatarReady && m_enabled)
{
@ -440,16 +461,15 @@ namespace ml_prm
m_forcedSwitch = false;
}
}
internal void OnPostAvatarReinitialize()
void OnAvatarPostReuse()
{
m_inVR = Utils.IsInVR();
m_vrIK = PlayerSetup.Instance._avatar.GetComponent<VRIK>();
if(m_vrIK != null)
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate);
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostSolverUpdate);
}
internal void OnAvatarScaling(float p_scaleDifference)
void OnAvatarScaling(float p_scaleDifference)
{
if(m_puppetRoot != null)
m_puppetRoot.localScale = Vector3.one * p_scaleDifference;
@ -458,7 +478,7 @@ namespace ml_prm
l_pair.Item1.connectedAnchor = l_pair.Item2 * p_scaleDifference;
}
internal void OnSeatSitDown(CVRSeat p_seat)
void OnSeatPreSit(CVRSeat p_seat)
{
if(m_avatarReady && m_enabled && !p_seat.occupied)
{
@ -469,7 +489,7 @@ namespace ml_prm
}
}
internal void OnStartCalibration()
void OnCalibrationStart()
{
if(m_avatarReady && m_enabled)
{
@ -480,22 +500,22 @@ namespace ml_prm
}
}
internal void OnWorldSpawn()
void OnWorldPreSpawn()
{
if(m_avatarReady && m_enabled)
SwitchRagdoll();
ResetStates();
OnGravityChange(Settings.Gravity);
OnPhysicsMaterialChange(true);
OnMovementDragChange(Settings.MovementDrag);
OnBuoyancyChange(Settings.Buoyancy);
OnGravityChanged(Settings.Gravity);
OnPhysicsMaterialChanged(true);
OnMovementDragChanged(Settings.MovementDrag);
OnBuoyancyChanged(Settings.Buoyancy);
}
internal void OnCombatDown()
void OnCombatPreDown()
{
if(m_avatarReady && !m_enabled && Settings.CombatReaction)
if(m_avatarReady && !m_enabled && CombatSystem.Instance.isDown && Settings.CombatReaction)
{
m_reachedGround = true;
m_forcedSwitch = true;
@ -505,7 +525,7 @@ namespace ml_prm
}
}
internal void OnChangeFlight()
void OnFlightChange()
{
if(m_avatarReady && m_enabled && BetterBetterCharacterController.Instance.IsFlying())
{
@ -532,8 +552,13 @@ namespace ml_prm
}
}
void OnIKOffsetUpdate(GameEvents.EventResult p_result)
{
p_result.m_result |= (m_enabled && (m_vrIK != null));
}
// VRIK updates
void OnIKPostUpdate()
void OnIKPostSolverUpdate()
{
if(!m_enabled)
{
@ -543,7 +568,7 @@ namespace ml_prm
}
// Settings
void OnMovementDragChange(float p_value)
void OnMovementDragChanged(float p_value)
{
if(m_avatarReady)
{
@ -558,7 +583,7 @@ namespace ml_prm
l_influencer.airDrag = l_drag;
}
}
void OnAngularDragChange(float p_value)
void OnAngularDragChanged(float p_value)
{
if(m_avatarReady)
{
@ -572,7 +597,7 @@ namespace ml_prm
l_influencer.airAngularDrag = p_value;
}
}
void OnGravityChange(bool p_state)
void OnGravityChanged(bool p_state)
{
if(m_avatarReady)
{
@ -584,12 +609,12 @@ namespace ml_prm
if(!l_gravity)
{
OnMovementDragChange(Settings.MovementDrag);
OnAngularDragChange(Settings.AngularDrag);
OnMovementDragChanged(Settings.MovementDrag);
OnAngularDragChanged(Settings.AngularDrag);
}
}
}
void OnPhysicsMaterialChange(bool p_state)
void OnPhysicsMaterialChanged(bool p_state)
{
if(m_physicsMaterial != null)
{
@ -602,7 +627,7 @@ namespace ml_prm
m_physicsMaterial.bounceCombine = (l_bounciness ? PhysicMaterialCombine.Maximum : PhysicMaterialCombine.Average);
}
}
void OnBuoyancyChange(bool p_state)
void OnBuoyancyChanged(bool p_state)
{
if(m_avatarReady)
{
@ -612,12 +637,12 @@ namespace ml_prm
if(!l_buoyancy)
{
OnMovementDragChange(Settings.MovementDrag);
OnAngularDragChange(Settings.AngularDrag);
OnMovementDragChanged(Settings.MovementDrag);
OnAngularDragChanged(Settings.AngularDrag);
}
}
}
void OnFallDamageChange(bool p_state)
void OnFallDamageChanged(bool p_state)
{
m_inAir = false;
m_inAirDistance = 0f;
@ -635,7 +660,7 @@ namespace ml_prm
m_wasSwimming = BetterBetterCharacterController.Instance.IsSwimming();
if(BetterBetterCharacterController.Instance.IsFlying())
BetterBetterCharacterController.Instance.ChangeFlight(false,true);
BetterBetterCharacterController.Instance.ChangeFlight(false, true);
BetterBetterCharacterController.Instance.SetImmobilized(true);
BetterBetterCharacterController.Instance.ClearFluidVolumes();
BodySystem.TrackingPositionWeight = 0f;
@ -713,8 +738,8 @@ namespace ml_prm
m_downTime = float.MinValue;
// Restore rigidbody properties that could be affected by buoyancy
OnMovementDragChange(Settings.MovementDrag);
OnAngularDragChange(Settings.AngularDrag);
OnMovementDragChanged(Settings.MovementDrag);
OnAngularDragChanged(Settings.AngularDrag);
// Restore movement if was ragdolled in water and left it
if(m_wasSwimming)
@ -764,11 +789,6 @@ namespace ml_prm
return (l_result || m_forcedSwitch);
}
internal bool ShoudlDisableHeadOffset()
{
return (m_enabled && (m_vrIK != null));
}
static void TryRestoreMovement()
{
bool l_state = true;

View file

@ -6,6 +6,14 @@ namespace ml_prm
{
static class Settings
{
internal class SettingEvent<T>
{
event Action<T> m_action;
public void AddHandler(Action<T> p_listener) => m_action += p_listener;
public void RemoveHandler(Action<T> p_listener) => m_action -= p_listener;
public void Invoke(T p_value) => m_action?.Invoke(p_value);
}
public enum ModSetting
{
Hotkey = 0,
@ -47,24 +55,24 @@ namespace ml_prm
public static bool FallDamage { get; private set; } = true;
public static float FallLimit { get; private set; } = 5f;
public static event Action<bool> HotkeyChange;
public static event Action<KeyCode> HotkeyKeyChange;
public static event Action<float> VelocityMultiplierChange;
public static event Action<float> MovementDragChange;
public static event Action<float> AngularDragChange;
public static event Action<bool> GravityChange;
public static event Action<bool> PointersReactionChange;
public static event Action<bool> IgnoreLocalChange;
public static event Action<bool> CombatReactionChange;
public static event Action<bool> AutoRecoverChange;
public static event Action<float> RecoverDelayChange;
public static event Action<bool> SlipperinessChange;
public static event Action<bool> BouncinessChange;
public static event Action<bool> ViewVelocityChange;
public static event Action<bool> JumpRecoverChange;
public static event Action<bool> BuoyancyChange;
public static event Action<bool> FallDamageChange;
public static event Action<float> FallLimitChange;
public static readonly SettingEvent<bool> OnHotkeyChanged = new SettingEvent<bool>();
public static readonly SettingEvent<KeyCode> OnHotkeyKeyChanged = new SettingEvent<KeyCode>();
public static readonly SettingEvent<float> OnVelocityMultiplierChanged = new SettingEvent<float>();
public static readonly SettingEvent<float> OnMovementDragChanged = new SettingEvent<float>();
public static readonly SettingEvent<float> OnAngularDragChanged = new SettingEvent<float>();
public static readonly SettingEvent<bool> OnGravityChanged = new SettingEvent<bool>();
public static readonly SettingEvent<bool> OnPointersReactionChanged = new SettingEvent<bool>();
public static readonly SettingEvent<bool> OnIgnoreLocalChanged = new SettingEvent<bool>();
public static readonly SettingEvent<bool> OnCombatReactionChanged = new SettingEvent<bool>();
public static readonly SettingEvent<bool> OnAutoRecoverChanged = new SettingEvent<bool>();
public static readonly SettingEvent<float> OnRecoverDelayChanged = new SettingEvent<float>();
public static readonly SettingEvent<bool> OnSlipperinessChanged = new SettingEvent<bool>();
public static readonly SettingEvent<bool> OnBouncinessChanged = new SettingEvent<bool>();
public static readonly SettingEvent<bool> OnViewVelocityChanged = new SettingEvent<bool>();
public static readonly SettingEvent<bool> OnJumpRecoverChanged = new SettingEvent<bool>();
public static readonly SettingEvent<bool> OnBuoyancyChanged = new SettingEvent<bool>();
public static readonly SettingEvent<bool> OnFallDamageChanged = new SettingEvent<bool>();
public static readonly SettingEvent<float> OnFallLimitChanged = new SettingEvent<float>();
static MelonLoader.MelonPreferences_Category ms_category = null;
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
@ -119,141 +127,155 @@ namespace ml_prm
static void OnMelonSettingSave_HotkeyKey(object p_oldValue, object p_newValue)
{
if(p_newValue is KeyCode)
try
{
HotkeyKey = (KeyCode)p_newValue;
HotkeyKeyChange?.Invoke(HotkeyKey);
if(p_newValue is KeyCode)
{
HotkeyKey = (KeyCode)p_newValue;
OnHotkeyKeyChanged.Invoke(HotkeyKey);
}
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
public static void SetSetting(ModSetting p_settings, object p_value)
{
switch(p_settings)
try
{
// Booleans
case ModSetting.Hotkey:
switch(p_settings)
{
Hotkey = (bool)p_value;
HotkeyChange?.Invoke((bool)p_value);
}
break;
// Booleans
case ModSetting.Hotkey:
{
Hotkey = (bool)p_value;
OnHotkeyChanged.Invoke(Hotkey);
}
break;
case ModSetting.Gravity:
{
Gravity = (bool)p_value;
GravityChange?.Invoke((bool)p_value);
}
break;
case ModSetting.Gravity:
{
Gravity = (bool)p_value;
OnGravityChanged.Invoke(Gravity);
}
break;
case ModSetting.PointersReaction:
{
PointersReaction = (bool)p_value;
PointersReactionChange?.Invoke((bool)p_value);
}
break;
case ModSetting.PointersReaction:
{
PointersReaction = (bool)p_value;
OnPointersReactionChanged.Invoke(PointersReaction);
}
break;
case ModSetting.IgnoreLocal:
{
IgnoreLocal = (bool)p_value;
IgnoreLocalChange?.Invoke((bool)p_value);
}
break;
case ModSetting.IgnoreLocal:
{
IgnoreLocal = (bool)p_value;
OnIgnoreLocalChanged.Invoke(IgnoreLocal);
}
break;
case ModSetting.CombatReaction:
{
CombatReaction = (bool)p_value;
CombatReactionChange?.Invoke((bool)p_value);
}
break;
case ModSetting.CombatReaction:
{
CombatReaction = (bool)p_value;
OnCombatReactionChanged.Invoke(CombatReaction);
}
break;
case ModSetting.AutoRecover:
{
AutoRecover = (bool)p_value;
AutoRecoverChange?.Invoke((bool)p_value);
}
break;
case ModSetting.AutoRecover:
{
AutoRecover = (bool)p_value;
OnAutoRecoverChanged.Invoke(AutoRecover);
}
break;
case ModSetting.Slipperiness:
{
Slipperiness = (bool)p_value;
SlipperinessChange?.Invoke((bool)p_value);
}
break;
case ModSetting.Slipperiness:
{
Slipperiness = (bool)p_value;
OnSlipperinessChanged.Invoke(Slipperiness);
}
break;
case ModSetting.Bounciness:
{
Bounciness = (bool)p_value;
BouncinessChange?.Invoke((bool)p_value);
}
break;
case ModSetting.Bounciness:
{
Bounciness = (bool)p_value;
OnBouncinessChanged.Invoke(Bounciness);
}
break;
case ModSetting.ViewVelocity:
{
ViewVelocity = (bool)p_value;
ViewVelocityChange?.Invoke((bool)p_value);
}
break;
case ModSetting.ViewVelocity:
{
ViewVelocity = (bool)p_value;
OnViewVelocityChanged.Invoke(ViewVelocity);
}
break;
case ModSetting.JumpRecover:
{
JumpRecover = (bool)p_value;
JumpRecoverChange?.Invoke((bool)p_value);
}
break;
case ModSetting.JumpRecover:
{
JumpRecover = (bool)p_value;
OnJumpRecoverChanged.Invoke(JumpRecover);
}
break;
case ModSetting.Buoyancy:
{
Buoyancy = (bool)p_value;
BuoyancyChange?.Invoke((bool)p_value);
}
break;
case ModSetting.Buoyancy:
{
Buoyancy = (bool)p_value;
OnBuoyancyChanged.Invoke(Buoyancy);
}
break;
case ModSetting.FallDamage:
{
FallDamage = (bool)p_value;
FallDamageChange?.Invoke((bool)p_value);
}
break;
case ModSetting.FallDamage:
{
FallDamage = (bool)p_value;
OnFallDamageChanged.Invoke(FallDamage);
}
break;
// Floats
case ModSetting.VelocityMultiplier:
{
VelocityMultiplier = (float)p_value;
VelocityMultiplierChange?.Invoke((float)p_value);
}
break;
// Floats
case ModSetting.VelocityMultiplier:
{
VelocityMultiplier = (float)p_value;
OnVelocityMultiplierChanged.Invoke(VelocityMultiplier);
}
break;
case ModSetting.MovementDrag:
{
MovementDrag = (float)p_value;
MovementDragChange?.Invoke((float)p_value);
}
break;
case ModSetting.MovementDrag:
{
MovementDrag = (float)p_value;
OnMovementDragChanged.Invoke(MovementDrag);
}
break;
case ModSetting.AngularDrag:
{
AngularDrag = (float)p_value;
AngularDragChange?.Invoke((float)p_value);
}
break;
case ModSetting.AngularDrag:
{
AngularDrag = (float)p_value;
OnAngularDragChanged.Invoke(AngularDrag);
}
break;
case ModSetting.RecoverDelay:
{
RecoverDelay = (float)p_value;
RecoverDelayChange?.Invoke((float)p_value);
}
break;
case ModSetting.RecoverDelay:
{
RecoverDelay = (float)p_value;
OnRecoverDelayChanged.Invoke(RecoverDelay);
}
break;
case ModSetting.FallLimit:
{
FallLimit = (float)p_value;
FallLimitChange?.Invoke((float)p_value);
case ModSetting.FallLimit:
{
FallLimit = (float)p_value;
OnFallLimitChanged.Invoke(FallLimit);
}
break;
}
break;
if(ms_entries != null)
ms_entries[(int)p_settings].BoxedValue = p_value;
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
if(ms_entries != null)
ms_entries[(int)p_settings].BoxedValue = p_value;
}
}
}

View file

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