Compare commits

..

12 commits
master ... r180

Author SHA1 Message Date
SDraw
b21d5497d9
Mask for controller rays 2025-08-02 17:18:36 +03:00
SDraw
6b0399f182
Fix for latest nightly build (27.07.2025) 2025-07-27 22:30:33 +03:00
SDraw
713d89565b
Le stupid fix 2025-07-13 17:04:11 +03:00
SDraw
9f78aa4620
New mod: PlayerAvatarHistory
Incremented version for nightly to prevent rollback by auto-updater
Minor fixes
2025-07-03 16:15:47 +03:00
SDraw
7f29079109
Fix of collision layers 2025-06-29 15:42:29 +03:00
SDraw
aef5af99af
Improved usage of PhysicsInfluencer, pointer-based grabbing 2025-06-26 18:59:35 +03:00
SDraw
aa5856b102
Fixes for 25/06/2025 nightly game build 2025-06-25 18:56:45 +03:00
SDraw
5261203833
Additional nightly fixes 2025-06-25 01:13:40 +03:00
SDraw
40b683d33c
Fixes for 24/06/2025 nightly build 2025-06-24 21:45:18 +03:00
SDraw
0902edd560
Separate stable and nightly game builds functionality 2025-06-05 14:28:20 +03:00
SDraw
080c0a5876
Avatar as parameter of any animator type 2025-05-31 23:36:46 +03:00
SDraw
adf7796f9e
Fix for new ControllerRay class 2025-05-31 13:03:22 +03:00
64 changed files with 1513 additions and 1255 deletions

View file

@ -15,8 +15,6 @@ namespace ml_amt
public void Invoke() => m_action?.Invoke(); public void Invoke() => m_action?.Invoke();
} }
public static readonly GameEvent OnAvatarSetup = new GameEvent();
public static readonly GameEvent OnAvatarClear = new GameEvent();
public static readonly GameEvent OnAvatarReuse = new GameEvent(); public static readonly GameEvent OnAvatarReuse = new GameEvent();
public static readonly GameEvent OnPlayspaceScale = new GameEvent(); public static readonly GameEvent OnPlayspaceScale = new GameEvent();
@ -24,18 +22,6 @@ namespace ml_amt
{ {
try try
{ {
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar), BindingFlags.Instance | BindingFlags.Public),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar), BindingFlags.Instance | BindingFlags.Public),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch( p_instance.Patch(
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public), typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
null, null,
@ -54,30 +40,6 @@ namespace ml_amt
} }
} }
static void OnAvatarClear_Postfix()
{
try
{
OnAvatarClear.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnSetupAvatar_Postfix()
{
try
{
OnAvatarSetup.Invoke();
}
catch(Exception l_exception)
{
MelonLoader.MelonLogger.Error(l_exception);
}
}
static void OnAvatarReinitialize_Postfix() static void OnAvatarReinitialize_Postfix()
{ {
try try

View file

@ -1,5 +1,7 @@
using ABI_RC.Core.Player; using ABI.CCK.Components;
using ABI_RC.Core.Player;
using ABI_RC.Core.Util.AnimatorManager; using ABI_RC.Core.Util.AnimatorManager;
using ABI_RC.Systems.GameEventSystem;
using ABI_RC.Systems.IK.SubSystems; using ABI_RC.Systems.IK.SubSystems;
using ABI_RC.Systems.Movement; using ABI_RC.Systems.Movement;
using RootMotion.FinalIK; using RootMotion.FinalIK;
@ -59,8 +61,8 @@ namespace ml_amt
Settings.OnProneLimitChanged.AddListener(this.OnProneLimitChanged); Settings.OnProneLimitChanged.AddListener(this.OnProneLimitChanged);
Settings.OnMassCenterChanged.AddListener(this.OnMassCenterChanged); Settings.OnMassCenterChanged.AddListener(this.OnMassCenterChanged);
GameEvents.OnAvatarSetup.AddListener(this.OnAvatarSetup); CVRGameEventSystem.Avatar.OnLocalAvatarLoad.AddListener(this.OnAvatarSetup);
GameEvents.OnAvatarClear.AddListener(this.OnAvatarClear); CVRGameEventSystem.Avatar.OnLocalAvatarClear.AddListener(this.OnAvatarClear);
GameEvents.OnAvatarReuse.AddListener(this.OnAvatarReuse); GameEvents.OnAvatarReuse.AddListener(this.OnAvatarReuse);
GameEvents.OnPlayspaceScale.AddListener(this.OnPlayspaceScale); GameEvents.OnPlayspaceScale.AddListener(this.OnPlayspaceScale);
} }
@ -78,8 +80,8 @@ namespace ml_amt
Settings.OnProneLimitChanged.RemoveListener(this.OnProneLimitChanged); Settings.OnProneLimitChanged.RemoveListener(this.OnProneLimitChanged);
Settings.OnMassCenterChanged.RemoveListener(this.OnMassCenterChanged); Settings.OnMassCenterChanged.RemoveListener(this.OnMassCenterChanged);
GameEvents.OnAvatarSetup.RemoveListener(this.OnAvatarSetup); CVRGameEventSystem.Avatar.OnLocalAvatarLoad.RemoveListener(this.OnAvatarSetup);
GameEvents.OnAvatarClear.RemoveListener(this.OnAvatarClear); CVRGameEventSystem.Avatar.OnLocalAvatarClear.RemoveListener(this.OnAvatarClear);
GameEvents.OnAvatarReuse.RemoveListener(this.OnAvatarReuse); GameEvents.OnAvatarReuse.RemoveListener(this.OnAvatarReuse);
GameEvents.OnPlayspaceScale.RemoveListener(this.OnPlayspaceScale); GameEvents.OnPlayspaceScale.RemoveListener(this.OnPlayspaceScale);
} }
@ -96,7 +98,9 @@ namespace ml_amt
} }
// Game events // Game events
void OnAvatarClear() void OnAvatarClear(CVRAvatar p_avatar)
{
try
{ {
m_vrIk = null; m_vrIk = null;
m_avatarReady = false; m_avatarReady = false;
@ -109,22 +113,29 @@ namespace ml_amt
BetterBetterCharacterController.Instance.avatarCrouchLimit = Mathf.Clamp01(Settings.CrouchLimit); BetterBetterCharacterController.Instance.avatarCrouchLimit = Mathf.Clamp01(Settings.CrouchLimit);
BetterBetterCharacterController.Instance.avatarProneLimit = Mathf.Clamp01(Settings.ProneLimit); BetterBetterCharacterController.Instance.avatarProneLimit = Mathf.Clamp01(Settings.ProneLimit);
} }
catch(System.Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
void OnAvatarSetup() void OnAvatarSetup(CVRAvatar p_avatar)
{
try
{ {
Utils.SetAvatarTPose(); Utils.SetAvatarTPose();
m_vrIk = PlayerSetup.Instance._avatar.GetComponent<VRIK>(); m_vrIk = PlayerSetup.Instance.AvatarObject.GetComponent<VRIK>();
m_avatarScale = Mathf.Abs(PlayerSetup.Instance._avatar.transform.localScale.y); m_avatarScale = Mathf.Abs(PlayerSetup.Instance.AvatarTransform.localScale.y);
// Parse animator parameters // Parse animator parameters
m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.Moving, PlayerSetup.Instance.animatorManager)); m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.Moving, PlayerSetup.Instance.AnimatorManager));
m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.MovementSpeed, PlayerSetup.Instance.animatorManager)); m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.MovementSpeed, PlayerSetup.Instance.AnimatorManager));
m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.Velocity, PlayerSetup.Instance.animatorManager)); m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.Velocity, PlayerSetup.Instance.AnimatorManager));
m_parameters.RemoveAll(p => !p.IsValid()); m_parameters.RemoveAll(p => !p.IsValid());
// Avatar custom IK limits // Avatar custom IK limits
m_ikLimits = PlayerSetup.Instance._avatar.transform.Find("[IKLimits]"); m_ikLimits = PlayerSetup.Instance.AvatarTransform.Find("[IKLimits]");
UpdateIKLimits(); UpdateIKLimits();
// Apply VRIK tweaks // Apply VRIK tweaks
@ -135,18 +146,18 @@ namespace ml_amt
if(m_vrIk.solver.HasToes()) if(m_vrIk.solver.HasToes())
{ {
Transform l_foot = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftFoot); Transform l_foot = PlayerSetup.Instance.Animator.GetBoneTransform(HumanBodyBones.LeftFoot);
if(l_foot == null) if(l_foot == null)
l_foot = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightFoot); l_foot = PlayerSetup.Instance.Animator.GetBoneTransform(HumanBodyBones.RightFoot);
Transform l_toe = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftToes); Transform l_toe = PlayerSetup.Instance.Animator.GetBoneTransform(HumanBodyBones.LeftToes);
if(l_toe == null) if(l_toe == null)
l_toe = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightToes); l_toe = PlayerSetup.Instance.Animator.GetBoneTransform(HumanBodyBones.RightToes);
if((l_foot != null) && (l_toe != null)) if((l_foot != null) && (l_toe != null))
{ {
Vector3 l_footPos = (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_foot.GetMatrix()).GetPosition(); Vector3 l_footPos = (PlayerSetup.Instance.AvatarTransform.GetMatrix().inverse * l_foot.GetMatrix()).GetPosition();
Vector3 l_toePos = (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_toe.GetMatrix()).GetPosition(); Vector3 l_toePos = (PlayerSetup.Instance.AvatarTransform.GetMatrix().inverse * l_toe.GetMatrix()).GetPosition();
m_massCenter = new Vector3(0f, 0f, l_toePos.z - l_footPos.z); m_massCenter = new Vector3(0f, 0f, l_toePos.z - l_footPos.z);
} }
} }
@ -159,6 +170,11 @@ namespace ml_amt
m_avatarReady = true; m_avatarReady = true;
} }
catch(System.Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
void OnPlayspaceScale() void OnPlayspaceScale()
{ {
@ -171,7 +187,7 @@ namespace ml_amt
// Old VRIK is destroyed by game // Old VRIK is destroyed by game
Utils.SetAvatarTPose(); Utils.SetAvatarTPose();
m_vrIk = PlayerSetup.Instance._animator.GetComponent<VRIK>(); m_vrIk = PlayerSetup.Instance.AvatarObject.GetComponent<VRIK>();
if(m_vrIk != null) if(m_vrIk != null)
{ {
m_vrIk.solver.locomotion.offset = (Settings.MassCenter ? m_massCenter : m_locomotionOffset); m_vrIk.solver.locomotion.offset = (Settings.MassCenter ? m_massCenter : m_locomotionOffset);
@ -241,7 +257,7 @@ namespace ml_amt
// Arbitrary // Arbitrary
float GetRelativeScale() float GetRelativeScale()
{ {
return ((m_avatarScale > 0f) ? (PlayerSetup.Instance._avatar.transform.localScale.y / m_avatarScale) : 0f); return ((m_avatarScale > 0f) ? (PlayerSetup.Instance.AvatarTransform.localScale.y / m_avatarScale) : 0f);
} }
void UpdateIKLimits() void UpdateIKLimits()
@ -258,7 +274,7 @@ namespace ml_amt
public bool IsMoving() => BetterBetterCharacterController.Instance.IsMoving(); public bool IsMoving() => BetterBetterCharacterController.Instance.IsMoving();
public float GetMovementSpeed() public float GetMovementSpeed()
{ {
AvatarAnimatorManager l_animatorManager = PlayerSetup.Instance.animatorManager; AvatarAnimatorManager l_animatorManager = PlayerSetup.Instance.AnimatorManager;
return Mathf.Sqrt(l_animatorManager.MovementX * l_animatorManager.MovementX + l_animatorManager.MovementY * l_animatorManager.MovementY); return Mathf.Sqrt(l_animatorManager.MovementX * l_animatorManager.MovementX + l_animatorManager.MovementY * l_animatorManager.MovementY);
} }
public float GetVelocity() => BetterBetterCharacterController.Instance.velocity.magnitude; public float GetVelocity() => BetterBetterCharacterController.Instance.velocity.magnitude;

View file

@ -65,31 +65,31 @@ namespace ml_amt
{ {
while(ViewManager.Instance == null) while(ViewManager.Instance == null)
yield return null; yield return null;
while(ViewManager.Instance.gameMenuView == null) while(ViewManager.Instance.cohtmlView == null)
yield return null; yield return null;
while(ViewManager.Instance.gameMenuView.Listener == null) while(ViewManager.Instance.cohtmlView.Listener == null)
yield return null; yield return null;
ViewManager.Instance.gameMenuView.Listener.ReadyForBindings += () => ViewManager.Instance.cohtmlView.Listener.ReadyForBindings += () =>
{ {
ViewManager.Instance.gameMenuView.View.BindCall("OnSliderUpdate_" + ms_category.Identifier, new Action<string, string>(OnSliderUpdate)); ViewManager.Instance.cohtmlView.View.BindCall("OnSliderUpdate_" + ms_category.Identifier, new Action<string, string>(OnSliderUpdate));
ViewManager.Instance.gameMenuView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate)); ViewManager.Instance.cohtmlView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate));
}; };
ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) => ViewManager.Instance.cohtmlView.Listener.FinishLoad += (_) =>
{ {
ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mods_extension.js")); ViewManager.Instance.cohtmlView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mods_extension.js"));
ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mod_menu.js")); ViewManager.Instance.cohtmlView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mod_menu.js"));
MelonLoader.MelonCoroutines.Start(UpdateMenuSettings()); MelonLoader.MelonCoroutines.Start(UpdateMenuSettings());
}; };
} }
static System.Collections.IEnumerator UpdateMenuSettings() static System.Collections.IEnumerator UpdateMenuSettings()
{ {
while(!ViewManager.Instance.IsReady || !ViewManager.Instance.IsMainMenuOpen) while(!ViewManager.Instance.IsReady || !ViewManager.Instance.IsViewShown)
yield return null; yield return null;
foreach(var l_entry in ms_entries) foreach(var l_entry in ms_entries)
ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString()); ViewManager.Instance.cohtmlView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString());
} }
static void OnSliderUpdate(string p_name, string p_value) static void OnSliderUpdate(string p_name, string p_value)

View file

@ -22,11 +22,11 @@ namespace ml_amt
public static void SetAvatarTPose() public static void SetAvatarTPose()
{ {
if(PlayerSetup.Instance._animator.isHuman) if(PlayerSetup.Instance.Animator.isHuman)
{ {
IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose); IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose);
PlayerSetup.Instance._avatar.transform.localPosition = Vector3.zero; PlayerSetup.Instance.AvatarTransform.localPosition = Vector3.zero;
PlayerSetup.Instance._avatar.transform.localRotation = Quaternion.identity; PlayerSetup.Instance.AvatarTransform.localRotation = Quaternion.identity;
} }
} }

View file

@ -44,30 +44,30 @@ namespace ml_asl
{ {
while(ViewManager.Instance == null) while(ViewManager.Instance == null)
yield return null; yield return null;
while(ViewManager.Instance.gameMenuView == null) while(ViewManager.Instance.cohtmlView == null)
yield return null; yield return null;
while(ViewManager.Instance.gameMenuView.Listener == null) while(ViewManager.Instance.cohtmlView.Listener == null)
yield return null; yield return null;
ViewManager.Instance.gameMenuView.Listener.ReadyForBindings += () => ViewManager.Instance.cohtmlView.Listener.ReadyForBindings += () =>
{ {
ViewManager.Instance.gameMenuView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate)); ViewManager.Instance.cohtmlView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate));
}; };
ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) => ViewManager.Instance.cohtmlView.Listener.FinishLoad += (_) =>
{ {
ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mods_extension.js")); ViewManager.Instance.cohtmlView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mods_extension.js"));
ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mod_menu.js")); ViewManager.Instance.cohtmlView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mod_menu.js"));
MelonLoader.MelonCoroutines.Start(UpdateMenuSettings()); MelonLoader.MelonCoroutines.Start(UpdateMenuSettings());
}; };
} }
static System.Collections.IEnumerator UpdateMenuSettings() static System.Collections.IEnumerator UpdateMenuSettings()
{ {
while(!ViewManager.Instance.IsReady || !ViewManager.Instance.IsMainMenuOpen) while(!ViewManager.Instance.IsReady || !ViewManager.Instance.IsViewShown)
yield return null; yield return null;
foreach(var l_entry in ms_entries) foreach(var l_entry in ms_entries)
ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString()); ViewManager.Instance.cohtmlView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString());
} }
static void OnToggleUpdate(string p_name, string p_value) static void OnToggleUpdate(string p_name, string p_value)

View file

@ -1,5 +1,7 @@
using ABI_RC.Core.Player; using ABI.CCK.Components;
using ABI_RC.Core.Player;
using ABI_RC.Core.Savior; using ABI_RC.Core.Savior;
using ABI_RC.Systems.GameEventSystem;
using ABI_RC.Systems.IK; using ABI_RC.Systems.IK;
using ABI_RC.Systems.InputManagement; using ABI_RC.Systems.InputManagement;
using System.Collections.Generic; using System.Collections.Generic;
@ -92,8 +94,8 @@ namespace ml_bft
m_pose = new HumanPose(); m_pose = new HumanPose();
m_lastValues = new float[40]; m_lastValues = new float[40];
GameEvents.OnAvatarSetup.AddListener(this.OnAvatarSetup); CVRGameEventSystem.Avatar.OnLocalAvatarLoad.AddListener(this.OnAvatarSetup);
GameEvents.OnAvatarClear.AddListener(this.OnAvatarClear); CVRGameEventSystem.Avatar.OnLocalAvatarClear.AddListener(this.OnAvatarClear);
GameEvents.OnAvatarReuse.AddListener(this.OnAvatarReuse); GameEvents.OnAvatarReuse.AddListener(this.OnAvatarReuse);
GameEvents.OnIKSystemLateUpdate.AddListener(this.OnIKSystemLateUpdate); GameEvents.OnIKSystemLateUpdate.AddListener(this.OnIKSystemLateUpdate);
} }
@ -106,20 +108,24 @@ namespace ml_bft
m_rightFingerOffsets.Clear(); m_rightFingerOffsets.Clear();
m_ready = false; m_ready = false;
GameEvents.OnAvatarSetup.RemoveListener(this.OnAvatarSetup); CVRGameEventSystem.Avatar.OnLocalAvatarLoad.RemoveListener(this.OnAvatarSetup);
GameEvents.OnAvatarClear.RemoveListener(this.OnAvatarClear); CVRGameEventSystem.Avatar.OnLocalAvatarClear.RemoveListener(this.OnAvatarClear);
GameEvents.OnAvatarReuse.RemoveListener(this.OnAvatarReuse); GameEvents.OnAvatarReuse.RemoveListener(this.OnAvatarReuse);
GameEvents.OnIKSystemLateUpdate.RemoveListener(this.OnIKSystemLateUpdate); GameEvents.OnIKSystemLateUpdate.RemoveListener(this.OnIKSystemLateUpdate);
} }
internal void OnAvatarSetup() internal void OnAvatarSetup(CVRAvatar p_avatar)
{ {
Animator l_animator = PlayerSetup.Instance._animator; try
{
Animator l_animator = PlayerSetup.Instance.Animator;
if(l_animator.isHuman) if(l_animator.isHuman)
{ {
Utils.SetAvatarTPose(); IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose);
InputHandler.Instance.Rebind(PlayerSetup.Instance.transform.rotation); PlayerSetup.Instance.AvatarTransform.localPosition = Vector3.zero;
PlayerSetup.Instance.AvatarTransform.localRotation = Quaternion.identity;
InputHandler.Instance.Rebind(PlayerSetup.Instance.transform.rotation);
foreach(var l_tuple in ms_fingersChains) foreach(var l_tuple in ms_fingersChains)
{ {
ReorientateTowards( ReorientateTowards(
@ -182,8 +188,15 @@ namespace ml_bft
m_ready = ((m_leftFingerOffsets.Count > 0) || (m_rightFingerOffsets.Count > 0)); m_ready = ((m_leftFingerOffsets.Count > 0) || (m_rightFingerOffsets.Count > 0));
} }
} }
catch(System.Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
internal void OnAvatarClear() internal void OnAvatarClear(CVRAvatar p_avatar)
{
try
{ {
m_ready = false; m_ready = false;
m_pose = new HumanPose(); m_pose = new HumanPose();
@ -194,25 +207,30 @@ namespace ml_bft
m_leftFingerOffsets.Clear(); m_leftFingerOffsets.Clear();
m_rightFingerOffsets.Clear(); m_rightFingerOffsets.Clear();
} }
catch(System.Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
internal void OnAvatarReuse() internal void OnAvatarReuse()
{ {
OnAvatarClear(); OnAvatarClear(PlayerSetup.Instance.AvatarDescriptor);
OnAvatarSetup(); OnAvatarSetup(PlayerSetup.Instance.AvatarDescriptor);
} }
internal void OnIKSystemLateUpdate(HumanPoseHandler p_handler, Transform p_hips) internal void OnIKSystemLateUpdate(HumanPoseHandler p_handler, Transform p_hips)
{ {
if(m_ready && MetaPort.Instance.isUsingVr && (p_handler != null) && Settings.SkeletalInput) if(m_ready && MetaPort.Instance.isUsingVr && (p_handler != null) && Settings.SkeletalInput)
{ {
if(CVRInputManager.Instance._leftController != ABI_RC.Systems.InputManagement.XR.eXRControllerType.None) if(CVRInputManager.Instance.IsLeftControllerTracking())
{ {
Quaternion l_turnBack = (m_leftHandOffset.m_source.rotation * m_leftHandOffset.m_offset) * Quaternion.Inverse(m_leftHandOffset.m_target.rotation); Quaternion l_turnBack = (m_leftHandOffset.m_source.rotation * m_leftHandOffset.m_offset) * Quaternion.Inverse(m_leftHandOffset.m_target.rotation);
foreach(var l_offset in m_leftFingerOffsets) foreach(var l_offset in m_leftFingerOffsets)
l_offset.m_target.rotation = l_turnBack * (l_offset.m_source.rotation * l_offset.m_offset); l_offset.m_target.rotation = l_turnBack * (l_offset.m_source.rotation * l_offset.m_offset);
} }
if(CVRInputManager.Instance._rightController != ABI_RC.Systems.InputManagement.XR.eXRControllerType.None) if(CVRInputManager.Instance.IsRightControllerTracking())
{ {
Quaternion l_turnBack = (m_rightHandOffset.m_source.rotation * m_rightHandOffset.m_offset) * Quaternion.Inverse(m_rightHandOffset.m_target.rotation); Quaternion l_turnBack = (m_rightHandOffset.m_source.rotation * m_rightHandOffset.m_offset) * Quaternion.Inverse(m_rightHandOffset.m_target.rotation);
foreach(var l_offset in m_rightFingerOffsets) foreach(var l_offset in m_rightFingerOffsets)

View file

@ -24,8 +24,6 @@ namespace ml_bft
public void Invoke(T1 p_objA, T2 p_objB) => m_action?.Invoke(p_objA, p_objB); public void Invoke(T1 p_objA, T2 p_objB) => m_action?.Invoke(p_objA, p_objB);
} }
public static readonly GameEvent OnAvatarSetup = new GameEvent();
public static readonly GameEvent OnAvatarClear = new GameEvent();
public static readonly GameEvent OnAvatarReuse = new GameEvent(); public static readonly GameEvent OnAvatarReuse = new GameEvent();
public static readonly GameEvent OnInputUpdate = new GameEvent(); public static readonly GameEvent OnInputUpdate = new GameEvent();
public static readonly GameEvent<HumanPoseHandler, Transform> OnIKSystemLateUpdate = new GameEvent<HumanPoseHandler, Transform>(); public static readonly GameEvent<HumanPoseHandler, Transform> OnIKSystemLateUpdate = new GameEvent<HumanPoseHandler, Transform>();
@ -34,18 +32,6 @@ namespace ml_bft
{ {
try try
{ {
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar), BindingFlags.Instance | BindingFlags.Public),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar), BindingFlags.Instance | BindingFlags.Public),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch( p_instance.Patch(
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public), typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
null, null,
@ -70,30 +56,6 @@ namespace ml_bft
} }
} }
static void OnAvatarClear_Postfix()
{
try
{
OnAvatarClear.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnSetupAvatar_Postfix()
{
try
{
OnAvatarSetup.Invoke();
}
catch(Exception l_exception)
{
MelonLoader.MelonLogger.Error(l_exception);
}
}
static void OnAvatarReinitialize_Postfix() static void OnAvatarReinitialize_Postfix()
{ {
try try

View file

@ -64,31 +64,31 @@ namespace ml_bft
{ {
while(ViewManager.Instance == null) while(ViewManager.Instance == null)
yield return null; yield return null;
while(ViewManager.Instance.gameMenuView == null) while(ViewManager.Instance.cohtmlView == null)
yield return null; yield return null;
while(ViewManager.Instance.gameMenuView.Listener == null) while(ViewManager.Instance.cohtmlView.Listener == null)
yield return null; yield return null;
ViewManager.Instance.gameMenuView.Listener.ReadyForBindings += () => ViewManager.Instance.cohtmlView.Listener.ReadyForBindings += () =>
{ {
ViewManager.Instance.gameMenuView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate)); ViewManager.Instance.cohtmlView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate));
ViewManager.Instance.gameMenuView.View.BindCall("OnDropdownUpdate_" + ms_category.Identifier, new Action<string, string>(OnDropdownUpdate)); ViewManager.Instance.cohtmlView.View.BindCall("OnDropdownUpdate_" + ms_category.Identifier, new Action<string, string>(OnDropdownUpdate));
}; };
ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) => ViewManager.Instance.cohtmlView.Listener.FinishLoad += (_) =>
{ {
ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mods_extension.js")); ViewManager.Instance.cohtmlView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mods_extension.js"));
ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mod_menu.js")); ViewManager.Instance.cohtmlView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mod_menu.js"));
MelonLoader.MelonCoroutines.Start(UpdateMenuSettings()); MelonLoader.MelonCoroutines.Start(UpdateMenuSettings());
}; };
} }
static System.Collections.IEnumerator UpdateMenuSettings() static System.Collections.IEnumerator UpdateMenuSettings()
{ {
while(!ViewManager.Instance.IsReady || !ViewManager.Instance.IsMainMenuOpen) while(!ViewManager.Instance.IsReady || !ViewManager.Instance.IsViewShown)
yield return null; yield return null;
foreach(var l_entry in ms_entries) foreach(var l_entry in ms_entries)
ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString()); ViewManager.Instance.cohtmlView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString());
} }
static void OnToggleUpdate(string p_name, string p_value) static void OnToggleUpdate(string p_name, string p_value)

View file

@ -17,12 +17,5 @@ namespace ml_bft
public static bool IsInVR() => ((MetaPort.Instance != null) && MetaPort.Instance.isUsingVr); public static bool IsInVR() => ((MetaPort.Instance != null) && MetaPort.Instance.isUsingVr);
public static bool AreKnucklesInUse() => ((CVRInputManager.Instance._leftController == ABI_RC.Systems.InputManagement.XR.eXRControllerType.Index) || (CVRInputManager.Instance._rightController == ABI_RC.Systems.InputManagement.XR.eXRControllerType.Index)); public static bool AreKnucklesInUse() => ((CVRInputManager.Instance._leftController == ABI_RC.Systems.InputManagement.XR.eXRControllerType.Index) || (CVRInputManager.Instance._rightController == ABI_RC.Systems.InputManagement.XR.eXRControllerType.Index));
public static void SetAvatarTPose()
{
IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose);
PlayerSetup.Instance._avatar.transform.localPosition = Vector3.zero;
PlayerSetup.Instance._avatar.transform.localRotation = Quaternion.identity;
}
} }
} }

View file

@ -35,8 +35,6 @@ namespace ml_dht
public void Invoke(T1 p_objA, T2 p_objB) => m_action?.Invoke(p_objA, p_objB); public void Invoke(T1 p_objA, T2 p_objB) => m_action?.Invoke(p_objA, p_objB);
} }
public static readonly GameEvent OnAvatarSetup = new GameEvent();
public static readonly GameEvent OnAvatarClear = new GameEvent();
public static readonly GameEvent OnAvatarReuse = new GameEvent(); public static readonly GameEvent OnAvatarReuse = new GameEvent();
public static readonly GameEvent<EyeMovementController> OnEyeControllerUpdate = new GameEvent<EyeMovementController>(); public static readonly GameEvent<EyeMovementController> OnEyeControllerUpdate = new GameEvent<EyeMovementController>();
public static readonly GameEvent<CVRFaceTracking, EventResult> OnFaceTrackingUpdate = new GameEvent<CVRFaceTracking, EventResult>(); public static readonly GameEvent<CVRFaceTracking, EventResult> OnFaceTrackingUpdate = new GameEvent<CVRFaceTracking, EventResult>();
@ -47,18 +45,6 @@ namespace ml_dht
{ {
try try
{ {
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar), BindingFlags.Instance | BindingFlags.Public),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar), BindingFlags.Instance | BindingFlags.Public),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch( p_instance.Patch(
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public), typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
null, null,
@ -92,30 +78,6 @@ namespace ml_dht
} }
} }
static void OnSetupAvatar_Postfix()
{
try
{
OnAvatarSetup.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnAvatarClear_Postfix()
{
try
{
OnAvatarClear.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnAvatarReinitialize_Postfix() static void OnAvatarReinitialize_Postfix()
{ {
try try

View file

@ -2,6 +2,7 @@
using ABI_RC.Core.Player; using ABI_RC.Core.Player;
using ABI_RC.Core.Player.EyeMovement; using ABI_RC.Core.Player.EyeMovement;
using ABI_RC.Systems.FaceTracking; using ABI_RC.Systems.FaceTracking;
using ABI_RC.Systems.GameEventSystem;
using ABI_RC.Systems.IK; using ABI_RC.Systems.IK;
using ABI_RC.Systems.VRModeSwitch; using ABI_RC.Systems.VRModeSwitch;
using RootMotion.FinalIK; using RootMotion.FinalIK;
@ -69,8 +70,8 @@ namespace ml_dht
Settings.OnHeadTrackingChanged.AddListener(this.OnEnabledOrHeadTrackingChanged); Settings.OnHeadTrackingChanged.AddListener(this.OnEnabledOrHeadTrackingChanged);
Settings.OnSmoothingChanged.AddListener(this.OnSmoothingChanged); Settings.OnSmoothingChanged.AddListener(this.OnSmoothingChanged);
GameEvents.OnAvatarClear.AddListener(this.OnAvatarClear); CVRGameEventSystem.Avatar.OnLocalAvatarLoad.AddListener(this.OnAvatarSetup);
GameEvents.OnAvatarSetup.AddListener(this.OnAvatarSetup); CVRGameEventSystem.Avatar.OnLocalAvatarClear.AddListener(this.OnAvatarClear);
GameEvents.OnAvatarReuse.AddListener(this.OnAvatarReuse); GameEvents.OnAvatarReuse.AddListener(this.OnAvatarReuse);
GameEvents.OnEyeControllerUpdate.AddListener(this.OnEyeControllerUpdate); GameEvents.OnEyeControllerUpdate.AddListener(this.OnEyeControllerUpdate);
GameEvents.OnFaceTrackingUpdate.AddListener(this.UpdateFaceTracking); GameEvents.OnFaceTrackingUpdate.AddListener(this.UpdateFaceTracking);
@ -89,8 +90,8 @@ namespace ml_dht
Settings.OnHeadTrackingChanged.RemoveListener(this.OnEnabledOrHeadTrackingChanged); Settings.OnHeadTrackingChanged.RemoveListener(this.OnEnabledOrHeadTrackingChanged);
Settings.OnSmoothingChanged.RemoveListener(this.OnSmoothingChanged); Settings.OnSmoothingChanged.RemoveListener(this.OnSmoothingChanged);
GameEvents.OnAvatarClear.RemoveListener(this.OnAvatarClear); CVRGameEventSystem.Avatar.OnLocalAvatarLoad.RemoveListener(this.OnAvatarSetup);
GameEvents.OnAvatarSetup.RemoveListener(this.OnAvatarSetup); CVRGameEventSystem.Avatar.OnLocalAvatarClear.RemoveListener(this.OnAvatarClear);
GameEvents.OnAvatarReuse.RemoveListener(this.OnAvatarReuse); GameEvents.OnAvatarReuse.RemoveListener(this.OnAvatarReuse);
GameEvents.OnEyeControllerUpdate.RemoveListener(this.OnEyeControllerUpdate); GameEvents.OnEyeControllerUpdate.RemoveListener(this.OnEyeControllerUpdate);
GameEvents.OnFaceTrackingUpdate.RemoveListener(this.UpdateFaceTracking); GameEvents.OnFaceTrackingUpdate.RemoveListener(this.UpdateFaceTracking);
@ -131,33 +132,42 @@ namespace ml_dht
{ {
m_lastHeadRotation = Quaternion.Slerp(m_lastHeadRotation, m_avatarDescriptor.transform.rotation * (m_headRotation * m_bindRotation), m_smoothing); m_lastHeadRotation = Quaternion.Slerp(m_lastHeadRotation, m_avatarDescriptor.transform.rotation * (m_headRotation * m_bindRotation), m_smoothing);
if(!PlayerSetup.Instance.IsEmotePlaying()) if(!PlayerSetup.Instance.IsEmotePlaying)
m_headBone.rotation = m_lastHeadRotation; m_headBone.rotation = m_lastHeadRotation;
} }
} }
// Game events // Game events
internal void OnAvatarSetup() internal void OnAvatarSetup(CVRAvatar p_avatar)
{ {
m_camera = PlayerSetup.Instance.GetActiveCamera().transform; try
m_avatarDescriptor = PlayerSetup.Instance._avatar.GetComponent<CVRAvatar>(); {
m_camera = PlayerSetup.Instance.activeCam.transform;
m_avatarDescriptor = PlayerSetup.Instance.AvatarObject.GetComponent<CVRAvatar>();
if(PlayerSetup.Instance._animator.isHuman) if(PlayerSetup.Instance.Animator.isHuman)
{ {
IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose); IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose);
PlayerSetup.Instance._avatar.transform.localPosition = Vector3.zero; PlayerSetup.Instance.AvatarTransform.localPosition = Vector3.zero;
PlayerSetup.Instance._avatar.transform.localRotation = Quaternion.identity; PlayerSetup.Instance.AvatarTransform.localRotation = Quaternion.identity;
m_headBone = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Head); m_headBone = PlayerSetup.Instance.Animator.GetBoneTransform(HumanBodyBones.Head);
if(m_headBone != null) if(m_headBone != null)
m_bindRotation = Quaternion.Inverse(m_avatarDescriptor.transform.rotation) * m_headBone.rotation; m_bindRotation = Quaternion.Inverse(m_avatarDescriptor.transform.rotation) * m_headBone.rotation;
m_lookIK = PlayerSetup.Instance._avatar.GetComponent<LookAtIK>(); m_lookIK = PlayerSetup.Instance.AvatarObject.GetComponent<LookAtIK>();
if(m_lookIK != null) if(m_lookIK != null)
m_lookIK.onPostSolverUpdate.AddListener(this.OnLookIKPostUpdate); m_lookIK.onPostSolverUpdate.AddListener(this.OnLookIKPostUpdate);
} }
} }
void OnAvatarClear() catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
void OnAvatarClear(CVRAvatar p_avatar)
{
try
{ {
m_avatarDescriptor = null; m_avatarDescriptor = null;
m_lookIK = null; m_lookIK = null;
@ -165,11 +175,16 @@ namespace ml_dht
m_lastHeadRotation = Quaternion.identity; m_lastHeadRotation = Quaternion.identity;
m_bindRotation = Quaternion.identity; m_bindRotation = Quaternion.identity;
} }
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
void OnAvatarReuse() void OnAvatarReuse()
{ {
m_camera = PlayerSetup.Instance.GetActiveCamera().transform; m_camera = PlayerSetup.Instance.activeCam.transform;
m_lookIK = PlayerSetup.Instance._avatar.GetComponent<LookAtIK>(); m_lookIK = PlayerSetup.Instance.AvatarObject.GetComponent<LookAtIK>();
if(m_lookIK != null) if(m_lookIK != null)
m_lookIK.onPostSolverUpdate.AddListener(this.OnLookIKPostUpdate); m_lookIK.onPostSolverUpdate.AddListener(this.OnLookIKPostUpdate);
} }

View file

@ -74,31 +74,31 @@ namespace ml_dht
{ {
while(ViewManager.Instance == null) while(ViewManager.Instance == null)
yield return null; yield return null;
while(ViewManager.Instance.gameMenuView == null) while(ViewManager.Instance.cohtmlView == null)
yield return null; yield return null;
while(ViewManager.Instance.gameMenuView.Listener == null) while(ViewManager.Instance.cohtmlView.Listener == null)
yield return null; yield return null;
ViewManager.Instance.gameMenuView.Listener.ReadyForBindings += () => ViewManager.Instance.cohtmlView.Listener.ReadyForBindings += () =>
{ {
ViewManager.Instance.gameMenuView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate)); ViewManager.Instance.cohtmlView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate));
ViewManager.Instance.gameMenuView.View.BindCall("OnSliderUpdate_" + ms_category.Identifier, new Action<string, string>(OnSliderUpdate)); ViewManager.Instance.cohtmlView.View.BindCall("OnSliderUpdate_" + ms_category.Identifier, new Action<string, string>(OnSliderUpdate));
}; };
ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) => ViewManager.Instance.cohtmlView.Listener.FinishLoad += (_) =>
{ {
ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mods_extension.js")); ViewManager.Instance.cohtmlView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mods_extension.js"));
ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mod_menu.js")); ViewManager.Instance.cohtmlView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mod_menu.js"));
MelonLoader.MelonCoroutines.Start(UpdateMenuSettings()); MelonLoader.MelonCoroutines.Start(UpdateMenuSettings());
}; };
} }
static System.Collections.IEnumerator UpdateMenuSettings() static System.Collections.IEnumerator UpdateMenuSettings()
{ {
while(!ViewManager.Instance.IsReady || !ViewManager.Instance.IsMainMenuOpen) while(!ViewManager.Instance.IsReady || !ViewManager.Instance.IsViewShown)
yield return null; yield return null;
foreach(var l_entry in ms_entries) foreach(var l_entry in ms_entries)
ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString()); ViewManager.Instance.cohtmlView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString());
} }
static void OnSliderUpdate(string p_name, string p_value) static void OnSliderUpdate(string p_name, string p_value)

View file

@ -23,8 +23,6 @@ namespace ml_lme
public void Invoke(T1 p_obj) => m_action?.Invoke(p_obj); 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 OnAvatarReuse = new GameEvent(); public static readonly GameEvent OnAvatarReuse = new GameEvent();
public static readonly GameEvent<float> OnRayScale = new GameEvent<float>(); public static readonly GameEvent<float> OnRayScale = new GameEvent<float>();
public static readonly GameEvent<float> OnPlayspaceScale = new GameEvent<float>(); public static readonly GameEvent<float> OnPlayspaceScale = new GameEvent<float>();
@ -34,18 +32,6 @@ namespace ml_lme
{ {
try try
{ {
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar), BindingFlags.Instance | BindingFlags.Public),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar), BindingFlags.Instance | BindingFlags.Public),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch( p_instance.Patch(
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public), typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
null, null,
@ -53,7 +39,7 @@ namespace ml_lme
); );
p_instance.Patch( p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetControllerRayScale), BindingFlags.Instance | BindingFlags.Public), typeof(PlayerSetup).GetMethod("SetControllerRayScale", BindingFlags.Instance | BindingFlags.NonPublic),
null, null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnRayScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnRayScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
); );
@ -76,30 +62,6 @@ namespace ml_lme
} }
} }
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_Postfix() static void OnAvatarReinitialize_Postfix()
{ {
try try

View file

@ -40,7 +40,6 @@ namespace ml_lme
m_handRayLeft.isInteractionRay = true; m_handRayLeft.isInteractionRay = true;
m_handRayLeft.triggerHoverEvents = false; m_handRayLeft.triggerHoverEvents = false;
m_handRayLeft.attachmentDistance = 0f; m_handRayLeft.attachmentDistance = 0f;
m_handRayLeft.uiMask = 32;
m_handRayLeft.isDesktopRay = !m_inVR; m_handRayLeft.isDesktopRay = !m_inVR;
m_lineLeft = m_handRayLeft.gameObject.AddComponent<LineRenderer>(); m_lineLeft = m_handRayLeft.gameObject.AddComponent<LineRenderer>();
@ -61,7 +60,6 @@ namespace ml_lme
m_handRayRight.isInteractionRay = true; m_handRayRight.isInteractionRay = true;
m_handRayRight.triggerHoverEvents = false; m_handRayRight.triggerHoverEvents = false;
m_handRayRight.attachmentDistance = 0f; m_handRayRight.attachmentDistance = 0f;
m_handRayRight.uiMask = 32;
m_handRayRight.isDesktopRay = !m_inVR; m_handRayRight.isDesktopRay = !m_inVR;
m_lineRight = m_handRayRight.gameObject.AddComponent<LineRenderer>(); m_lineRight = m_handRayRight.gameObject.AddComponent<LineRenderer>();
@ -120,12 +118,10 @@ namespace ml_lme
m_lineLeft.material = PlayerSetup.Instance.vrRayLeft.lineRenderer.material; m_lineLeft.material = PlayerSetup.Instance.vrRayLeft.lineRenderer.material;
m_lineLeft.gameObject.layer = PlayerSetup.Instance.vrRayLeft.gameObject.layer; m_lineLeft.gameObject.layer = PlayerSetup.Instance.vrRayLeft.gameObject.layer;
m_handRayLeft.highlightMaterial = PlayerSetup.Instance.vrRayLeft.highlightMaterial;
m_handRayLeft.SetVRActive(m_inVR); m_handRayLeft.SetVRActive(m_inVR);
m_lineRight.material = PlayerSetup.Instance.vrRayLeft.lineRenderer.material; m_lineRight.material = PlayerSetup.Instance.vrRayLeft.lineRenderer.material;
m_lineRight.gameObject.layer = PlayerSetup.Instance.vrRayLeft.gameObject.layer; m_lineRight.gameObject.layer = PlayerSetup.Instance.vrRayLeft.gameObject.layer;
m_handRayRight.highlightMaterial = PlayerSetup.Instance.vrRayLeft.highlightMaterial;
m_handRayRight.SetVRActive(m_inVR); m_handRayRight.SetVRActive(m_inVR);
} }
@ -655,7 +651,7 @@ namespace ml_lme
void SetGameFingersTracking(bool p_state) void SetGameFingersTracking(bool p_state)
{ {
base._inputManager.individualFingerTracking = p_state; base._inputManager.individualFingerTracking = p_state;
IKSystem.Instance.FingerSystem.controlActive = base._inputManager.individualFingerTracking; IKSystem.Instance.FingerSystem.ControlActive = base._inputManager.individualFingerTracking;
} }
} }
} }

View file

@ -1,4 +1,6 @@
using ABI_RC.Core.Player; using ABI.CCK.Components;
using ABI_RC.Core.Player;
using ABI_RC.Systems.GameEventSystem;
using ABI_RC.Systems.IK; using ABI_RC.Systems.IK;
using RootMotion.FinalIK; using RootMotion.FinalIK;
using System.Collections.Generic; using System.Collections.Generic;
@ -148,8 +150,8 @@ namespace ml_lme
Settings.OnFingersOnlyChanged.AddListener(this.OnEnabledOrFingersOnlyChanged); Settings.OnFingersOnlyChanged.AddListener(this.OnEnabledOrFingersOnlyChanged);
Settings.OnTrackElbowsChanged.AddListener(this.OnTrackElbowsChanged); Settings.OnTrackElbowsChanged.AddListener(this.OnTrackElbowsChanged);
GameEvents.OnAvatarClear.AddListener(this.OnAvatarClear); CVRGameEventSystem.Avatar.OnLocalAvatarLoad.AddListener(this.OnAvatarSetup);
GameEvents.OnAvatarSetup.AddListener(this.OnAvatarSetup); CVRGameEventSystem.Avatar.OnLocalAvatarClear.AddListener(this.OnAvatarClear);
GameEvents.OnAvatarReuse.AddListener(this.OnAvatarReuse); GameEvents.OnAvatarReuse.AddListener(this.OnAvatarReuse);
} }
@ -174,8 +176,8 @@ namespace ml_lme
Settings.OnFingersOnlyChanged.RemoveListener(this.OnEnabledOrFingersOnlyChanged); Settings.OnFingersOnlyChanged.RemoveListener(this.OnEnabledOrFingersOnlyChanged);
Settings.OnTrackElbowsChanged.RemoveListener(this.OnTrackElbowsChanged); Settings.OnTrackElbowsChanged.RemoveListener(this.OnTrackElbowsChanged);
GameEvents.OnAvatarClear.RemoveListener(this.OnAvatarClear); CVRGameEventSystem.Avatar.OnLocalAvatarLoad.RemoveListener(this.OnAvatarSetup);
GameEvents.OnAvatarSetup.RemoveListener(this.OnAvatarSetup); CVRGameEventSystem.Avatar.OnLocalAvatarClear.RemoveListener(this.OnAvatarClear);
GameEvents.OnAvatarReuse.RemoveListener(this.OnAvatarReuse); GameEvents.OnAvatarReuse.RemoveListener(this.OnAvatarReuse);
} }
@ -255,7 +257,9 @@ namespace ml_lme
} }
// Game events // Game events
void OnAvatarClear() void OnAvatarClear(CVRAvatar p_avatar)
{
try
{ {
m_vrIK = null; m_vrIK = null;
m_hips = null; m_hips = null;
@ -278,10 +282,17 @@ namespace ml_lme
m_leftFingerOffsets.Clear(); m_leftFingerOffsets.Clear();
m_rightFingerOffsets.Clear(); m_rightFingerOffsets.Clear();
} }
catch(System.Exception e)
void OnAvatarSetup()
{ {
Animator l_animator = PlayerSetup.Instance._animator; MelonLoader.MelonLogger.Error(e);
}
}
void OnAvatarSetup(CVRAvatar p_avatar)
{
try
{
Animator l_animator = PlayerSetup.Instance.Animator;
if(l_animator.isHuman) if(l_animator.isHuman)
{ {
Utils.SetAvatarTPose(); Utils.SetAvatarTPose();
@ -309,11 +320,16 @@ namespace ml_lme
SetupArmIK(); SetupArmIK();
} }
} }
catch(System.Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
void OnAvatarReuse() void OnAvatarReuse()
{ {
// Old VRIK is destroyed by game // Old VRIK is destroyed by game
m_vrIK = PlayerSetup.Instance._animator.GetComponent<VRIK>(); m_vrIK = PlayerSetup.Instance.AvatarObject.GetComponent<VRIK>();
if(Utils.IsInVR()) if(Utils.IsInVR())
RemoveArmIK(); RemoveArmIK();
@ -409,7 +425,7 @@ namespace ml_lme
void SetupArmIK() void SetupArmIK()
{ {
Animator l_animator = PlayerSetup.Instance._animator; Animator l_animator = PlayerSetup.Instance.Animator;
Transform l_chest = l_animator.GetBoneTransform(HumanBodyBones.UpperChest); Transform l_chest = l_animator.GetBoneTransform(HumanBodyBones.UpperChest);
if(l_chest == null) if(l_chest == null)
l_chest = l_animator.GetBoneTransform(HumanBodyBones.Chest); l_chest = l_animator.GetBoneTransform(HumanBodyBones.Chest);
@ -472,7 +488,7 @@ namespace ml_lme
LeapTracking.Instance.Rebind(PlayerSetup.Instance.transform.rotation); LeapTracking.Instance.Rebind(PlayerSetup.Instance.transform.rotation);
// Align rotations of leap fingers to avatar fingers // Align rotations of leap fingers to avatar fingers
Animator l_animator = PlayerSetup.Instance._animator; Animator l_animator = PlayerSetup.Instance.Animator;
LeapHand l_leapLeft = LeapTracking.Instance.GetLeftHand(); LeapHand l_leapLeft = LeapTracking.Instance.GetLeftHand();
LeapHand l_leapRight = LeapTracking.Instance.GetRightHand(); LeapHand l_leapRight = LeapTracking.Instance.GetRightHand();
// Try to "fix" rotations, slightly inaccurate after 0YX plane rotation // Try to "fix" rotations, slightly inaccurate after 0YX plane rotation

View file

@ -136,7 +136,7 @@ namespace ml_lme
{ {
if(Settings.Enabled) if(Settings.Enabled)
{ {
Transform l_camera = PlayerSetup.Instance.GetActiveCamera().transform; Transform l_camera = PlayerSetup.Instance.activeCam.transform;
m_root.position = l_camera.position; m_root.position = l_camera.position;
m_root.rotation = (Settings.HeadAttach ? l_camera.rotation : PlayerSetup.Instance.GetPlayerRotation()); m_root.rotation = (Settings.HeadAttach ? l_camera.rotation : PlayerSetup.Instance.GetPlayerRotation());

View file

@ -146,32 +146,32 @@ namespace ml_lme
{ {
while(ViewManager.Instance == null) while(ViewManager.Instance == null)
yield return null; yield return null;
while(ViewManager.Instance.gameMenuView == null) while(ViewManager.Instance.cohtmlView == null)
yield return null; yield return null;
while(ViewManager.Instance.gameMenuView.Listener == null) while(ViewManager.Instance.cohtmlView.Listener == null)
yield return null; yield return null;
ViewManager.Instance.gameMenuView.Listener.ReadyForBindings += () => ViewManager.Instance.cohtmlView.Listener.ReadyForBindings += () =>
{ {
ViewManager.Instance.gameMenuView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate)); ViewManager.Instance.cohtmlView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate));
ViewManager.Instance.gameMenuView.View.BindCall("OnSliderUpdate_" + ms_category.Identifier, new Action<string, string>(OnSliderUpdate)); ViewManager.Instance.cohtmlView.View.BindCall("OnSliderUpdate_" + ms_category.Identifier, new Action<string, string>(OnSliderUpdate));
ViewManager.Instance.gameMenuView.View.BindCall("OnDropdownUpdate_" + ms_category.Identifier, new Action<string, string>(OnDropdownUpdate)); ViewManager.Instance.cohtmlView.View.BindCall("OnDropdownUpdate_" + ms_category.Identifier, new Action<string, string>(OnDropdownUpdate));
}; };
ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) => ViewManager.Instance.cohtmlView.Listener.FinishLoad += (_) =>
{ {
ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mods_extension.js")); ViewManager.Instance.cohtmlView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mods_extension.js"));
ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mod_menu.js")); ViewManager.Instance.cohtmlView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mod_menu.js"));
MelonLoader.MelonCoroutines.Start(UpdateMenuSettings()); MelonLoader.MelonCoroutines.Start(UpdateMenuSettings());
}; };
} }
static System.Collections.IEnumerator UpdateMenuSettings() static System.Collections.IEnumerator UpdateMenuSettings()
{ {
while(!ViewManager.Instance.IsReady || !ViewManager.Instance.IsMainMenuOpen) while(!ViewManager.Instance.IsReady || !ViewManager.Instance.IsViewShown)
yield return null; yield return null;
foreach(var l_entry in ms_entries) foreach(var l_entry in ms_entries)
ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString()); ViewManager.Instance.cohtmlView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString());
} }
static void OnToggleUpdate(string p_name, string p_value) static void OnToggleUpdate(string p_name, string p_value)

View file

@ -59,8 +59,8 @@ namespace ml_lme
public static void SetAvatarTPose() public static void SetAvatarTPose()
{ {
IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose); IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose);
PlayerSetup.Instance._avatar.transform.localPosition = Vector3.zero; PlayerSetup.Instance.AvatarTransform.localPosition = Vector3.zero;
PlayerSetup.Instance._avatar.transform.localRotation = Quaternion.identity; PlayerSetup.Instance.AvatarTransform.localRotation = Quaternion.identity;
} }
public static void Swap<T>(ref T lhs, ref T rhs) public static void Swap<T>(ref T lhs, ref T rhs)

View file

@ -32,6 +32,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_ppu", "ml_ppu\ml_ppu.csp
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_vet", "ml_vet\ml_vet.csproj", "{8DB32590-FC5B-46A8-9747-344E86B18ACF}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_vet", "ml_vet\ml_vet.csproj", "{8DB32590-FC5B-46A8-9747-344E86B18ACF}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_pah", "ml_pah\ml_pah.csproj", "{C4659F60-3FED-4F43-88E4-969907D4C7A6}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64 Debug|x64 = Debug|x64
@ -83,6 +85,9 @@ Global
{8DB32590-FC5B-46A8-9747-344E86B18ACF}.Debug|x64.Build.0 = Debug|x64 {8DB32590-FC5B-46A8-9747-344E86B18ACF}.Debug|x64.Build.0 = Debug|x64
{8DB32590-FC5B-46A8-9747-344E86B18ACF}.Release|x64.ActiveCfg = Release|x64 {8DB32590-FC5B-46A8-9747-344E86B18ACF}.Release|x64.ActiveCfg = Release|x64
{8DB32590-FC5B-46A8-9747-344E86B18ACF}.Release|x64.Build.0 = Release|x64 {8DB32590-FC5B-46A8-9747-344E86B18ACF}.Release|x64.Build.0 = Release|x64
{C4659F60-3FED-4F43-88E4-969907D4C7A6}.Debug|x64.ActiveCfg = Debug|x64
{C4659F60-3FED-4F43-88E4-969907D4C7A6}.Release|x64.ActiveCfg = Release|x64
{C4659F60-3FED-4F43-88E4-969907D4C7A6}.Release|x64.Build.0 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

14
ml_pah/AvatarEntry.cs Normal file
View file

@ -0,0 +1,14 @@
using System;
namespace ml_pah
{
[Serializable]
class AvatarEntry
{
public string m_id;
public string m_name;
public string m_imageUrl;
public DateTime m_lastUsageDate;
public bool m_cached = false;
}
}

205
ml_pah/HistoryManager.cs Normal file
View file

@ -0,0 +1,205 @@
using ABI_RC.Core.Networking.API;
using ABI_RC.Core.Networking.API.Responses;
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace ml_pah
{
static class HistoryManager
{
internal class EntriesUpdateEvent
{
event Action m_action;
public void AddListener(Action p_listener) => m_action += p_listener;
public void RemoveListener(Action p_listener) => m_action -= p_listener;
public void Invoke() => m_action?.Invoke();
}
public static readonly EntriesUpdateEvent OnEntriesUpdated = new EntriesUpdateEvent();
static bool ms_initialized = false;
static string ms_historyPath;
readonly static List<AvatarEntry> ms_avatarEntries = new List<AvatarEntry>();
static int ms_lastTick = 0;
// Init
internal static void Initialize()
{
if(!ms_initialized)
{
ms_historyPath = Path.Combine(MelonLoader.Utils.MelonEnvironment.UserDataDirectory, "PlayerAvatarHistory.json");
try
{
if(File.Exists(ms_historyPath))
{
string l_json = File.ReadAllText(ms_historyPath);
List<AvatarEntry> l_entries = JsonConvert.DeserializeObject<List<AvatarEntry>>(l_json);
if(l_entries != null)
{
ms_avatarEntries.AddRange(l_entries);
LimitEntries();
ms_avatarEntries.Sort((a, b) => a.m_lastUsageDate.CompareTo(b.m_lastUsageDate));
}
}
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
ms_lastTick = Environment.TickCount;
Settings.OnAutosaveTimeChanged.AddListener(OnAutosaveTimeChanged);
ms_initialized = true;
}
}
internal static void Shutdown()
{
if(ms_initialized)
{
SaveHistory();
Settings.OnAutosaveTimeChanged.RemoveListener(OnAutosaveTimeChanged);
ms_initialized = false;
}
}
// Update
public static void Update()
{
if(ms_initialized && (Settings.AutosaveTime > 0))
{
int l_tick = Environment.TickCount;
if((l_tick - ms_lastTick) >= (Settings.AutosaveTime * 60000))
{
MelonLoader.MelonCoroutines.Start(AutosaveCoroutine());
ms_lastTick = l_tick;
}
}
}
// Entries
internal static List<AvatarEntry> GetAvatarEntries() => ms_avatarEntries;
internal static void AddEntry(string p_id)
{
if(ms_initialized)
{
int l_index = ms_avatarEntries.FindIndex(l_entry => l_entry.m_id == p_id);
if(l_index != -1)
{
ms_avatarEntries[l_index].m_lastUsageDate = DateTime.Now;
if(l_index != 0)
{
// Move in list
AvatarEntry l_entry = ms_avatarEntries[l_index];
ms_avatarEntries.RemoveAt(l_index);
ms_avatarEntries.Insert(0, l_entry);
OnEntriesUpdated?.Invoke();
}
}
else
{
AvatarEntry l_entry = new AvatarEntry();
l_entry.m_id = p_id;
l_entry.m_name = "Loading ...";
l_entry.m_lastUsageDate = DateTime.Now;
MelonLoader.MelonCoroutines.Start(RequestAvatarInfo(l_entry));
}
}
}
// History
internal static void ClearHistory() => ms_avatarEntries.Clear();
internal static void SaveHistory()
{
if(ms_initialized)
{
try
{
string l_json = JsonConvert.SerializeObject(ms_avatarEntries, Formatting.Indented);
File.WriteAllText(ms_historyPath, l_json);
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
}
static IEnumerator AutosaveCoroutine()
{
List<AvatarEntry> l_listCopy = new List<AvatarEntry>();
l_listCopy.AddRange(ms_avatarEntries);
Task l_task = Task.Run(() => AutosaveTask(l_listCopy));
while(!l_task.IsCompleted)
yield return null;
}
static async Task AutosaveTask(List<AvatarEntry> p_entries)
{
try
{
string l_json = JsonConvert.SerializeObject(p_entries, Formatting.Indented);
File.WriteAllText(ms_historyPath, l_json);
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
await Task.Delay(1);
}
// Network request
static IEnumerator RequestAvatarInfo(AvatarEntry p_entry)
{
Task l_task = Task.Run(() => RequestAvatarInfoTask(p_entry));
while(!l_task.IsCompleted)
yield return null;
ms_avatarEntries.Insert(0, p_entry);
LimitEntries();
OnEntriesUpdated?.Invoke();
}
static async Task RequestAvatarInfoTask(AvatarEntry p_entry)
{
BaseResponse<AvatarDetailsResponse> l_baseResponse = await ApiConnection.MakeRequest<AvatarDetailsResponse>(ApiConnection.ApiOperation.AvatarDetail, new { avatarID = p_entry.m_id });
if(l_baseResponse != null)
{
if(!l_baseResponse.IsSuccessStatusCode) return;
p_entry.m_name = l_baseResponse.Data.Name;
p_entry.m_imageUrl = l_baseResponse.Data.ImageUrl;
p_entry.m_cached = true;
}
}
// Settings
static void OnAutosaveTimeChanged(int p_value)
{
ms_lastTick = Environment.TickCount;
}
// Utility
static void LimitEntries()
{
int l_currentLimit = Settings.AvatarsLimit;
while(ms_avatarEntries.Count > l_currentLimit)
ms_avatarEntries.RemoveAt(ms_avatarEntries.Count - 1);
}
}
}

59
ml_pah/Main.cs Normal file
View file

@ -0,0 +1,59 @@
using ABI.CCK.Components;
using ABI_RC.Core;
using System;
using System.Collections;
using ABI_RC.Systems.GameEventSystem;
namespace ml_pah
{
public class PlayerAvatarHistory : MelonLoader.MelonMod
{
public override void OnInitializeMelon()
{
Settings.Init();
HistoryManager.Initialize();
ModUi.Initialize();
MelonLoader.MelonCoroutines.Start(WaitForRootLogic());
}
public override void OnDeinitializeMelon()
{
CVRGameEventSystem.Avatar.OnLocalAvatarLoad.RemoveListener(this.OnLocalAvatarLoad);
HistoryManager.OnEntriesUpdated.RemoveListener(this.OnHistoryEntriesUpdated);
ModUi.Shutdown();
HistoryManager.Shutdown();
}
IEnumerator WaitForRootLogic()
{
while(RootLogic.Instance == null)
yield return null;
CVRGameEventSystem.Avatar.OnLocalAvatarLoad.AddListener(this.OnLocalAvatarLoad);
HistoryManager.OnEntriesUpdated.AddListener(this.OnHistoryEntriesUpdated);
}
public override void OnUpdate()
{
HistoryManager.Update();
}
// Game events
void OnLocalAvatarLoad(CVRAvatar p_avatar)
{
try
{
if((p_avatar.AssetInfo != null) && (p_avatar.AssetInfo.objectId.Length > 0))
HistoryManager.AddEntry(p_avatar.AssetInfo.objectId);
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
// Mod events
void OnHistoryEntriesUpdated() => ModUi.UpdateAvatarsList();
}
}

131
ml_pah/ModUi.cs Normal file
View file

@ -0,0 +1,131 @@
using ABI_RC.Core.EventSystem;
using ABI_RC.Core.InteractionSystem;
using BTKUILib.UIObjects;
using BTKUILib.UIObjects.Components;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
namespace ml_pah
{
static class ModUi
{
readonly static string ms_namespace = typeof(ModUi).Namespace;
static bool ms_initialized = false;
static Page ms_page = null;
static Category ms_settingsCategory = null;
static Button ms_settingsClearButton = null;
static Button ms_settingSaveButton = null;
static SliderFloat ms_settingsEntriesLimit = null;
static SliderFloat ms_settingsAutosaveTime = null;
static Category ms_buttonsCategory = null;
static readonly List<Button> ms_avatarButtons = new List<Button>();
// Init
internal static void Initialize()
{
if(!ms_initialized)
{
BTKUILib.QuickMenuAPI.PrepareIcon("PlayerAvatarHistory", "guardian", GetIconStream("guardian.png"));
BTKUILib.QuickMenuAPI.PrepareIcon("PlayerAvatarHistory", "delete", GetIconStream("delete.png"));
BTKUILib.QuickMenuAPI.PrepareIcon("PlayerAvatarHistory", "save", GetIconStream("save.png"));
ms_page = new Page("PlayerAvatarHistory", "MainPage", true, "guardian");
ms_page.MenuTitle = "Player Avatar History";
ms_page.MenuSubtitle = "List of last used avatars";
ms_settingsCategory = ms_page.AddCategory("Settings");
ms_settingsClearButton = ms_settingsCategory.AddButton("Clear history", "delete", "Clear current history");
ms_settingsClearButton.OnPress += ClearHistory;
ms_settingSaveButton = ms_settingsCategory.AddButton("Save history", "save", "Manually save current history");
ms_settingSaveButton.OnPress += SaveHistory;
ms_settingsEntriesLimit = ms_settingsCategory.AddSlider("History limit", "Number of saved avatar history entries.<p>Warning: Large value can impact performance.", Settings.AvatarsLimit, 10f, 100f, 0);
ms_settingsEntriesLimit.OnValueUpdated += OnAvatarLimitChange;
ms_settingsAutosaveTime = ms_settingsCategory.AddSlider("Autosave period", "Automatic history saving in minutes.", Settings.AutosaveTime, 0f, 60f, 0);
ms_settingsAutosaveTime.OnValueUpdated += OnAutosaveTimeChange;
ms_buttonsCategory = ms_page.AddCategory("Avatars");
RegenerateAvatarButtons();
ms_initialized = true;
}
}
internal static void Shutdown()
{
if(ms_initialized)
{
ms_page = null;
ms_buttonsCategory = null;
ms_avatarButtons.Clear();
ms_settingsCategory = null;
ms_settingSaveButton = null;
ms_settingsClearButton = null;
ms_initialized = false;
}
}
// History
static void ClearHistory()
{
BTKUILib.QuickMenuAPI.ShowConfirm(
"Clear history", "Are you sure want to clear all avatar history?",
() =>
{
HistoryManager.ClearHistory();
RegenerateAvatarButtons();
}
);
}
static void SaveHistory() => HistoryManager.SaveHistory();
// Update
public static void UpdateAvatarsList()
{
if(ms_initialized)
RegenerateAvatarButtons();
}
// Settings
static void OnAvatarLimitChange(float p_value) => Settings.SetSetting(Settings.ModSetting.AvatarsLimit, (int)p_value);
static void OnAutosaveTimeChange(float p_value) => Settings.SetSetting(Settings.ModSetting.AutosaveTime, (int)p_value);
// Utility
static void RegenerateAvatarButtons()
{
if(ms_avatarButtons.Count > 0)
{
foreach(Button l_button in ms_avatarButtons)
l_button.Delete();
ms_avatarButtons.Clear();
}
foreach(AvatarEntry l_entry in HistoryManager.GetAvatarEntries())
{
Button l_button = ms_buttonsCategory.AddButton("", "", "", ButtonStyle.FullSizeImage);
l_button.ButtonText = (l_entry.m_cached ? l_entry.m_name : "Loading ...");
l_button.ButtonIcon = (l_entry.m_cached ? l_entry.m_imageUrl : "");
l_button.ButtonTooltip = string.Format("Click to open avatar page, hold to switch avatar.<p>Last used time: {0}", l_entry.m_lastUsageDate.ToString("g"));
l_button.OnPress += () => ViewManager.Instance.RequestAvatarDetailsPage(l_entry.m_id);
l_button.OnHeld += () => AssetManagement.Instance.LoadLocalAvatarFromNetwork(l_entry.m_id);
ms_avatarButtons.Add(l_button);
}
}
static Stream GetIconStream(string p_name) => Assembly.GetExecutingAssembly().GetManifestResourceStream(ms_namespace + ".resources." + p_name);
}
}

View file

@ -0,0 +1,4 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_pah.PlayerAvatarHistory), "PlayerAvatarHistory", "1.0.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]

77
ml_pah/Settings.cs Normal file
View file

@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace ml_pah
{
static class Settings
{
internal class SettingEvent<T>
{
event Action<T> m_action;
public void AddListener(Action<T> p_listener) => m_action += p_listener;
public void RemoveListener(Action<T> p_listener) => m_action -= p_listener;
public void Invoke(T p_value) => m_action?.Invoke(p_value);
}
public enum ModSetting
{
AvatarsLimit = 0,
AutosaveTime
}
public static int AvatarsLimit { get; private set; } = 12;
public static int AutosaveTime { get; private set; } = 15;
public static readonly SettingEvent<int> OnAvatarsLimitChanged = new SettingEvent<int>();
public static readonly SettingEvent<int> OnAutosaveTimeChanged = new SettingEvent<int>();
static MelonLoader.MelonPreferences_Category ms_category = null;
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
internal static void Init()
{
ms_category = MelonLoader.MelonPreferences.CreateCategory("PAH", "Player Avatar History");
ms_entries = new List<MelonLoader.MelonPreferences_Entry>()
{
ms_category.CreateEntry(ModSetting.AvatarsLimit.ToString(), AvatarsLimit),
ms_category.CreateEntry(ModSetting.AutosaveTime.ToString(), AutosaveTime)
};
AvatarsLimit = Mathf.Clamp((int)ms_entries[(int)ModSetting.AvatarsLimit].BoxedValue, 10, 100);
AutosaveTime = Mathf.Clamp((int)ms_entries[(int)ModSetting.AutosaveTime].BoxedValue, 0, 60);
}
public static void SetSetting(ModSetting p_settings, object p_value)
{
try
{
switch(p_settings)
{
// Booleans
case ModSetting.AvatarsLimit:
{
AvatarsLimit = (int)p_value;
OnAvatarsLimitChanged.Invoke(AvatarsLimit);
}
break;
case ModSetting.AutosaveTime:
{
AutosaveTime = (int)p_value;
OnAutosaveTimeChanged.Invoke(AutosaveTime);
}
break;
}
if(ms_entries != null)
ms_entries[(int)p_settings].BoxedValue = p_value;
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
}
}

60
ml_pah/ml_pah.csproj Normal file
View file

@ -0,0 +1,60 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<Platforms>x64</Platforms>
<PackageId>PlayerAvatarHistory</PackageId>
<AssemblyName>PlayerAvatarHistory</AssemblyName>
<Authors>SDraw</Authors>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DebugType>embedded</DebugType>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<None Remove="resources\delete.png" />
<None Remove="resources\guardian.png" />
<None Remove="resources\save.png" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="resources\delete.png" />
<EmbeddedResource Include="resources\guardian.png" />
<EmbeddedResource Include="resources\save.png" />
</ItemGroup>
<ItemGroup>
<Reference Include="Assembly-CSharp">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll</HintPath>
<Private>false</Private>
<SpecificVersion>false</SpecificVersion>
</Reference>
<Reference Include="BTKUILib">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\Mods\BTKUILib.dll</HintPath>
<Private>false</Private>
<SpecificVersion>false</SpecificVersion>
</Reference>
<Reference Include="MelonLoader">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\MelonLoader.dll</HintPath>
<Private>false</Private>
<SpecificVersion>false</SpecificVersion>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Newtonsoft.Json.dll</HintPath>
<SpecificVersion>false</SpecificVersion>
<Private>false</Private>
</Reference>
<Reference Include="UnityEngine.CoreModule">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
<SpecificVersion>false</SpecificVersion>
<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>

BIN
ml_pah/resources/delete.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
ml_pah/resources/save.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View file

@ -1,6 +1,7 @@
using ABI.CCK.Components; using ABI.CCK.Components;
using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.InteractionSystem;
using ABI_RC.Core.Player; using ABI_RC.Core.Player;
using ABI_RC.Systems.GameEventSystem;
using ABI_RC.Systems.VRModeSwitch; using ABI_RC.Systems.VRModeSwitch;
using RootMotion.FinalIK; using RootMotion.FinalIK;
using System.Collections; using System.Collections;
@ -68,7 +69,7 @@ namespace ml_pam
void Start() void Start()
{ {
m_camera = PlayerSetup.Instance.GetActiveCamera().transform; m_camera = PlayerSetup.Instance.activeCam.transform;
m_root = new GameObject("Root").transform; m_root = new GameObject("Root").transform;
m_root.parent = this.transform; m_root.parent = this.transform;
@ -100,8 +101,8 @@ namespace ml_pam
Settings.OnLeadingHandChanged.AddListener(this.OnLeadingHandChanged); Settings.OnLeadingHandChanged.AddListener(this.OnLeadingHandChanged);
Settings.OnHandsExtensionChanged.AddListener(this.OnHandsExtensionChanged); Settings.OnHandsExtensionChanged.AddListener(this.OnHandsExtensionChanged);
GameEvents.OnAvatarClear.AddListener(this.OnAvatarClear); CVRGameEventSystem.Avatar.OnLocalAvatarClear.AddListener(this.OnAvatarClear);
GameEvents.OnAvatarSetup.AddListener(this.OnAvatarSetup); CVRGameEventSystem.Avatar.OnLocalAvatarLoad.AddListener(this.OnAvatarSetup);
GameEvents.OnAvatarReuse.AddListener(this.OnAvatarReuse); GameEvents.OnAvatarReuse.AddListener(this.OnAvatarReuse);
GameEvents.OnIKScaling.AddListener(this.OnIKScaling); GameEvents.OnIKScaling.AddListener(this.OnIKScaling);
GameEvents.OnPickupGrab.AddListener(this.OnPickupGrab); GameEvents.OnPickupGrab.AddListener(this.OnPickupGrab);
@ -149,10 +150,10 @@ namespace ml_pam
Settings.OnLeadingHandChanged.RemoveListener(this.OnLeadingHandChanged); Settings.OnLeadingHandChanged.RemoveListener(this.OnLeadingHandChanged);
Settings.OnHandsExtensionChanged.RemoveListener(this.OnHandsExtensionChanged); Settings.OnHandsExtensionChanged.RemoveListener(this.OnHandsExtensionChanged);
GameEvents.OnAvatarClear.RemoveListener(this.OnAvatarClear); CVRGameEventSystem.Avatar.OnLocalAvatarClear.RemoveListener(this.OnAvatarClear);
GameEvents.OnAvatarSetup.RemoveListener(this.OnAvatarSetup); CVRGameEventSystem.Avatar.OnLocalAvatarLoad.RemoveListener(this.OnAvatarSetup);
GameEvents.OnAvatarReuse.RemoveListener(this.OnAvatarReuse); GameEvents.OnAvatarReuse.RemoveListener(this.OnAvatarReuse);
GameEvents.OnIKScaling.AddListener(this.OnIKScaling); GameEvents.OnIKScaling.RemoveListener(this.OnIKScaling);
GameEvents.OnPickupGrab.RemoveListener(this.OnPickupGrab); GameEvents.OnPickupGrab.RemoveListener(this.OnPickupGrab);
GameEvents.OnPickupDrop.RemoveListener(this.OnPickupDrop); GameEvents.OnPickupDrop.RemoveListener(this.OnPickupDrop);
@ -341,7 +342,9 @@ namespace ml_pam
} }
// Game events // Game events
void OnAvatarClear() void OnAvatarClear(CVRAvatar p_avatar)
{
try
{ {
m_vrIK = null; m_vrIK = null;
m_armIKLeft = null; m_armIKLeft = null;
@ -350,17 +353,24 @@ namespace ml_pam
m_leftHandParameter = null; m_leftHandParameter = null;
m_rightHandParameter = null; m_rightHandParameter = null;
} }
catch(System.Exception e)
void OnAvatarSetup()
{ {
m_camera = PlayerSetup.Instance.GetActiveCamera().transform; MelonLoader.MelonLogger.Error(e);
}
}
if(PlayerSetup.Instance._animator.isHuman) void OnAvatarSetup(CVRAvatar p_avatar)
{ {
m_vrIK = PlayerSetup.Instance._animator.GetComponent<VRIK>(); try
{
m_camera = PlayerSetup.Instance.activeCam.transform;
if(PlayerSetup.Instance.Animator.isHuman)
{
m_vrIK = PlayerSetup.Instance.Animator.GetComponent<VRIK>();
Utils.SetAvatarTPose(); Utils.SetAvatarTPose();
Animator l_animator = PlayerSetup.Instance._animator; Animator l_animator = PlayerSetup.Instance.Animator;
Matrix4x4 l_avatarMatrixInv = l_animator.transform.GetMatrix().inverse; // Animator and avatar are on same game object Matrix4x4 l_avatarMatrixInv = l_animator.transform.GetMatrix().inverse; // Animator and avatar are on same game object
Transform l_leftHand = l_animator.GetBoneTransform(HumanBodyBones.LeftHand); Transform l_leftHand = l_animator.GetBoneTransform(HumanBodyBones.LeftHand);
@ -395,18 +405,23 @@ namespace ml_pam
} }
} }
m_leftHandParameter = new AvatarBoolParameter("LeftHandExtended", PlayerSetup.Instance.animatorManager); m_leftHandParameter = new AvatarBoolParameter("LeftHandExtended", PlayerSetup.Instance.AnimatorManager);
m_rightHandParameter = new AvatarBoolParameter("RightHandExtended", PlayerSetup.Instance.animatorManager); m_rightHandParameter = new AvatarBoolParameter("RightHandExtended", PlayerSetup.Instance.AnimatorManager);
OnEnabledChanged(Settings.Enabled); OnEnabledChanged(Settings.Enabled);
OnGrabOffsetChanged(Settings.GrabOffset); OnGrabOffsetChanged(Settings.GrabOffset);
OnIKScaling(1f); // Reset scaling, game doesn't do this anymore on avatar switch OnIKScaling(1f); // Reset scaling, game doesn't do this anymore on avatar switch
} }
catch(System.Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
void OnAvatarReuse() void OnAvatarReuse()
{ {
// Old VRIK is destroyed by game // Old VRIK is destroyed by game
m_vrIK = PlayerSetup.Instance._animator.GetComponent<VRIK>(); m_vrIK = PlayerSetup.Instance.Animator.GetComponent<VRIK>();
if(Utils.IsInVR()) if(Utils.IsInVR())
RemoveArmIK(); RemoveArmIK();
@ -470,7 +485,7 @@ namespace ml_pam
{ {
try try
{ {
m_camera = PlayerSetup.Instance.GetActiveCamera().transform; m_camera = PlayerSetup.Instance.activeCam.transform;
this.enabled = !Utils.IsInVR(); this.enabled = !Utils.IsInVR();
} }
catch(System.Exception e) catch(System.Exception e)
@ -482,7 +497,7 @@ namespace ml_pam
// Arbitrary // Arbitrary
void SetupArmIK() void SetupArmIK()
{ {
Animator l_animator = PlayerSetup.Instance._animator; Animator l_animator = PlayerSetup.Instance.Animator;
Transform l_chest = l_animator.GetBoneTransform(HumanBodyBones.UpperChest); Transform l_chest = l_animator.GetBoneTransform(HumanBodyBones.UpperChest);
if(l_chest == null) if(l_chest == null)
@ -490,7 +505,7 @@ namespace ml_pam
if(l_chest == null) if(l_chest == null)
l_chest = l_animator.GetBoneTransform(HumanBodyBones.Spine); l_chest = l_animator.GetBoneTransform(HumanBodyBones.Spine);
m_armIKLeft = PlayerSetup.Instance._avatar.AddComponent<ArmIK>(); m_armIKLeft = PlayerSetup.Instance.AvatarObject.AddComponent<ArmIK>();
m_armIKLeft.solver.isLeft = true; m_armIKLeft.solver.isLeft = true;
m_armIKLeft.solver.SetChain( m_armIKLeft.solver.SetChain(
l_chest, l_chest,
@ -507,7 +522,7 @@ namespace ml_pam
m_armIKLeft.solver.IKRotationWeight = 0f; m_armIKLeft.solver.IKRotationWeight = 0f;
m_armIKLeft.enabled = false; m_armIKLeft.enabled = false;
m_armIKRight = PlayerSetup.Instance._avatar.AddComponent<ArmIK>(); m_armIKRight = PlayerSetup.Instance.AvatarObject.AddComponent<ArmIK>();
m_armIKRight.solver.isLeft = false; m_armIKRight.solver.isLeft = false;
m_armIKRight.solver.SetChain( m_armIKRight.solver.SetChain(
l_chest, l_chest,

View file

@ -31,8 +31,6 @@ namespace ml_pam
public void Invoke(T1 p_objA, T2 p_objB) => m_action?.Invoke(p_objA, p_objB); public void Invoke(T1 p_objA, T2 p_objB) => m_action?.Invoke(p_objA, p_objB);
} }
public static readonly GameEvent OnAvatarSetup = new GameEvent();
public static readonly GameEvent OnAvatarClear = new GameEvent();
public static readonly GameEvent OnAvatarReuse = new GameEvent(); public static readonly GameEvent OnAvatarReuse = new GameEvent();
public static readonly GameEvent<float> OnIKScaling = new GameEvent<float>(); public static readonly GameEvent<float> OnIKScaling = new GameEvent<float>();
public static readonly GameEvent<CVRPickupObject, Vector3> OnPickupGrab = new GameEvent<CVRPickupObject, Vector3>(); public static readonly GameEvent<CVRPickupObject, Vector3> OnPickupGrab = new GameEvent<CVRPickupObject, Vector3>();
@ -42,18 +40,6 @@ namespace ml_pam
{ {
try try
{ {
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar), BindingFlags.Instance | BindingFlags.Public),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar), BindingFlags.Instance | BindingFlags.Public),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch( p_instance.Patch(
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public), typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
null, null,
@ -84,30 +70,6 @@ namespace ml_pam
} }
} }
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_Postfix() static void OnAvatarReinitialize_Postfix()
{ {
try try

View file

@ -84,33 +84,33 @@ namespace ml_pam
{ {
while(ViewManager.Instance == null) while(ViewManager.Instance == null)
yield return null; yield return null;
while(ViewManager.Instance.gameMenuView == null) while(ViewManager.Instance.cohtmlView == null)
yield return null; yield return null;
while(ViewManager.Instance.gameMenuView.Listener == null) while(ViewManager.Instance.cohtmlView.Listener == null)
yield return null; yield return null;
ViewManager.Instance.gameMenuView.Listener.ReadyForBindings += () => ViewManager.Instance.cohtmlView.Listener.ReadyForBindings += () =>
{ {
ViewManager.Instance.gameMenuView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate)); ViewManager.Instance.cohtmlView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate));
ViewManager.Instance.gameMenuView.View.BindCall("OnSliderUpdate_" + ms_category.Identifier, new Action<string, string>(OnSliderUpdate)); ViewManager.Instance.cohtmlView.View.BindCall("OnSliderUpdate_" + ms_category.Identifier, new Action<string, string>(OnSliderUpdate));
ViewManager.Instance.gameMenuView.View.BindCall("OnDropdownUpdate_" + ms_category.Identifier, new Action<string, string>(OnDropdownUpdate)); ViewManager.Instance.cohtmlView.View.BindCall("OnDropdownUpdate_" + ms_category.Identifier, new Action<string, string>(OnDropdownUpdate));
}; };
ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) => ViewManager.Instance.cohtmlView.Listener.FinishLoad += (_) =>
{ {
ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResources("mods_extension.js")); ViewManager.Instance.cohtmlView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResources("mods_extension.js"));
ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResources("mod_menu.js")); ViewManager.Instance.cohtmlView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResources("mod_menu.js"));
MelonLoader.MelonCoroutines.Start(UpdateMenuSettings()); MelonLoader.MelonCoroutines.Start(UpdateMenuSettings());
}; };
} }
static System.Collections.IEnumerator UpdateMenuSettings() static System.Collections.IEnumerator UpdateMenuSettings()
{ {
while(!ViewManager.Instance.IsReady || !ViewManager.Instance.IsMainMenuOpen) while(!ViewManager.Instance.IsReady || !ViewManager.Instance.IsViewShown)
yield return null; yield return null;
foreach(var l_entry in ms_entries) foreach(var l_entry in ms_entries)
ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString()); ViewManager.Instance.cohtmlView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString());
} }
static void OnMelonSettingSave_LeftHandKey(object p_oldValue, object p_newValue) static void OnMelonSettingSave_LeftHandKey(object p_oldValue, object p_newValue)

View file

@ -18,8 +18,8 @@ namespace ml_pam
public static void SetAvatarTPose() public static void SetAvatarTPose()
{ {
IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose); IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose);
PlayerSetup.Instance._avatar.transform.localPosition = Vector3.zero; PlayerSetup.Instance.AvatarTransform.localPosition = Vector3.zero;
PlayerSetup.Instance._avatar.transform.localRotation = Quaternion.identity; PlayerSetup.Instance.AvatarTransform.localRotation = Quaternion.identity;
} }
// Extensions // Extensions

View file

@ -2,6 +2,7 @@
using ABI_RC.Core.Networking.IO.Social; using ABI_RC.Core.Networking.IO.Social;
using ABI_RC.Core.Player; using ABI_RC.Core.Player;
using ABI_RC.Core.Savior; using ABI_RC.Core.Savior;
using ABI_RC.Core.Networking.IO.Instancing;
using ABI_RC.Systems.GameEventSystem; using ABI_RC.Systems.GameEventSystem;
using System; using System;
using System.Collections; using System.Collections;
@ -107,9 +108,9 @@ namespace ml_pin
bool ShouldNotifyInCurrentInstance() bool ShouldNotifyInCurrentInstance()
{ {
bool l_isInPublic = ((MetaPort.Instance.CurrentInstancePrivacyType == MetaPort.InstancePrivacy.Public) && Settings.NotifyInPublic); bool l_isInPublic = ((MetaPort.Instance.CurrentInstancePrivacyType == Instances.InstancePrivacyType.Public) && Settings.NotifyInPublic);
bool l_isInFriends = (((MetaPort.Instance.CurrentInstancePrivacyType == MetaPort.InstancePrivacy.Friends) || (MetaPort.Instance.CurrentInstancePrivacyType == MetaPort.InstancePrivacy.FriendsOfFriends)) && Settings.NotifyInFriends); bool l_isInFriends = (((MetaPort.Instance.CurrentInstancePrivacyType == Instances.InstancePrivacyType.Friends) || (MetaPort.Instance.CurrentInstancePrivacyType == Instances.InstancePrivacyType.FriendsOfFriends)) && Settings.NotifyInFriends);
bool l_isInPrivate = (((MetaPort.Instance.CurrentInstancePrivacyType == MetaPort.InstancePrivacy.EveryoneCanInvite) || (MetaPort.Instance.CurrentInstancePrivacyType == MetaPort.InstancePrivacy.OwnerMustInvite)) && Settings.NotifyInPrivate); bool l_isInPrivate = (((MetaPort.Instance.CurrentInstancePrivacyType == Instances.InstancePrivacyType.EveryoneCanInvite) || (MetaPort.Instance.CurrentInstancePrivacyType == Instances.InstancePrivacyType.OwnerMustInvite)) && Settings.NotifyInPrivate);
return (l_isInPublic || l_isInFriends || l_isInPrivate); return (l_isInPublic || l_isInFriends || l_isInPrivate);
} }
} }

View file

@ -81,32 +81,32 @@ namespace ml_pin
{ {
while(ViewManager.Instance == null) while(ViewManager.Instance == null)
yield return null; yield return null;
while(ViewManager.Instance.gameMenuView == null) while(ViewManager.Instance.cohtmlView == null)
yield return null; yield return null;
while(ViewManager.Instance.gameMenuView.Listener == null) while(ViewManager.Instance.cohtmlView.Listener == null)
yield return null; yield return null;
ViewManager.Instance.gameMenuView.Listener.ReadyForBindings += () => ViewManager.Instance.cohtmlView.Listener.ReadyForBindings += () =>
{ {
ViewManager.Instance.gameMenuView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate)); ViewManager.Instance.cohtmlView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate));
ViewManager.Instance.gameMenuView.View.BindCall("OnSliderUpdate_" + ms_category.Identifier, new Action<string, string>(OnSliderUpdate)); ViewManager.Instance.cohtmlView.View.BindCall("OnSliderUpdate_" + ms_category.Identifier, new Action<string, string>(OnSliderUpdate));
ViewManager.Instance.gameMenuView.View.BindCall("OnDropdownUpdate_" + ms_category.Identifier, new Action<string, string>(OnDropdownUpdate)); ViewManager.Instance.cohtmlView.View.BindCall("OnDropdownUpdate_" + ms_category.Identifier, new Action<string, string>(OnDropdownUpdate));
}; };
ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) => ViewManager.Instance.cohtmlView.Listener.FinishLoad += (_) =>
{ {
ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mods_extension.js")); ViewManager.Instance.cohtmlView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mods_extension.js"));
ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mod_menu.js")); ViewManager.Instance.cohtmlView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mod_menu.js"));
MelonLoader.MelonCoroutines.Start(UpdateMenuSettings()); MelonLoader.MelonCoroutines.Start(UpdateMenuSettings());
}; };
} }
static System.Collections.IEnumerator UpdateMenuSettings() static System.Collections.IEnumerator UpdateMenuSettings()
{ {
while(!ViewManager.Instance.IsReady || !ViewManager.Instance.IsMainMenuOpen) while(!ViewManager.Instance.IsReady || !ViewManager.Instance.IsViewShown)
yield return null; yield return null;
foreach(var l_entry in ms_entries) foreach(var l_entry in ms_entries)
ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString()); ViewManager.Instance.cohtmlView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString());
} }
static void OnToggleUpdate(string p_name, string p_value) static void OnToggleUpdate(string p_name, string p_value)

View file

@ -15,8 +15,6 @@ namespace ml_pmc
public void Invoke() => m_action?.Invoke(); public void Invoke() => m_action?.Invoke();
} }
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 OnAvatarPreReuse = new GameEvent();
public static readonly GameEvent OnAvatarPostReuse = new GameEvent(); public static readonly GameEvent OnAvatarPostReuse = new GameEvent();
@ -24,18 +22,6 @@ namespace ml_pmc
{ {
try try
{ {
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar), BindingFlags.Instance | BindingFlags.Public),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar), BindingFlags.Instance | BindingFlags.Public),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch( p_instance.Patch(
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public), 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_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
@ -48,30 +34,6 @@ namespace ml_pmc
} }
} }
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() static void OnAvatarReinitialize_Prefix()
{ {
try try

View file

@ -1,5 +1,7 @@
using ABI_RC.Core.Networking.IO.Social; using ABI.CCK.Components;
using ABI_RC.Core.Networking.IO.Social;
using ABI_RC.Core.Player; using ABI_RC.Core.Player;
using ABI_RC.Systems.GameEventSystem;
using ABI_RC.Systems.IK; using ABI_RC.Systems.IK;
using ABI_RC.Systems.IK.SubSystems; using ABI_RC.Systems.IK.SubSystems;
using ABI_RC.Systems.InputManagement; using ABI_RC.Systems.InputManagement;
@ -55,8 +57,8 @@ namespace ml_pmc
void Start() void Start()
{ {
GameEvents.OnAvatarClear.AddListener(this.OnAvatarClear); CVRGameEventSystem.Avatar.OnLocalAvatarClear.AddListener(this.OnAvatarClear);
GameEvents.OnAvatarSetup.AddListener(this.OnAvatarSetup); CVRGameEventSystem.Avatar.OnLocalAvatarLoad.AddListener(this.OnAvatarSetup);
GameEvents.OnAvatarPreReuse.AddListener(this.OnAvatarPreReuse); GameEvents.OnAvatarPreReuse.AddListener(this.OnAvatarPreReuse);
GameEvents.OnAvatarPostReuse.AddListener(this.OnAvatarPostReuse); GameEvents.OnAvatarPostReuse.AddListener(this.OnAvatarPostReuse);
@ -78,8 +80,8 @@ namespace ml_pmc
m_vrIk = null; m_vrIk = null;
m_lookAtIk = null; m_lookAtIk = null;
GameEvents.OnAvatarClear.RemoveListener(this.OnAvatarClear); CVRGameEventSystem.Avatar.OnLocalAvatarClear.RemoveListener(this.OnAvatarClear);
GameEvents.OnAvatarSetup.RemoveListener(this.OnAvatarSetup); CVRGameEventSystem.Avatar.OnLocalAvatarLoad.RemoveListener(this.OnAvatarSetup);
GameEvents.OnAvatarPreReuse.RemoveListener(this.OnAvatarPreReuse); GameEvents.OnAvatarPreReuse.RemoveListener(this.OnAvatarPreReuse);
GameEvents.OnAvatarPostReuse.RemoveListener(this.OnAvatarPostReuse); GameEvents.OnAvatarPostReuse.RemoveListener(this.OnAvatarPostReuse);
@ -110,7 +112,7 @@ namespace ml_pmc
m_fingerTracking = true; m_fingerTracking = true;
CVRInputManager.Instance.individualFingerTracking = true; CVRInputManager.Instance.individualFingerTracking = true;
IKSystem.Instance.FingerSystem.controlActive = true; IKSystem.Instance.FingerSystem.ControlActive = true;
ref readonly float[] l_curls = ref m_puppetParser.GetFingerCurls(); ref readonly float[] l_curls = ref m_puppetParser.GetFingerCurls();
ref readonly float[] l_spreads = ref m_puppetParser.GetFingerSpreads(); ref readonly float[] l_spreads = ref m_puppetParser.GetFingerSpreads();
@ -196,9 +198,9 @@ namespace ml_pmc
{ {
if(m_inVr) if(m_inVr)
{ {
Vector3 l_avatarPos = PlayerSetup.Instance._avatar.transform.position; Vector3 l_avatarPos = PlayerSetup.Instance.AvatarTransform.position;
PlayerSetup.Instance.transform.rotation = l_result.rotation; PlayerSetup.Instance.transform.rotation = l_result.rotation;
Vector3 l_dif = l_avatarPos - PlayerSetup.Instance._avatar.transform.position; Vector3 l_dif = l_avatarPos - PlayerSetup.Instance.AvatarTransform.position;
PlayerSetup.Instance.transform.position += l_dif; PlayerSetup.Instance.transform.position += l_dif;
} }
else else
@ -229,7 +231,9 @@ namespace ml_pmc
} }
// Game events // Game events
void OnAvatarClear() void OnAvatarClear(CVRAvatar p_avatar)
{
try
{ {
if(m_active) if(m_active)
{ {
@ -254,13 +258,20 @@ namespace ml_pmc
m_fingerTracking = false; m_fingerTracking = false;
m_pose = new HumanPose(); m_pose = new HumanPose();
} }
catch(System.Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
void OnAvatarSetup() void OnAvatarSetup(CVRAvatar p_avatar)
{
try
{ {
m_inVr = Utils.IsInVR(); m_inVr = Utils.IsInVR();
m_animator = PlayerSetup.Instance._animator; m_animator = PlayerSetup.Instance.Animator;
m_vrIk = PlayerSetup.Instance._avatar.GetComponent<VRIK>(); m_vrIk = PlayerSetup.Instance.AvatarObject.GetComponent<VRIK>();
m_lookAtIk = PlayerSetup.Instance._avatar.GetComponent<LookAtIK>(); m_lookAtIk = PlayerSetup.Instance.AvatarObject.GetComponent<LookAtIK>();
if((m_animator != null) && m_animator.isHuman) if((m_animator != null) && m_animator.isHuman)
{ {
@ -282,6 +293,11 @@ namespace ml_pmc
else else
m_animator = null; m_animator = null;
} }
catch(System.Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
void OnAvatarPreReuse() void OnAvatarPreReuse()
{ {
@ -293,8 +309,8 @@ namespace ml_pmc
m_inVr = Utils.IsInVR(); m_inVr = Utils.IsInVR();
// Old VRIK and LookAtIK are destroyed by game // Old VRIK and LookAtIK are destroyed by game
m_vrIk = PlayerSetup.Instance._avatar.GetComponent<VRIK>(); m_vrIk = PlayerSetup.Instance.AvatarObject.GetComponent<VRIK>();
m_lookAtIk = PlayerSetup.Instance._avatar.GetComponent<LookAtIK>(); m_lookAtIk = PlayerSetup.Instance.AvatarObject.GetComponent<LookAtIK>();
if(m_vrIk != null) if(m_vrIk != null)
{ {
@ -320,10 +336,10 @@ namespace ml_pmc
{ {
if(Friends.FriendsWith(p_id)) if(Friends.FriendsWith(p_id))
{ {
if(CVRPlayerManager.Instance.GetPlayerPuppetMaster(p_id, out PuppetMaster l_puppetMaster)) if(CVRPlayerManager.Instance.UserIdToPlayerEntity.TryGetValue(p_id, out CVRPlayerEntity l_playerEntity))
{ {
if(Utils.IsInSight(BetterBetterCharacterController.Instance.KinematicTriggerProxy.Collider, l_puppetMaster.GetComponent<CapsuleCollider>(), Utils.GetWorldMovementLimit())) if(Utils.IsInSight(BetterBetterCharacterController.Instance.KinematicTriggerProxy.Collider, l_playerEntity.PuppetMaster.GetComponent<CapsuleCollider>(), Utils.GetWorldMovementLimit()))
SetTarget(l_puppetMaster); SetTarget(l_playerEntity.PuppetMaster);
else else
ModUi.ShowAlert("Selected player is too far away or obstructed"); ModUi.ShowAlert("Selected player is too far away or obstructed");
} }
@ -374,9 +390,9 @@ namespace ml_pmc
{ {
if(!m_active) if(!m_active)
{ {
if((p_target != null) && (p_target.animatorManager != null) && (p_target.animatorManager.Animator != null) && p_target.animatorManager.Animator.isHuman) if((p_target != null) && (p_target.AnimatorManager != null) && (p_target.Animator != null) && p_target.Animator.isHuman)
{ {
m_puppetParser = p_target.animatorManager.Animator.gameObject.AddComponent<PuppetParser>(); m_puppetParser = p_target.Animator.gameObject.AddComponent<PuppetParser>();
m_puppetParser.m_puppetMaster = p_target; m_puppetParser.m_puppetMaster = p_target;
m_distanceLimit = Utils.GetWorldMovementLimit(); m_distanceLimit = Utils.GetWorldMovementLimit();
@ -425,7 +441,7 @@ namespace ml_pmc
void RestoreFingerTracking() void RestoreFingerTracking()
{ {
CVRInputManager.Instance.individualFingerTracking = (m_inVr && Utils.AreKnucklesInUse() && !CVRInputManager._moduleXR.SkeletalToggleValue); CVRInputManager.Instance.individualFingerTracking = (m_inVr && Utils.AreKnucklesInUse() && !CVRInputManager._moduleXR.SkeletalToggleValue);
IKSystem.Instance.FingerSystem.controlActive = CVRInputManager.Instance.individualFingerTracking; IKSystem.Instance.FingerSystem.ControlActive = CVRInputManager.Instance.individualFingerTracking;
if(!CVRInputManager.Instance.individualFingerTracking) if(!CVRInputManager.Instance.individualFingerTracking)
{ {

View file

@ -1,4 +1,4 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_pmc.PlayerMovementCopycat), "PlayerMovementCopycat", "1.1.1", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonInfo(typeof(ml_pmc.PlayerMovementCopycat), "PlayerMovementCopycat", "1.1.2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
[assembly: MelonLoader.MelonPriority(3)] [assembly: MelonLoader.MelonPriority(3)]
[assembly: MelonLoader.MelonAdditionalDependencies("BTKUILib")] [assembly: MelonLoader.MelonAdditionalDependencies("BTKUILib")]

View file

@ -1,4 +1,5 @@
using ABI.CCK.Components; using ABI.CCK.Components;
using ABI_RC.Core;
using ABI_RC.Core.Savior; using ABI_RC.Core.Savior;
using ABI_RC.Systems.InputManagement; using ABI_RC.Systems.InputManagement;
using System.Collections.Generic; using System.Collections.Generic;
@ -86,9 +87,9 @@ namespace ml_pmc
List<RaycastHit> l_hits = Physics.RaycastAll(l_ray, p_limit).ToList(); List<RaycastHit> l_hits = Physics.RaycastAll(l_ray, p_limit).ToList();
if(l_hits.Count > 0) 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 == CVRLayers.UIInternal); // 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 == CVRLayers.PlayerLocal);
l_hits.RemoveAll(hit => hit.collider.gameObject.layer == LayerMask.NameToLayer("PlayerClone")); l_hits.RemoveAll(hit => hit.collider.gameObject.layer == CVRLayers.PlayerClone);
l_hits.Sort((a, b) => ((a.distance < b.distance) ? -1 : 1)); l_hits.Sort((a, b) => ((a.distance < b.distance) ? -1 : 1));
l_result = (l_hits[0].collider.gameObject.transform.root == p_target.transform.root); l_result = (l_hits[0].collider.gameObject.transform.root == p_target.transform.root);
} }

View file

@ -7,7 +7,7 @@
<Authors>SDraw</Authors> <Authors>SDraw</Authors>
<Company>SDraw</Company> <Company>SDraw</Company>
<Product>PlayerMovementCopycat</Product> <Product>PlayerMovementCopycat</Product>
<Version>1.1.1</Version> <Version>1.1.2</Version>
<AssemblyName>PlayerMovementCopycat</AssemblyName> <AssemblyName>PlayerMovementCopycat</AssemblyName>
</PropertyGroup> </PropertyGroup>
@ -23,6 +23,7 @@
<ItemGroup> <ItemGroup>
<None Remove="resources\dancing.png" /> <None Remove="resources\dancing.png" />
<None Remove="resources\dancing_on.png" /> <None Remove="resources\dancing_on.png" />
<None Remove="Utils.cs~RFd8ec2a.TMP" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -23,8 +23,6 @@ namespace ml_ppu
public void Invoke(T1 p_obj) => m_action?.Invoke(p_obj); 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<float> OnIKScaling = new GameEvent<float>(); public static readonly GameEvent<float> OnIKScaling = new GameEvent<float>();
public static readonly GameEvent OnWorldPreSpawn = new GameEvent(); public static readonly GameEvent OnWorldPreSpawn = new GameEvent();
public static readonly GameEvent<CVRSeat> OnSeatPreSit = new GameEvent<CVRSeat>(); public static readonly GameEvent<CVRSeat> OnSeatPreSit = new GameEvent<CVRSeat>();
@ -33,18 +31,6 @@ namespace ml_ppu
{ {
try try
{ {
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar), BindingFlags.Instance | BindingFlags.Public),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static |BindingFlags.NonPublic))
);
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar), BindingFlags.Instance | BindingFlags.Public),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch( p_instance.Patch(
typeof(PlayerSetup).GetMethod("SetupIKScaling", BindingFlags.Instance | BindingFlags.NonPublic), typeof(PlayerSetup).GetMethod("SetupIKScaling", BindingFlags.Instance | BindingFlags.NonPublic),
null, null,
@ -69,30 +55,6 @@ namespace ml_ppu
} }
} }
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 OnSetupIKScaling_Postfix(ref UnityEngine.Vector3 ___scaleDifference) static void OnSetupIKScaling_Postfix(ref UnityEngine.Vector3 ___scaleDifference)
{ {
try try

View file

@ -1,6 +1,8 @@
using ABI.CCK.Components; using ABI.CCK.Components;
using ABI_RC.Core;
using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.InteractionSystem;
using ABI_RC.Core.Player; using ABI_RC.Core.Player;
using ABI_RC.Systems.GameEventSystem;
using ABI_RC.Systems.IK; using ABI_RC.Systems.IK;
using ABI_RC.Systems.Movement; using ABI_RC.Systems.Movement;
using UnityEngine; using UnityEngine;
@ -45,8 +47,8 @@ namespace ml_ppu
void Start() void Start()
{ {
GameEvents.OnAvatarSetup.AddListener(this.OnAvatarSetup); CVRGameEventSystem.Avatar.OnLocalAvatarLoad.AddListener(this.OnAvatarSetup);
GameEvents.OnAvatarClear.AddListener(this.OnAvatarClear); CVRGameEventSystem.Avatar.OnLocalAvatarClear.AddListener(this.OnAvatarClear);
GameEvents.OnIKScaling.AddListener(this.OnIKScaling); GameEvents.OnIKScaling.AddListener(this.OnIKScaling);
GameEvents.OnWorldPreSpawn.AddListener(this.OnWorldPreSpawn); GameEvents.OnWorldPreSpawn.AddListener(this.OnWorldPreSpawn);
GameEvents.OnSeatPreSit.AddListener(this.OnSeatPreSit); GameEvents.OnSeatPreSit.AddListener(this.OnSeatPreSit);
@ -59,8 +61,8 @@ namespace ml_ppu
if(Instance == this) if(Instance == this)
Instance = null; Instance = null;
GameEvents.OnAvatarSetup.RemoveListener(this.OnAvatarSetup); CVRGameEventSystem.Avatar.OnLocalAvatarLoad.RemoveListener(this.OnAvatarSetup);
GameEvents.OnAvatarClear.RemoveListener(this.OnAvatarClear); CVRGameEventSystem.Avatar.OnLocalAvatarClear.RemoveListener(this.OnAvatarClear);
GameEvents.OnIKScaling.RemoveListener(this.OnIKScaling); GameEvents.OnIKScaling.RemoveListener(this.OnIKScaling);
GameEvents.OnWorldPreSpawn.RemoveListener(this.OnWorldPreSpawn); GameEvents.OnWorldPreSpawn.RemoveListener(this.OnWorldPreSpawn);
GameEvents.OnSeatPreSit.RemoveListener(this.OnSeatPreSit); GameEvents.OnSeatPreSit.RemoveListener(this.OnSeatPreSit);
@ -81,7 +83,7 @@ namespace ml_ppu
} }
Vector3 l_armsMidPoint = (m_armLeft.position + m_armRight.position) * 0.5f; Vector3 l_armsMidPoint = (m_armLeft.position + m_armRight.position) * 0.5f;
Quaternion l_avatarRot = PlayerSetup.Instance._avatar.transform.rotation; Quaternion l_avatarRot = PlayerSetup.Instance.AvatarTransform.rotation;
m_collider.transform.position = Vector3.zero; m_collider.transform.position = Vector3.zero;
m_collider.transform.rotation = Quaternion.identity; m_collider.transform.rotation = Quaternion.identity;
@ -125,14 +127,16 @@ namespace ml_ppu
} }
} }
void OnAvatarSetup() void OnAvatarSetup(CVRAvatar p_avatar)
{ {
Animator l_animator = PlayerSetup.Instance._animator; try
{
Animator l_animator = PlayerSetup.Instance.Animator;
if((l_animator != null) && l_animator.isHuman) if((l_animator != null) && l_animator.isHuman)
{ {
IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose); IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose);
PlayerSetup.Instance._avatar.transform.localPosition = Vector3.zero; PlayerSetup.Instance.AvatarTransform.localPosition = Vector3.zero;
PlayerSetup.Instance._avatar.transform.localRotation = Quaternion.identity; PlayerSetup.Instance.AvatarTransform.localRotation = Quaternion.identity;
m_hips = l_animator.GetBoneTransform(HumanBodyBones.Hips); m_hips = l_animator.GetBoneTransform(HumanBodyBones.Hips);
m_armLeft = l_animator.GetBoneTransform(HumanBodyBones.LeftUpperArm); m_armLeft = l_animator.GetBoneTransform(HumanBodyBones.LeftUpperArm);
@ -140,11 +144,12 @@ namespace ml_ppu
if((m_hips != null) && (m_armLeft != null) && (m_armRight != null)) if((m_hips != null) && (m_armLeft != null) && (m_armRight != null))
{ {
Matrix4x4 l_avatarMatInv = PlayerSetup.Instance._avatar.transform.GetMatrix().inverse; Matrix4x4 l_avatarMatInv = PlayerSetup.Instance.AvatarTransform.GetMatrix().inverse;
Vector3 l_hipsPos = (l_avatarMatInv * m_hips.GetMatrix()).GetPosition(); Vector3 l_hipsPos = (l_avatarMatInv * m_hips.GetMatrix()).GetPosition();
Vector3 l_armPos = (l_avatarMatInv * m_armLeft.GetMatrix()).GetPosition(); Vector3 l_armPos = (l_avatarMatInv * m_armLeft.GetMatrix()).GetPosition();
m_collider = new GameObject("[Collider]").AddComponent<CapsuleCollider>(); m_collider = new GameObject("[Collider]").AddComponent<CapsuleCollider>();
m_collider.gameObject.layer = CVRLayers.PassPlayer;
m_collider.transform.parent = this.transform; m_collider.transform.parent = this.transform;
m_collider.isTrigger = true; m_collider.isTrigger = true;
m_collider.height = Vector3.Distance(l_hipsPos, new Vector3(0f, l_armPos.y, l_armPos.z)); m_collider.height = Vector3.Distance(l_hipsPos, new Vector3(0f, l_armPos.y, l_armPos.z));
@ -156,8 +161,15 @@ namespace ml_ppu
} }
} }
} }
catch(System.Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
void OnAvatarClear() void OnAvatarClear(CVRAvatar p_avatar)
{
try
{ {
m_ready = false; m_ready = false;
m_held = false; m_held = false;
@ -172,6 +184,11 @@ namespace ml_ppu
m_holderPointB = null; m_holderPointB = null;
m_holderPointerB = null; m_holderPointerB = null;
} }
catch(System.Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
void OnIKScaling(float p_scale) void OnIKScaling(float p_scale)
{ {

View file

@ -1,4 +1,4 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_ppu.PlayerPickUp), "PlayerPickUp", "1.0.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonInfo(typeof(ml_ppu.PlayerPickUp), "PlayerPickUp", "1.0.1", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
[assembly: MelonLoader.MelonOptionalDependencies("PlayerRagdollMod")] [assembly: MelonLoader.MelonOptionalDependencies("PlayerRagdollMod")]
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]

View file

@ -1,5 +1,6 @@
using ABI_RC.Core; using ABI_RC.Core;
using ABI_RC.Core.Player; using ABI_RC.Core.Player;
using ABI_RC.Core.Savior;
using ABI_RC.Systems.Movement; using ABI_RC.Systems.Movement;
using ABI_RC.Systems.Safety.AdvancedSafety; using ABI_RC.Systems.Safety.AdvancedSafety;
using UnityEngine; using UnityEngine;
@ -8,6 +9,8 @@ namespace ml_ppu
{ {
static class Utils static class Utils
{ {
public static bool IsInVR() => ((MetaPort.Instance != null) && MetaPort.Instance.isUsingVr);
public static Matrix4x4 GetMatrix(this Transform p_transform, bool p_pos = true, bool p_rot = true, bool p_scl = false) public static Matrix4x4 GetMatrix(this Transform p_transform, bool p_pos = true, bool p_rot = true, bool p_scl = false)
{ {
return Matrix4x4.TRS(p_pos ? p_transform.position : Vector3.zero, p_rot ? p_transform.rotation : Quaternion.identity, p_scl ? p_transform.lossyScale : Vector3.one); return Matrix4x4.TRS(p_pos ? p_transform.position : Vector3.zero, p_rot ? p_transform.rotation : Quaternion.identity, p_scl ? p_transform.lossyScale : Vector3.one);

View file

@ -5,6 +5,7 @@
<Platforms>x64</Platforms> <Platforms>x64</Platforms>
<AssemblyName>PlayerPickUp</AssemblyName> <AssemblyName>PlayerPickUp</AssemblyName>
<Authors>SDraw</Authors> <Authors>SDraw</Authors>
<Version>1.0.1</Version>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

View file

@ -1,43 +0,0 @@
using ABI_RC.Core.Util.AnimatorManager;
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 AvatarAnimatorManager m_manager = null;
public AvatarBoolParameter(string p_name, AvatarAnimatorManager 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_sync = !l_param.name.StartsWith('#');
m_hash = l_param.nameHash;
break;
}
}
}
public void SetValue(bool p_value)
{
if(m_hash != 0)
{
if(m_sync)
m_manager.SetParameter(m_name, p_value);
else
m_manager.Animator.SetBool(m_hash, p_value);
}
}
}
}

109
ml_prm/AvatarParameter.cs Normal file
View file

@ -0,0 +1,109 @@
using ABI_RC.Core.Util.AnimatorManager;
using System.Text.RegularExpressions;
using UnityEngine;
namespace ml_prm
{
class AvatarParameter
{
public readonly string m_name;
public readonly int m_hash = 0;
public readonly bool m_sync;
public readonly AnimatorControllerParameterType m_type;
readonly AvatarAnimatorManager m_manager = null;
public AvatarParameter(string p_name, AvatarAnimatorManager 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))
{
m_name = l_param.name;
m_sync = !l_param.name.StartsWith('#');
m_hash = l_param.nameHash;
m_type = l_param.type;
break;
}
}
}
public void SetValue(bool p_value)
{
if(m_hash != 0)
{
if(m_sync)
m_manager.SetParameter(m_name, p_value);
else
{
switch(m_type)
{
case AnimatorControllerParameterType.Bool:
case AnimatorControllerParameterType.Trigger:
m_manager.Animator.SetBool(m_hash, p_value);
break;
case AnimatorControllerParameterType.Int:
m_manager.Animator.SetInteger(m_hash, p_value ? 1 : 0);
break;
case AnimatorControllerParameterType.Float:
m_manager.Animator.SetFloat(m_hash, p_value ? 1f : 0f);
break;
}
}
}
}
public void SetValue(int p_value)
{
if(m_hash != 0)
{
if(m_sync)
m_manager.SetParameter(m_name, p_value);
else
{
switch(m_type)
{
case AnimatorControllerParameterType.Bool:
case AnimatorControllerParameterType.Trigger:
m_manager.Animator.SetBool(m_hash, p_value > 0);
break;
case AnimatorControllerParameterType.Int:
m_manager.Animator.SetInteger(m_hash, p_value);
break;
case AnimatorControllerParameterType.Float:
m_manager.Animator.SetFloat(m_hash, p_value);
break;
}
}
}
}
public void SetValue(float p_value)
{
if(m_hash != 0)
{
if(m_sync)
m_manager.SetParameter(m_name, p_value);
else
{
switch(m_type)
{
case AnimatorControllerParameterType.Bool:
case AnimatorControllerParameterType.Trigger:
m_manager.Animator.SetBool(m_hash, p_value > 0f);
break;
case AnimatorControllerParameterType.Int:
m_manager.Animator.SetInteger(m_hash, (int)p_value);
break;
case AnimatorControllerParameterType.Float:
m_manager.Animator.SetFloat(m_hash, p_value);
break;
}
}
}
}
}
}

View file

@ -32,8 +32,6 @@ namespace ml_prm
public void Invoke(T1 p_obj) => m_action?.Invoke(p_obj); 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 OnAvatarPreReuse = new GameEvent();
public static readonly GameEvent OnAvatarPostReuse = new GameEvent(); public static readonly GameEvent OnAvatarPostReuse = new GameEvent();
public static readonly GameEvent<float> OnIKScaling = new GameEvent<float>(); public static readonly GameEvent<float> OnIKScaling = new GameEvent<float>();
@ -50,18 +48,6 @@ namespace ml_prm
{ {
try try
{ {
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar), BindingFlags.Instance | BindingFlags.Public),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static |BindingFlags.NonPublic))
);
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar), BindingFlags.Instance | BindingFlags.Public),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch( p_instance.Patch(
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public), 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_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
@ -108,30 +94,12 @@ namespace ml_prm
typeof(IKSystem).GetMethod("OnPreSolverUpdateActiveOffset", BindingFlags.Instance | BindingFlags.NonPublic), typeof(IKSystem).GetMethod("OnPreSolverUpdateActiveOffset", BindingFlags.Instance | BindingFlags.NonPublic),
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnOffsetUpdate_Prefix), BindingFlags.Static | 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() p_instance.Patch(
{ typeof(ControllerRay).GetMethod("UpdateInteractionMask", BindingFlags.Instance | BindingFlags.NonPublic),
try null,
{ new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnControllerRayUpdateInteractionMask_Prefix), BindingFlags.Static | BindingFlags.NonPublic))
OnAvatarClear.Invoke(); );
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnSetupAvatar_Postfix()
{
try
{
OnAvatarSetup.Invoke();
} }
catch(Exception e) catch(Exception e)
{ {
@ -248,5 +216,10 @@ namespace ml_prm
} }
return !ms_result.m_result; return !ms_result.m_result;
} }
static void OnControllerRayUpdateInteractionMask_Prefix(ControllerRay __instance)
{
__instance.generalMask &= ~(1 << CVRLayers.PlayerClone);
}
} }
} }

View file

@ -1,8 +1,4 @@
using ABI_RC.Core.Player; using ABI_RC.Core.Util.AssetFiltering;
using ABI_RC.Core.Util.AssetFiltering;
using System;
using System.Collections.Generic;
using System.Reflection;
namespace ml_prm namespace ml_prm
{ {
@ -27,7 +23,6 @@ namespace ml_prm
yield return null; yield return null;
m_controller = new UnityEngine.GameObject("[PlayerRagdollMod]").AddComponent<RagdollController>(); m_controller = new UnityEngine.GameObject("[PlayerRagdollMod]").AddComponent<RagdollController>();
m_controller.gameObject.AddComponent<RemoteGesturesManager>();
} }
System.Collections.IEnumerator WaitForWhitelist() System.Collections.IEnumerator WaitForWhitelist()

View file

@ -36,8 +36,7 @@ namespace ml_prm
RecoverDelay, RecoverDelay,
FallLimit, FallLimit,
GestureGrab, GestureGrab,
FriendsGrab, FriendsGrab
GrabDistance
} }
const string c_ragdollKeyTooltip = "Switch ragdoll mode with '{0}' key"; const string c_ragdollKeyTooltip = "Switch ragdoll mode with '{0}' key";
@ -69,7 +68,6 @@ namespace ml_prm
static SliderFloat ms_angularMovementDragSlider = null; static SliderFloat ms_angularMovementDragSlider = null;
static SliderFloat ms_recoverDelaySlider = null; static SliderFloat ms_recoverDelaySlider = null;
static SliderFloat ms_fallLimitSlider = null; static SliderFloat ms_fallLimitSlider = null;
static SliderFloat ms_grabDistanceSlider = null;
static Button ms_resetButton = null; static Button ms_resetButton = null;
internal static void Init() internal static void Init()
@ -145,9 +143,6 @@ namespace ml_prm
ms_fallLimitSlider.SliderTooltip = string.Format(c_fallLimitTooltip, GetDropHeight(Settings.FallLimit)); ms_fallLimitSlider.SliderTooltip = string.Format(c_fallLimitTooltip, GetDropHeight(Settings.FallLimit));
ms_fallLimitSlider.OnValueUpdated += (value) => OnSliderUpdate(UiIndex.FallLimit, value); ms_fallLimitSlider.OnValueUpdated += (value) => OnSliderUpdate(UiIndex.FallLimit, value);
ms_grabDistanceSlider = ms_category.AddSlider("Grab distance", "Minimal distance for successful grab", Settings.GrabDistance, 0f, 1f);
ms_grabDistanceSlider.OnValueUpdated += (value) => OnSliderUpdate(UiIndex.GrabDistance, value);
ms_resetButton = ms_category.AddButton("Reset settings", "", "Reset mod settings to default"); ms_resetButton = ms_category.AddButton("Reset settings", "", "Reset mod settings to default");
ms_resetButton.OnPress += Reset; ms_resetButton.OnPress += Reset;
} }
@ -261,10 +256,6 @@ namespace ml_prm
ms_fallLimitSlider.SliderTooltip = string.Format(c_fallLimitTooltip, GetDropHeight(p_value)); ms_fallLimitSlider.SliderTooltip = string.Format(c_fallLimitTooltip, GetDropHeight(p_value));
} }
break; break;
case UiIndex.GrabDistance:
Settings.SetSetting(Settings.ModSetting.GrabDistance, p_value);
break;
} }
} }
catch(Exception e) catch(Exception e)
@ -331,9 +322,6 @@ namespace ml_prm
OnSliderUpdate(UiIndex.FallLimit, 9.899494f); OnSliderUpdate(UiIndex.FallLimit, 9.899494f);
ms_fallLimitSlider.SetSliderValue(9.899494f); ms_fallLimitSlider.SetSliderValue(9.899494f);
OnSliderUpdate(UiIndex.GrabDistance, 0.1f);
ms_grabDistanceSlider.SetSliderValue(0.1f);
} }
static void OnHotkeyKeyChanged(UnityEngine.KeyCode p_keyCode) static void OnHotkeyKeyChanged(UnityEngine.KeyCode p_keyCode)

View file

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

View file

@ -41,7 +41,6 @@ Optional mod's settings page with [BTKUILib](https://github.com/BTK-Development/
* **Angular movement drag:** angular movement resistance; `2.0` by default. * **Angular movement drag:** angular movement resistance; `2.0` by default.
* **Recover delay:** time delay for enabled `Auto recover` in seconds; `3.0` by default. * **Recover delay:** time delay for enabled `Auto recover` in seconds; `3.0` by default.
* **Fall limit:** height limit for fall damage; `5.0` by default. * **Fall limit:** height limit for fall damage; `5.0` by default.
* **Grab distance:** minimal distance for successful grab; `0.1` by default.
* **Reset settings:** resets mod settings to default. * **Reset settings:** resets mod settings to default.
Optional mod's settings in [UIExpansionKit](https://github.com/ddakebono/ChilloutMods): Optional mod's settings in [UIExpansionKit](https://github.com/ddakebono/ChilloutMods):

View file

@ -1,4 +1,6 @@
using ABI.CCK.Components; using ABI.CCK.Components;
using ABI_RC.Core;
using ABI_RC.Core.Networking.IO.Social;
using ABI_RC.Core.Player; using ABI_RC.Core.Player;
using ABI_RC.Core.Savior; using ABI_RC.Core.Savior;
using ABI_RC.Systems.Movement; using ABI_RC.Systems.Movement;
@ -10,24 +12,24 @@ namespace ml_prm
class RagdollBodypartHandler : MonoBehaviour, CVRTriggerVolume class RagdollBodypartHandler : MonoBehaviour, CVRTriggerVolume
{ {
const string c_ragdollPointerType = "ragdoll"; const string c_ragdollPointerType = "ragdoll";
const string c_grabPointerType = "grab";
bool m_ready = false;
Rigidbody m_rigidBody = null; Rigidbody m_rigidBody = null;
public Collider collider { get; set; } = null; public Collider collider { get; set; } = null;
PhysicsInfluencer m_physicsInfluencer = null;
bool m_shouldHaveInfluencer = false; PhysicsInfluencer m_physicsInfluencer = null;
bool m_activeGravity = true; public bool UseBuoyancy { get; set; } = false;
bool m_attached = false; bool m_attached = false;
Transform m_attachedHand = null; CVRPointer m_attachedPointer = null;
Transform m_attachTransform = null; Transform m_attachTransform = null;
FixedJoint m_attachJoint = null; FixedJoint m_attachJoint = null;
// Unity events // Unity events
void Awake() void Awake()
{ {
this.gameObject.layer = LayerMask.NameToLayer("PlayerLocal");
collider = this.GetComponent<Collider>(); collider = this.GetComponent<Collider>();
m_rigidBody = this.GetComponent<Rigidbody>(); m_rigidBody = this.GetComponent<Rigidbody>();
@ -40,30 +42,25 @@ namespace ml_prm
} }
if(collider != null) if(collider != null)
{ RemoveGameCollision();
Physics.IgnoreCollision(collider, BetterBetterCharacterController.Instance.Collider, true);
Physics.IgnoreCollision(collider, BetterBetterCharacterController.Instance.KinematicTriggerProxy.Collider, true);
Physics.IgnoreCollision(collider, BetterBetterCharacterController.Instance.NonKinematicProxy.Collider, true);
Physics.IgnoreCollision(collider, BetterBetterCharacterController.Instance.SphereProxy.Collider, true);
BetterBetterCharacterController.Instance.IgnoreCollision(collider, true);
}
} }
void Start() void Start()
{ {
if(m_shouldHaveInfluencer && (m_rigidBody != null) && (collider != null)) if((m_rigidBody != null) && (collider != null))
{ {
m_physicsInfluencer = this.gameObject.AddComponent<PhysicsInfluencer>(); m_physicsInfluencer = this.gameObject.AddComponent<PhysicsInfluencer>();
m_physicsInfluencer.fluidDrag = 3f; m_physicsInfluencer.fluidDrag = 3f;
m_physicsInfluencer.fluidAngularDrag = 1f; m_physicsInfluencer.fluidAngularDrag = 1f;
m_physicsInfluencer.enableBuoyancy = true; m_physicsInfluencer.enableInfluence = true;
m_physicsInfluencer.enableInfluence = false;
m_physicsInfluencer.forceAlignUpright = false;
float mass = m_rigidBody.mass;
m_physicsInfluencer.UpdateDensity();
m_rigidBody.mass = mass;
m_physicsInfluencer.volume = mass * 0.005f;
m_physicsInfluencer.enableLocalGravity = true; m_physicsInfluencer.enableLocalGravity = true;
m_physicsInfluencer.enableBuoyancy = true;
m_physicsInfluencer.forceAlignUpright = false;
float l_mass = m_rigidBody.mass;
m_physicsInfluencer.UpdateDensity();
m_rigidBody.mass = l_mass;
m_physicsInfluencer.volume = l_mass * 0.005f;
this.gameObject.name = string.Format("{0} [NoGizmo]", this.gameObject.name); this.gameObject.name = string.Format("{0} [NoGizmo]", this.gameObject.name);
} }
@ -83,45 +80,36 @@ namespace ml_prm
Detach(); Detach();
} }
void FixedUpdate()
{
if(m_rigidBody != null)
{
m_rigidBody.useGravity = false;
if(!m_attached && m_activeGravity && ((m_physicsInfluencer == null) || !m_physicsInfluencer.enableInfluence || !m_physicsInfluencer.GetSubmerged()))
m_rigidBody.AddForce(BetterBetterCharacterController.Instance.GravityResult.AppliedGravity * m_rigidBody.mass);
}
}
void Update() void Update()
{ {
if(m_attached && !ReferenceEquals(m_attachTransform, null) && (m_attachTransform == null)) if(m_attached && ((m_attachedPointer == null) || !m_attachedPointer.isActiveAndEnabled))
{ Detach();
m_attachTransform = null;
if(m_attachJoint != null)
Object.Destroy(m_attachJoint);
m_attachJoint = null;
m_attachedHand = null;
m_attached = false;
}
} }
void OnTriggerEnter(Collider p_col) void OnTriggerEnter(Collider p_col)
{ {
if(Settings.PointersReaction && (RagdollController.Instance != null) && !RagdollController.Instance.IsRagdolled()) if(m_ready && (RagdollController.Instance != null))
{ {
CVRPointer l_pointer = p_col.GetComponent<CVRPointer>(); CVRPointer l_pointer = p_col.GetComponent<CVRPointer>();
if((l_pointer != null) && (l_pointer.type == c_ragdollPointerType) && l_pointer.enabled && !IsIgnored(l_pointer.transform))
// Ragdolling
if(Settings.PointersReaction && !RagdollController.Instance.IsRagdolled())
{
if((l_pointer != null) && (l_pointer.type == c_ragdollPointerType) && l_pointer.enabled && !IgnoreCheck(l_pointer.transform))
RagdollController.Instance.Ragdoll(); RagdollController.Instance.Ragdoll();
} }
//Attachment
if(!m_attached && RagdollController.Instance.IsRagdolled())
{
if((l_pointer != null) && (l_pointer.type == c_grabPointerType) && RestrictionsCheck(p_col.transform.root))
Attach(l_pointer);
}
}
} }
// Arbitrary // Arbitrary
public bool IsReady() => ((m_rigidBody != null) && (collider != null) && (!m_shouldHaveInfluencer || ((m_physicsInfluencer != null) && m_physicsInfluencer.IsReady()))); public bool IsReady() => ((m_rigidBody != null) && (collider != null) && (m_physicsInfluencer != null) && m_physicsInfluencer.IsReady());
public void SetInfuencerUsage(bool p_state) => m_shouldHaveInfluencer = p_state;
public void SetColliderMaterial(PhysicMaterial p_material) public void SetColliderMaterial(PhysicMaterial p_material)
{ {
@ -134,13 +122,15 @@ namespace ml_prm
public void SetAsKinematic(bool p_state) public void SetAsKinematic(bool p_state)
{ {
if(collider != null)
collider.isTrigger = p_state;
if(m_rigidBody != null) if(m_rigidBody != null)
{ {
m_rigidBody.isKinematic = p_state; m_rigidBody.isKinematic = p_state;
m_rigidBody.collisionDetectionMode = (p_state ? CollisionDetectionMode.Discrete : CollisionDetectionMode.ContinuousDynamic); m_rigidBody.collisionDetectionMode = (p_state ? CollisionDetectionMode.Discrete : CollisionDetectionMode.ContinuousDynamic);
} }
if(collider != null)
collider.isTrigger = p_state;
if(m_physicsInfluencer != null)
m_physicsInfluencer.enabled = !p_state;
} }
public void SetVelocity(Vector3 p_vec) public void SetVelocity(Vector3 p_vec)
@ -157,10 +147,8 @@ namespace ml_prm
public void SetActiveGravity(bool p_state) public void SetActiveGravity(bool p_state)
{ {
m_activeGravity = p_state;
if(m_physicsInfluencer != null) if(m_physicsInfluencer != null)
m_physicsInfluencer.enabled = m_activeGravity; m_physicsInfluencer.gravityFactor = (p_state ? 1f : 0f);
} }
public void SetDrag(float p_value) public void SetDrag(float p_value)
@ -188,7 +176,7 @@ namespace ml_prm
public void SetBuoyancy(bool p_state) public void SetBuoyancy(bool p_state)
{ {
if(m_physicsInfluencer != null) if(m_physicsInfluencer != null)
m_physicsInfluencer.enableInfluence = p_state; m_physicsInfluencer.enableBuoyancy = (UseBuoyancy && p_state);
} }
public void ClearFluidVolumes() public void ClearFluidVolumes()
@ -197,21 +185,27 @@ namespace ml_prm
m_physicsInfluencer.ClearFluidVolumes(); m_physicsInfluencer.ClearFluidVolumes();
} }
static bool IsIgnored(Transform p_transform) internal void RemovePhysicsController()
{ {
return (Settings.IgnoreLocal && (p_transform.root == PlayerSetup.Instance.transform)); if(this.gameObject.TryGetComponent<CVRSharedPhysicsController>(out var l_controller))
{
Object.Destroy(l_controller); // Yeet!
m_ready = true;
}
if(collider != null)
RemoveGameCollision();
} }
public bool Attach(Transform p_hand, Vector3 p_pos) void Attach(CVRPointer p_pointer)
{ {
bool l_result = false; if(!m_attached && (collider != null) && (m_rigidBody != null))
{
m_attachedPointer = p_pointer;
if(!m_attached && (collider != null) && (Vector3.Distance(p_pos, collider.ClosestPoint(p_pos)) <= Settings.GrabDistance))
{
GameObject l_attachPoint = new GameObject("[AttachPoint]"); GameObject l_attachPoint = new GameObject("[AttachPoint]");
l_attachPoint.layer = CVRLayers.PlayerNetwork;
m_attachTransform = l_attachPoint.transform; m_attachTransform = l_attachPoint.transform;
m_attachTransform.parent = p_hand; m_attachTransform.parent = p_pointer.transform;
m_attachTransform.position = p_pos;
Rigidbody l_body = l_attachPoint.AddComponent<Rigidbody>(); Rigidbody l_body = l_attachPoint.AddComponent<Rigidbody>();
l_body.isKinematic = true; l_body.isKinematic = true;
@ -223,16 +217,12 @@ namespace ml_prm
m_attachJoint.breakTorque = Mathf.Infinity; m_attachJoint.breakTorque = Mathf.Infinity;
m_attached = true; m_attached = true;
m_attachedHand = p_hand;
l_result = true;
} }
return l_result;
} }
public void Detach() => Detach(m_attachedHand); public void Detach()
public void Detach(Transform p_hand)
{ {
if(m_attached && ReferenceEquals(m_attachedHand, p_hand)) if(m_attached)
{ {
if(m_attachTransform != null) if(m_attachTransform != null)
Object.Destroy(m_attachTransform.gameObject); Object.Destroy(m_attachTransform.gameObject);
@ -242,19 +232,46 @@ namespace ml_prm
Object.Destroy(m_attachJoint); Object.Destroy(m_attachJoint);
m_attachJoint = null; m_attachJoint = null;
m_attachedHand = null; m_attachedPointer = null;
m_attached = false; m_attached = false;
} }
} }
void RemoveGameCollision()
{
Physics.IgnoreCollision(collider, BetterBetterCharacterController.Instance.Collider, true);
Physics.IgnoreCollision(collider, BetterBetterCharacterController.Instance.KinematicTriggerProxy.Collider, true);
Physics.IgnoreCollision(collider, BetterBetterCharacterController.Instance.NonKinematicProxy.Collider, true);
Physics.IgnoreCollision(collider, BetterBetterCharacterController.Instance.SphereProxy.Collider, true);
BetterBetterCharacterController.Instance.IgnoreCollision(collider);
}
// CVRTriggerVolume // CVRTriggerVolume
public void TriggerEnter(CVRPointer pointer) public void TriggerEnter(CVRPointer pointer)
{ {
if(Settings.PointersReaction && (pointer != null) && pointer.enabled && (pointer.type == c_ragdollPointerType) && !IsIgnored(pointer.transform) && (RagdollController.Instance != null) && !RagdollController.Instance.IsRagdolled()) if(Settings.PointersReaction && (pointer != null) && pointer.enabled && (pointer.type == c_ragdollPointerType) && !IgnoreCheck(pointer.transform) && (RagdollController.Instance != null) && !RagdollController.Instance.IsRagdolled())
RagdollController.Instance.Ragdoll(); RagdollController.Instance.Ragdoll();
} }
public void TriggerExit(CVRPointer pointer) public void TriggerExit(CVRPointer pointer)
{ {
} }
// Static utility
static bool IgnoreCheck(Transform p_transform)
{
return (Settings.IgnoreLocal && (p_transform.root == PlayerSetup.Instance.transform));
}
static bool RestrictionsCheck(Transform p_transform)
{
if(p_transform == PlayerSetup.Instance.transform)
return false;
PlayerDescriptor l_playerDescriptor = p_transform.GetComponent<PlayerDescriptor>();
if(l_playerDescriptor != null)
return (!Settings.FriendsGrab || Friends.FriendsWith(l_playerDescriptor.ownerId));
return false;
}
} }
} }

View file

@ -1,6 +1,8 @@
using ABI.CCK.Components; using ABI.CCK.Components;
using ABI_RC.Core;
using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.InteractionSystem;
using ABI_RC.Core.Player; using ABI_RC.Core.Player;
using ABI_RC.Systems.GameEventSystem;
using ABI_RC.Systems.IK; using ABI_RC.Systems.IK;
using ABI_RC.Systems.IK.SubSystems; using ABI_RC.Systems.IK.SubSystems;
using ABI_RC.Systems.InputManagement; using ABI_RC.Systems.InputManagement;
@ -39,7 +41,7 @@ namespace ml_prm
readonly List<System.Tuple<CharacterJoint, Vector3>> m_jointAnchors = null; readonly List<System.Tuple<CharacterJoint, Vector3>> m_jointAnchors = null;
RagdollToggle m_avatarRagdollToggle = null; // Custom component available for editor RagdollToggle m_avatarRagdollToggle = null; // Custom component available for editor
AvatarBoolParameter m_ragdolledParameter = null; AvatarParameter m_ragdolledParameter = null;
PhysicMaterial m_physicsMaterial = null; PhysicMaterial m_physicsMaterial = null;
bool m_inAir = false; bool m_inAir = false;
@ -75,7 +77,7 @@ namespace ml_prm
void Start() void Start()
{ {
this.gameObject.layer = LayerMask.NameToLayer("PlayerLocal"); this.gameObject.layer = CVRLayers.PlayerClone;
m_physicsMaterial = new PhysicMaterial("Ragdoll"); m_physicsMaterial = new PhysicMaterial("Ragdoll");
m_physicsMaterial.dynamicFriction = c_defaultFriction; m_physicsMaterial.dynamicFriction = c_defaultFriction;
@ -98,8 +100,8 @@ namespace ml_prm
Settings.OnFallDamageChanged.AddListener(this.OnFallDamageChanged); Settings.OnFallDamageChanged.AddListener(this.OnFallDamageChanged);
Settings.OnGestureGrabChanged.AddListener(this.OnGestureGrabChanged); Settings.OnGestureGrabChanged.AddListener(this.OnGestureGrabChanged);
GameEvents.OnAvatarClear.AddListener(this.OnAvatarClear); CVRGameEventSystem.Avatar.OnLocalAvatarClear.AddListener(this.OnAvatarClear);
GameEvents.OnAvatarSetup.AddListener(this.OnAvatarSetup); CVRGameEventSystem.Avatar.OnLocalAvatarLoad.AddListener(this.OnAvatarSetup);
GameEvents.OnAvatarPreReuse.AddListener(this.OnAvatarPreReuse); GameEvents.OnAvatarPreReuse.AddListener(this.OnAvatarPreReuse);
GameEvents.OnAvatarPostReuse.AddListener(this.OnAvatarPostReuse); GameEvents.OnAvatarPostReuse.AddListener(this.OnAvatarPostReuse);
GameEvents.OnIKScaling.AddListener(this.OnAvatarScaling); GameEvents.OnIKScaling.AddListener(this.OnAvatarScaling);
@ -112,7 +114,6 @@ namespace ml_prm
BetterBetterCharacterController.OnTeleport.AddListener(this.OnPlayerTeleport); BetterBetterCharacterController.OnTeleport.AddListener(this.OnPlayerTeleport);
ModUi.OnSwitchChanged.AddListener(this.SwitchRagdoll); ModUi.OnSwitchChanged.AddListener(this.SwitchRagdoll);
RemoteGesturesManager.OnGestureState.AddListener(this.OnRemoteGestureStateChanged);
} }
void OnDestroy() void OnDestroy()
@ -147,8 +148,8 @@ namespace ml_prm
Settings.OnFallDamageChanged.RemoveListener(this.OnFallDamageChanged); Settings.OnFallDamageChanged.RemoveListener(this.OnFallDamageChanged);
Settings.OnGestureGrabChanged.RemoveListener(this.OnGestureGrabChanged); Settings.OnGestureGrabChanged.RemoveListener(this.OnGestureGrabChanged);
GameEvents.OnAvatarClear.RemoveListener(this.OnAvatarClear); CVRGameEventSystem.Avatar.OnLocalAvatarClear.RemoveListener(this.OnAvatarClear);
GameEvents.OnAvatarSetup.RemoveListener(this.OnAvatarSetup); CVRGameEventSystem.Avatar.OnLocalAvatarLoad.RemoveListener(this.OnAvatarSetup);
GameEvents.OnAvatarPreReuse.RemoveListener(this.OnAvatarPreReuse); GameEvents.OnAvatarPreReuse.RemoveListener(this.OnAvatarPreReuse);
GameEvents.OnAvatarPostReuse.RemoveListener(this.OnAvatarPostReuse); GameEvents.OnAvatarPostReuse.RemoveListener(this.OnAvatarPostReuse);
GameEvents.OnIKScaling.RemoveListener(this.OnAvatarScaling); GameEvents.OnIKScaling.RemoveListener(this.OnAvatarScaling);
@ -161,7 +162,6 @@ namespace ml_prm
BetterBetterCharacterController.OnTeleport.RemoveListener(this.OnPlayerTeleport); BetterBetterCharacterController.OnTeleport.RemoveListener(this.OnPlayerTeleport);
ModUi.OnSwitchChanged.RemoveListener(this.SwitchRagdoll); ModUi.OnSwitchChanged.RemoveListener(this.SwitchRagdoll);
RemoteGesturesManager.OnGestureState.RemoveListener(this.OnRemoteGestureStateChanged);
} }
void Update() void Update()
@ -194,7 +194,7 @@ namespace ml_prm
BodySystem.TrackingPositionWeight = 0f; BodySystem.TrackingPositionWeight = 0f;
BetterBetterCharacterController.Instance.PauseGroundConstraint(); BetterBetterCharacterController.Instance.PauseGroundConstraint();
BetterBetterCharacterController.Instance.ResetAllForces(); BetterBetterCharacterController.Instance.ResetAllForces();
PlayerSetup.Instance.animatorManager.CancelEmote = true; PlayerSetup.Instance.AnimatorManager.CancelEmote = true;
} }
if(!m_ragdolled && !m_reachedGround && (BetterBetterCharacterController.Instance.IsOnGround() || BetterBetterCharacterController.Instance.IsInWater() || BetterBetterCharacterController.Instance.IsSitting())) if(!m_ragdolled && !m_reachedGround && (BetterBetterCharacterController.Instance.IsOnGround() || BetterBetterCharacterController.Instance.IsInWater() || BetterBetterCharacterController.Instance.IsSitting()))
@ -251,7 +251,9 @@ namespace ml_prm
} }
// Game events // Game events
void OnAvatarClear() void OnAvatarClear(CVRAvatar p_avatar)
{
try
{ {
if(m_initTask != null) if(m_initTask != null)
{ {
@ -287,18 +289,29 @@ namespace ml_prm
m_puppet.localScale = Vector3.one; m_puppet.localScale = Vector3.one;
m_inAir = false; m_inAir = false;
} }
catch(System.Exception e)
void OnAvatarSetup()
{ {
if(PlayerSetup.Instance._animator.isHuman) MelonLoader.MelonLogger.Error(e);
{ }
m_avatarTransform = PlayerSetup.Instance._avatar.transform; }
m_hips = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Hips);
Utils.SetAvatarTPose();
BipedRagdollReferences l_avatarReferences = BipedRagdollReferences.FromAvatar(PlayerSetup.Instance._animator); void OnAvatarSetup(CVRAvatar p_avatar)
{
try
{
if(PlayerSetup.Instance.Animator.isHuman)
{
m_avatarTransform = PlayerSetup.Instance.AvatarTransform;
m_hips = PlayerSetup.Instance.Animator.GetBoneTransform(HumanBodyBones.Hips);
IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose);
PlayerSetup.Instance.AvatarTransform.localPosition = Vector3.zero;
PlayerSetup.Instance.AvatarTransform.localRotation = Quaternion.identity;
BipedRagdollReferences l_avatarReferences = BipedRagdollReferences.FromAvatar(PlayerSetup.Instance.Animator);
m_puppetRoot = new GameObject("Root").transform; m_puppetRoot = new GameObject("Root").transform;
m_puppetRoot.gameObject.layer = CVRLayers.PlayerClone;
m_puppetRoot.parent = m_puppet; m_puppetRoot.parent = m_puppet;
m_puppetRoot.position = m_avatarTransform.position; m_puppetRoot.position = m_avatarTransform.position;
m_puppetRoot.rotation = m_avatarTransform.rotation; m_puppetRoot.rotation = m_avatarTransform.rotation;
@ -356,7 +369,7 @@ namespace ml_prm
if((l_body != null) && (l_collider != null)) if((l_body != null) && (l_collider != null))
{ {
RagdollBodypartHandler l_handler = l_puppetTransforms[i].gameObject.AddComponent<RagdollBodypartHandler>(); RagdollBodypartHandler l_handler = l_puppetTransforms[i].gameObject.AddComponent<RagdollBodypartHandler>();
l_handler.SetInfuencerUsage(Utils.IsInEnumeration(l_puppetTransforms[i], l_influencedTransforms)); l_handler.UseBuoyancy = Utils.IsObjectInArray(l_puppetTransforms[i], l_influencedTransforms);
m_ragdollBodyHandlers.Add(l_handler); m_ragdollBodyHandlers.Add(l_handler);
} }
@ -365,16 +378,21 @@ namespace ml_prm
} }
} }
m_vrIK = PlayerSetup.Instance._avatar.GetComponent<VRIK>(); m_vrIK = PlayerSetup.Instance.AvatarObject.GetComponent<VRIK>();
if(m_vrIK != null) if(m_vrIK != null)
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostSolverUpdate); m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostSolverUpdate);
m_avatarRagdollToggle = PlayerSetup.Instance._avatar.GetComponentInChildren<RagdollToggle>(true); m_avatarRagdollToggle = PlayerSetup.Instance.AvatarObject.GetComponentInChildren<RagdollToggle>(true);
m_ragdolledParameter = new AvatarBoolParameter("Ragdolled", PlayerSetup.Instance.animatorManager); m_ragdolledParameter = new AvatarParameter("Ragdolled", PlayerSetup.Instance.AnimatorManager);
m_initTask = StartCoroutine(WaitForBodyHandlers()); m_initTask = StartCoroutine(WaitForBodyHandlers());
} }
} }
catch(System.Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
IEnumerator WaitForBodyHandlers() IEnumerator WaitForBodyHandlers()
{ {
@ -383,6 +401,7 @@ namespace ml_prm
foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers) foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
{ {
l_handler.RemovePhysicsController();
l_handler.SetAsKinematic(true); l_handler.SetAsKinematic(true);
l_handler.SetColliderMaterial(m_physicsMaterial); l_handler.SetColliderMaterial(m_physicsMaterial);
} }
@ -408,7 +427,7 @@ namespace ml_prm
} }
void OnAvatarPostReuse() void OnAvatarPostReuse()
{ {
m_vrIK = PlayerSetup.Instance._avatar.GetComponent<VRIK>(); m_vrIK = PlayerSetup.Instance.AvatarObject.GetComponent<VRIK>();
if(m_vrIK != null) if(m_vrIK != null)
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostSolverUpdate); m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostSolverUpdate);
@ -501,31 +520,6 @@ namespace ml_prm
p_result.m_result |= (m_ragdolled && (m_vrIK != null)); p_result.m_result |= (m_ragdolled && (m_vrIK != null));
} }
// Custom game events
void OnRemoteGestureStateChanged(ABI_RC.Core.Player.PuppetMaster p_master, RemoteGesturesManager.GestureHand p_hand, bool p_state)
{
if(m_avatarReady && m_ragdolled && Settings.GestureGrab && (p_master.animatorManager.Animator != null))
{
Transform l_hand = p_master.animatorManager.Animator.GetBoneTransform((p_hand == RemoteGesturesManager.GestureHand.Left) ? HumanBodyBones.LeftHand : HumanBodyBones.RightHand);
Transform l_finger = p_master.animatorManager.Animator.GetBoneTransform((p_hand == RemoteGesturesManager.GestureHand.Left) ? HumanBodyBones.LeftMiddleProximal : HumanBodyBones.RightMiddleProximal);
if(l_hand != null)
{
Vector3 l_pos = (l_finger != null) ? ((l_hand.position + l_finger.position) * 0.5f) : l_hand.position;
foreach(var l_bodyHandler in m_ragdollBodyHandlers)
{
if(p_state)
{
if(l_bodyHandler.Attach(l_hand, l_pos))
break;
}
else
l_bodyHandler.Detach(l_hand);
}
}
}
}
// VRIK updates // VRIK updates
void OnIKPostSolverUpdate() void OnIKPostSolverUpdate()
{ {
@ -640,7 +634,7 @@ namespace ml_prm
if(Settings.ViewVelocity && WorldManager.IsSafeWorld()) if(Settings.ViewVelocity && WorldManager.IsSafeWorld())
{ {
float l_mag = l_velocity.magnitude; float l_mag = l_velocity.magnitude;
l_velocity = PlayerSetup.Instance.GetActiveCamera().transform.forward * l_mag; l_velocity = PlayerSetup.Instance.activeCam.transform.forward * l_mag;
} }
Vector3 l_playerPos = PlayerSetup.Instance.transform.position; Vector3 l_playerPos = PlayerSetup.Instance.transform.position;
@ -664,7 +658,7 @@ namespace ml_prm
m_applyHipsRotation = IKSystem.Instance.applyOriginalHipRotation; m_applyHipsRotation = IKSystem.Instance.applyOriginalHipRotation;
IKSystem.Instance.applyOriginalHipRotation = true; IKSystem.Instance.applyOriginalHipRotation = true;
PlayerSetup.Instance.animatorManager.CancelEmote = true; PlayerSetup.Instance.AnimatorManager.CancelEmote = true;
m_ragdolledParameter.SetValue(true); m_ragdolledParameter.SetValue(true);
if(!WorldManager.IsSafeWorld()) if(!WorldManager.IsSafeWorld())
@ -781,6 +775,7 @@ namespace ml_prm
static Transform CloneTransform(Transform p_source, Transform p_parent, string p_name) static Transform CloneTransform(Transform p_source, Transform p_parent, string p_name)
{ {
Transform l_target = new GameObject(p_name).transform; Transform l_target = new GameObject(p_name).transform;
l_target.gameObject.layer = CVRLayers.PlayerClone;
l_target.parent = p_parent; l_target.parent = p_parent;
p_source.CopyGlobal(l_target); p_source.CopyGlobal(l_target);
return l_target; return l_target;

View file

@ -1,148 +0,0 @@
using ABI_RC.Core.Networking.IO.Social;
using ABI_RC.Core.Player;
using ABI_RC.Systems.GameEventSystem;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace ml_prm
{
[DisallowMultipleComponent]
class RemoteGesturesManager : MonoBehaviour
{
public enum GestureHand
{
Left = 0,
Right
}
internal class GestureEvent<T1, T2, T3>
{
event Action<T1, T2, T3> m_action;
public void AddListener(Action<T1, T2, T3> p_listener) => m_action += p_listener;
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
{
public CVRPlayerEntity m_entity = null;
public PuppetMaster m_puppetMaster = null;
public bool m_stateLeft = false;
public bool m_stateRight = false;
}
static RemoteGesturesManager ms_instance = null;
readonly List<PlayerEntry> m_entries = null;
internal RemoteGesturesManager()
{
m_entries = new List<PlayerEntry>();
}
void Awake()
{
if(ms_instance != null)
{
DestroyImmediate(this);
return;
}
ms_instance = this;
DontDestroyOnLoad(this);
}
void Start()
{
CVRGameEventSystem.Player.OnJoinEntity.AddListener(OnRemotePlayerCreated);
CVRGameEventSystem.Player.OnLeaveEntity.AddListener(OnRemotePlayerDestroyed);
Settings.OnGestureGrabChanged.AddListener(OnGestureGrabChanged);
}
void OnDestroy()
{
if(ms_instance == this)
ms_instance = null;
m_entries.Clear();
CVRGameEventSystem.Player.OnJoinEntity.RemoveListener(OnRemotePlayerCreated);
CVRGameEventSystem.Player.OnLeaveEntity.RemoveListener(OnRemotePlayerDestroyed);
Settings.OnGestureGrabChanged.RemoveListener(OnGestureGrabChanged);
}
void Update()
{
if(Settings.GestureGrab)
{
foreach(var l_entry in m_entries)
{
bool l_state = l_entry.m_puppetMaster.IsLeftGrabPointerActive();
if(l_entry.m_stateLeft != l_state)
{
l_entry.m_stateLeft = l_state;
if(!Settings.FriendsGrab || Friends.FriendsWith(l_entry.m_entity.PlayerDescriptor.ownerId))
OnGestureState.Invoke(l_entry.m_puppetMaster, GestureHand.Left, l_entry.m_stateLeft);
}
l_state = l_entry.m_puppetMaster.IsRightGrabPointerActive();
if(l_entry.m_stateRight != l_state)
{
l_entry.m_stateRight = l_state;
if(!Settings.FriendsGrab || Friends.FriendsWith(l_entry.m_entity.PlayerDescriptor.ownerId))
OnGestureState.Invoke(l_entry.m_puppetMaster, GestureHand.Right, l_entry.m_stateRight);
}
}
}
}
void OnRemotePlayerCreated(CVRPlayerEntity p_player)
{
try
{
if((p_player != null) && (p_player.PuppetMaster != null))
{
PlayerEntry l_entry = new PlayerEntry()
{
m_entity = p_player,
m_puppetMaster = p_player.PuppetMaster,
m_stateLeft = false,
m_stateRight = false
};
m_entries.Add(l_entry);
}
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
void OnRemotePlayerDestroyed(CVRPlayerEntity p_player)
{
try
{
if(p_player != null)
m_entries.RemoveAll(e => ReferenceEquals(e.m_puppetMaster, p_player.PuppetMaster));
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
void OnGestureGrabChanged(bool p_state)
{
if(!p_state)
{
foreach(var l_entry in m_entries)
{
l_entry.m_stateLeft = false;
l_entry.m_stateRight = false;
}
}
}
}
}

View file

@ -35,8 +35,7 @@ namespace ml_prm
FallDamage, FallDamage,
FallLimit, FallLimit,
GestureGrab, GestureGrab,
FriendsGrab, FriendsGrab
GrabDistance
} }
public static bool Hotkey { get; private set; } = true; public static bool Hotkey { get; private set; } = true;
@ -111,8 +110,7 @@ namespace ml_prm
ms_category.CreateEntry(ModSetting.FallDamage.ToString(), FallDamage, null, null, true), ms_category.CreateEntry(ModSetting.FallDamage.ToString(), FallDamage, null, null, true),
ms_category.CreateEntry(ModSetting.FallLimit.ToString(), FallLimit, null, null, true), ms_category.CreateEntry(ModSetting.FallLimit.ToString(), FallLimit, null, null, true),
ms_category.CreateEntry(ModSetting.GestureGrab.ToString(), GestureGrab, null, null, true), ms_category.CreateEntry(ModSetting.GestureGrab.ToString(), GestureGrab, null, null, true),
ms_category.CreateEntry(ModSetting.FriendsGrab.ToString(), FriendsGrab, null, null, true), ms_category.CreateEntry(ModSetting.FriendsGrab.ToString(), FriendsGrab, null, null, true)
ms_category.CreateEntry(ModSetting.GrabDistance.ToString(), GrabDistance, null, null, true),
}; };
ms_entries[(int)ModSetting.HotkeyKey].OnEntryValueChangedUntyped.Subscribe(OnMelonSettingSave_HotkeyKey); ms_entries[(int)ModSetting.HotkeyKey].OnEntryValueChangedUntyped.Subscribe(OnMelonSettingSave_HotkeyKey);
@ -137,7 +135,6 @@ namespace ml_prm
FallLimit = Mathf.Clamp((float)ms_entries[(int)ModSetting.FallLimit].BoxedValue, 4.5f, 44.5f); FallLimit = Mathf.Clamp((float)ms_entries[(int)ModSetting.FallLimit].BoxedValue, 4.5f, 44.5f);
GestureGrab = (bool)ms_entries[(int)ModSetting.GestureGrab].BoxedValue; GestureGrab = (bool)ms_entries[(int)ModSetting.GestureGrab].BoxedValue;
FriendsGrab = (bool)ms_entries[(int)ModSetting.FriendsGrab].BoxedValue; FriendsGrab = (bool)ms_entries[(int)ModSetting.FriendsGrab].BoxedValue;
GrabDistance = Mathf.Clamp01((float)ms_entries[(int)ModSetting.GrabDistance].BoxedValue);
} }
static void OnMelonSettingSave_HotkeyKey(object p_oldValue, object p_newValue) static void OnMelonSettingSave_HotkeyKey(object p_oldValue, object p_newValue)
@ -296,13 +293,6 @@ namespace ml_prm
OnFallLimitChanged.Invoke(FallLimit); OnFallLimitChanged.Invoke(FallLimit);
} }
break; break;
case ModSetting.GrabDistance:
{
GrabDistance = (float)p_value;
OnGrabDistanceChanged.Invoke(GrabDistance);
}
break;
} }
if(ms_entries != null) if(ms_entries != null)

View file

@ -7,7 +7,6 @@ using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using UnityEngine; using UnityEngine;
using System.Linq; using System.Linq;
using ABI_RC.Systems.IK.SubSystems;
using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.InteractionSystem;
namespace ml_prm namespace ml_prm
@ -22,12 +21,6 @@ namespace ml_prm
public static void ClearFluidVolumes(this BetterBetterCharacterController p_instance) => (ms_touchingVolumes?.GetValue(p_instance) as List<FluidVolume>)?.Clear(); public static void ClearFluidVolumes(this BetterBetterCharacterController p_instance) => (ms_touchingVolumes?.GetValue(p_instance) as List<FluidVolume>)?.Clear();
public static void CopyGlobal(this Transform p_source, Transform p_target)
{
p_target.position = p_source.position;
p_target.rotation = p_source.rotation;
}
public static bool IsReady(this PhysicsInfluencer p_instance) public static bool IsReady(this PhysicsInfluencer p_instance)
{ {
return ((ms_referencePoints.GetValue(p_instance) as List<Vector3>).Count > 0); return ((ms_referencePoints.GetValue(p_instance) as List<Vector3>).Count > 0);
@ -38,27 +31,15 @@ namespace ml_prm
(ms_influencerSubmergedColliders.GetValue(p_instance) as Dictionary<FluidVolume, int>)?.Clear(); (ms_influencerSubmergedColliders.GetValue(p_instance) as Dictionary<FluidVolume, int>)?.Clear();
} }
public static void SetAvatarTPose() public static bool IsObjectInArray(object p_obj, object[] p_enumeration) => p_enumeration.Contains(p_obj);
{
IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose);
PlayerSetup.Instance._avatar.transform.localPosition = Vector3.zero;
PlayerSetup.Instance._avatar.transform.localRotation = Quaternion.identity;
}
public static bool IsInEnumeration(object p_obj, object[] p_enumeration) => p_enumeration.Contains(p_obj);
public static bool IsLeftGrabPointerActive(this PuppetMaster p_source)
{
return p_source._playerAvatarMovementDataCurrent.IsLeftHandGrabbing();
}
public static bool IsRightGrabPointerActive(this PuppetMaster p_source)
{
return p_source._playerAvatarMovementDataCurrent.IsRightHandGrabbing();
}
public static CVRSeat GetCurrentSeat(this BetterBetterCharacterController p_instance) => (ms_lastCVRSeat?.GetValue(p_instance) as CVRSeat); 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)); // Unity specific
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

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

View file

@ -60,31 +60,31 @@ namespace ml_vei
{ {
while(ViewManager.Instance == null) while(ViewManager.Instance == null)
yield return null; yield return null;
while(ViewManager.Instance.gameMenuView == null) while(ViewManager.Instance.cohtmlView == null)
yield return null; yield return null;
while(ViewManager.Instance.gameMenuView.Listener == null) while(ViewManager.Instance.cohtmlView.Listener == null)
yield return null; yield return null;
ViewManager.Instance.gameMenuView.Listener.ReadyForBindings += () => ViewManager.Instance.cohtmlView.Listener.ReadyForBindings += () =>
{ {
ViewManager.Instance.gameMenuView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate)); ViewManager.Instance.cohtmlView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate));
ViewManager.Instance.gameMenuView.View.BindCall("OnDropdownUpdate_" + ms_category.Identifier, new Action<string, string>(OnDropdownUpdate)); ViewManager.Instance.cohtmlView.View.BindCall("OnDropdownUpdate_" + ms_category.Identifier, new Action<string, string>(OnDropdownUpdate));
}; };
ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) => ViewManager.Instance.cohtmlView.Listener.FinishLoad += (_) =>
{ {
ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mods_extension.js")); ViewManager.Instance.cohtmlView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mods_extension.js"));
ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mod_menu.js")); ViewManager.Instance.cohtmlView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mod_menu.js"));
MelonLoader.MelonCoroutines.Start(UpdateMenuSettings()); MelonLoader.MelonCoroutines.Start(UpdateMenuSettings());
}; };
} }
static System.Collections.IEnumerator UpdateMenuSettings() static System.Collections.IEnumerator UpdateMenuSettings()
{ {
while(!ViewManager.Instance.IsReady || !ViewManager.Instance.IsMainMenuOpen) while(!ViewManager.Instance.IsReady || !ViewManager.Instance.IsViewShown)
yield return null; yield return null;
foreach(var l_entry in ms_entries) foreach(var l_entry in ms_entries)
ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString()); ViewManager.Instance.cohtmlView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString());
} }
static void OnToggleUpdate(string p_name, string p_value) static void OnToggleUpdate(string p_name, string p_value)

View file

@ -174,9 +174,12 @@ namespace ml_vet
if(p_controller.IsLocal && IsReadyForUpdate()) if(p_controller.IsLocal && IsReadyForUpdate())
{ {
p_controller.manualBlinking = true; p_controller.manualBlinking = true;
#if NIGHTLY_BUILD
p_controller.blinkProgressLeft = 1f - m_openness.x; p_controller.blinkProgressLeft = 1f - m_openness.x;
p_controller.blinkProgressRight = 1f - m_openness.y; p_controller.blinkProgressRight = 1f - m_openness.y;
#else
p_controller.blinkProgress = 1f - (m_openness.x + m_openness.y) * 0.5f;
#endif
p_controller.manualViewTarget = true; p_controller.manualViewTarget = true;
Vector3 l_gazePoint = m_gazePoint; Vector3 l_gazePoint = m_gazePoint;

View file

@ -54,31 +54,31 @@ namespace ml_vet
{ {
while(ViewManager.Instance == null) while(ViewManager.Instance == null)
yield return null; yield return null;
while(ViewManager.Instance.gameMenuView == null) while(ViewManager.Instance.cohtmlView == null)
yield return null; yield return null;
while(ViewManager.Instance.gameMenuView.Listener == null) while(ViewManager.Instance.cohtmlView.Listener == null)
yield return null; yield return null;
ViewManager.Instance.gameMenuView.Listener.ReadyForBindings += () => ViewManager.Instance.cohtmlView.Listener.ReadyForBindings += () =>
{ {
ViewManager.Instance.gameMenuView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate)); ViewManager.Instance.cohtmlView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate));
ViewManager.Instance.gameMenuView.View.BindCall("OnSliderUpdate_" + ms_category.Identifier, new Action<string, string>(OnSliderUpdate)); ViewManager.Instance.cohtmlView.View.BindCall("OnSliderUpdate_" + ms_category.Identifier, new Action<string, string>(OnSliderUpdate));
}; };
ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) => ViewManager.Instance.cohtmlView.Listener.FinishLoad += (_) =>
{ {
ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mods_extension.js")); ViewManager.Instance.cohtmlView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mods_extension.js"));
ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mod_menu.js")); ViewManager.Instance.cohtmlView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mod_menu.js"));
MelonLoader.MelonCoroutines.Start(UpdateMenuSettings()); MelonLoader.MelonCoroutines.Start(UpdateMenuSettings());
}; };
} }
static System.Collections.IEnumerator UpdateMenuSettings() static System.Collections.IEnumerator UpdateMenuSettings()
{ {
while(!ViewManager.Instance.IsReady || !ViewManager.Instance.IsMainMenuOpen) while(!ViewManager.Instance.IsReady || !ViewManager.Instance.IsViewShown)
yield return null; yield return null;
foreach(var l_entry in ms_entries) foreach(var l_entry in ms_entries)
ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString()); ViewManager.Instance.cohtmlView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString());
} }
static void OnToggleUpdate(string p_name, string p_value) static void OnToggleUpdate(string p_name, string p_value)

View file

@ -14,6 +14,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DebugType>embedded</DebugType> <DebugType>embedded</DebugType>
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DefineConstants>TRACE;NIGHTLY_BUILD</DefineConstants>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View file

@ -1,4 +1,4 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_vpc.VideoPlayerCookies), "VideoPlayerCookies", "1.0.1", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonInfo(typeof(ml_vpc.VideoPlayerCookies), "VideoPlayerCookies", "1.0.2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)] [assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]

View file

@ -6,7 +6,7 @@
<AssemblyName>VideoPlayerCookies</AssemblyName> <AssemblyName>VideoPlayerCookies</AssemblyName>
<Authors>SDraw</Authors> <Authors>SDraw</Authors>
<Company>SDraw</Company> <Company>SDraw</Company>
<Version>1.0.1</Version> <Version>1.0.2</Version>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">