diff --git a/ml_amt/ml_amt.csproj b/ml_amt/ml_amt.csproj
index 7f1eb30..2d26d8b 100644
--- a/ml_amt/ml_amt.csproj
+++ b/ml_amt/ml_amt.csproj
@@ -63,15 +63,10 @@
false
false
-
- D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\EasyCharacterMovement.CharacterMovement.dll
- false
+
+ D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\ECM2.dll
false
-
-
- D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\EasyCharacterMovement.Characters.dll
false
- false
D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\MelonLoader.dll
diff --git a/ml_pmc/Main.cs b/ml_pmc/Main.cs
index 269254a..0274988 100644
--- a/ml_pmc/Main.cs
+++ b/ml_pmc/Main.cs
@@ -1,171 +1,171 @@
-using ABI_RC.Core.Networking.IO.Social;
-using ABI_RC.Core.Player;
-using ABI_RC.Systems.IK;
-using ABI_RC.Systems.Movement;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-using UnityEngine;
-
-namespace ml_pmc
-{
- public class PlayerMovementCopycat : MelonLoader.MelonMod
- {
- static PlayerMovementCopycat ms_instance = null;
-
- PoseCopycat m_localCopycat = 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(PlayerMovementCopycat).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
- );
- HarmonyInstance.Patch(
- typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
- null,
- new HarmonyLib.HarmonyMethod(typeof(PlayerMovementCopycat).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
- );
- HarmonyInstance.Patch(
- typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
- new HarmonyLib.HarmonyMethod(typeof(PlayerMovementCopycat).GetMethod(nameof(OnAvatarReinitialize_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
- new HarmonyLib.HarmonyMethod(typeof(PlayerMovementCopycat).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
- );
-
- MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
- }
-
- public override void OnDeinitializeMelon()
- {
- if(ms_instance == this)
- ms_instance = null;
-
- ModUi.CopySwitch -= this.OnTargetSelect;
-
- if(m_localCopycat != null)
- UnityEngine.Object.Destroy(m_localCopycat);
- m_localCopycat = null;
- }
-
- System.Collections.IEnumerator WaitForLocalPlayer()
- {
- while(PlayerSetup.Instance == null)
- yield return null;
-
- m_localCopycat = PlayerSetup.Instance.gameObject.AddComponent();
- ModUi.CopySwitch += this.OnTargetSelect;
- }
-
- void OnTargetSelect(string p_id)
- {
- if(m_localCopycat != null)
- {
- if(m_localCopycat.IsActive())
- m_localCopycat.SetTarget(null);
- else
- {
- if(Friends.FriendsWith(p_id))
- {
- if(CVRPlayerManager.Instance.GetPlayerPuppetMaster(p_id, out PuppetMaster l_puppetMaster))
- {
- if(IsInSight(BetterBetterCharacterController.Instance.KinematicTriggerProxy.Collider, l_puppetMaster.GetComponent(), Utils.GetWorldMovementLimit()))
- m_localCopycat.SetTarget(l_puppetMaster);
- else
- ModUi.ShowAlert("Selected player is too far away or obstructed");
- }
- else
- ModUi.ShowAlert("Selected player isn't connected or ready yet");
- }
- else
- ModUi.ShowAlert("Selected player isn't your friend");
- }
- }
- }
-
- static bool IsInSight(CapsuleCollider p_source, CapsuleCollider p_target, float p_limit)
- {
- bool l_result = false;
- if((p_source != null) && (p_target != null))
- {
- Ray l_ray = new Ray();
- l_ray.origin = p_source.bounds.center;
- l_ray.direction = p_target.bounds.center - l_ray.origin;
- List l_hits = Physics.RaycastAll(l_ray, p_limit).ToList();
- if(l_hits.Count > 0)
- {
- l_hits.RemoveAll(hit => hit.collider.gameObject.layer == LayerMask.NameToLayer("UI Internal")); // Somehow layer mask in RaycastAll just ignores players entirely
- l_hits.RemoveAll(hit => hit.collider.gameObject.layer == LayerMask.NameToLayer("PlayerLocal"));
- l_hits.RemoveAll(hit => hit.collider.gameObject.layer == LayerMask.NameToLayer("PlayerClone"));
- l_hits.Sort((a, b) => ((a.distance < b.distance) ? -1 : 1));
- l_result = (l_hits.First().collider.gameObject.transform.root == p_target.transform.root);
- }
- }
- return l_result;
- }
-
- // Patches
- static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear();
- void OnAvatarClear()
- {
- try
- {
- if(m_localCopycat != null)
- m_localCopycat.OnAvatarClear();
- }
- catch(Exception e)
- {
- MelonLoader.MelonLogger.Error(e);
- }
- }
-
- static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar();
- void OnSetupAvatar()
- {
- try
- {
- if(m_localCopycat != null)
- m_localCopycat.OnAvatarSetup();
- }
- catch(Exception e)
- {
- MelonLoader.MelonLogger.Error(e);
- }
- }
-
- static void OnAvatarReinitialize_Prefix() => ms_instance?.OnPreAvatarReinitialize();
- void OnPreAvatarReinitialize()
- {
- try
- {
- if(m_localCopycat != null)
- m_localCopycat.OnPreAvatarReinitialize();
- }
- catch(System.Exception e)
- {
- MelonLoader.MelonLogger.Error(e);
- }
- }
-
- static void OnAvatarReinitialize_Postfix() => ms_instance?.OnPostAvatarReinitialize();
- void OnPostAvatarReinitialize()
- {
- try
- {
- if(m_localCopycat != null)
- m_localCopycat.OnPostAvatarReinitialize();
- }
- catch(System.Exception e)
- {
- MelonLoader.MelonLogger.Error(e);
- }
- }
- }
-}
+using ABI_RC.Core.Networking.IO.Social;
+using ABI_RC.Core.Player;
+using ABI_RC.Systems.IK;
+using ABI_RC.Systems.Movement;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using UnityEngine;
+
+namespace ml_pmc
+{
+ public class PlayerMovementCopycat : MelonLoader.MelonMod
+ {
+ static PlayerMovementCopycat ms_instance = null;
+
+ PoseCopycat m_localCopycat = 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(PlayerMovementCopycat).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
+ );
+ HarmonyInstance.Patch(
+ typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
+ null,
+ new HarmonyLib.HarmonyMethod(typeof(PlayerMovementCopycat).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
+ );
+ HarmonyInstance.Patch(
+ typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
+ new HarmonyLib.HarmonyMethod(typeof(PlayerMovementCopycat).GetMethod(nameof(OnAvatarReinitialize_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
+ new HarmonyLib.HarmonyMethod(typeof(PlayerMovementCopycat).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
+ );
+
+ MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
+ }
+
+ public override void OnDeinitializeMelon()
+ {
+ if(ms_instance == this)
+ ms_instance = null;
+
+ ModUi.CopySwitch -= this.OnTargetSelect;
+
+ if(m_localCopycat != null)
+ UnityEngine.Object.Destroy(m_localCopycat);
+ m_localCopycat = null;
+ }
+
+ System.Collections.IEnumerator WaitForLocalPlayer()
+ {
+ while(PlayerSetup.Instance == null)
+ yield return null;
+
+ m_localCopycat = PlayerSetup.Instance.gameObject.AddComponent();
+ ModUi.CopySwitch += this.OnTargetSelect;
+ }
+
+ void OnTargetSelect(string p_id)
+ {
+ if(m_localCopycat != null)
+ {
+ if(m_localCopycat.IsActive())
+ m_localCopycat.SetTarget(null);
+ else
+ {
+ if(Friends.FriendsWith(p_id))
+ {
+ if(CVRPlayerManager.Instance.GetPlayerPuppetMaster(p_id, out PuppetMaster l_puppetMaster))
+ {
+ if(IsInSight(BetterBetterCharacterController.Instance.KinematicTriggerProxy.Collider, l_puppetMaster.GetComponent(), Utils.GetWorldMovementLimit()))
+ m_localCopycat.SetTarget(l_puppetMaster);
+ else
+ ModUi.ShowAlert("Selected player is too far away or obstructed");
+ }
+ else
+ ModUi.ShowAlert("Selected player isn't connected or ready yet");
+ }
+ else
+ ModUi.ShowAlert("Selected player isn't your friend");
+ }
+ }
+ }
+
+ static bool IsInSight(CapsuleCollider p_source, CapsuleCollider p_target, float p_limit)
+ {
+ bool l_result = false;
+ if((p_source != null) && (p_target != null))
+ {
+ Ray l_ray = new Ray();
+ l_ray.origin = p_source.bounds.center;
+ l_ray.direction = p_target.bounds.center - l_ray.origin;
+ List l_hits = Physics.RaycastAll(l_ray, p_limit).ToList();
+ if(l_hits.Count > 0)
+ {
+ l_hits.RemoveAll(hit => hit.collider.gameObject.layer == LayerMask.NameToLayer("UI Internal")); // Somehow layer mask in RaycastAll just ignores players entirely
+ l_hits.RemoveAll(hit => hit.collider.gameObject.layer == LayerMask.NameToLayer("PlayerLocal"));
+ l_hits.RemoveAll(hit => hit.collider.gameObject.layer == LayerMask.NameToLayer("PlayerClone"));
+ l_hits.Sort((a, b) => ((a.distance < b.distance) ? -1 : 1));
+ l_result = (l_hits.First().collider.gameObject.transform.root == p_target.transform.root);
+ }
+ }
+ return l_result;
+ }
+
+ // Patches
+ static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear();
+ void OnAvatarClear()
+ {
+ try
+ {
+ if(m_localCopycat != null)
+ m_localCopycat.OnAvatarClear();
+ }
+ catch(Exception e)
+ {
+ MelonLoader.MelonLogger.Error(e);
+ }
+ }
+
+ static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar();
+ void OnSetupAvatar()
+ {
+ try
+ {
+ if(m_localCopycat != null)
+ m_localCopycat.OnAvatarSetup();
+ }
+ catch(Exception e)
+ {
+ MelonLoader.MelonLogger.Error(e);
+ }
+ }
+
+ static void OnAvatarReinitialize_Prefix() => ms_instance?.OnPreAvatarReinitialize();
+ void OnPreAvatarReinitialize()
+ {
+ try
+ {
+ if(m_localCopycat != null)
+ m_localCopycat.OnPreAvatarReinitialize();
+ }
+ catch(System.Exception e)
+ {
+ MelonLoader.MelonLogger.Error(e);
+ }
+ }
+
+ static void OnAvatarReinitialize_Postfix() => ms_instance?.OnPostAvatarReinitialize();
+ void OnPostAvatarReinitialize()
+ {
+ try
+ {
+ if(m_localCopycat != null)
+ m_localCopycat.OnPostAvatarReinitialize();
+ }
+ catch(System.Exception e)
+ {
+ MelonLoader.MelonLogger.Error(e);
+ }
+ }
+ }
+}
diff --git a/ml_pmc/PoseCopycat.cs b/ml_pmc/PoseCopycat.cs
index ed37598..46ea306 100644
--- a/ml_pmc/PoseCopycat.cs
+++ b/ml_pmc/PoseCopycat.cs
@@ -1,368 +1,368 @@
-using ABI_RC.Core.Player;
-using ABI_RC.Systems.IK;
-using ABI_RC.Systems.IK.SubSystems;
-using ABI_RC.Systems.InputManagement;
-using ABI_RC.Systems.Movement;
-using ABI_RC.Systems.VRModeSwitch;
-using RootMotion.FinalIK;
-using UnityEngine;
-
-namespace ml_pmc
-{
- [DisallowMultipleComponent]
- public class PoseCopycat : MonoBehaviour
- {
- static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f);
-
- static public PoseCopycat Instance { get; private set; } = null;
- static internal System.Action OnActivityChange;
-
- Animator m_animator = null;
- VRIK m_vrIk = null;
- float m_ikWeight = 1f;
- LookAtIK m_lookAtIk = null;
- float m_lookIkWeight = 1f;
- bool m_sitting = false;
- bool m_inVr = false;
-
- bool m_active = false;
- float m_distanceLimit = float.MaxValue;
- bool m_fingerTracking = false;
-
- HumanPoseHandler m_poseHandler = null;
- HumanPose m_pose;
- PuppetParser m_puppetParser = null;
-
- void Start()
- {
- if(Instance == null)
- Instance = this;
- }
- void OnDestroy()
- {
- if(Instance == this)
- Instance = null;
-
- m_poseHandler?.Dispose();
- m_poseHandler = null;
-
- if(m_puppetParser != null)
- Object.Destroy(m_puppetParser);
- m_puppetParser = null;
-
- m_animator = null;
- m_vrIk = null;
- m_lookAtIk = null;
- }
-
- // Unity events
- void Update()
- {
- m_sitting = BetterBetterCharacterController.Instance.IsSitting();
-
- if(m_active)
- {
- if(m_puppetParser != null)
- {
- OverrideIK();
-
- bool l_mirror = Settings.MirrorPose;
-
- if(Settings.Gestures)
- {
- CVRInputManager.Instance.gestureLeft = (l_mirror ? m_puppetParser.GetRightGesture() : m_puppetParser.GetLeftGesture());
- CVRInputManager.Instance.gestureRight = (l_mirror ? m_puppetParser.GetLeftGesture() : m_puppetParser.GetRightGesture());
- }
-
- if(m_puppetParser.HasFingerTracking())
- {
- m_fingerTracking = true;
-
- CVRInputManager.Instance.individualFingerTracking = true;
- IKSystem.Instance.FingerSystem.controlActive = true;
-
- ref readonly float[] l_curls = ref m_puppetParser.GetFingerCurls();
- ref readonly float[] l_spreads = ref m_puppetParser.GetFingerSpreads();
-
- CVRInputManager.Instance.fingerCurlLeftThumb = l_curls[l_mirror ? 5 : 0];
- CVRInputManager.Instance.fingerCurlLeftIndex = l_curls[l_mirror ? 6 : 1];
- CVRInputManager.Instance.fingerCurlLeftMiddle = l_curls[l_mirror ? 7 : 2];
- CVRInputManager.Instance.fingerCurlLeftRing = l_curls[l_mirror ? 8 : 3];
- CVRInputManager.Instance.fingerCurlLeftPinky = l_curls[l_mirror ? 9 : 4];
- CVRInputManager.Instance.fingerCurlRightThumb = l_curls[l_mirror ? 0 : 5];
- CVRInputManager.Instance.fingerCurlRightIndex = l_curls[l_mirror ? 1 : 6];
- CVRInputManager.Instance.fingerCurlRightMiddle = l_curls[l_mirror ? 2 : 7];
- CVRInputManager.Instance.fingerCurlRightRing = l_curls[l_mirror ? 3 : 8];
- CVRInputManager.Instance.fingerCurlRightPinky = l_curls[l_mirror ? 4 : 9];
-
- CVRInputManager.Instance.fingerSpreadLeftThumb = l_spreads[l_mirror ? 5 : 0];
- CVRInputManager.Instance.fingerSpreadLeftIndex = l_spreads[l_mirror ? 6 : 1];
- CVRInputManager.Instance.fingerSpreadLeftMiddle = l_spreads[l_mirror ? 7 : 2];
- CVRInputManager.Instance.fingerSpreadLeftRing = l_spreads[l_mirror ? 8 : 3];
- CVRInputManager.Instance.fingerSpreadLeftPinky = l_spreads[l_mirror ? 9 : 4];
- CVRInputManager.Instance.fingerSpreadRightThumb = l_spreads[l_mirror ? 0 : 5];
- CVRInputManager.Instance.fingerSpreadRightIndex = l_spreads[l_mirror ? 1 : 6];
- CVRInputManager.Instance.fingerSpreadRightMiddle = l_spreads[l_mirror ? 2 : 7];
- CVRInputManager.Instance.fingerSpreadRightRing = l_spreads[l_mirror ? 3 : 8];
- CVRInputManager.Instance.fingerSpreadRightPinky = l_spreads[l_mirror ? 4 : 9];
- }
- else
- {
- if(m_fingerTracking)
- {
- RestoreFingerTracking();
- m_fingerTracking = false;
- }
- }
-
- Matrix4x4 l_offset = m_puppetParser.GetLastOffset();
- Vector3 l_pos = l_offset * ms_pointVector;
- Quaternion l_rot = l_offset.rotation;
-
- l_pos.y = 0f;
- if(Settings.MirrorPosition)
- l_pos.x *= -1f;
- l_pos = Vector3.ClampMagnitude(l_pos, m_distanceLimit);
-
- l_rot = Quaternion.Euler(0f, l_rot.eulerAngles.y * (Settings.MirrorRotation ? -1f : 1f), 0f);
-
- Matrix4x4 l_result = PlayerSetup.Instance.transform.GetMatrix() * Matrix4x4.TRS(l_pos, l_rot, Vector3.one);
-
- if(Settings.Position && !m_sitting && !m_puppetParser.IsSitting() && Utils.IsWorldSafe() && Utils.IsCombatSafe())
- PlayerSetup.Instance.transform.position = l_result * ms_pointVector;
-
- if(Settings.Rotation && !m_sitting && !m_puppetParser.IsSitting() && Utils.IsCombatSafe())
- {
- if(m_inVr)
- {
- Vector3 l_avatarPos = PlayerSetup.Instance._avatar.transform.position;
- PlayerSetup.Instance.transform.rotation = l_result.rotation;
- Vector3 l_dif = l_avatarPos - PlayerSetup.Instance._avatar.transform.position;
- PlayerSetup.Instance.transform.position += l_dif;
- }
- else
- PlayerSetup.Instance.transform.rotation = l_result.rotation;
- }
-
- if(Vector3.Distance(this.transform.position, m_puppetParser.transform.position) > m_distanceLimit)
- SetTarget(null);
- }
- else
- SetTarget(null);
- }
- }
-
- void LateUpdate()
- {
- if(m_active && (m_animator != null) && (m_puppetParser != null))
- {
- OverrideIK();
-
- m_puppetParser.GetPose().CopyTo(ref m_pose);
-
- if(Settings.MirrorPose)
- Utils.MirrorPose(ref m_pose);
-
- m_poseHandler.SetHumanPose(ref m_pose);
- }
- }
-
- // Patches
- internal void OnAvatarClear()
- {
- if(m_active)
- {
- RestoreIK();
- RestoreFingerTracking();
- OnActivityChange?.Invoke(false);
- }
- m_active = false;
-
- if(m_puppetParser != null)
- Object.Destroy(m_puppetParser);
- m_puppetParser = null;
-
- m_animator = null;
- m_vrIk = null;
- m_lookAtIk = null;
-
- m_poseHandler?.Dispose();
- m_poseHandler = null;
-
- m_distanceLimit = float.MaxValue;
- m_fingerTracking = false;
- m_pose = new HumanPose();
- }
- internal void OnAvatarSetup()
- {
- m_inVr = Utils.IsInVR();
- m_animator = PlayerSetup.Instance._animator;
- m_vrIk = PlayerSetup.Instance._avatar.GetComponent();
- m_lookAtIk = PlayerSetup.Instance._avatar.GetComponent();
-
- if((m_animator != null) && m_animator.isHuman)
- {
- m_poseHandler = new HumanPoseHandler(m_animator.avatar, m_animator.transform);
- m_poseHandler.GetHumanPose(ref m_pose);
-
- if(m_vrIk != null)
- {
- m_vrIk.onPreSolverUpdate.AddListener(this.OnVRIKPreUpdate);
- m_vrIk.onPostSolverUpdate.AddListener(this.OnVRIKPostUpdate);
- }
-
- if(m_lookAtIk != null)
- {
- m_lookAtIk.onPreSolverUpdate.AddListener(this.OnLookAtIKPreUpdate);
- m_lookAtIk.onPostSolverUpdate.AddListener(this.OnLookAtIKPostUpdate);
- }
- }
- else
- m_animator = null;
- }
-
- internal void OnPreAvatarReinitialize()
- {
- if(m_active)
- SetTarget(null);
- }
- internal void OnPostAvatarReinitialize()
- {
- m_inVr = Utils.IsInVR();
-
- // Old VRIK and LookAtIK are destroyed by game
- m_vrIk = PlayerSetup.Instance._avatar.GetComponent();
- m_lookAtIk = PlayerSetup.Instance._avatar.GetComponent();
-
- if(m_vrIk != null)
- {
- m_vrIk.onPreSolverUpdate.AddListener(this.OnVRIKPreUpdate);
- m_vrIk.onPostSolverUpdate.AddListener(this.OnVRIKPostUpdate);
- }
-
- if(m_lookAtIk != null)
- {
- m_lookAtIk.onPreSolverUpdate.AddListener(this.OnLookAtIKPreUpdate);
- m_lookAtIk.onPostSolverUpdate.AddListener(this.OnLookAtIKPostUpdate);
- }
- }
-
- // IK updates
- void OnVRIKPreUpdate()
- {
- if(m_active)
- {
- m_ikWeight = m_vrIk.solver.IKPositionWeight;
- m_vrIk.solver.IKPositionWeight = 0f;
- }
- }
- void OnVRIKPostUpdate()
- {
- if(m_active)
- m_vrIk.solver.IKPositionWeight = m_ikWeight;
- }
-
- void OnLookAtIKPreUpdate()
- {
- if(m_active && !Settings.LookAtMix)
- {
- m_lookIkWeight = m_lookAtIk.solver.IKPositionWeight;
- m_lookAtIk.solver.IKPositionWeight = 0f;
- }
- }
- void OnLookAtIKPostUpdate()
- {
- if(m_active && !Settings.LookAtMix)
- m_lookAtIk.solver.IKPositionWeight = m_lookIkWeight;
- }
-
- // Arbitrary
- public void SetTarget(PuppetMaster p_target)
- {
- if(m_animator != null)
- {
- if(!m_active)
- {
- if((p_target != null) && (p_target.animatorManager != null) && (p_target.animatorManager.animator != null) && p_target.animatorManager.animator.isHuman)
- {
- m_puppetParser = p_target.animatorManager.animator.gameObject.AddComponent();
- m_puppetParser.m_puppetMaster = p_target;
- m_distanceLimit = Utils.GetWorldMovementLimit();
-
- m_active = true;
- OnActivityChange?.Invoke(m_active);
- }
- }
- else
- {
- if(p_target == null)
- {
- if(m_puppetParser != null)
- Object.Destroy(m_puppetParser);
- m_puppetParser = null;
-
- if(!m_sitting)
- {
- Quaternion l_rot = PlayerSetup.Instance.transform.rotation;
- PlayerSetup.Instance.transform.rotation = Quaternion.Euler(0f, l_rot.eulerAngles.y, 0f);
- }
-
- RestoreIK();
- RestoreFingerTracking();
- m_fingerTracking = false;
-
- m_active = false;
- OnActivityChange?.Invoke(m_active);
- }
- }
- }
- }
-
- public bool IsActive() => m_active;
- public bool IsFingerTrackingActive() => m_fingerTracking;
-
- void OverrideIK()
- {
- if(!BodySystem.isCalibrating)
- BodySystem.TrackingPositionWeight = 0f;
- }
- void RestoreIK()
- {
- if(!BodySystem.isCalibrating)
- BodySystem.TrackingPositionWeight = 1f;
-
- if(m_vrIk != null)
- m_vrIk.solver.Reset();
- }
- void RestoreFingerTracking()
- {
- CVRInputManager.Instance.individualFingerTracking = (m_inVr && Utils.AreKnucklesInUse() && !CVRInputManager._moduleXR.GestureToggleValue);
- IKSystem.Instance.FingerSystem.controlActive = CVRInputManager.Instance.individualFingerTracking;
-
- if(!CVRInputManager.Instance.individualFingerTracking)
- {
- CVRInputManager.Instance.fingerCurlLeftThumb = 0f;
- CVRInputManager.Instance.fingerCurlLeftIndex = 0f;
- CVRInputManager.Instance.fingerCurlLeftMiddle = 0f;
- CVRInputManager.Instance.fingerCurlLeftRing = 0f;
- CVRInputManager.Instance.fingerCurlLeftPinky = 0f;
- CVRInputManager.Instance.fingerCurlRightThumb = 0f;
- CVRInputManager.Instance.fingerCurlRightIndex = 0f;
- CVRInputManager.Instance.fingerCurlRightMiddle = 0f;
- CVRInputManager.Instance.fingerCurlRightRing = 0f;
- CVRInputManager.Instance.fingerCurlRightPinky = 0f;
-
- CVRInputManager.Instance.fingerSpreadLeftThumb = 0.5f;
- CVRInputManager.Instance.fingerSpreadLeftIndex = 0.5f;
- CVRInputManager.Instance.fingerSpreadLeftMiddle = 0.5f;
- CVRInputManager.Instance.fingerSpreadLeftRing = 0.5f;
- CVRInputManager.Instance.fingerSpreadLeftPinky = 0.5f;
- CVRInputManager.Instance.fingerSpreadRightThumb = 0.5f;
- CVRInputManager.Instance.fingerSpreadRightIndex = 0.5f;
- CVRInputManager.Instance.fingerSpreadRightMiddle = 0.5f;
- CVRInputManager.Instance.fingerSpreadRightRing = 0.5f;
- CVRInputManager.Instance.fingerSpreadRightPinky = 0.5f;
- }
- }
- }
-}
+using ABI_RC.Core.Player;
+using ABI_RC.Systems.IK;
+using ABI_RC.Systems.IK.SubSystems;
+using ABI_RC.Systems.InputManagement;
+using ABI_RC.Systems.Movement;
+using ABI_RC.Systems.VRModeSwitch;
+using RootMotion.FinalIK;
+using UnityEngine;
+
+namespace ml_pmc
+{
+ [DisallowMultipleComponent]
+ public class PoseCopycat : MonoBehaviour
+ {
+ static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f);
+
+ static public PoseCopycat Instance { get; private set; } = null;
+ static internal System.Action OnActivityChange;
+
+ Animator m_animator = null;
+ VRIK m_vrIk = null;
+ float m_ikWeight = 1f;
+ LookAtIK m_lookAtIk = null;
+ float m_lookIkWeight = 1f;
+ bool m_sitting = false;
+ bool m_inVr = false;
+
+ bool m_active = false;
+ float m_distanceLimit = float.MaxValue;
+ bool m_fingerTracking = false;
+
+ HumanPoseHandler m_poseHandler = null;
+ HumanPose m_pose;
+ PuppetParser m_puppetParser = null;
+
+ void Start()
+ {
+ if(Instance == null)
+ Instance = this;
+ }
+ void OnDestroy()
+ {
+ if(Instance == this)
+ Instance = null;
+
+ m_poseHandler?.Dispose();
+ m_poseHandler = null;
+
+ if(m_puppetParser != null)
+ Object.Destroy(m_puppetParser);
+ m_puppetParser = null;
+
+ m_animator = null;
+ m_vrIk = null;
+ m_lookAtIk = null;
+ }
+
+ // Unity events
+ void Update()
+ {
+ m_sitting = BetterBetterCharacterController.Instance.IsSitting();
+
+ if(m_active)
+ {
+ if(m_puppetParser != null)
+ {
+ OverrideIK();
+
+ bool l_mirror = Settings.MirrorPose;
+
+ if(Settings.Gestures)
+ {
+ CVRInputManager.Instance.gestureLeft = (l_mirror ? m_puppetParser.GetRightGesture() : m_puppetParser.GetLeftGesture());
+ CVRInputManager.Instance.gestureRight = (l_mirror ? m_puppetParser.GetLeftGesture() : m_puppetParser.GetRightGesture());
+ }
+
+ if(m_puppetParser.HasFingerTracking())
+ {
+ m_fingerTracking = true;
+
+ CVRInputManager.Instance.individualFingerTracking = true;
+ IKSystem.Instance.FingerSystem.controlActive = true;
+
+ ref readonly float[] l_curls = ref m_puppetParser.GetFingerCurls();
+ ref readonly float[] l_spreads = ref m_puppetParser.GetFingerSpreads();
+
+ CVRInputManager.Instance.fingerCurlLeftThumb = l_curls[l_mirror ? 5 : 0];
+ CVRInputManager.Instance.fingerCurlLeftIndex = l_curls[l_mirror ? 6 : 1];
+ CVRInputManager.Instance.fingerCurlLeftMiddle = l_curls[l_mirror ? 7 : 2];
+ CVRInputManager.Instance.fingerCurlLeftRing = l_curls[l_mirror ? 8 : 3];
+ CVRInputManager.Instance.fingerCurlLeftPinky = l_curls[l_mirror ? 9 : 4];
+ CVRInputManager.Instance.fingerCurlRightThumb = l_curls[l_mirror ? 0 : 5];
+ CVRInputManager.Instance.fingerCurlRightIndex = l_curls[l_mirror ? 1 : 6];
+ CVRInputManager.Instance.fingerCurlRightMiddle = l_curls[l_mirror ? 2 : 7];
+ CVRInputManager.Instance.fingerCurlRightRing = l_curls[l_mirror ? 3 : 8];
+ CVRInputManager.Instance.fingerCurlRightPinky = l_curls[l_mirror ? 4 : 9];
+
+ CVRInputManager.Instance.fingerSpreadLeftThumb = l_spreads[l_mirror ? 5 : 0];
+ CVRInputManager.Instance.fingerSpreadLeftIndex = l_spreads[l_mirror ? 6 : 1];
+ CVRInputManager.Instance.fingerSpreadLeftMiddle = l_spreads[l_mirror ? 7 : 2];
+ CVRInputManager.Instance.fingerSpreadLeftRing = l_spreads[l_mirror ? 8 : 3];
+ CVRInputManager.Instance.fingerSpreadLeftPinky = l_spreads[l_mirror ? 9 : 4];
+ CVRInputManager.Instance.fingerSpreadRightThumb = l_spreads[l_mirror ? 0 : 5];
+ CVRInputManager.Instance.fingerSpreadRightIndex = l_spreads[l_mirror ? 1 : 6];
+ CVRInputManager.Instance.fingerSpreadRightMiddle = l_spreads[l_mirror ? 2 : 7];
+ CVRInputManager.Instance.fingerSpreadRightRing = l_spreads[l_mirror ? 3 : 8];
+ CVRInputManager.Instance.fingerSpreadRightPinky = l_spreads[l_mirror ? 4 : 9];
+ }
+ else
+ {
+ if(m_fingerTracking)
+ {
+ RestoreFingerTracking();
+ m_fingerTracking = false;
+ }
+ }
+
+ Matrix4x4 l_offset = m_puppetParser.GetLastOffset();
+ Vector3 l_pos = l_offset * ms_pointVector;
+ Quaternion l_rot = l_offset.rotation;
+
+ l_pos.y = 0f;
+ if(Settings.MirrorPosition)
+ l_pos.x *= -1f;
+ l_pos = Vector3.ClampMagnitude(l_pos, m_distanceLimit);
+
+ l_rot = Quaternion.Euler(0f, l_rot.eulerAngles.y * (Settings.MirrorRotation ? -1f : 1f), 0f);
+
+ Matrix4x4 l_result = PlayerSetup.Instance.transform.GetMatrix() * Matrix4x4.TRS(l_pos, l_rot, Vector3.one);
+
+ if(Settings.Position && !m_sitting && !m_puppetParser.IsSitting() && Utils.IsWorldSafe() && Utils.IsCombatSafe())
+ PlayerSetup.Instance.transform.position = l_result * ms_pointVector;
+
+ if(Settings.Rotation && !m_sitting && !m_puppetParser.IsSitting() && Utils.IsCombatSafe())
+ {
+ if(m_inVr)
+ {
+ Vector3 l_avatarPos = PlayerSetup.Instance._avatar.transform.position;
+ PlayerSetup.Instance.transform.rotation = l_result.rotation;
+ Vector3 l_dif = l_avatarPos - PlayerSetup.Instance._avatar.transform.position;
+ PlayerSetup.Instance.transform.position += l_dif;
+ }
+ else
+ PlayerSetup.Instance.transform.rotation = l_result.rotation;
+ }
+
+ if(Vector3.Distance(this.transform.position, m_puppetParser.transform.position) > m_distanceLimit)
+ SetTarget(null);
+ }
+ else
+ SetTarget(null);
+ }
+ }
+
+ void LateUpdate()
+ {
+ if(m_active && (m_animator != null) && (m_puppetParser != null))
+ {
+ OverrideIK();
+
+ m_puppetParser.GetPose().CopyTo(ref m_pose);
+
+ if(Settings.MirrorPose)
+ Utils.MirrorPose(ref m_pose);
+
+ m_poseHandler.SetHumanPose(ref m_pose);
+ }
+ }
+
+ // Patches
+ internal void OnAvatarClear()
+ {
+ if(m_active)
+ {
+ RestoreIK();
+ RestoreFingerTracking();
+ OnActivityChange?.Invoke(false);
+ }
+ m_active = false;
+
+ if(m_puppetParser != null)
+ Object.Destroy(m_puppetParser);
+ m_puppetParser = null;
+
+ m_animator = null;
+ m_vrIk = null;
+ m_lookAtIk = null;
+
+ m_poseHandler?.Dispose();
+ m_poseHandler = null;
+
+ m_distanceLimit = float.MaxValue;
+ m_fingerTracking = false;
+ m_pose = new HumanPose();
+ }
+ internal void OnAvatarSetup()
+ {
+ m_inVr = Utils.IsInVR();
+ m_animator = PlayerSetup.Instance._animator;
+ m_vrIk = PlayerSetup.Instance._avatar.GetComponent();
+ m_lookAtIk = PlayerSetup.Instance._avatar.GetComponent();
+
+ if((m_animator != null) && m_animator.isHuman)
+ {
+ m_poseHandler = new HumanPoseHandler(m_animator.avatar, m_animator.transform);
+ m_poseHandler.GetHumanPose(ref m_pose);
+
+ if(m_vrIk != null)
+ {
+ m_vrIk.onPreSolverUpdate.AddListener(this.OnVRIKPreUpdate);
+ m_vrIk.onPostSolverUpdate.AddListener(this.OnVRIKPostUpdate);
+ }
+
+ if(m_lookAtIk != null)
+ {
+ m_lookAtIk.onPreSolverUpdate.AddListener(this.OnLookAtIKPreUpdate);
+ m_lookAtIk.onPostSolverUpdate.AddListener(this.OnLookAtIKPostUpdate);
+ }
+ }
+ else
+ m_animator = null;
+ }
+
+ internal void OnPreAvatarReinitialize()
+ {
+ if(m_active)
+ SetTarget(null);
+ }
+ internal void OnPostAvatarReinitialize()
+ {
+ m_inVr = Utils.IsInVR();
+
+ // Old VRIK and LookAtIK are destroyed by game
+ m_vrIk = PlayerSetup.Instance._avatar.GetComponent();
+ m_lookAtIk = PlayerSetup.Instance._avatar.GetComponent();
+
+ if(m_vrIk != null)
+ {
+ m_vrIk.onPreSolverUpdate.AddListener(this.OnVRIKPreUpdate);
+ m_vrIk.onPostSolverUpdate.AddListener(this.OnVRIKPostUpdate);
+ }
+
+ if(m_lookAtIk != null)
+ {
+ m_lookAtIk.onPreSolverUpdate.AddListener(this.OnLookAtIKPreUpdate);
+ m_lookAtIk.onPostSolverUpdate.AddListener(this.OnLookAtIKPostUpdate);
+ }
+ }
+
+ // IK updates
+ void OnVRIKPreUpdate()
+ {
+ if(m_active)
+ {
+ m_ikWeight = m_vrIk.solver.IKPositionWeight;
+ m_vrIk.solver.IKPositionWeight = 0f;
+ }
+ }
+ void OnVRIKPostUpdate()
+ {
+ if(m_active)
+ m_vrIk.solver.IKPositionWeight = m_ikWeight;
+ }
+
+ void OnLookAtIKPreUpdate()
+ {
+ if(m_active && !Settings.LookAtMix)
+ {
+ m_lookIkWeight = m_lookAtIk.solver.IKPositionWeight;
+ m_lookAtIk.solver.IKPositionWeight = 0f;
+ }
+ }
+ void OnLookAtIKPostUpdate()
+ {
+ if(m_active && !Settings.LookAtMix)
+ m_lookAtIk.solver.IKPositionWeight = m_lookIkWeight;
+ }
+
+ // Arbitrary
+ public void SetTarget(PuppetMaster p_target)
+ {
+ if(m_animator != null)
+ {
+ if(!m_active)
+ {
+ if((p_target != null) && (p_target.animatorManager != null) && (p_target.animatorManager.animator != null) && p_target.animatorManager.animator.isHuman)
+ {
+ m_puppetParser = p_target.animatorManager.animator.gameObject.AddComponent();
+ m_puppetParser.m_puppetMaster = p_target;
+ m_distanceLimit = Utils.GetWorldMovementLimit();
+
+ m_active = true;
+ OnActivityChange?.Invoke(m_active);
+ }
+ }
+ else
+ {
+ if(p_target == null)
+ {
+ if(m_puppetParser != null)
+ Object.Destroy(m_puppetParser);
+ m_puppetParser = null;
+
+ if(!m_sitting)
+ {
+ Quaternion l_rot = PlayerSetup.Instance.transform.rotation;
+ PlayerSetup.Instance.transform.rotation = Quaternion.Euler(0f, l_rot.eulerAngles.y, 0f);
+ }
+
+ RestoreIK();
+ RestoreFingerTracking();
+ m_fingerTracking = false;
+
+ m_active = false;
+ OnActivityChange?.Invoke(m_active);
+ }
+ }
+ }
+ }
+
+ public bool IsActive() => m_active;
+ public bool IsFingerTrackingActive() => m_fingerTracking;
+
+ void OverrideIK()
+ {
+ if(!BodySystem.isCalibrating)
+ BodySystem.TrackingPositionWeight = 0f;
+ }
+ void RestoreIK()
+ {
+ if(!BodySystem.isCalibrating)
+ BodySystem.TrackingPositionWeight = 1f;
+
+ if(m_vrIk != null)
+ m_vrIk.solver.Reset();
+ }
+ void RestoreFingerTracking()
+ {
+ CVRInputManager.Instance.individualFingerTracking = (m_inVr && Utils.AreKnucklesInUse() && !CVRInputManager._moduleXR.GestureToggleValue);
+ IKSystem.Instance.FingerSystem.controlActive = CVRInputManager.Instance.individualFingerTracking;
+
+ if(!CVRInputManager.Instance.individualFingerTracking)
+ {
+ CVRInputManager.Instance.fingerCurlLeftThumb = 0f;
+ CVRInputManager.Instance.fingerCurlLeftIndex = 0f;
+ CVRInputManager.Instance.fingerCurlLeftMiddle = 0f;
+ CVRInputManager.Instance.fingerCurlLeftRing = 0f;
+ CVRInputManager.Instance.fingerCurlLeftPinky = 0f;
+ CVRInputManager.Instance.fingerCurlRightThumb = 0f;
+ CVRInputManager.Instance.fingerCurlRightIndex = 0f;
+ CVRInputManager.Instance.fingerCurlRightMiddle = 0f;
+ CVRInputManager.Instance.fingerCurlRightRing = 0f;
+ CVRInputManager.Instance.fingerCurlRightPinky = 0f;
+
+ CVRInputManager.Instance.fingerSpreadLeftThumb = 0.5f;
+ CVRInputManager.Instance.fingerSpreadLeftIndex = 0.5f;
+ CVRInputManager.Instance.fingerSpreadLeftMiddle = 0.5f;
+ CVRInputManager.Instance.fingerSpreadLeftRing = 0.5f;
+ CVRInputManager.Instance.fingerSpreadLeftPinky = 0.5f;
+ CVRInputManager.Instance.fingerSpreadRightThumb = 0.5f;
+ CVRInputManager.Instance.fingerSpreadRightIndex = 0.5f;
+ CVRInputManager.Instance.fingerSpreadRightMiddle = 0.5f;
+ CVRInputManager.Instance.fingerSpreadRightRing = 0.5f;
+ CVRInputManager.Instance.fingerSpreadRightPinky = 0.5f;
+ }
+ }
+ }
+}
diff --git a/ml_pmc/ml_pmc.csproj b/ml_pmc/ml_pmc.csproj
index fb7fa59..75e32d0 100644
--- a/ml_pmc/ml_pmc.csproj
+++ b/ml_pmc/ml_pmc.csproj
@@ -45,15 +45,10 @@
false
false
-
- D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\EasyCharacterMovement.CharacterMovement.dll
- false
+
+ D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\ECM2.dll
false
-
-
- D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\EasyCharacterMovement.Characters.dll
false
- false
D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\MelonLoader.dll
diff --git a/ml_prm/GravityInfluencer.cs b/ml_prm/GravityInfluencer.cs
index 3645439..183fb70 100644
--- a/ml_prm/GravityInfluencer.cs
+++ b/ml_prm/GravityInfluencer.cs
@@ -1,29 +1,30 @@
-using ABI.CCK.Components;
-using ABI_RC.Systems.Movement;
-using UnityEngine;
-
-namespace ml_prm
-{
- [DisallowMultipleComponent]
- class GravityInfluencer : MonoBehaviour
- {
- Rigidbody m_rigidBody = null;
- PhysicsInfluencer m_physicsInfluencer = null;
- bool m_activeGravity = true;
-
- void Start()
- {
- m_rigidBody = this.GetComponent();
- m_physicsInfluencer = this.GetComponent();
- }
-
- void FixedUpdate()
- {
- m_rigidBody.useGravity = false;
- if(m_activeGravity && ((m_physicsInfluencer == null) || !m_physicsInfluencer.enableInfluence || !m_physicsInfluencer.GetSubmerged()))
- m_rigidBody.AddForce(BetterBetterCharacterController.Instance.GravityResult.AppliedGravity * m_rigidBody.mass);
- }
-
- public void SetActiveGravity(bool p_state) => m_activeGravity = p_state;
- }
-}
+using ABI.CCK.Components;
+using ABI_RC.Systems.Gravity;
+using ABI_RC.Systems.Movement;
+using UnityEngine;
+
+namespace ml_prm
+{
+ [DisallowMultipleComponent]
+ class GravityInfluencer : MonoBehaviour
+ {
+ Rigidbody m_rigidBody = null;
+ PhysicsInfluencer m_physicsInfluencer = null;
+ bool m_activeGravity = true;
+
+ void Start()
+ {
+ m_rigidBody = this.GetComponent();
+ m_physicsInfluencer = this.GetComponent();
+ }
+
+ void FixedUpdate()
+ {
+ m_rigidBody.useGravity = false;
+ if(m_activeGravity && ((m_physicsInfluencer == null) || !m_physicsInfluencer.enableInfluence || !m_physicsInfluencer.GetSubmerged()))
+ m_rigidBody.AddForce(BetterBetterCharacterController.Instance.GravityResult.AppliedGravity * m_rigidBody.mass);
+ }
+
+ public void SetActiveGravity(bool p_state) => m_activeGravity = p_state;
+ }
+}
diff --git a/ml_prm/RagdollController.cs b/ml_prm/RagdollController.cs
index c614a51..c1b3e9b 100644
--- a/ml_prm/RagdollController.cs
+++ b/ml_prm/RagdollController.cs
@@ -381,6 +381,7 @@ namespace ml_prm
l_physicsInfluencer.fluidAngularDrag = 1f;
l_physicsInfluencer.enableBuoyancy = true;
l_physicsInfluencer.enableInfluence = false;
+ l_physicsInfluencer.forceAlignUpright = false;
float mass = l_body.mass;
l_physicsInfluencer.UpdateDensity();
l_body.mass = mass;
@@ -715,7 +716,7 @@ namespace ml_prm
// Restore movement if was ragdolled in water and left it
if(m_wasSwimming)
- BetterBetterCharacterController.Instance.SetMovementMode(EasyCharacterMovement.MovementMode.Swimming);
+ BetterBetterCharacterController.Instance.SetMovementMode(ECM2.Character.MovementMode.Swimming);
m_enabled = false;
}
diff --git a/ml_prm/ml_prm.csproj b/ml_prm/ml_prm.csproj
index 877c39d..e84b7ac 100644
--- a/ml_prm/ml_prm.csproj
+++ b/ml_prm/ml_prm.csproj
@@ -41,15 +41,10 @@
false
false
-
- D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\EasyCharacterMovement.CharacterMovement.dll
- false
- false
-
-
- D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\EasyCharacterMovement.Characters.dll
- false
- false
+
+ D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\ECM2.dll
+ false
+ false
D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\MelonLoader.dll