Too many changes

This commit is contained in:
SDraw 2024-10-05 15:42:32 +03:00
parent 45557943c4
commit a22e5992d0
No known key found for this signature in database
GPG key ID: BB95B4DAB2BB8BB5
72 changed files with 1064 additions and 927 deletions

View file

@ -248,6 +248,5 @@ namespace ml_prm
}
return !ms_result.m_result;
}
}
}

View file

@ -42,14 +42,9 @@ namespace ml_prm
System.Collections.IEnumerator WaitForWhitelist()
{
// Whitelist the toggle script
FieldInfo l_field = typeof(SharedFilter).GetField("_localComponentWhitelist", BindingFlags.NonPublic | BindingFlags.Static);
HashSet<Type> l_hashSet = l_field?.GetValue(null) as HashSet<Type>;
while(l_hashSet == null)
{
l_hashSet = l_field?.GetValue(null) as HashSet<Type>;
while(SharedFilter.LocalComponentWhitelist == null)
yield return null;
}
l_hashSet.Add(typeof(RagdollToggle));
SharedFilter.LocalComponentWhitelist.Add(typeof(RagdollToggle));
}
}
}

View file

@ -43,6 +43,7 @@ namespace ml_prm
const string c_ragdollKeyTooltip = "Switch ragdoll mode with '{0}' key";
const string c_fallLimitTooltip = "Fall limit based on impact velocity<p>Current value corresponds to drop from {0} units with default gravity</p>";
readonly static string ms_namespace = typeof(ModUi).Namespace;
internal static readonly UiEvent OnSwitchChanged = new UiEvent();
static Page ms_page = null;
@ -345,7 +346,7 @@ namespace ml_prm
{
Assembly l_assembly = Assembly.GetExecutingAssembly();
string l_assemblyName = l_assembly.GetName().Name;
return l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name);
return l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + p_name);
}
static float GetDropHeight(float p_speed, float p_gravity = 9.8f)

View file

@ -65,7 +65,7 @@ Now you can animate both parameters available:
![](.github/img_01.png)
Note: In order to work the game object needs to be active and the component enabled.
# Mods Integration
# 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`
@ -75,9 +75,3 @@ Available methods:
* ```void SwitchRagdoll()```
* ```void Ragdoll()```
* ```void Unragdoll()```
# 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.
* Add transition from `Any state` to state with A-pose/T-pose animation and condition with `Ragdolled` parameter on main avatar's animator layer.

View file

@ -26,8 +26,10 @@ namespace ml_prm
bool m_applyHipsPosition = false;
bool m_applyHipsRotation = false;
bool m_avatarReady = false;
bool m_ragdolled = false;
bool m_forcedSwitch = false;
Coroutine m_initTask = null;
Transform m_puppet = null;
Transform m_puppetRoot = null;
@ -36,10 +38,6 @@ namespace ml_prm
readonly List<System.Tuple<Transform, Transform>> m_boneLinks = null;
readonly List<System.Tuple<CharacterJoint, Vector3>> m_jointAnchors = null;
bool m_avatarReady = false;
Coroutine m_initCoroutine = null;
Vector3 m_ragdollLastPos = Vector3.zero;
RagdollToggle m_avatarRagdollToggle = null; // Custom component available for editor
AvatarBoolParameter m_ragdolledParameter = null;
PhysicMaterial m_physicsMaterial = null;
@ -49,6 +47,11 @@ namespace ml_prm
float m_groundedTime = 0f;
float m_downTime = float.MinValue;
Vector3 m_lastRagdollPosition;
Vector3 m_lastSeatPositon;
Vector3 m_seatVelocity;
Plane m_playerPlane;
internal RagdollController()
{
m_ragdollBodyHandlers = new List<RagdollBodypartHandler>();
@ -59,10 +62,14 @@ namespace ml_prm
// Unity events
void Awake()
{
if((Instance != null) && (Instance != this))
Object.Destroy(this);
else
Instance = this;
if(Instance != null)
{
DestroyImmediate(this);
return;
}
Instance = this;
DontDestroyOnLoad(this);
}
void Start()
@ -112,9 +119,9 @@ namespace ml_prm
if(Instance == this)
Instance = null;
if(m_initCoroutine != null)
StopCoroutine(m_initCoroutine);
m_initCoroutine = null;
if(m_initTask != null)
StopCoroutine(m_initTask);
m_initTask = null;
if(m_puppet != null)
Object.Destroy(m_puppet);
@ -160,7 +167,7 @@ namespace ml_prm
{
if(m_avatarReady)
{
if(!m_ragdolled && Settings.FallDamage && !BetterBetterCharacterController.Instance.IsFlying())
if(!m_ragdolled && Settings.FallDamage && !BetterBetterCharacterController.Instance.IsFlying() && !BetterBetterCharacterController.Instance.IsSitting())
{
bool l_grounded = BetterBetterCharacterController.Instance.IsGrounded();
bool l_inWater = BetterBetterCharacterController.Instance.IsInWater();
@ -170,6 +177,17 @@ namespace ml_prm
m_inAir = !(l_grounded || l_inWater);
}
if(!m_ragdolled && BetterBetterCharacterController.Instance.IsSitting()) // Those seats without velocity, smh
{
CVRSeat l_seat = BetterBetterCharacterController.Instance.GetCurrentSeat();
if(l_seat != null)
{
Vector3 l_pos = l_seat.transform.position;
m_seatVelocity = (l_pos - m_lastSeatPositon) / Time.deltaTime;
m_lastSeatPositon = l_pos;
}
}
if(m_ragdolled)
{
BodySystem.TrackingPositionWeight = 0f;
@ -178,7 +196,7 @@ namespace ml_prm
PlayerSetup.Instance.animatorManager.CancelEmote = true;
}
if(!m_ragdolled && !m_reachedGround && (BetterBetterCharacterController.Instance.IsOnGround() || BetterBetterCharacterController.Instance.IsInWater()))
if(!m_ragdolled && !m_reachedGround && (BetterBetterCharacterController.Instance.IsOnGround() || BetterBetterCharacterController.Instance.IsInWater() || BetterBetterCharacterController.Instance.IsSitting()))
{
m_groundedTime += Time.unscaledDeltaTime;
if(m_groundedTime >= 0.25f)
@ -210,9 +228,18 @@ namespace ml_prm
{
if(m_avatarReady && m_ragdolled)
{
Vector3 l_currentPos = m_puppetReferences.hips.position;
PlayerSetup.Instance.transform.position += (l_currentPos - m_ragdollLastPos);
m_ragdollLastPos = l_currentPos;
Vector3 l_diff = m_puppetReferences.hips.position - m_lastRagdollPosition;
m_playerPlane.SetNormalAndPosition(PlayerSetup.Instance.transform.rotation * Vector3.up, PlayerSetup.Instance.transform.position);
PlayerSetup.Instance.transform.position += l_diff;
m_lastRagdollPosition = m_puppetReferences.hips.position;
// Project on plane and fix our position if we under previous plane
if(m_playerPlane.GetDistanceToPoint(m_lastRagdollPosition) < 0f)
m_playerPlane.Flip();
float l_distance = m_playerPlane.GetDistanceToPoint(PlayerSetup.Instance.transform.position);
if(l_distance < 0f)
PlayerSetup.Instance.transform.position = m_playerPlane.ClosestPointOnPlane(PlayerSetup.Instance.transform.position);
}
}
@ -242,10 +269,10 @@ namespace ml_prm
// Game events
void OnAvatarClear()
{
if(m_initCoroutine != null)
if(m_initTask != null)
{
StopCoroutine(m_initCoroutine);
m_initCoroutine = null;
StopCoroutine(m_initTask);
m_initTask = null;
}
if(m_ragdolled)
@ -365,7 +392,7 @@ namespace ml_prm
m_avatarRagdollToggle = PlayerSetup.Instance._avatar.GetComponentInChildren<RagdollToggle>(true);
m_ragdolledParameter = new AvatarBoolParameter("Ragdolled", PlayerSetup.Instance.animatorManager);
m_initCoroutine = StartCoroutine(WaitForBodyHandlers());
m_initTask = StartCoroutine(WaitForBodyHandlers());
}
}
@ -381,7 +408,7 @@ namespace ml_prm
}
m_avatarReady = true;
m_initCoroutine = null;
m_initTask = null;
OnMovementDragChanged(Settings.MovementDrag);
OnAngularDragChanged(Settings.AngularDrag);
@ -414,6 +441,8 @@ namespace ml_prm
void OnSeatPreSit(CVRSeat p_seat)
{
m_lastSeatPositon = p_seat.transform.position;
if(!p_seat.occupied)
{
m_forcedSwitch = true;
@ -473,9 +502,8 @@ namespace ml_prm
if(m_avatarReady && m_ragdolled)
{
Vector3 l_pos = m_hips.position;
m_puppetReferences.hips.position = l_pos;
m_ragdollLastPos = l_pos;
m_puppetReferences.hips.position = m_hips.position;
m_lastRagdollPosition = m_puppetReferences.hips.position;
}
}
catch(System.Exception e)
@ -600,7 +628,7 @@ namespace ml_prm
void OnGestureGrabChanged(bool p_state)
{
if(m_avatarReady && m_ragdolled & !p_state)
if(m_avatarReady && m_ragdolled && !p_state)
{
foreach(var l_hanlder in m_ragdollBodyHandlers)
l_hanlder.Detach();
@ -622,13 +650,24 @@ namespace ml_prm
{
if(m_avatarReady && !m_ragdolled && CanRagdoll())
{
Vector3 l_velocity = Vector3.ClampMagnitude(BetterBetterCharacterController.Instance.velocity * (WorldManager.IsSafeWorld() ? Settings.VelocityMultiplier : 1f), WorldManager.GetMovementLimit());
Vector3 l_velocity = (BetterBetterCharacterController.Instance.IsSitting() ? m_seatVelocity : BetterBetterCharacterController.Instance.velocity);
l_velocity *= (WorldManager.IsSafeWorld() ? Settings.VelocityMultiplier : 1f);
l_velocity = Vector3.ClampMagnitude(l_velocity, WorldManager.GetMovementLimit());
if(Settings.ViewVelocity && WorldManager.IsSafeWorld())
{
float l_mag = l_velocity.magnitude;
l_velocity = PlayerSetup.Instance.GetActiveCamera().transform.forward * l_mag;
}
Vector3 l_playerPos = PlayerSetup.Instance.transform.position;
Quaternion l_playerRot = PlayerSetup.Instance.transform.rotation;
bool l_wasSitting = BetterBetterCharacterController.Instance.IsSitting();
if(BetterBetterCharacterController.Instance.IsSitting())
{
BetterBetterCharacterController.Instance.SetSitting(false);
l_wasSitting = true;
}
if(BetterBetterCharacterController.Instance.IsFlying())
BetterBetterCharacterController.Instance.ChangeFlight(false, true);
BetterBetterCharacterController.Instance.SetImmobilized(true);
@ -662,7 +701,12 @@ namespace ml_prm
l_handler.SetAngularVelocity(Vector3.zero);
}
m_ragdollLastPos = m_puppetReferences.hips.position;
if(l_wasSitting)
{
PlayerSetup.Instance.transform.position = l_playerPos;
PlayerSetup.Instance.transform.rotation = l_playerRot;
}
m_lastRagdollPosition = m_puppetReferences.hips.position;
m_downTime = 0f;
m_ragdolled = true;
@ -675,12 +719,6 @@ namespace ml_prm
{
BetterBetterCharacterController.Instance.TeleportPlayerTo(m_puppetReferences.hips.position, PlayerSetup.Instance.GetPlayerRotation().eulerAngles, false, false);
TryRestoreMovement();
if(!WorldManager.IsSafeWorld())
{
Vector3 l_vec = BetterBetterCharacterController.Instance.GetVelocity();
l_vec.y = Mathf.Clamp(l_vec.y, float.MinValue, 0f);
BetterBetterCharacterController.Instance.SetVelocity(l_vec);
}
BodySystem.TrackingPositionWeight = 1f;
IKSystem.Instance.applyOriginalHipPosition = m_applyHipsPosition;
IKSystem.Instance.applyOriginalHipRotation = m_applyHipsRotation;
@ -725,7 +763,6 @@ namespace ml_prm
bool l_result = m_reachedGround;
l_result &= !BodySystem.isCalibrating;
l_result &= !BetterBetterCharacterController.Instance.IsSitting();
l_result &= ((CombatSystem.Instance == null) || !CombatSystem.Instance.isDown);
return (l_result || m_forcedSwitch);
}

View file

@ -22,6 +22,7 @@ namespace ml_prm
public void RemoveListener(Action<T1, T2, T3> p_listener) => m_action -= p_listener;
public void Invoke(T1 p_objA, T2 p_objB, T3 p_objC) => m_action?.Invoke(p_objA, p_objB, p_objC);
}
public static readonly GestureEvent<PuppetMaster, GestureHand, bool> OnGestureState = new GestureEvent<PuppetMaster, GestureHand, bool>();
class PlayerEntry
@ -32,6 +33,8 @@ namespace ml_prm
public bool m_stateRight = false;
}
static RemoteGesturesManager ms_instance = null;
readonly List<PlayerEntry> m_entries = null;
internal RemoteGesturesManager()
@ -39,10 +42,20 @@ namespace ml_prm
m_entries = new List<PlayerEntry>();
}
void Awake()
{
if(ms_instance != null)
{
DestroyImmediate(this);
return;
}
ms_instance = this;
DontDestroyOnLoad(this);
}
void Start()
{
DontDestroyOnLoad(this);
CVRGameEventSystem.Player.OnJoinEntity.AddListener(OnRemotePlayerCreated);
CVRGameEventSystem.Player.OnLeaveEntity.AddListener(OnRemotePlayerDestroyed);
Settings.OnGestureGrabChanged.AddListener(OnGestureGrabChanged);
@ -50,6 +63,9 @@ namespace ml_prm
void OnDestroy()
{
if(ms_instance == this)
ms_instance = null;
m_entries.Clear();
CVRGameEventSystem.Player.OnJoinEntity.RemoveListener(OnRemotePlayerCreated);

View file

@ -8,6 +8,7 @@ using System.Reflection;
using UnityEngine;
using System.Linq;
using ABI_RC.Systems.IK.SubSystems;
using ABI_RC.Core.InteractionSystem;
namespace ml_prm
{
@ -17,6 +18,7 @@ namespace ml_prm
static readonly FieldInfo ms_referencePoints = typeof(PhysicsInfluencer).GetField("_referencePoints", BindingFlags.NonPublic | BindingFlags.Instance);
static readonly FieldInfo ms_influencerTouchingVolumes = typeof(PhysicsInfluencer).GetField("_touchingVolumes", BindingFlags.NonPublic | BindingFlags.Instance);
static readonly FieldInfo ms_influencerSubmergedColliders = typeof(PhysicsInfluencer).GetField("_submergedColliders", BindingFlags.NonPublic | BindingFlags.Instance);
static readonly FieldInfo ms_lastCVRSeat = typeof(BetterBetterCharacterController).GetField("_lastCvrSeat", BindingFlags.NonPublic | BindingFlags.Instance);
public static void ClearFluidVolumes(this BetterBetterCharacterController p_instance) => (ms_touchingVolumes.GetValue(p_instance) as List<FluidVolume>)?.Clear();
@ -58,5 +60,9 @@ namespace ml_prm
l_result |= ((FingerSystem.GetCurlNormalized(p_source._playerAvatarMovementDataCurrent.RightMiddle1Stretched) >= 0.5f) && (FingerSystem.GetCurlNormalized(p_source._playerAvatarMovementDataCurrent.RightMiddle2Stretched) >= 0.5f) && (FingerSystem.GetCurlNormalized(p_source._playerAvatarMovementDataCurrent.RightMiddle3Stretched) >= 0.5f));
return l_result;
}
public static CVRSeat GetCurrentSeat(this BetterBetterCharacterController p_instance) => (ms_lastCVRSeat?.GetValue(p_instance) as CVRSeat);
public static bool IsInRange(float p_value, float p_min, float p_max) => ((p_min <= p_value) && (p_value <= p_max));
}
}

View file

@ -1,5 +1,6 @@
using ABI.CCK.Components;
using ABI_RC.Systems.GameEventSystem;
using System;
using UnityEngine;
namespace ml_prm
@ -22,18 +23,25 @@ namespace ml_prm
static void OnWorldLoad(string p_id)
{
ms_safeWorld = ((CVRWorld.Instance != null) && CVRWorld.Instance.allowFlying);
ms_movementLimit = 1f;
GameObject l_restrictObj = GameObject.Find("[RagdollRestriction]");
ms_restrictedWorld = ((l_restrictObj == null) ? false : (l_restrictObj.scene.name != "DontDestroyOnLoad"));
if(CVRWorld.Instance != null)
try
{
ms_movementLimit = CVRWorld.Instance.baseMovementSpeed;
ms_movementLimit *= CVRWorld.Instance.sprintMultiplier;
ms_movementLimit *= CVRWorld.Instance.inAirMovementMultiplier;
ms_movementLimit *= CVRWorld.Instance.flyMultiplier;
ms_safeWorld = ((CVRWorld.Instance != null) && CVRWorld.Instance.allowFlying);
ms_movementLimit = 1f;
GameObject l_restrictObj = GameObject.Find("[RagdollRestriction]");
ms_restrictedWorld = ((l_restrictObj == null) ? false : (l_restrictObj.scene.name != "DontDestroyOnLoad"));
if(CVRWorld.Instance != null)
{
ms_movementLimit = CVRWorld.Instance.baseMovementSpeed;
ms_movementLimit *= CVRWorld.Instance.sprintMultiplier;
ms_movementLimit *= CVRWorld.Instance.inAirMovementMultiplier;
ms_movementLimit *= CVRWorld.Instance.flyMultiplier;
}
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}