diff --git a/README.md b/README.md index e30a555..3ec094a 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,15 @@ Merged set of MelonLoader mods for ChilloutVR. -**Table for game build 2023r175:** -| Full name | Short name | Latest version | -|:---------:|:----------:|:--------------:| -| [Avatar Motion Tweaker](/ml_amt/README.md) | ml_amt | 1.4.1 [:arrow_down:](../../releases/latest/download/ml_amt.dll)| -| [Avatar Synced Look](/ml_asl/README.md) | ml_asl | 1.0.4 [:arrow_down:](../../releases/latest/download/ml_asl.dll)| -| [Better Fingers Tracking](/ml_bft/README.md) | ml_bft | 1.0.4 [:arrow_down:](../../releases/latest/download/ml_bft.dll)| -| [Desktop Head Tracking](/ml_dht/README.md) | ml_dht | 1.2.5 [:arrow_down:](../../releases/latest/download/ml_dht.dll)| -| [Leap Motion Extension](/ml_lme/README.md)| ml_lme | 1.5.2 [:arrow_down:](../../releases/latest/download/ml_lme.dll)| -| [Pickup Arm Movement](/ml_pam/README.md)| ml_pam | 1.1.4 [:arrow_down:](../../releases/latest/download/ml_pam.dll)| -| [Player Movement Copycat](/ml_pmc/README.md)| ml_pmc | 1.0.8 [:arrow_down:](../../releases/latest/download/ml_pmc.dll)| -| [Player Ragdoll Mod](/ml_prm/README.md) | ml_prm | 1.1.9 [:arrow_down:](../../releases/latest/download/ml_prm.dll)| -| [Players Instance Notifier](/ml_pin/README.md) | ml_pin | 1.0.8 [:arrow_down:](../../releases/latest/download/ml_ml_pin.dll)| -| [Vive Extended Input](/ml_vei/README.md) | ml_vei | 1.0.4 [:arrow_down:](../../releases/latest/download/ml_vei.dll)| - -**Archived mods:** -| Full name | Short name | Notes | -|:---------:|:----------:|-------| -| Avatar Change Info | ml_aci | Superseded by `Extended Game Notifications` | -| Desktop Reticle Switch | ml_drs | Boring functionality | -| Extended Game Notifications | ml_egn | In-game feature since 2023r172 update | -| Four Point Tracking | ml_fpt | In-game feature since 2022r170 update | -| Game Main Fixes | ml_gmf | In-game feature since 2023r172 update | -| Server Connection Info | ml_sci | Superseded by `Extended Game Notifications` +**Table for game build 2023r177:** +| Full name | Latest version | +|:---------:|:--------------:| +|[Avatar Motion Tweaker](/ml_amt/README.md)|1.5.0 [:arrow_down:](../../releases/latest/download/ml_amt.dll)| +|[Avatar Synced Look](/ml_asl/README.md)|1.1.0 [:arrow_down:](../../releases/latest/download/ml_asl.dll)| +|[Better Fingers Tracking](/ml_bft/README.md)|1.1.0 [:arrow_down:](../../releases/latest/download/ml_bft.dll)| +|[Desktop Head Tracking](/ml_dht/README.md)|1.3.0 [:arrow_down:](../../releases/latest/download/ml_dht.dll)| +|[Leap Motion Extension](/ml_lme/README.md)| 1.6.0 [:arrow_down:](../../releases/latest/download/ml_lme.dll)| +|[Pickup Arm Movement](/ml_pam/README.md)|1.2.0 [:arrow_down:](../../releases/latest/download/ml_pam.dll)| +|[Player Movement Copycat](/ml_pmc/README.md)|1.1.0 [:arrow_down:](../../releases/latest/download/ml_pmc.dll)| +|[Player Ragdoll Mod](/ml_prm/README.md)|1.2.0 [:arrow_down:](../../releases/latest/download/ml_prm.dll)| +|[Players Instance Notifier](/ml_pin/README.md)|1.1.0 [:arrow_down:](../../releases/latest/download/ml_ml_pin.dll)| +|[Vive Extended Input](/ml_vei/README.md)|1.1.0 [:arrow_down:](../../releases/latest/download/ml_vei.dll)| diff --git a/ml_amt/MotionTweaker.cs b/ml_amt/MotionTweaker.cs index 8e10389..9c01ef5 100644 --- a/ml_amt/MotionTweaker.cs +++ b/ml_amt/MotionTweaker.cs @@ -11,7 +11,7 @@ namespace ml_amt [DisallowMultipleComponent] class MotionTweaker : MonoBehaviour { - struct IKState + struct IKInfo { public float m_weight; public float m_locomotionWeight; @@ -20,7 +20,9 @@ struct IKState public bool m_bendNormalRight; } - IKState m_ikState; + static MotionTweaker ms_instance = null; + + IKInfo m_ikInfo; VRIK m_vrIk = null; float m_avatarScale = 1f; Vector3 m_locomotionOffset = Vector3.zero; // Original locomotion offset @@ -37,10 +39,19 @@ internal MotionTweaker() } // Unity events - void Start() + void Awake() { - DontDestroyOnLoad(this); + if(ms_instance != null) + { + DestroyImmediate(this); + return; + } + ms_instance = this; + DontDestroyOnLoad(this); + } + void Start() + { OnCrouchLimitChanged(Settings.CrouchLimit); OnProneLimitChanged(Settings.ProneLimit); @@ -56,6 +67,9 @@ void Start() void OnDestroy() { + if(ms_instance == this) + ms_instance = null; + m_vrIk = null; m_ikLimits = null; m_parameters.Clear(); @@ -170,11 +184,11 @@ void OnAvatarReuse() // IK events void OnIKPreSolverUpdate() { - m_ikState.m_weight = m_vrIk.solver.IKPositionWeight; - m_ikState.m_locomotionWeight = m_vrIk.solver.locomotion.weight; - m_ikState.m_plantFeet = m_vrIk.solver.plantFeet; - m_ikState.m_bendNormalLeft = m_vrIk.solver.leftLeg.useAnimatedBendNormal; - m_ikState.m_bendNormalRight = m_vrIk.solver.rightLeg.useAnimatedBendNormal; + m_ikInfo.m_weight = m_vrIk.solver.IKPositionWeight; + m_ikInfo.m_locomotionWeight = m_vrIk.solver.locomotion.weight; + m_ikInfo.m_plantFeet = m_vrIk.solver.plantFeet; + m_ikInfo.m_bendNormalLeft = m_vrIk.solver.leftLeg.useAnimatedBendNormal; + m_ikInfo.m_bendNormalRight = m_vrIk.solver.rightLeg.useAnimatedBendNormal; if(!BodySystem.isCalibratedAsFullBody) { @@ -200,11 +214,11 @@ void OnIKPreSolverUpdate() void OnIKPostSolverUpdate() { - m_vrIk.solver.IKPositionWeight = m_ikState.m_weight; - m_vrIk.solver.locomotion.weight = m_ikState.m_locomotionWeight; - m_vrIk.solver.plantFeet = m_ikState.m_plantFeet; - m_vrIk.solver.leftLeg.useAnimatedBendNormal = m_ikState.m_bendNormalLeft; - m_vrIk.solver.rightLeg.useAnimatedBendNormal = m_ikState.m_bendNormalRight; + m_vrIk.solver.IKPositionWeight = m_ikInfo.m_weight; + m_vrIk.solver.locomotion.weight = m_ikInfo.m_locomotionWeight; + m_vrIk.solver.plantFeet = m_ikInfo.m_plantFeet; + m_vrIk.solver.leftLeg.useAnimatedBendNormal = m_ikInfo.m_bendNormalLeft; + m_vrIk.solver.rightLeg.useAnimatedBendNormal = m_ikInfo.m_bendNormalRight; } // Settings diff --git a/ml_amt/ResourcesHandler.cs b/ml_amt/ResourcesHandler.cs index 7c1479c..d929fc4 100644 --- a/ml_amt/ResourcesHandler.cs +++ b/ml_amt/ResourcesHandler.cs @@ -6,15 +6,16 @@ namespace ml_amt { static class ResourcesHandler { + readonly static string ms_namespace = typeof(ResourcesHandler).Namespace; + public static string GetEmbeddedResource(string p_name) { string l_result = ""; Assembly l_assembly = Assembly.GetExecutingAssembly(); - string l_assemblyName = l_assembly.GetName().Name; try { - Stream l_libraryStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name); + Stream l_libraryStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + p_name); StreamReader l_streadReader = new StreamReader(l_libraryStream); l_result = l_streadReader.ReadToEnd(); } diff --git a/ml_amt/Utils.cs b/ml_amt/Utils.cs index 8086ca2..0b86b15 100644 --- a/ml_amt/Utils.cs +++ b/ml_amt/Utils.cs @@ -18,20 +18,6 @@ static class Utils public static bool HasToes(this IKSolverVR p_instance) => (bool)ms_hasToes.GetValue(p_instance); - public static bool IsWorldSafe() => ((CVRWorld.Instance != null) && CVRWorld.Instance.allowFlying); - public static float GetWorldMovementLimit() - { - float l_result = 1f; - if(CVRWorld.Instance != null) - { - l_result = CVRWorld.Instance.baseMovementSpeed; - l_result *= CVRWorld.Instance.sprintMultiplier; - l_result *= CVRWorld.Instance.inAirMovementMultiplier; - l_result *= CVRWorld.Instance.flyMultiplier; - } - return l_result; - } - public static void ExecuteScript(this CohtmlControlledViewWrapper p_instance, string p_script) => ((cohtml.Net.View)ms_view.GetValue(p_instance)).ExecuteScript(p_script); public static void SetAvatarTPose() diff --git a/ml_amt/ml_amt.csproj b/ml_amt/ml_amt.csproj index e7c9f9f..99c60bc 100644 --- a/ml_amt/ml_amt.csproj +++ b/ml_amt/ml_amt.csproj @@ -6,7 +6,7 @@ SDraw AvatarMotionTweaker AvatarMotionTweaker - 1.4.2 + 1.5.0 x64 AvatarMotionTweaker diff --git a/ml_asl/Main.cs b/ml_asl/Main.cs index 8f7e414..9b6dc98 100644 --- a/ml_asl/Main.cs +++ b/ml_asl/Main.cs @@ -1,10 +1,13 @@ using ABI_RC.Core.Player; using System.Reflection; +using UnityEngine; namespace ml_asl { public class AvatarSyncedLook : MelonLoader.MelonMod { + readonly static Matrix4x4 ms_back = Matrix4x4.Translate(Vector3.back); + public override void OnInitializeMelon() { Settings.Init(); @@ -19,7 +22,14 @@ public override void OnInitializeMelon() static void OnPlayerAvatarMovementDataUpdate_Postfix(ref PlayerSetup __instance, PlayerAvatarMovementData ____playerAvatarMovementData) { if(Settings.Enabled && (__instance.EyeMovementController != null)) + { ____playerAvatarMovementData.EyeTrackingOverride = true; + + if(__instance.EyeMovementController.CurrentTarget != null) + ____playerAvatarMovementData.EyeTrackingPosition = __instance.EyeMovementController.CurrentTarget.GetPosition(); + else + ____playerAvatarMovementData.EyeTrackingPosition = (__instance.transform.GetMatrix() * ms_back).GetPosition(); + } } } } diff --git a/ml_asl/Properties/AssemblyInfo.cs b/ml_asl/Properties/AssemblyInfo.cs index 60f2cb3..72d8f26 100644 --- a/ml_asl/Properties/AssemblyInfo.cs +++ b/ml_asl/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -[assembly: MelonLoader.MelonInfo(typeof(ml_asl.AvatarSyncedLook), "AvatarSyncedLook", "1.0.4", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_asl.AvatarSyncedLook), "AvatarSyncedLook", "1.1.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)] diff --git a/ml_asl/README.md b/ml_asl/README.md index 7573805..003f297 100644 --- a/ml_asl/README.md +++ b/ml_asl/README.md @@ -1,14 +1,11 @@ # Avatar Synced Look -This mod Forces local player's eyes look direction to be synced for remote players. +This mod forces local player's eyes look direction to be synced for remote players. # Installation * Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader) * Get [latest release DLL](../../../releases/latest): - * Put `ml_asl.dll` in `Mods` folder of game + * Put `AvatarSyncedLook.dll` in `Mods` folder of game # Usage Available mod's settings in `Settings - Interactions - Avatar Synced Look`: * **Enabled:** sets eyes look direction to be synced or locally generated on remote users side; `true` by default. - -# Notes -* Remote users with [EyeMovementFix](https://github.com/kafeijao/Kafe_CVR_Mods/tree/master/EyeMovementFix) installed can't see synced look direction. diff --git a/ml_asl/ResourcesHandler.cs b/ml_asl/ResourcesHandler.cs index 77a0c35..03fba8c 100644 --- a/ml_asl/ResourcesHandler.cs +++ b/ml_asl/ResourcesHandler.cs @@ -6,15 +6,16 @@ namespace ml_asl { static class ResourcesHandler { + readonly static string ms_namespace = typeof(ResourcesHandler).Namespace; + public static string GetEmbeddedResource(string p_name) { string l_result = ""; Assembly l_assembly = Assembly.GetExecutingAssembly(); - string l_assemblyName = l_assembly.GetName().Name; try { - Stream l_libraryStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name); + Stream l_libraryStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + p_name); StreamReader l_streadReader = new StreamReader(l_libraryStream); l_result = l_streadReader.ReadToEnd(); } diff --git a/ml_asl/Utils.cs b/ml_asl/Utils.cs index fe7a1a8..7b7bcdd 100644 --- a/ml_asl/Utils.cs +++ b/ml_asl/Utils.cs @@ -1,5 +1,6 @@ using ABI_RC.Core.UI; using System.Reflection; +using UnityEngine; namespace ml_asl { @@ -8,5 +9,11 @@ static class Utils static readonly FieldInfo ms_view = typeof(CohtmlControlledViewWrapper).GetField("_view", BindingFlags.NonPublic | BindingFlags.Instance); public static void ExecuteScript(this CohtmlControlledViewWrapper p_instance, string p_script) => ((cohtml.Net.View)ms_view.GetValue(p_instance)).ExecuteScript(p_script); + + // Extensions + 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.localScale : Vector3.one); + } } } diff --git a/ml_asl/ml_asl.csproj b/ml_asl/ml_asl.csproj index 3b77c0a..315d2ec 100644 --- a/ml_asl/ml_asl.csproj +++ b/ml_asl/ml_asl.csproj @@ -5,9 +5,10 @@ x64 AvatarSyncedLook SDraw - None + SDraw AvatarSyncedLook - 1.0.4 + 1.1.0 + AvatarSyncedLook @@ -50,6 +51,11 @@ false false + + D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.dll + false + false + D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll false diff --git a/ml_bft/AssetsHandler.cs b/ml_bft/AssetsHandler.cs index 87e74d7..3473fd1 100644 --- a/ml_bft/AssetsHandler.cs +++ b/ml_bft/AssetsHandler.cs @@ -7,10 +7,11 @@ namespace ml_bft { static class AssetsHandler { + readonly static string ms_namespace = typeof(AssetsHandler).Namespace; + static readonly List ms_assets = new List() { - "ovr_fingers.asset", - "oxr_fingers.asset" + "ovr_fingers.asset" }; static readonly Dictionary ms_loadedAssets = new Dictionary(); @@ -19,13 +20,12 @@ static class AssetsHandler public static void Load() { Assembly l_assembly = Assembly.GetExecutingAssembly(); - string l_assemblyName = l_assembly.GetName().Name; foreach(string l_assetName in ms_assets) { try { - Stream l_assetStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + l_assetName); + Stream l_assetStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + l_assetName); if(l_assetStream != null) { MemoryStream l_memorySteam = new MemoryStream((int)l_assetStream.Length); diff --git a/ml_bft/FingerSystem.cs b/ml_bft/FingerSystem.cs index eabf0e0..3a56cde 100644 --- a/ml_bft/FingerSystem.cs +++ b/ml_bft/FingerSystem.cs @@ -45,18 +45,28 @@ public void Reset() HumanBodyBones.RightRingProximal, HumanBodyBones.RightRingIntermediate, HumanBodyBones.RightRingDistal, HumanBodyBones.RightLittleProximal, HumanBodyBones.RightLittleIntermediate, HumanBodyBones.RightLittleDistal }; - static readonly (HumanBodyBones, HumanBodyBones, bool)[] ms_rotationFixChains = + static readonly (HumanBodyBones, HumanBodyBones, bool)[] ms_fingersChains = { - (HumanBodyBones.LeftThumbProximal,HumanBodyBones.LeftThumbIntermediate,true), (HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.LeftThumbDistal,true), - (HumanBodyBones.LeftIndexProximal,HumanBodyBones.LeftIndexIntermediate,true), (HumanBodyBones.LeftIndexIntermediate, HumanBodyBones.LeftIndexDistal,true), - (HumanBodyBones.LeftMiddleProximal,HumanBodyBones.LeftMiddleIntermediate,true), (HumanBodyBones.LeftMiddleIntermediate, HumanBodyBones.LeftMiddleDistal,true), - (HumanBodyBones.LeftRingProximal,HumanBodyBones.LeftRingIntermediate,true), (HumanBodyBones.LeftRingIntermediate, HumanBodyBones.LeftRingDistal,true), - (HumanBodyBones.LeftLittleProximal,HumanBodyBones.LeftLittleIntermediate,true), (HumanBodyBones.LeftLittleIntermediate, HumanBodyBones.LeftLittleDistal,true), - (HumanBodyBones.RightThumbProximal,HumanBodyBones.RightThumbIntermediate,false), (HumanBodyBones.RightThumbIntermediate, HumanBodyBones.RightThumbDistal,false), - (HumanBodyBones.RightIndexProximal,HumanBodyBones.RightIndexIntermediate,false), (HumanBodyBones.RightIndexIntermediate, HumanBodyBones.RightIndexDistal,false), - (HumanBodyBones.RightMiddleProximal,HumanBodyBones.RightMiddleIntermediate,false), (HumanBodyBones.RightMiddleIntermediate, HumanBodyBones.RightMiddleDistal,false), - (HumanBodyBones.RightRingProximal,HumanBodyBones.RightRingIntermediate,false), (HumanBodyBones.RightRingIntermediate, HumanBodyBones.RightRingDistal,false), - (HumanBodyBones.RightLittleProximal,HumanBodyBones.RightLittleIntermediate,false), (HumanBodyBones.RightLittleIntermediate, HumanBodyBones.RightLittleDistal,false) + (HumanBodyBones.LeftThumbProximal,HumanBodyBones.LeftThumbIntermediate,true), (HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.LeftThumbDistal,true), (HumanBodyBones.LeftThumbDistal,HumanBodyBones.LastBone,true), + (HumanBodyBones.LeftIndexProximal,HumanBodyBones.LeftIndexIntermediate,true), (HumanBodyBones.LeftIndexIntermediate, HumanBodyBones.LeftIndexDistal,true), (HumanBodyBones.LeftIndexDistal,HumanBodyBones.LastBone,true), + (HumanBodyBones.LeftMiddleProximal,HumanBodyBones.LeftMiddleIntermediate,true), (HumanBodyBones.LeftMiddleIntermediate, HumanBodyBones.LeftMiddleDistal,true), (HumanBodyBones.LeftMiddleDistal,HumanBodyBones.LastBone,true), + (HumanBodyBones.LeftRingProximal,HumanBodyBones.LeftRingIntermediate,true), (HumanBodyBones.LeftRingIntermediate, HumanBodyBones.LeftRingDistal,true), (HumanBodyBones.LeftRingDistal,HumanBodyBones.LastBone,true), + (HumanBodyBones.LeftLittleProximal,HumanBodyBones.LeftLittleIntermediate,true), (HumanBodyBones.LeftLittleIntermediate, HumanBodyBones.LeftLittleDistal,true), (HumanBodyBones.LeftLittleDistal,HumanBodyBones.LastBone,true), + (HumanBodyBones.RightThumbProximal,HumanBodyBones.RightThumbIntermediate,false), (HumanBodyBones.RightThumbIntermediate, HumanBodyBones.RightThumbDistal,false), (HumanBodyBones.RightThumbDistal,HumanBodyBones.LastBone,false), + (HumanBodyBones.RightIndexProximal,HumanBodyBones.RightIndexIntermediate,false), (HumanBodyBones.RightIndexIntermediate, HumanBodyBones.RightIndexDistal,false), (HumanBodyBones.RightIndexDistal,HumanBodyBones.LastBone,false), + (HumanBodyBones.RightMiddleProximal,HumanBodyBones.RightMiddleIntermediate,false), (HumanBodyBones.RightMiddleIntermediate, HumanBodyBones.RightMiddleDistal,false), (HumanBodyBones.RightMiddleDistal,HumanBodyBones.LastBone,false), + (HumanBodyBones.RightRingProximal,HumanBodyBones.RightRingIntermediate,false), (HumanBodyBones.RightRingIntermediate, HumanBodyBones.RightRingDistal,false), (HumanBodyBones.RightRingDistal,HumanBodyBones.LastBone,false), + (HumanBodyBones.RightLittleProximal,HumanBodyBones.RightLittleIntermediate,false), (HumanBodyBones.RightLittleIntermediate, HumanBodyBones.RightLittleDistal,false),(HumanBodyBones.RightLittleDistal,HumanBodyBones.LastBone,false), + }; + + static readonly Vector3[] ms_directions = + { + Vector3.forward, + Vector3.back, + Vector3.left, + Vector3.right, + Vector3.up, + Vector3.down, }; public static FingerSystem Instance { get; private set; } = null; @@ -104,39 +114,39 @@ internal void Cleanup() internal void OnAvatarSetup() { - if(PlayerSetup.Instance._animator.isHuman) + Animator l_animator = PlayerSetup.Instance._animator; + if(l_animator.isHuman) { Utils.SetAvatarTPose(); InputHandler.Instance.Rebind(PlayerSetup.Instance.transform.rotation); - if(Settings.FixFingers) + foreach(var l_tuple in ms_fingersChains) { - foreach(var l_tuple in ms_rotationFixChains) - { - ReorientateTowards( - PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item1), - PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item2), - InputHandler.Instance.GetSourceForBone(l_tuple.Item1, l_tuple.Item3), - InputHandler.Instance.GetSourceForBone(l_tuple.Item2, l_tuple.Item3), - PlaneType.OXZ - ); - ReorientateTowards( - PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item1), - PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item2), - InputHandler.Instance.GetSourceForBone(l_tuple.Item1, l_tuple.Item3), - InputHandler.Instance.GetSourceForBone(l_tuple.Item2, l_tuple.Item3), - PlaneType.OYX - ); - } + ReorientateTowards( + PlayerSetup.Instance.transform, + l_animator.GetBoneTransform(l_tuple.Item1), + (l_tuple.Item2 != HumanBodyBones.LastBone) ? l_animator.GetBoneTransform(l_tuple.Item2) : null, + InputHandler.Instance.GetSourceForBone(l_tuple.Item1, l_tuple.Item3), + InputHandler.Instance.GetSourceForBone(l_tuple.Item2, l_tuple.Item3), + PlaneType.OXZ + ); + ReorientateTowards( + PlayerSetup.Instance.transform, + l_animator.GetBoneTransform(l_tuple.Item1), + (l_tuple.Item2 != HumanBodyBones.LastBone) ? l_animator.GetBoneTransform(l_tuple.Item2) : null, + InputHandler.Instance.GetSourceForBone(l_tuple.Item1, l_tuple.Item3), + InputHandler.Instance.GetSourceForBone(l_tuple.Item2, l_tuple.Item3), + PlaneType.OYX + ); } // Bind hands - m_leftHandOffset.m_source = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand); + m_leftHandOffset.m_source = l_animator.GetBoneTransform(HumanBodyBones.LeftHand); m_leftHandOffset.m_target = InputHandler.Instance.GetSourceForBone(HumanBodyBones.LeftHand, true); if((m_leftHandOffset.m_source != null) && (m_leftHandOffset.m_target != null)) m_leftHandOffset.m_offset = Quaternion.Inverse(m_leftHandOffset.m_source.rotation) * m_leftHandOffset.m_target.rotation; - m_rightHandOffset.m_source = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand); + m_rightHandOffset.m_source = l_animator.GetBoneTransform(HumanBodyBones.RightHand); m_rightHandOffset.m_target = InputHandler.Instance.GetSourceForBone(HumanBodyBones.RightHand, false); if((m_rightHandOffset.m_source != null) && (m_rightHandOffset.m_target != null)) m_rightHandOffset.m_offset = Quaternion.Inverse(m_rightHandOffset.m_source.rotation) * m_rightHandOffset.m_target.rotation; @@ -144,7 +154,7 @@ internal void OnAvatarSetup() // Bind fingers foreach(HumanBodyBones p_bone in ms_leftFingerBones) { - Transform l_avatarBone = PlayerSetup.Instance._animator.GetBoneTransform(p_bone); + Transform l_avatarBone = l_animator.GetBoneTransform(p_bone); Transform l_controllerBone = InputHandler.Instance.GetSourceForBone(p_bone, true); if((l_avatarBone != null) && (l_controllerBone != null)) { @@ -157,7 +167,7 @@ internal void OnAvatarSetup() } foreach(HumanBodyBones p_bone in ms_rightFingerBones) { - Transform l_avatarBone = PlayerSetup.Instance._animator.GetBoneTransform(p_bone); + Transform l_avatarBone = l_animator.GetBoneTransform(p_bone); Transform l_controllerBone = InputHandler.Instance.GetSourceForBone(p_bone, false); if((l_avatarBone != null) && (l_controllerBone != null)) { @@ -262,13 +272,13 @@ internal void OnIKSystemLateUpdate(HumanPoseHandler p_handler, Transform p_hips) } } - void ReorientateTowards(Transform p_target, Transform p_targetEnd, Transform p_source, Transform p_sourceEnd, PlaneType p_plane) + static void ReorientateTowards(Transform root, Transform p_source, Transform p_sourceEnd, Transform p_target, Transform p_targetEnd, PlaneType p_plane) { - if((p_target != null) && (p_targetEnd != null) && (p_source != null) && (p_sourceEnd != null)) + if((root != null) && (p_target != null) && (p_source != null)) { - Quaternion l_playerInv = Quaternion.Inverse(PlayerSetup.Instance.transform.rotation); - Vector3 l_targetDir = l_playerInv * (p_targetEnd.position - p_target.position); - Vector3 l_sourceDir = l_playerInv * (p_sourceEnd.position - p_source.position); + Quaternion l_rootInv = Quaternion.Inverse(root.rotation); + Vector3 l_targetDir = l_rootInv * (((p_targetEnd != null) ? p_targetEnd.position : GuessEnd(p_target)) - p_target.position); + Vector3 l_sourceDir = l_rootInv * (((p_sourceEnd != null) ? p_sourceEnd.position : GuessEnd(p_source)) - p_source.position); switch(p_plane) { case PlaneType.OXZ: @@ -301,9 +311,30 @@ void ReorientateTowards(Transform p_target, Transform p_targetEnd, Transform p_s if(p_plane == PlaneType.OYX) l_diff = Quaternion.Euler(0f, 0f, l_diff.eulerAngles.y); - Quaternion l_adjusted = l_diff * (l_playerInv * p_target.rotation); - p_target.rotation = PlayerSetup.Instance.transform.rotation * l_adjusted; + Quaternion l_adjusted = l_diff * (l_rootInv * p_target.rotation); + p_target.rotation = root.rotation * l_adjusted; + } + } + + static Vector3 GuessEnd(Transform p_target) + { + Vector3 l_result = p_target.position; + if(p_target.parent != null) + { + float l_dot = -1f; + Vector3 l_axisDir = p_target.position - p_target.parent.position; + foreach(Vector3 l_dir in ms_directions) + { + Vector3 l_rotDir = p_target.rotation * l_dir; + float l_stepDot = Vector3.Dot(l_rotDir, l_axisDir); + if(l_stepDot >= l_dot) + { + l_dot = l_stepDot; + l_result = p_target.position + l_rotDir; + } + } } + return l_result; } } } diff --git a/ml_bft/HandHandlerVR.cs b/ml_bft/HandHandlerVR.cs index fca93cb..055f30b 100644 --- a/ml_bft/HandHandlerVR.cs +++ b/ml_bft/HandHandlerVR.cs @@ -90,6 +90,7 @@ public HandHandlerVR(Transform p_root, bool p_left) OnShowHandsChanged(Settings.ShowHands); OnMotionRangeChanged(Settings.MotionRange); + Settings.OnSkeletalInputChanged.AddListener(this.OnSkeletalInputChanged); Settings.OnShowHandsChanged.AddListener(this.OnShowHandsChanged); Settings.OnMotionRangeChanged.AddListener(this.OnMotionRangeChanged); } @@ -106,6 +107,7 @@ public void Cleanup() m_skeletonAction = null; + Settings.OnSkeletalInputChanged.RemoveListener(this.OnSkeletalInputChanged); Settings.OnShowHandsChanged.RemoveListener(this.OnShowHandsChanged); Settings.OnMotionRangeChanged.RemoveListener(this.OnMotionRangeChanged); } @@ -254,12 +256,17 @@ public void Rebind(Quaternion p_base) } // Settings + void OnSkeletalInputChanged(bool p_state) + { + OnShowHandsChanged(Settings.ShowHands); + } + void OnShowHandsChanged(bool p_state) { foreach(var l_render in m_renderers) { if(l_render != null) - l_render.enabled = p_state; + l_render.enabled = (Settings.SkeletalInput && p_state); } } diff --git a/ml_bft/InputHandler.cs b/ml_bft/InputHandler.cs index c38219d..c0910d4 100644 --- a/ml_bft/InputHandler.cs +++ b/ml_bft/InputHandler.cs @@ -25,8 +25,7 @@ internal InputHandler() if(MetaPort.Instance.isUsingVr) SetupHandlers(); - VRModeSwitchEvents.OnInitializeXR.AddListener(this.OnSwitchToVR); - VRModeSwitchEvents.OnDeinitializeXR.AddListener(this.OnSwitchToDesktop); + VRModeSwitchEvents.OnCompletedVRModeSwitch.AddListener(this.OnVRModeSwitch); Settings.OnSkeletalInputChanged.AddListener(this.OnSkeletalInputChanged); @@ -39,6 +38,8 @@ internal void Cleanup() RemoveHandlers(); + VRModeSwitchEvents.OnCompletedVRModeSwitch.RemoveListener(this.OnVRModeSwitch); + Settings.OnSkeletalInputChanged.RemoveListener(this.OnSkeletalInputChanged); GameEvents.OnInputUpdate.RemoveListener(this.OnInputUpdate); @@ -133,23 +134,14 @@ internal void OnInputUpdate() } } - void OnSwitchToVR() - { - try - { - SetupHandlers(); - } - catch(System.Exception e) - { - MelonLoader.MelonLogger.Error(e); - } - } - - void OnSwitchToDesktop() + void OnVRModeSwitch(bool p_state) { try { - RemoveHandlers(); + if(Utils.IsInVR()) + SetupHandlers(); + else + RemoveHandlers(); } catch(System.Exception e) { diff --git a/ml_bft/Properties/AssemblyInfo.cs b/ml_bft/Properties/AssemblyInfo.cs index 7dad7fa..93c43a0 100644 --- a/ml_bft/Properties/AssemblyInfo.cs +++ b/ml_bft/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -[assembly: MelonLoader.MelonInfo(typeof(ml_bft.BetterFingersTracking), "BetterFingersTracking", "1.0.5", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_bft.BetterFingersTracking), "BetterFingersTracking", "1.1.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)] diff --git a/ml_bft/README.md b/ml_bft/README.md index 1ed1de3..88ece6b 100644 --- a/ml_bft/README.md +++ b/ml_bft/README.md @@ -13,7 +13,7 @@ Available mod's settings in `Settings - Input & Key-Bindings - Better Fingers Tr * **Filter humanoid limits:** Limits fingers rotations to be valid for Unity's Mechanim; `true` by default * Note: Enabling this option ensures that visual representation of your fingers will be same for you and remote players, but it cancels out additional finger segments rotations that can be better visually in most cases. * **Show hands model:** shows transparent hands model (mostly as debug option); `false` by default -* **Change fingers direction at bind:** tries to allign avatar's fingers for more accurate poses +* **Change fingers direction at bind:** tries to allign avatar's fingers for more accurate poses; `true` by default # Notes * Currently supports only SteamVR environment, OpenXR support is planned. diff --git a/ml_bft/ResourcesHandler.cs b/ml_bft/ResourcesHandler.cs index 1d444a2..210bb71 100644 --- a/ml_bft/ResourcesHandler.cs +++ b/ml_bft/ResourcesHandler.cs @@ -6,15 +6,16 @@ namespace ml_bft { static class ResourcesHandler { + readonly static string ms_namespace = typeof(ResourcesHandler).Namespace; + public static string GetEmbeddedResource(string p_name) { string l_result = ""; Assembly l_assembly = Assembly.GetExecutingAssembly(); - string l_assemblyName = l_assembly.GetName().Name; try { - Stream l_libraryStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name); + Stream l_libraryStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + p_name); StreamReader l_streadReader = new StreamReader(l_libraryStream); l_result = l_streadReader.ReadToEnd(); } diff --git a/ml_bft/Settings.cs b/ml_bft/Settings.cs index aa6f5e4..e7b3471 100644 --- a/ml_bft/Settings.cs +++ b/ml_bft/Settings.cs @@ -32,7 +32,6 @@ enum ModSetting public static MotionRangeType MotionRange { get; private set; } = MotionRangeType.WithController; public static bool ShowHands { get; private set; } = false; public static bool MechanimFilter { get; private set; } = true; - public static bool FixFingers { get; private set; } = true; static MelonLoader.MelonPreferences_Category ms_category = null; static List ms_entries = null; @@ -41,7 +40,6 @@ enum ModSetting public static readonly SettingEvent OnMotionRangeChanged = new SettingEvent(); public static readonly SettingEvent OnShowHandsChanged = new SettingEvent(); public static readonly SettingEvent OnMechanimFilterChanged = new SettingEvent(); - public static readonly SettingEvent OnFixFingersChanged = new SettingEvent(); internal static void Init() { @@ -52,14 +50,12 @@ internal static void Init() ms_category.CreateEntry(ModSetting.SkeletalInput.ToString(), SkeletalInput), ms_category.CreateEntry(ModSetting.MotionRange.ToString(), (int)MotionRange), ms_category.CreateEntry(ModSetting.ShowHands.ToString(), ShowHands), - ms_category.CreateEntry(ModSetting.MechanimFilter.ToString(), MechanimFilter), - ms_category.CreateEntry(ModSetting.FixFingers.ToString(), FixFingers) + ms_category.CreateEntry(ModSetting.MechanimFilter.ToString(), MechanimFilter) }; SkeletalInput = (bool)ms_entries[(int)ModSetting.SkeletalInput].BoxedValue; MotionRange = (MotionRangeType)(int)ms_entries[(int)ModSetting.MotionRange].BoxedValue; ShowHands = (bool)ms_entries[(int)ModSetting.ShowHands].BoxedValue; - FixFingers = (bool)ms_entries[(int)ModSetting.FixFingers].BoxedValue; MelonLoader.MelonCoroutines.Start(WaitMainMenuUi()); } @@ -115,13 +111,6 @@ static void OnToggleUpdate(string p_name, string p_value) OnMechanimFilterChanged.Invoke(MechanimFilter); } break; - - case ModSetting.FixFingers: - { - FixFingers = l_value; - OnFixFingersChanged.Invoke(FixFingers); - } - break; } ms_entries[(int)l_setting].BoxedValue = l_value; diff --git a/ml_bft/Utils.cs b/ml_bft/Utils.cs index 340630f..c913803 100644 --- a/ml_bft/Utils.cs +++ b/ml_bft/Utils.cs @@ -1,4 +1,5 @@ using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; using ABI_RC.Core.UI; using ABI_RC.Systems.IK; using ABI_RC.Systems.InputManagement; @@ -13,6 +14,8 @@ static class Utils public static void ExecuteScript(this CohtmlControlledViewWrapper p_instance, string p_script) => ((cohtml.Net.View)ms_view.GetValue(p_instance)).ExecuteScript(p_script); + 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 void SetAvatarTPose() diff --git a/ml_bft/ml_bft.csproj b/ml_bft/ml_bft.csproj index d37a131..bd2a16a 100644 --- a/ml_bft/ml_bft.csproj +++ b/ml_bft/ml_bft.csproj @@ -7,7 +7,7 @@ SDraw SDraw BetterFingersTracking - 1.0.5 + 1.1.0 BetterFingersTracking diff --git a/ml_bft/resources/mod_menu.js b/ml_bft/resources/mod_menu.js index b23f726..e682f83 100644 --- a/ml_bft/resources/mod_menu.js +++ b/ml_bft/resources/mod_menu.js @@ -19,13 +19,6 @@
- -
-
Change fingers direction at bind:
-
-
-
-
Filter humanoid limits:
diff --git a/ml_dht/HeadTracked.cs b/ml_dht/HeadTracked.cs index fdcd5d5..03d25b1 100644 --- a/ml_dht/HeadTracked.cs +++ b/ml_dht/HeadTracked.cs @@ -2,9 +2,9 @@ using ABI_RC.Core.Player; using ABI_RC.Core.Player.EyeMovement; using ABI_RC.Systems.FaceTracking; +using ABI_RC.Systems.VRModeSwitch; using RootMotion.FinalIK; using System; -using System.Reflection; using UnityEngine; using ViveSR.anipal.Lip; @@ -13,11 +13,7 @@ namespace ml_dht [DisallowMultipleComponent] class HeadTracked : MonoBehaviour { - static FieldInfo ms_emotePlaying = typeof(PlayerSetup).GetField("_emotePlaying", BindingFlags.NonPublic | BindingFlags.Instance); - - bool m_enabled = false; - bool m_headTracking = true; - float m_smoothing = 0.5f; + static HeadTracked ms_instance = null; CVRAvatar m_avatarDescriptor = null; Transform m_camera = null; @@ -34,6 +30,9 @@ class HeadTracked : MonoBehaviour Quaternion m_bindRotation; Quaternion m_lastHeadRotation; + DataParser m_dataParser = null; + float m_smoothing = 0.5f; + internal HeadTracked() { m_lipData = new LipData_v2(); @@ -45,14 +44,28 @@ internal HeadTracked() } // Unity events + void Awake() + { + if(ms_instance != null) + { + DestroyImmediate(this); + return; + } + + DontDestroyOnLoad(this); + + ms_instance = this; + m_dataParser = new DataParser(); + } + void Start() { - OnEnabledChanged(Settings.Enabled); - OnHeadTrackingChanged(Settings.HeadTracking); OnSmoothingChanged(Settings.Smoothing); - Settings.OnEnabledChanged.AddListener(this.OnEnabledChanged); - Settings.OnHeadTrackingChanged.AddListener(this.OnHeadTrackingChanged); + OnVRModeSwitch(true); + + Settings.OnEnabledChanged.AddListener(this.OnEnabledOrHeadTrackingChanged); + Settings.OnHeadTrackingChanged.AddListener(this.OnEnabledOrHeadTrackingChanged); Settings.OnSmoothingChanged.AddListener(this.OnSmoothingChanged); GameEvents.OnAvatarClear.AddListener(this.OnAvatarClear); @@ -60,12 +73,19 @@ void Start() GameEvents.OnAvatarReuse.AddListener(this.OnAvatarReuse); GameEvents.OnEyeControllerUpdate.AddListener(this.OnEyeControllerUpdate); GameEvents.OnFaceTrackingUpdate.AddListener(this.UpdateFaceTracking); + + VRModeSwitchEvents.OnCompletedVRModeSwitch.AddListener(this.OnVRModeSwitch); } void OnDestroy() { - Settings.OnEnabledChanged.RemoveListener(this.OnEnabledChanged); - Settings.OnHeadTrackingChanged.RemoveListener(this.OnHeadTrackingChanged); + if(ms_instance == this) + ms_instance = null; + + m_dataParser = null; + + Settings.OnEnabledChanged.RemoveListener(this.OnEnabledOrHeadTrackingChanged); + Settings.OnHeadTrackingChanged.RemoveListener(this.OnEnabledOrHeadTrackingChanged); Settings.OnSmoothingChanged.RemoveListener(this.OnSmoothingChanged); GameEvents.OnAvatarClear.RemoveListener(this.OnAvatarClear); @@ -73,12 +93,20 @@ void OnDestroy() GameEvents.OnAvatarReuse.RemoveListener(this.OnAvatarReuse); GameEvents.OnEyeControllerUpdate.RemoveListener(this.OnEyeControllerUpdate); GameEvents.OnFaceTrackingUpdate.RemoveListener(this.UpdateFaceTracking); + + VRModeSwitchEvents.OnCompletedVRModeSwitch.RemoveListener(this.OnVRModeSwitch); } void Update() { if(m_lipDataSent) m_lipDataSent = false; + + if(Settings.Enabled && (m_dataParser != null)) + { + m_dataParser.Update(); + UpdateTrackingData(ref m_dataParser.GetLatestTrackingData()); + } } // Tracking updates @@ -98,11 +126,11 @@ public void UpdateTrackingData(ref TrackingData p_data) void OnLookIKPostUpdate() { - if(m_enabled && m_headTracking && (m_headBone != null)) + if(Settings.Enabled && Settings.HeadTracking && (m_headBone != null)) { m_lastHeadRotation = Quaternion.Slerp(m_lastHeadRotation, m_avatarDescriptor.transform.rotation * (m_headRotation * m_bindRotation), m_smoothing); - if(!(bool)ms_emotePlaying.GetValue(PlayerSetup.Instance)) + if(!PlayerSetup.Instance.IsEmotePlaying()) m_headBone.rotation = m_lastHeadRotation; } } @@ -142,7 +170,7 @@ void OnAvatarReuse() void OnEyeControllerUpdate(EyeMovementController p_component) { - if(m_enabled) + if(this.enabled && Settings.Enabled) { // Gaze if(Settings.EyeTracking && (m_camera != null)) @@ -162,7 +190,7 @@ void OnEyeControllerUpdate(EyeMovementController p_component) void UpdateFaceTracking(CVRFaceTracking p_component, GameEvents.EventResult p_result) { - if(p_component.isLocal && p_component.UseFacialTracking && m_enabled && Settings.FaceTracking) + if(this.enabled && Settings.Enabled && Settings.FaceTracking && p_component.isLocal && p_component.UseFacialTracking ) { if(!m_lipDataSent) { @@ -176,33 +204,27 @@ void UpdateFaceTracking(CVRFaceTracking p_component, GameEvents.EventResult p_re } } - // Settings - void OnEnabledChanged(bool p_state) + void OnVRModeSwitch(bool p_state) { - if(m_enabled != p_state) + try { - m_enabled = p_state; - TryRestoreHeadRotation(); + this.enabled = !Utils.IsInVR(); } - } - void OnHeadTrackingChanged(bool p_state) - { - if(m_headTracking != p_state) + catch(Exception e) { - m_headTracking = p_state; - TryRestoreHeadRotation(); + MelonLoader.MelonLogger.Error(e); } } - void OnSmoothingChanged(float p_value) - { - m_smoothing = 1f - Mathf.Clamp(p_value, 0f, 0.99f); - } - // Arbitrary - void TryRestoreHeadRotation() + // Settings + void OnEnabledOrHeadTrackingChanged(bool p_state) { - if(m_enabled && m_headTracking) + if(Settings.Enabled && Settings.HeadTracking) m_lastHeadRotation = ((m_headBone != null) ? m_headBone.rotation : m_bindRotation); } + void OnSmoothingChanged(float p_value) + { + m_smoothing = 1f - Mathf.Clamp(p_value, 0f, 0.99f); + } } } diff --git a/ml_dht/Main.cs b/ml_dht/Main.cs index 7778fb6..a2675d2 100644 --- a/ml_dht/Main.cs +++ b/ml_dht/Main.cs @@ -1,12 +1,13 @@ using ABI_RC.Core.Player; using ABI_RC.Core.Savior; +using UnityEngine; namespace ml_dht { public class DesktopHeadTracking : MelonLoader.MelonMod { - DataParser m_dataParser = null; - HeadTracked m_localTracked = null; + + HeadTracked m_tracked = null; public override void OnInitializeMelon() { @@ -26,24 +27,14 @@ System.Collections.IEnumerator WaitForInstances() GameEvents.InitB(HarmonyInstance); - m_dataParser = new DataParser(); - m_localTracked = PlayerSetup.Instance.gameObject.AddComponent(); + m_tracked = new GameObject("[DesktopHeadTracking]").AddComponent(); } public override void OnDeinitializeMelon() { - m_dataParser = null; - m_localTracked = null; - } - - public override void OnUpdate() - { - if(Settings.Enabled && (m_dataParser != null)) - { - m_dataParser.Update(); - if(m_localTracked != null) - m_localTracked.UpdateTrackingData(ref m_dataParser.GetLatestTrackingData()); - } + if(m_tracked != null) + Object.Destroy(m_tracked.gameObject); + m_tracked = null; } } } \ No newline at end of file diff --git a/ml_dht/Properties/AssemblyInfo.cs b/ml_dht/Properties/AssemblyInfo.cs index a80a9a7..dedea0a 100644 --- a/ml_dht/Properties/AssemblyInfo.cs +++ b/ml_dht/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -[assembly: MelonLoader.MelonInfo(typeof(ml_dht.DesktopHeadTracking), "DesktopHeadTracking", "1.2.5", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_dht.DesktopHeadTracking), "DesktopHeadTracking", "1.3.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)] \ No newline at end of file diff --git a/ml_dht/README.md b/ml_dht/README.md index 1b6065b..52275aa 100644 --- a/ml_dht/README.md +++ b/ml_dht/README.md @@ -13,7 +13,7 @@ Refer to `TrackingData.cs` for reference in case of implementing own software. # Installation * Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader) * Get [latest release DLL](../../../releases/latest): - * Put `ml_dht.dll` in `Mods` folder of game + * Put `DesktopHeadTracking.dll` in `Mods` folder of game # Usage Available mod's settings in `Settings - Implementation - Desktop Head Tracking`: diff --git a/ml_dht/ResourcesHandler.cs b/ml_dht/ResourcesHandler.cs index b7c0553..d0d22ac 100644 --- a/ml_dht/ResourcesHandler.cs +++ b/ml_dht/ResourcesHandler.cs @@ -6,15 +6,16 @@ namespace ml_dht { static class ResourcesHandler { + readonly static string ms_namespace = typeof(ResourcesHandler).Namespace; + public static string GetEmbeddedResource(string p_name) { string l_result = ""; Assembly l_assembly = Assembly.GetExecutingAssembly(); - string l_assemblyName = l_assembly.GetName().Name; try { - Stream l_libraryStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name); + Stream l_libraryStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + p_name); StreamReader l_streadReader = new StreamReader(l_libraryStream); l_result = l_streadReader.ReadToEnd(); } diff --git a/ml_dht/Utils.cs b/ml_dht/Utils.cs index 3376e66..e561038 100644 --- a/ml_dht/Utils.cs +++ b/ml_dht/Utils.cs @@ -1,5 +1,6 @@ using ABI.CCK.Components; using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; using ABI_RC.Core.UI; using ABI_RC.Systems.IK; using System.Reflection; @@ -13,6 +14,8 @@ static class Utils static readonly FieldInfo ms_view = typeof(CohtmlControlledViewWrapper).GetField("_view", BindingFlags.NonPublic | BindingFlags.Instance); static readonly MethodInfo ms_updateShapesLocal = typeof(CVRFaceTracking).GetMethod("UpdateShapesLocal", BindingFlags.NonPublic | BindingFlags.Instance); + public static bool IsInVR() => ((MetaPort.Instance != null) && MetaPort.Instance.isUsingVr); + public static void ExecuteScript(this CohtmlControlledViewWrapper p_instance, string p_script) => ((cohtml.Net.View)ms_view.GetValue(p_instance)).ExecuteScript(p_script); public static void UpdateShapesLocal_Private(this CVRFaceTracking p_instance) => ms_updateShapesLocal?.Invoke(p_instance, ms_emptyArray); diff --git a/ml_dht/ml_dht.csproj b/ml_dht/ml_dht.csproj index 467126d..cfca6d6 100644 --- a/ml_dht/ml_dht.csproj +++ b/ml_dht/ml_dht.csproj @@ -4,10 +4,11 @@ netstandard2.1 DesktopHeadTracking SDraw - None + SDraw DesktopHeadTracking - 1.2.5 + 1.3.0 x64 + DesktopHeadTracking diff --git a/ml_lme/AssetsHandler.cs b/ml_lme/AssetsHandler.cs index 8aaf1f9..36c3ebf 100644 --- a/ml_lme/AssetsHandler.cs +++ b/ml_lme/AssetsHandler.cs @@ -7,6 +7,8 @@ namespace ml_lme { static class AssetsHandler { + readonly static string ms_namespace = typeof(AssetsHandler).Namespace; + static readonly List ms_assets = new List() { "leapmotion_controller.asset", @@ -19,13 +21,12 @@ static class AssetsHandler public static void Load() { Assembly l_assembly = Assembly.GetExecutingAssembly(); - string l_assemblyName = l_assembly.GetName().Name; foreach(string l_assetName in ms_assets) { try { - Stream l_assetStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + l_assetName); + Stream l_assetStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + l_assetName); if(l_assetStream != null) { MemoryStream l_memorySteam = new MemoryStream((int)l_assetStream.Length); diff --git a/ml_lme/DependenciesHandler.cs b/ml_lme/DependenciesHandler.cs index dec1bdd..3dbc8da 100644 --- a/ml_lme/DependenciesHandler.cs +++ b/ml_lme/DependenciesHandler.cs @@ -8,6 +8,8 @@ namespace ml_lme { static class DependenciesHandler { + readonly static string ms_namespace = typeof(DependenciesHandler).Namespace; + static readonly List ms_libraries = new List() { "LeapC.dll" @@ -16,11 +18,10 @@ static class DependenciesHandler public static void ExtractDependencies() { Assembly l_assembly = Assembly.GetExecutingAssembly(); - string l_assemblyName = l_assembly.GetName().Name; foreach(string l_library in ms_libraries) { - Stream l_libraryStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + l_library); + Stream l_libraryStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + l_library); if(!File.Exists(l_library)) { diff --git a/ml_lme/LeapHand.cs b/ml_lme/LeapHand.cs index 797f87b..e6d6f65 100644 --- a/ml_lme/LeapHand.cs +++ b/ml_lme/LeapHand.cs @@ -123,107 +123,89 @@ public void Rebind(Quaternion p_base) } public Transform GetRoot() => m_root; - public Transform GetBone(HumanBodyBones p_bone) + public Transform GetLinkedBone(HumanBodyBones p_bone) { Transform l_result = null; switch(p_bone) { case HumanBodyBones.LeftHand: - l_result = (m_left ? m_wrist : null); - break; - case HumanBodyBones.LeftThumbProximal: - l_result = (m_left ? m_fingersBones[(int)FingerBone.ThumbProximal] : null); - break; - case HumanBodyBones.LeftThumbIntermediate: - l_result = (m_left ? m_fingersBones[(int)FingerBone.ThumbIntermediate] : null); - break; - case HumanBodyBones.LeftThumbDistal: - l_result = (m_left ? m_fingersBones[(int)FingerBone.ThumbDistal] : null); - break; - case HumanBodyBones.LeftIndexProximal: - l_result = (m_left ? m_fingersBones[(int)FingerBone.IndexProximal] : null); - break; - case HumanBodyBones.LeftIndexIntermediate: - l_result = (m_left ? m_fingersBones[(int)FingerBone.IndexIntermediate] : null); - break; - case HumanBodyBones.LeftIndexDistal: - l_result = (m_left ? m_fingersBones[(int)FingerBone.IndexDistal] : null); - break; - case HumanBodyBones.LeftMiddleProximal: - l_result = (m_left ? m_fingersBones[(int)FingerBone.MiddleProximal] : null); - break; - case HumanBodyBones.LeftMiddleIntermediate: - l_result = (m_left ? m_fingersBones[(int)FingerBone.MiddleIntermediate] : null); - break; - case HumanBodyBones.LeftMiddleDistal: - l_result = (m_left ? m_fingersBones[(int)FingerBone.MiddleDistal] : null); - break; - case HumanBodyBones.LeftRingProximal: - l_result = (m_left ? m_fingersBones[(int)FingerBone.RingProximal] : null); - break; - case HumanBodyBones.LeftRingIntermediate: - l_result = (m_left ? m_fingersBones[(int)FingerBone.RingIntermediate] : null); - break; - case HumanBodyBones.LeftRingDistal: - l_result = (m_left ? m_fingersBones[(int)FingerBone.RingDistal] : null); - break; - case HumanBodyBones.LeftLittleProximal: - l_result = (m_left ? m_fingersBones[(int)FingerBone.PinkyProximal] : null); - break; - case HumanBodyBones.LeftLittleIntermediate: - l_result = (m_left ? m_fingersBones[(int)FingerBone.PinkyIntermediate] : null); - break; - case HumanBodyBones.LeftLittleDistal: - l_result = (m_left ? m_fingersBones[(int)FingerBone.PinkyDistal] : null); - break; - case HumanBodyBones.RightHand: - l_result = (!m_left ? m_wrist : null); + l_result = m_wrist; break; + + case HumanBodyBones.LeftThumbProximal: case HumanBodyBones.RightThumbProximal: - l_result = (!m_left ? m_fingersBones[(int)FingerBone.ThumbProximal] : null); + l_result = m_fingersBones[(int)FingerBone.ThumbProximal]; break; + + case HumanBodyBones.LeftThumbIntermediate: case HumanBodyBones.RightThumbIntermediate: - l_result = (!m_left ? m_fingersBones[(int)FingerBone.ThumbIntermediate] : null); + l_result = m_fingersBones[(int)FingerBone.ThumbIntermediate]; break; + + case HumanBodyBones.LeftThumbDistal: case HumanBodyBones.RightThumbDistal: - l_result = (!m_left ? m_fingersBones[(int)FingerBone.ThumbDistal] : null); + l_result = m_fingersBones[(int)FingerBone.ThumbDistal]; break; + + case HumanBodyBones.LeftIndexProximal: case HumanBodyBones.RightIndexProximal: - l_result = (!m_left ? m_fingersBones[(int)FingerBone.IndexProximal] : null); + l_result = m_fingersBones[(int)FingerBone.IndexProximal]; break; + + case HumanBodyBones.LeftIndexIntermediate: case HumanBodyBones.RightIndexIntermediate: - l_result = (!m_left ? m_fingersBones[(int)FingerBone.IndexIntermediate] : null); + l_result = m_fingersBones[(int)FingerBone.IndexIntermediate]; break; + + case HumanBodyBones.LeftIndexDistal: case HumanBodyBones.RightIndexDistal: - l_result = (!m_left ? m_fingersBones[(int)FingerBone.IndexDistal] : null); + l_result = m_fingersBones[(int)FingerBone.IndexDistal]; break; + + case HumanBodyBones.LeftMiddleProximal: case HumanBodyBones.RightMiddleProximal: - l_result = (!m_left ? m_fingersBones[(int)FingerBone.MiddleProximal] : null); + l_result = m_fingersBones[(int)FingerBone.MiddleProximal]; break; + + case HumanBodyBones.LeftMiddleIntermediate: case HumanBodyBones.RightMiddleIntermediate: - l_result = (!m_left ? m_fingersBones[(int)FingerBone.MiddleIntermediate] : null); + l_result = m_fingersBones[(int)FingerBone.MiddleIntermediate]; break; + + case HumanBodyBones.LeftMiddleDistal: case HumanBodyBones.RightMiddleDistal: - l_result = (!m_left ? m_fingersBones[(int)FingerBone.MiddleDistal] : null); + l_result = m_fingersBones[(int)FingerBone.MiddleDistal]; break; + + case HumanBodyBones.LeftRingProximal: case HumanBodyBones.RightRingProximal: - l_result = (!m_left ? m_fingersBones[(int)FingerBone.RingProximal] : null); + l_result = m_fingersBones[(int)FingerBone.RingProximal]; break; + + case HumanBodyBones.LeftRingIntermediate: case HumanBodyBones.RightRingIntermediate: - l_result = (!m_left ? m_fingersBones[(int)FingerBone.RingIntermediate] : null); + l_result = m_fingersBones[(int)FingerBone.RingIntermediate]; break; + + case HumanBodyBones.LeftRingDistal: case HumanBodyBones.RightRingDistal: - l_result = (!m_left ? m_fingersBones[(int)FingerBone.RingDistal] : null); + l_result = m_fingersBones[(int)FingerBone.RingDistal]; break; + + case HumanBodyBones.LeftLittleProximal: case HumanBodyBones.RightLittleProximal: - l_result = (!m_left ? m_fingersBones[(int)FingerBone.PinkyProximal] : null); + l_result = m_fingersBones[(int)FingerBone.PinkyProximal]; break; + + case HumanBodyBones.LeftLittleIntermediate: case HumanBodyBones.RightLittleIntermediate: - l_result = (!m_left ? m_fingersBones[(int)FingerBone.PinkyIntermediate] : null); + l_result = m_fingersBones[(int)FingerBone.PinkyIntermediate]; break; + + case HumanBodyBones.LeftLittleDistal: case HumanBodyBones.RightLittleDistal: - l_result = (!m_left ? m_fingersBones[(int)FingerBone.PinkyDistal] : null); + l_result = m_fingersBones[(int)FingerBone.PinkyDistal]; break; } return l_result; @@ -234,5 +216,7 @@ public void SetMeshActive(bool p_state) if(m_mesh != null) m_mesh.SetActive(p_state); } + + public bool IsLeft() => m_left; } } diff --git a/ml_lme/LeapInput.cs b/ml_lme/LeapInput.cs index 70e8634..bf76497 100644 --- a/ml_lme/LeapInput.cs +++ b/ml_lme/LeapInput.cs @@ -89,8 +89,7 @@ public override void ModuleAdded() MelonLoader.MelonCoroutines.Start(WaitForSettings()); MelonLoader.MelonCoroutines.Start(WaitForMaterial()); - VRModeSwitchEvents.OnInitializeXR.AddListener(OnModeSwitch); - VRModeSwitchEvents.OnDeinitializeXR.AddListener(OnModeSwitch); + VRModeSwitchEvents.OnCompletedVRModeSwitch.AddListener(OnVRModeSwitch); Settings.OnEnabledChanged.AddListener(this.OnEnableChanged); Settings.OnInteractionChanged.AddListener(this.OnInteractionChanged); @@ -153,8 +152,7 @@ public override void ModuleDestroyed() m_lineRight = null; MetaPort.Instance.settings.settingBoolChanged.RemoveListener(this.OnGameSettingBoolChange); - VRModeSwitchEvents.OnInitializeXR.RemoveListener(OnModeSwitch); - VRModeSwitchEvents.OnDeinitializeXR.RemoveListener(OnModeSwitch); + VRModeSwitchEvents.OnCompletedVRModeSwitch.RemoveListener(OnVRModeSwitch); Settings.OnEnabledChanged.RemoveListener(this.OnEnableChanged); Settings.OnInteractionChanged.RemoveListener(this.OnInteractionChanged); @@ -291,7 +289,7 @@ public override void UpdateInput() m_handVisibleRight = false; } - if(!ModSupporter.SkipFingersOverride() && (!m_inVR || !Utils.AreKnucklesInUse())) + if(!m_inVR || !Utils.AreKnucklesInUse()) SetGameFingersTracking(m_handVisibleRight || m_handVisibleLeft); base.UpdateInput(); @@ -384,7 +382,7 @@ void OnEnableChanged(bool p_state) ResetGestures(false); } - // Reset to default, FreedomFingers can go brrr, player should press funny controller button two times + // Reset to default SetGameFingersTracking(m_inVR && Utils.AreKnucklesInUse() && !CVRInputManager._moduleXR.GestureToggleValue); } @@ -450,23 +448,30 @@ void OnPickupGrab(CVRPickupObject p_pickup) } } - void OnModeSwitch() + void OnVRModeSwitch(bool p_state) { - m_inVR = Utils.IsInVR(); - base._inputManager.SetModuleAsLast(this); - - if(m_handRayLeft != null) + try { - m_handRayLeft.isDesktopRay = !m_inVR; - m_handRayLeft.SetVRActive(m_inVR); + m_inVR = Utils.IsInVR(); + base._inputManager.SetModuleAsLast(this); + + if(m_handRayLeft != null) + { + m_handRayLeft.isDesktopRay = !m_inVR; + m_handRayLeft.SetVRActive(m_inVR); + } + if(m_handRayRight != null) + { + m_handRayRight.isDesktopRay = !m_inVR; + m_handRayRight.SetVRActive(m_inVR); + } + + OnEnableChanged(Settings.Enabled); } - if(m_handRayRight != null) + catch(System.Exception e) { - m_handRayRight.isDesktopRay = !m_inVR; - m_handRayRight.SetVRActive(m_inVR); + MelonLoader.MelonLogger.Error(e); } - - OnEnableChanged(Settings.Enabled); } // Arbitrary diff --git a/ml_lme/LeapManager.cs b/ml_lme/LeapManager.cs index 3d9e5e8..9512396 100644 --- a/ml_lme/LeapManager.cs +++ b/ml_lme/LeapManager.cs @@ -19,9 +19,9 @@ class LeapManager : MonoBehaviour void Awake() { - if((Instance != null) && (Instance != this)) + if(Instance != null) { - Object.DestroyImmediate(this); + DestroyImmediate(this); return; } @@ -44,8 +44,7 @@ void Start() Settings.OnEnabledChanged.AddListener(this.OnEnableChanged); Settings.OnTrackingModeChanged.AddListener(this.OnTrackingModeChanged); - m_leapTracking = new GameObject("[LeapTrackingRoot]").AddComponent(); - m_leapTracking.transform.parent = this.transform; + m_leapTracking = this.gameObject.AddComponent(); OnEnableChanged(Settings.Enabled); OnTrackingModeChanged(Settings.TrackingMode); @@ -102,7 +101,7 @@ IEnumerator WaitForObjects() m_leapInput = new LeapInput(); CVRInputManager.Instance.AddInputModule(m_leapInput); - m_leapTracked = PlayerSetup.Instance.gameObject.AddComponent(); + m_leapTracked = this.gameObject.AddComponent(); } void Update() diff --git a/ml_lme/LeapTracked.cs b/ml_lme/LeapTracked.cs index 4121ac7..0d9cccb 100644 --- a/ml_lme/LeapTracked.cs +++ b/ml_lme/LeapTracked.cs @@ -77,18 +77,28 @@ static readonly (HumanBodyBones, bool)[] ms_fingers = (HumanBodyBones.RightLittleIntermediate, false), (HumanBodyBones.RightLittleDistal, false), }; - static readonly (HumanBodyBones, HumanBodyBones, bool)[] ms_rotationFixChains = + static readonly (HumanBodyBones, HumanBodyBones, bool)[] ms_fingersChains = { - (HumanBodyBones.LeftThumbProximal,HumanBodyBones.LeftThumbIntermediate,true), (HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.LeftThumbDistal,true), - (HumanBodyBones.LeftIndexProximal,HumanBodyBones.LeftIndexIntermediate,true), (HumanBodyBones.LeftIndexIntermediate, HumanBodyBones.LeftIndexDistal,true), - (HumanBodyBones.LeftMiddleProximal,HumanBodyBones.LeftMiddleIntermediate,true), (HumanBodyBones.LeftMiddleIntermediate, HumanBodyBones.LeftMiddleDistal,true), - (HumanBodyBones.LeftRingProximal,HumanBodyBones.LeftRingIntermediate,true), (HumanBodyBones.LeftRingIntermediate, HumanBodyBones.LeftRingDistal,true), - (HumanBodyBones.LeftLittleProximal,HumanBodyBones.LeftLittleIntermediate,true), (HumanBodyBones.LeftLittleIntermediate, HumanBodyBones.LeftLittleDistal,true), - (HumanBodyBones.RightThumbProximal,HumanBodyBones.RightThumbIntermediate,false), (HumanBodyBones.RightThumbIntermediate, HumanBodyBones.RightThumbDistal,false), - (HumanBodyBones.RightIndexProximal,HumanBodyBones.RightIndexIntermediate,false), (HumanBodyBones.RightIndexIntermediate, HumanBodyBones.RightIndexDistal,false), - (HumanBodyBones.RightMiddleProximal,HumanBodyBones.RightMiddleIntermediate,false), (HumanBodyBones.RightMiddleIntermediate, HumanBodyBones.RightMiddleDistal,false), - (HumanBodyBones.RightRingProximal,HumanBodyBones.RightRingIntermediate,false), (HumanBodyBones.RightRingIntermediate, HumanBodyBones.RightRingDistal,false), - (HumanBodyBones.RightLittleProximal,HumanBodyBones.RightLittleIntermediate,false), (HumanBodyBones.RightLittleIntermediate, HumanBodyBones.RightLittleDistal,false) + (HumanBodyBones.LeftThumbProximal,HumanBodyBones.LeftThumbIntermediate,true), (HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.LeftThumbDistal,true), (HumanBodyBones.LeftThumbDistal,HumanBodyBones.LastBone,true), + (HumanBodyBones.LeftIndexProximal,HumanBodyBones.LeftIndexIntermediate,true), (HumanBodyBones.LeftIndexIntermediate, HumanBodyBones.LeftIndexDistal,true), (HumanBodyBones.LeftIndexDistal,HumanBodyBones.LastBone,true), + (HumanBodyBones.LeftMiddleProximal,HumanBodyBones.LeftMiddleIntermediate,true), (HumanBodyBones.LeftMiddleIntermediate, HumanBodyBones.LeftMiddleDistal,true), (HumanBodyBones.LeftMiddleDistal,HumanBodyBones.LastBone,true), + (HumanBodyBones.LeftRingProximal,HumanBodyBones.LeftRingIntermediate,true), (HumanBodyBones.LeftRingIntermediate, HumanBodyBones.LeftRingDistal,true), (HumanBodyBones.LeftRingDistal,HumanBodyBones.LastBone,true), + (HumanBodyBones.LeftLittleProximal,HumanBodyBones.LeftLittleIntermediate,true), (HumanBodyBones.LeftLittleIntermediate, HumanBodyBones.LeftLittleDistal,true), (HumanBodyBones.LeftLittleDistal,HumanBodyBones.LastBone,true), + (HumanBodyBones.RightThumbProximal,HumanBodyBones.RightThumbIntermediate,false), (HumanBodyBones.RightThumbIntermediate, HumanBodyBones.RightThumbDistal,false), (HumanBodyBones.RightThumbDistal,HumanBodyBones.LastBone,false), + (HumanBodyBones.RightIndexProximal,HumanBodyBones.RightIndexIntermediate,false), (HumanBodyBones.RightIndexIntermediate, HumanBodyBones.RightIndexDistal,false), (HumanBodyBones.RightIndexDistal,HumanBodyBones.LastBone,false), + (HumanBodyBones.RightMiddleProximal,HumanBodyBones.RightMiddleIntermediate,false), (HumanBodyBones.RightMiddleIntermediate, HumanBodyBones.RightMiddleDistal,false), (HumanBodyBones.RightMiddleDistal,HumanBodyBones.LastBone,false), + (HumanBodyBones.RightRingProximal,HumanBodyBones.RightRingIntermediate,false), (HumanBodyBones.RightRingIntermediate, HumanBodyBones.RightRingDistal,false), (HumanBodyBones.RightRingDistal,HumanBodyBones.LastBone,false), + (HumanBodyBones.RightLittleProximal,HumanBodyBones.RightLittleIntermediate,false), (HumanBodyBones.RightLittleIntermediate, HumanBodyBones.RightLittleDistal,false),(HumanBodyBones.RightLittleDistal,HumanBodyBones.LastBone,false), + }; + + static readonly Vector3[] ms_directions = + { + Vector3.forward, + Vector3.back, + Vector3.left, + Vector3.right, + Vector3.up, + Vector3.down, }; public static readonly float[] ms_lastLeftFingerBones = new float[20]; @@ -97,10 +107,6 @@ static readonly (HumanBodyBones, HumanBodyBones, bool)[] ms_rotationFixChains = VRIK m_vrIK = null; Transform m_hips = null; - bool m_enabled = true; - bool m_fingersOnly = false; - bool m_trackElbows = true; - IKInfo m_vrIKInfo; ArmIK m_leftArmIK = null; ArmIK m_rightArmIK = null; @@ -135,12 +141,11 @@ void Start() m_rightHandTarget.localPosition = Vector3.zero; m_rightHandTarget.localRotation = Quaternion.identity; - OnEnabledChanged(Settings.Enabled); - OnFingersOnlyChanged(Settings.FingersOnly); + OnEnabledOrFingersOnlyChanged(Settings.Enabled || Settings.FingersOnly); OnTrackElbowsChanged(Settings.TrackElbows); - Settings.OnEnabledChanged.AddListener(this.OnEnabledChanged); - Settings.OnFingersOnlyChanged.AddListener(this.OnFingersOnlyChanged); + Settings.OnEnabledChanged.AddListener(this.OnEnabledOrFingersOnlyChanged); + Settings.OnFingersOnlyChanged.AddListener(this.OnEnabledOrFingersOnlyChanged); Settings.OnTrackElbowsChanged.AddListener(this.OnTrackElbowsChanged); GameEvents.OnAvatarClear.AddListener(this.OnAvatarClear); @@ -165,8 +170,8 @@ void OnDestroy() m_vrIK = null; - Settings.OnEnabledChanged.RemoveListener(this.OnEnabledChanged); - Settings.OnFingersOnlyChanged.RemoveListener(this.OnFingersOnlyChanged); + Settings.OnEnabledChanged.RemoveListener(this.OnEnabledOrFingersOnlyChanged); + Settings.OnFingersOnlyChanged.RemoveListener(this.OnEnabledOrFingersOnlyChanged); Settings.OnTrackElbowsChanged.RemoveListener(this.OnTrackElbowsChanged); GameEvents.OnAvatarClear.RemoveListener(this.OnAvatarClear); @@ -176,24 +181,24 @@ void OnDestroy() void Update() { - if(m_enabled) + if(Settings.Enabled) { LeapParser.LeapData l_data = LeapManager.Instance.GetLatestData(); if((m_leftArmIK != null) && (m_rightArmIK != null)) { - m_leftArmIK.solver.IKPositionWeight = Mathf.Lerp(m_leftArmIK.solver.IKPositionWeight, (l_data.m_leftHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); - m_leftArmIK.solver.IKRotationWeight = Mathf.Lerp(m_leftArmIK.solver.IKRotationWeight, (l_data.m_leftHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); - if(m_trackElbows) - m_leftArmIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_leftArmIK.solver.arm.bendGoalWeight, (l_data.m_leftHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); - - m_rightArmIK.solver.IKPositionWeight = Mathf.Lerp(m_rightArmIK.solver.IKPositionWeight, (l_data.m_rightHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); - m_rightArmIK.solver.IKRotationWeight = Mathf.Lerp(m_rightArmIK.solver.IKRotationWeight, (l_data.m_rightHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); - if(m_trackElbows) - m_rightArmIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_rightArmIK.solver.arm.bendGoalWeight, (l_data.m_rightHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_leftArmIK.solver.IKPositionWeight = Mathf.Lerp(m_leftArmIK.solver.IKPositionWeight, (l_data.m_leftHand.m_present && !Settings.FingersOnly) ? 1f : 0f, 0.25f); + m_leftArmIK.solver.IKRotationWeight = Mathf.Lerp(m_leftArmIK.solver.IKRotationWeight, (l_data.m_leftHand.m_present && !Settings.FingersOnly) ? 1f : 0f, 0.25f); + if(Settings.TrackElbows) + m_leftArmIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_leftArmIK.solver.arm.bendGoalWeight, (l_data.m_leftHand.m_present && !Settings.FingersOnly) ? 1f : 0f, 0.25f); + + m_rightArmIK.solver.IKPositionWeight = Mathf.Lerp(m_rightArmIK.solver.IKPositionWeight, (l_data.m_rightHand.m_present && !Settings.FingersOnly) ? 1f : 0f, 0.25f); + m_rightArmIK.solver.IKRotationWeight = Mathf.Lerp(m_rightArmIK.solver.IKRotationWeight, (l_data.m_rightHand.m_present && !Settings.FingersOnly) ? 1f : 0f, 0.25f); + if(Settings.TrackElbows) + m_rightArmIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_rightArmIK.solver.arm.bendGoalWeight, (l_data.m_rightHand.m_present && !Settings.FingersOnly) ? 1f : 0f, 0.25f); } - if((m_vrIK != null) && !m_fingersOnly) + if((m_vrIK != null) && !Settings.FingersOnly) { m_leftTargetActive = l_data.m_leftHand.m_present; m_rightTargetActive = l_data.m_rightHand.m_present; @@ -203,7 +208,7 @@ void Update() void LateUpdate() { - if(m_enabled && (m_poseHandler != null)) + if(Settings.Enabled && (m_poseHandler != null)) { LeapParser.LeapData l_data = LeapManager.Instance.GetLatestData(); if(l_data.m_leftHand.m_present) @@ -276,24 +281,25 @@ void OnAvatarClear() void OnAvatarSetup() { - if(PlayerSetup.Instance._animator.isHuman) + Animator l_animator = PlayerSetup.Instance._animator; + if(l_animator.isHuman) { Utils.SetAvatarTPose(); - m_poseHandler = new HumanPoseHandler(PlayerSetup.Instance._animator.avatar, PlayerSetup.Instance._animator.transform); + m_poseHandler = new HumanPoseHandler(l_animator.avatar, l_animator.transform); m_poseHandler.GetHumanPose(ref m_pose); - m_hips = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Hips); + m_hips = l_animator.GetBoneTransform(HumanBodyBones.Hips); - m_leftHandOffset.m_source = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand); - m_leftHandTarget.localRotation = ms_offsetLeft * (Quaternion.Inverse(PlayerSetup.Instance._avatar.transform.rotation) * m_leftHandOffset.m_source.rotation); + m_leftHandOffset.m_source = l_animator.GetBoneTransform(HumanBodyBones.LeftHand); + m_leftHandTarget.localRotation = ms_offsetLeft * (Quaternion.Inverse(l_animator.transform.rotation) * m_leftHandOffset.m_source.rotation); - m_rightHandOffset.m_source = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand); - m_rightHandTarget.localRotation = ms_offsetRight * (Quaternion.Inverse(PlayerSetup.Instance._avatar.transform.rotation) * m_rightHandOffset.m_source.rotation); + m_rightHandOffset.m_source = l_animator.GetBoneTransform(HumanBodyBones.RightHand); + m_rightHandTarget.localRotation = ms_offsetRight * (Quaternion.Inverse(l_animator.transform.rotation) * m_rightHandOffset.m_source.rotation); ParseFingersBones(); - m_vrIK = PlayerSetup.Instance._animator.GetComponent(); + m_vrIK = l_animator.GetComponent(); if(m_vrIK != null) { m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreSolverUpdate); @@ -339,7 +345,7 @@ void OnIKPreSolverUpdate() m_vrIK.solver.leftArm.positionWeight = 1f; m_vrIK.solver.leftArm.rotationWeight = 1f; m_vrIK.solver.leftArm.bendGoal = LeapTracking.Instance.GetLeftElbow(); - m_vrIK.solver.leftArm.bendGoalWeight = (m_trackElbows ? 1f : 0f); + m_vrIK.solver.leftArm.bendGoalWeight = (Settings.TrackElbows ? 1f : 0f); } if(m_rightTargetActive) { @@ -353,7 +359,7 @@ void OnIKPreSolverUpdate() m_vrIK.solver.rightArm.positionWeight = 1f; m_vrIK.solver.rightArm.rotationWeight = 1f; m_vrIK.solver.rightArm.bendGoal = LeapTracking.Instance.GetRightElbow(); - m_vrIK.solver.rightArm.bendGoalWeight = (m_trackElbows ? 1f : 0f); + m_vrIK.solver.rightArm.bendGoalWeight = (Settings.TrackElbows ? 1f : 0f); } } void OnIKPostSolverUpdate() @@ -377,30 +383,18 @@ void OnIKPostSolverUpdate() } // Settings - void OnEnabledChanged(bool p_state) + void OnEnabledOrFingersOnlyChanged(bool p_state) { - m_enabled = p_state; - - RefreshArmIK(); - ResetTargetsStates(); - } - - void OnFingersOnlyChanged(bool p_state) - { - m_fingersOnly = p_state; - RefreshArmIK(); ResetTargetsStates(); } void OnTrackElbowsChanged(bool p_state) { - m_trackElbows = p_state; - if((m_leftArmIK != null) && (m_rightArmIK != null)) { - m_leftArmIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f); - m_rightArmIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f); + m_leftArmIK.solver.arm.bendGoalWeight = (p_state ? 1f : 0f); + m_rightArmIK.solver.arm.bendGoalWeight = (p_state ? 1f : 0f); } ResetTargetsStates(); @@ -415,41 +409,42 @@ void ResetTargetsStates() void SetupArmIK() { - Transform l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.UpperChest); + Animator l_animator = PlayerSetup.Instance._animator; + Transform l_chest = l_animator.GetBoneTransform(HumanBodyBones.UpperChest); if(l_chest == null) - l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Chest); + l_chest = l_animator.GetBoneTransform(HumanBodyBones.Chest); if(l_chest == null) - l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Spine); + l_chest = l_animator.GetBoneTransform(HumanBodyBones.Spine); - m_leftArmIK = PlayerSetup.Instance._avatar.AddComponent(); + m_leftArmIK = l_animator.gameObject.AddComponent(); m_leftArmIK.solver.isLeft = true; m_leftArmIK.solver.SetChain( l_chest, - PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftShoulder), - PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftUpperArm), - PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftLowerArm), - PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand), - PlayerSetup.Instance._animator.transform + l_animator.GetBoneTransform(HumanBodyBones.LeftShoulder), + l_animator.GetBoneTransform(HumanBodyBones.LeftUpperArm), + l_animator.GetBoneTransform(HumanBodyBones.LeftLowerArm), + l_animator.GetBoneTransform(HumanBodyBones.LeftHand), + l_animator.transform ); m_leftArmIK.solver.arm.target = m_leftHandTarget; m_leftArmIK.solver.arm.bendGoal = LeapTracking.Instance.GetLeftElbow(); - m_leftArmIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f); - m_leftArmIK.enabled = (m_enabled && !m_fingersOnly); + m_leftArmIK.solver.arm.bendGoalWeight = (Settings.TrackElbows ? 1f : 0f); + m_leftArmIK.enabled = (Settings.Enabled && !Settings.FingersOnly); - m_rightArmIK = PlayerSetup.Instance._avatar.AddComponent(); + m_rightArmIK = l_animator.gameObject.AddComponent(); m_rightArmIK.solver.isLeft = false; m_rightArmIK.solver.SetChain( l_chest, - PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightShoulder), - PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightUpperArm), - PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightLowerArm), - PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand), - PlayerSetup.Instance._animator.transform + l_animator.GetBoneTransform(HumanBodyBones.RightShoulder), + l_animator.GetBoneTransform(HumanBodyBones.RightUpperArm), + l_animator.GetBoneTransform(HumanBodyBones.RightLowerArm), + l_animator.GetBoneTransform(HumanBodyBones.RightHand), + l_animator.transform ); m_rightArmIK.solver.arm.target = m_rightHandTarget; m_rightArmIK.solver.arm.bendGoal = LeapTracking.Instance.GetRightElbow(); - m_rightArmIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f); - m_rightArmIK.enabled = (m_enabled && !m_fingersOnly); + m_rightArmIK.solver.arm.bendGoalWeight = (Settings.TrackElbows ? 1f : 0f); + m_rightArmIK.enabled = (Settings.Enabled && !Settings.FingersOnly); } void RemoveArmIK() @@ -467,8 +462,8 @@ void RefreshArmIK() { if((m_leftArmIK != null) && (m_rightArmIK != null)) { - m_leftArmIK.enabled = (m_enabled && !m_fingersOnly); - m_rightArmIK.enabled = (m_enabled && !m_fingersOnly); + m_leftArmIK.enabled = (Settings.Enabled && !Settings.FingersOnly); + m_rightArmIK.enabled = (Settings.Enabled && !Settings.FingersOnly); } } @@ -476,42 +471,48 @@ void ParseFingersBones() { LeapTracking.Instance.Rebind(PlayerSetup.Instance.transform.rotation); + // Align rotations of leap fingers to avatar fingers + Animator l_animator = PlayerSetup.Instance._animator; + LeapHand l_leapLeft = LeapTracking.Instance.GetLeftHand(); + LeapHand l_leapRight = LeapTracking.Instance.GetRightHand(); // Try to "fix" rotations, slightly inaccurate after 0YX plane rotation - foreach(var l_tuple in ms_rotationFixChains) + foreach(var l_tuple in ms_fingersChains) { ReorientateTowards( - PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item1), - PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item2), - l_tuple.Item3 ? LeapTracking.Instance.GetLeftHand().GetBone(l_tuple.Item1) : LeapTracking.Instance.GetRightHand().GetBone(l_tuple.Item1), - l_tuple.Item3 ? LeapTracking.Instance.GetLeftHand().GetBone(l_tuple.Item2) : LeapTracking.Instance.GetRightHand().GetBone(l_tuple.Item2), + PlayerSetup.Instance.transform, + l_animator.GetBoneTransform(l_tuple.Item1), + (l_tuple.Item2 != HumanBodyBones.LastBone) ? l_animator.GetBoneTransform(l_tuple.Item2) : null, + l_tuple.Item3 ? l_leapLeft.GetLinkedBone(l_tuple.Item1) : l_leapRight.GetLinkedBone(l_tuple.Item1), + l_tuple.Item3 ? l_leapLeft.GetLinkedBone(l_tuple.Item2) : l_leapRight.GetLinkedBone(l_tuple.Item2), PlaneType.OXZ ); ReorientateTowards( - PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item1), - PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item2), - l_tuple.Item3 ? LeapTracking.Instance.GetLeftHand().GetBone(l_tuple.Item1) : LeapTracking.Instance.GetRightHand().GetBone(l_tuple.Item1), - l_tuple.Item3 ? LeapTracking.Instance.GetLeftHand().GetBone(l_tuple.Item2) : LeapTracking.Instance.GetRightHand().GetBone(l_tuple.Item2), + PlayerSetup.Instance.transform, + l_animator.GetBoneTransform(l_tuple.Item1), + (l_tuple.Item2 != HumanBodyBones.LastBone) ? l_animator.GetBoneTransform(l_tuple.Item2) : null, + l_tuple.Item3 ? l_leapLeft.GetLinkedBone(l_tuple.Item1) : l_leapRight.GetLinkedBone(l_tuple.Item1), + l_tuple.Item3 ? l_leapLeft.GetLinkedBone(l_tuple.Item2) : l_leapRight.GetLinkedBone(l_tuple.Item2), PlaneType.OYX ); } // Bind - m_leftHandOffset.m_target = LeapTracking.Instance.GetLeftHand().GetBone(HumanBodyBones.LeftHand); + m_leftHandOffset.m_target = l_leapLeft.GetLinkedBone(HumanBodyBones.LeftHand); if((m_leftHandOffset.m_source != null) && (m_leftHandOffset.m_target != null)) m_leftHandOffset.m_offset = Quaternion.Inverse(m_leftHandOffset.m_source.rotation) * m_leftHandOffset.m_target.rotation; - m_rightHandOffset.m_target = LeapTracking.Instance.GetRightHand().GetBone(HumanBodyBones.RightHand); + m_rightHandOffset.m_target = l_leapRight.GetLinkedBone(HumanBodyBones.RightHand); if((m_rightHandOffset.m_source != null) && (m_rightHandOffset.m_target != null)) m_rightHandOffset.m_offset = Quaternion.Inverse(m_rightHandOffset.m_source.rotation) * m_rightHandOffset.m_target.rotation; foreach(var l_link in ms_fingers) { - Transform l_transform = PlayerSetup.Instance._animator.GetBoneTransform(l_link.Item1); + Transform l_transform = l_animator.GetBoneTransform(l_link.Item1); if(l_transform != null) { RotationOffset l_offset = new RotationOffset(); l_offset.m_target = l_transform; - l_offset.m_source = (l_link.Item2 ? LeapTracking.Instance.GetLeftHand().GetBone(l_link.Item1) : LeapTracking.Instance.GetRightHand().GetBone(l_link.Item1)); + l_offset.m_source = (l_link.Item2 ? l_leapLeft.GetLinkedBone(l_link.Item1) : l_leapRight.GetLinkedBone(l_link.Item1)); l_offset.m_offset = Quaternion.Inverse(l_offset.m_source.rotation) * l_offset.m_target.rotation; if(l_link.Item2) @@ -522,13 +523,13 @@ void ParseFingersBones() } } - void ReorientateTowards(Transform p_target, Transform p_targetEnd, Transform p_source, Transform p_sourceEnd, PlaneType p_plane) + static void ReorientateTowards(Transform root, Transform p_source, Transform p_sourceEnd, Transform p_target, Transform p_targetEnd, PlaneType p_plane) { - if((p_target != null) && (p_targetEnd != null) && (p_source != null) && (p_sourceEnd != null)) + if((root != null) && (p_target != null) && (p_source != null)) { - Quaternion l_playerInv = Quaternion.Inverse(PlayerSetup.Instance.transform.rotation); - Vector3 l_targetDir = l_playerInv * (p_targetEnd.position - p_target.position); - Vector3 l_sourceDir = l_playerInv * (p_sourceEnd.position - p_source.position); + Quaternion l_rootInv = Quaternion.Inverse(root.rotation); + Vector3 l_targetDir = l_rootInv * (((p_targetEnd != null) ? p_targetEnd.position : GuessEnd(p_target)) - p_target.position); + Vector3 l_sourceDir = l_rootInv * (((p_sourceEnd != null) ? p_sourceEnd.position : GuessEnd(p_source)) - p_source.position); switch(p_plane) { case PlaneType.OXZ: @@ -561,9 +562,30 @@ void ReorientateTowards(Transform p_target, Transform p_targetEnd, Transform p_s if(p_plane == PlaneType.OYX) l_diff = Quaternion.Euler(0f, 0f, l_diff.eulerAngles.y); - Quaternion l_adjusted = l_diff * (l_playerInv * p_target.rotation); - p_target.rotation = PlayerSetup.Instance.transform.rotation * l_adjusted; + Quaternion l_adjusted = l_diff * (l_rootInv * p_target.rotation); + p_target.rotation = root.rotation * l_adjusted; + } + } + + static Vector3 GuessEnd(Transform p_target) + { + Vector3 l_result = p_target.position; + if(p_target.parent != null) + { + float l_dot = -1f; + Vector3 l_axisDir = p_target.position - p_target.parent.position; + foreach(Vector3 l_dir in ms_directions) + { + Vector3 l_rotDir = p_target.rotation * l_dir; + float l_stepDot = Vector3.Dot(l_rotDir, l_axisDir); + if(l_stepDot >= l_dot) + { + l_dot = l_stepDot; + l_result = p_target.position + l_rotDir; + } + } } + return l_result; } } } diff --git a/ml_lme/LeapTracking.cs b/ml_lme/LeapTracking.cs index 89ee4b9..eb96377 100644 --- a/ml_lme/LeapTracking.cs +++ b/ml_lme/LeapTracking.cs @@ -1,6 +1,4 @@ using ABI_RC.Core.Player; -using ABI_RC.Systems.VRModeSwitch; -using System.Collections; using UnityEngine; namespace ml_lme @@ -13,8 +11,8 @@ class LeapTracking : MonoBehaviour static readonly Quaternion ms_hmdRotation = new Quaternion(0f, 0.7071068f, 0.7071068f, 0f); static readonly Quaternion ms_screentopRotation = new Quaternion(0f, 0f, -1f, 0f); - bool m_inVR = false; - + Transform m_root = null; + Transform m_offsetPoint = null; GameObject m_leapHands = null; LeapHand m_leapHandLeft = null; LeapHand m_leapHandRight = null; @@ -22,26 +20,33 @@ class LeapTracking : MonoBehaviour Transform m_leapElbowRight = null; GameObject m_leapControllerModel = null; - float m_scaleRelation = 1f; - void Start() { - if((Instance != null) && (Instance != this)) + if(Instance != null) { Object.DestroyImmediate(this); return; } Instance = this; - m_inVR = Utils.IsInVR(); + + m_root = new GameObject("Root").transform; + m_root.parent = this.transform; + m_root.localPosition = Vector3.zero; + m_root.localRotation = Quaternion.identity; + + m_offsetPoint = new GameObject("OffsetPoint").transform; + m_offsetPoint.parent = m_root; + m_offsetPoint.localPosition = Vector3.zero; + m_offsetPoint.localRotation = Quaternion.identity; m_leapElbowLeft = new GameObject("LeapElbowLeft").transform; - m_leapElbowLeft.parent = this.transform; + m_leapElbowLeft.parent = m_offsetPoint; m_leapElbowLeft.localPosition = Vector3.zero; m_leapElbowLeft.localRotation = Quaternion.identity; m_leapElbowRight = new GameObject("LeapElbowRight").transform; - m_leapElbowRight.parent = this.transform; + m_leapElbowRight.parent = m_offsetPoint; m_leapElbowRight.localPosition = Vector3.zero; m_leapElbowRight.localRotation = Quaternion.identity; @@ -49,7 +54,7 @@ void Start() if(m_leapControllerModel != null) { m_leapControllerModel.name = "LeapModel"; - m_leapControllerModel.transform.parent = this.transform; + m_leapControllerModel.transform.parent = m_offsetPoint; m_leapControllerModel.transform.localPosition = Vector3.zero; m_leapControllerModel.transform.localRotation = Quaternion.identity; } @@ -58,7 +63,7 @@ void Start() if(m_leapHands != null) { m_leapHands.name = "LeapHands"; - m_leapHands.transform.parent = this.transform; + m_leapHands.transform.parent = m_offsetPoint; m_leapHands.transform.localPosition = Vector3.zero; m_leapHands.transform.localRotation = Quaternion.identity; @@ -69,34 +74,21 @@ void Start() OnModelVisibilityChanged(Settings.ModelVisibility); OnVisualHandsChanged(Settings.VisualHands); OnTrackingModeChanged(Settings.TrackingMode); + OnHeadAttachChanged(Settings.HeadAttach); OnRootAngleChanged(Settings.RootAngle); - MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); - - VRModeSwitchEvents.OnInitializeXR.AddListener(this.OnAvatarSetup); - VRModeSwitchEvents.OnDeinitializeXR.AddListener(this.OnAvatarSetup); - - Settings.OnDesktopOffsetChanged.AddListener(this.OnDesktopOffsetChanged); + Settings.OnEnabledChanged.AddListener(this.OnEnabledChanged); Settings.OnModelVisibilityChanged.AddListener(this.OnModelVisibilityChanged); Settings.OnVisualHandsChanged.AddListener(this.OnVisualHandsChanged); Settings.OnTrackingModeChanged.AddListener(this.OnTrackingModeChanged); - Settings.OnRootAngleChanged.AddListener(this.OnRootAngleChanged); Settings.OnHeadAttachChanged.AddListener(this.OnHeadAttachChanged); Settings.OnHeadOffsetChanged.AddListener(this.OnHeadOffsetChanged); + Settings.OnDesktopOffsetChanged.AddListener(this.OnDesktopOffsetChanged); + Settings.OnRootAngleChanged.AddListener(this.OnRootAngleChanged); - GameEvents.OnAvatarClear.AddListener(this.OnAvatarClear); - GameEvents.OnAvatarSetup.AddListener(this.OnAvatarSetup); GameEvents.OnPlayspaceScale.AddListener(this.OnPlayspaceScale); } - IEnumerator WaitForLocalPlayer() - { - while(PlayerSetup.Instance == null) - yield return null; - - OnHeadAttachChanged(Settings.HeadAttach); - } - void OnDestroy() { if(Instance == this) @@ -120,19 +112,23 @@ void OnDestroy() Object.Destroy(m_leapControllerModel); m_leapControllerModel = null; - VRModeSwitchEvents.OnInitializeXR.RemoveListener(this.OnAvatarSetup); - VRModeSwitchEvents.OnDeinitializeXR.RemoveListener(this.OnAvatarSetup); + if(m_offsetPoint != null) + Destroy(m_offsetPoint.gameObject); + m_offsetPoint = null; - Settings.OnDesktopOffsetChanged.RemoveListener(this.OnDesktopOffsetChanged); + if(m_root != null) + Destroy(m_root.gameObject); + m_root = null; + + Settings.OnEnabledChanged.RemoveListener(this.OnEnabledChanged); Settings.OnModelVisibilityChanged.RemoveListener(this.OnModelVisibilityChanged); Settings.OnVisualHandsChanged.RemoveListener(this.OnVisualHandsChanged); Settings.OnTrackingModeChanged.RemoveListener(this.OnTrackingModeChanged); - Settings.OnRootAngleChanged.RemoveListener(this.OnRootAngleChanged); Settings.OnHeadAttachChanged.RemoveListener(this.OnHeadAttachChanged); Settings.OnHeadOffsetChanged.RemoveListener(this.OnHeadOffsetChanged); + Settings.OnDesktopOffsetChanged.RemoveListener(this.OnDesktopOffsetChanged); + Settings.OnRootAngleChanged.RemoveListener(this.OnRootAngleChanged); - GameEvents.OnAvatarClear.RemoveListener(this.OnAvatarClear); - GameEvents.OnAvatarSetup.RemoveListener(this.OnAvatarSetup); GameEvents.OnPlayspaceScale.RemoveListener(this.OnPlayspaceScale); } @@ -140,6 +136,10 @@ void Update() { if(Settings.Enabled) { + Transform l_camera = PlayerSetup.Instance.GetActiveCamera().transform; + m_root.position = l_camera.position; + m_root.rotation = (Settings.HeadAttach ? l_camera.rotation : PlayerSetup.Instance.GetPlayerRotation()); + LeapParser.LeapData l_data = LeapManager.Instance.GetLatestData(); if(l_data.m_leftHand.m_present) @@ -185,21 +185,22 @@ public void Rebind(Quaternion p_base) } // Settings - void OnDesktopOffsetChanged(Vector3 p_offset) + void OnEnabledChanged(bool p_state) { - if(!Settings.HeadAttach) - this.transform.localPosition = p_offset * (!m_inVR ? m_scaleRelation : 1f); + OnModelVisibilityChanged(Settings.ModelVisibility); + OnVisualHandsChanged(Settings.VisualHands); } void OnModelVisibilityChanged(bool p_state) { - m_leapControllerModel.SetActive(p_state); + if(m_leapControllerModel != null) + m_leapControllerModel.SetActive(Settings.Enabled && p_state); } void OnVisualHandsChanged(bool p_state) { - m_leapHandLeft?.SetMeshActive(p_state); - m_leapHandRight?.SetMeshActive(p_state); + m_leapHandLeft?.SetMeshActive(Settings.Enabled && p_state); + m_leapHandRight?.SetMeshActive(Settings.Enabled && p_state); } void OnTrackingModeChanged(Settings.LeapTrackingMode p_mode) @@ -218,51 +219,42 @@ void OnTrackingModeChanged(Settings.LeapTrackingMode p_mode) } } - void OnRootAngleChanged(Vector3 p_angle) - { - this.transform.localRotation = Quaternion.Euler(p_angle); - } - void OnHeadAttachChanged(bool p_state) { - if(!m_inVR) - { - this.transform.parent = (p_state ? PlayerSetup.Instance.desktopCamera.transform : PlayerSetup.Instance.desktopCameraRig.transform); - this.transform.localPosition = (p_state ? Settings.HeadOffset : Settings.DesktopOffset) * m_scaleRelation; - } - else - { - this.transform.parent = (p_state ? PlayerSetup.Instance.vrCamera.transform : PlayerSetup.Instance.vrCameraRig.transform); - this.transform.localPosition = (p_state ? Settings.HeadOffset : Settings.DesktopOffset); - } - - this.transform.localScale = Vector3.one * (!m_inVR ? m_scaleRelation : 1f); - this.transform.localRotation = Quaternion.Euler(Settings.RootAngle); + if(m_offsetPoint != null) + m_offsetPoint.localPosition = (p_state ? Settings.HeadOffset : Settings.DesktopOffset); } void OnHeadOffsetChanged(Vector3 p_offset) { - if(Settings.HeadAttach) - this.transform.localPosition = p_offset * (!m_inVR ? m_scaleRelation : 1f); + if(Settings.HeadAttach && (m_offsetPoint != null)) + m_offsetPoint.localPosition = p_offset; } - // Game events - void OnAvatarClear() + void OnDesktopOffsetChanged(Vector3 p_offset) { - m_scaleRelation = 1f; - OnHeadAttachChanged(Settings.HeadAttach); + if(!Settings.HeadAttach && (m_offsetPoint != null)) + m_offsetPoint.localPosition = p_offset; } - void OnAvatarSetup() + void OnRootAngleChanged(Vector3 p_angle) { - m_inVR = Utils.IsInVR(); - OnHeadAttachChanged(Settings.HeadAttach); + if(m_offsetPoint != null) + m_offsetPoint.localRotation = Quaternion.Euler(p_angle); } + // Game events void OnPlayspaceScale(float p_relation) { - m_scaleRelation = p_relation; - OnHeadAttachChanged(Settings.HeadAttach); + try + { + if(m_root != null) + m_root.localScale = Vector3.one * p_relation; + } + catch(System.Exception e) + { + MelonLoader.MelonLogger.Error(e); + } } // Utils diff --git a/ml_lme/Main.cs b/ml_lme/Main.cs index db72a55..c4eeebc 100644 --- a/ml_lme/Main.cs +++ b/ml_lme/Main.cs @@ -14,7 +14,6 @@ public override void OnInitializeMelon() Settings.Init(); AssetsHandler.Load(); GameEvents.Init(HarmonyInstance); - ModSupporter.Init(); MelonLoader.MelonCoroutines.Start(WaitForRootLogic()); } @@ -31,7 +30,7 @@ IEnumerator WaitForRootLogic() while(ABI_RC.Core.RootLogic.Instance == null) yield return null; - m_leapManager = new GameObject("LeapMotionManager").AddComponent(); + m_leapManager = new GameObject("[LeapMotionExtension]").AddComponent(); } } } diff --git a/ml_lme/ModSupporter.cs b/ml_lme/ModSupporter.cs deleted file mode 100644 index d957c58..0000000 --- a/ml_lme/ModSupporter.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Collections; -using System.Linq; - -namespace ml_lme -{ - static class ModSupporter - { - static bool ms_copycatMod = false; - - public static void Init() - { - if(MelonLoader.MelonMod.RegisteredMelons.FirstOrDefault(m => m.Info.Name == "PlayerMovementCopycat") != null) - MelonLoader.MelonCoroutines.Start(WaitForCopycatInstance()); - } - - // PlayerMovementCopycat support - static IEnumerator WaitForCopycatInstance() - { - while(ml_pmc.PoseCopycat.Instance == null) - yield return null; - - ms_copycatMod = true; - } - static bool IsCopycating() => (ml_pmc.PoseCopycat.Instance.IsActive() && ml_pmc.PoseCopycat.Instance.IsFingerTrackingActive()); - - public static bool SkipFingersOverride() - { - bool l_result = false; - l_result |= (ms_copycatMod && IsCopycating()); - return l_result; - } - } -} diff --git a/ml_lme/Properties/AssemblyInfo.cs b/ml_lme/Properties/AssemblyInfo.cs index 723f088..a3079fe 100644 --- a/ml_lme/Properties/AssemblyInfo.cs +++ b/ml_lme/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.5.2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.6.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")] [assembly: MelonLoader.MelonOptionalDependencies("ml_pmc")] [assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] diff --git a/ml_lme/README.md b/ml_lme/README.md index 0d2a0ec..fa7d034 100644 --- a/ml_lme/README.md +++ b/ml_lme/README.md @@ -1,13 +1,13 @@ # Leap Motion Extension This mod allows you to use your Leap Motion controller for hands and fingers tracking. -[![](.github/img_01.png)](https://youtu.be/nak1C8uibgc) +![](.github/img_01.png) # Installation * Install [latest Ultraleap Gemini tracking software](https://developer.leapmotion.com/tracking-software-download) * Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader) * Get [latest release DLL](../../../releases/latest): - * Put `ml_lme.dll` in `Mods` folder of game + * Put `LeapMotionExtension.dll` in `Mods` folder of game # Usage ## Settings @@ -26,4 +26,4 @@ Available mod's settings in `Settings - Implementation - Leap Motion Tracking`: * **Interact gesture threadhold:** activation limit for interaction based on hand gesture; 80 by default. * **Grip gesture threadhold:** activation limit for grip based on hand gesture; 40 by default. * **Filter humanoid limits:** Limits fingers rotations to be valid for Unity's Mechanim; `true` by default - * Note: Enabling this option ensures that visual representation of your fingers will be same for you and remote players, but it cancels out additional finger segments rotations that can be better visually in most cases. + * Note: Enabling this option ensures that visual representation of your fingers will be same for you and remote players, but it cancels out additional finger segments rotations that can be better visually in some cases. diff --git a/ml_lme/ResourcesHandler.cs b/ml_lme/ResourcesHandler.cs index 302657d..1804d96 100644 --- a/ml_lme/ResourcesHandler.cs +++ b/ml_lme/ResourcesHandler.cs @@ -6,15 +6,16 @@ namespace ml_lme { static class ResourcesHandler { + readonly static string ms_namespace = typeof(ResourcesHandler).Namespace; + public static string GetEmbeddedResource(string p_name) { string l_result = ""; Assembly l_assembly = Assembly.GetExecutingAssembly(); - string l_assemblyName = l_assembly.GetName().Name; try { - Stream l_libraryStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name); + Stream l_libraryStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + p_name); StreamReader l_streadReader = new StreamReader(l_libraryStream); l_result = l_streadReader.ReadToEnd(); } diff --git a/ml_lme/Utils.cs b/ml_lme/Utils.cs index 2638fb7..f920f88 100644 --- a/ml_lme/Utils.cs +++ b/ml_lme/Utils.cs @@ -31,9 +31,9 @@ public static void ShowHUDNotification(string p_title, string p_message, string if(CohtmlHud.Instance != null) { if(p_immediate) - CohtmlHud.Instance.ViewDropTextImmediate(p_title, p_message, p_small); + CohtmlHud.Instance.ViewDropTextImmediate(p_title, p_message, p_small, "", false); else - CohtmlHud.Instance.ViewDropText(p_title, p_message, p_small); + CohtmlHud.Instance.ViewDropText(p_title, p_message, p_small, "", false); } } diff --git a/ml_lme/ml_lme.csproj b/ml_lme/ml_lme.csproj index a6dae4c..c983b40 100644 --- a/ml_lme/ml_lme.csproj +++ b/ml_lme/ml_lme.csproj @@ -4,10 +4,11 @@ netstandard2.1 x64 LeapMotionExtension - 1.5.2 + 1.6.0 SDraw - None + SDraw LeapMotionExtension + LeapMotionExtension @@ -68,11 +69,6 @@ false false - - D:\games\Steam\steamapps\common\ChilloutVR\Mods\ml_pmc.dll - false - false - D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.dll false diff --git a/ml_pam/ArmMover.cs b/ml_pam/ArmMover.cs index 51afdea..11fdfdd 100644 --- a/ml_pam/ArmMover.cs +++ b/ml_pam/ArmMover.cs @@ -1,7 +1,9 @@ using ABI.CCK.Components; using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.Player; +using ABI_RC.Systems.VRModeSwitch; using RootMotion.FinalIK; +using System.Collections; using UnityEngine; namespace ml_pam @@ -22,61 +24,79 @@ struct IKInfo public Transform m_rightHandTarget; } - const float c_offsetLimit = 0.5f; const KeyCode c_leftKey = KeyCode.Q; const KeyCode c_rightKey = KeyCode.E; - static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f); + static ArmMover ms_instance = null; + static readonly Quaternion ms_offsetLeft = Quaternion.Euler(270f, 90f, 0f); static readonly Quaternion ms_offsetRight = Quaternion.Euler(270f, 270f, 0f); - bool m_inVR = false; VRIK m_vrIK = null; - float m_armLength = 0f; - float m_playspaceScale = 1f; + Vector4 m_armsLength; // x,y - from upper arm to hand; z,w - from center to upper arm + Transform m_camera = null; + IKInfo m_ikInfo; - bool m_enabled = true; - IKInfo m_vrIKInfo; - Transform m_rootLeft = null; - Transform m_rootRight = null; + Transform m_root = null; Transform m_leftTarget = null; Transform m_rightTarget = null; + Transform m_leftRotationTarget = null; + Transform m_rightRotationTarget = null; ArmIK m_armIKLeft = null; ArmIK m_armIKRight = null; CVRPickupObject m_pickup = null; Matrix4x4 m_offset; + HandState m_leftHandState = HandState.Empty; HandState m_rightHandState = HandState.Empty; + Vector2 m_handsWeights; AvatarBoolParameter m_leftHandParameter = null; AvatarBoolParameter m_rightHandParameter = null; + Coroutine m_disableTask = null; + // Unity events + void Awake() + { + if(ms_instance != null) + { + DestroyImmediate(this); + return; + } + + ms_instance = this; + DontDestroyOnLoad(this); + } + void Start() { - m_inVR = Utils.IsInVR(); + m_camera = PlayerSetup.Instance.GetActiveCamera().transform; - m_rootLeft = new GameObject("[ArmPickupLeft]").transform; - m_rootLeft.parent = PlayerSetup.Instance.GetActiveCamera().transform; - m_rootLeft.localPosition = Vector3.zero; - m_rootLeft.localRotation = Quaternion.identity; + m_root = new GameObject("Root").transform; + m_root.parent = this.transform; + m_root.localPosition = Vector3.zero; + m_root.localRotation = Quaternion.identity; - m_leftTarget = new GameObject("Target").transform; - m_leftTarget.parent = m_rootLeft; - m_leftTarget.localPosition = new Vector3(c_offsetLimit * -Settings.GrabOffset, 0f, 0f); + m_leftTarget = new GameObject("TargetLeft").transform; + m_leftTarget.parent = m_root; + m_leftTarget.localPosition = Vector3.zero; m_leftTarget.localRotation = Quaternion.identity; - m_rootRight = new GameObject("[ArmPickupRight]").transform; - m_rootRight.parent = PlayerSetup.Instance.GetActiveCamera().transform; - m_rootRight.localPosition = Vector3.zero; - m_rootRight.localRotation = Quaternion.identity; + m_leftRotationTarget = new GameObject("RotationTarget").transform; + m_leftRotationTarget.parent = m_leftTarget; + m_leftRotationTarget.localPosition = Vector3.zero; + m_leftRotationTarget.localRotation = Quaternion.identity; - m_rightTarget = new GameObject("Target").transform; - m_rightTarget.parent = m_rootRight; - m_rightTarget.localPosition = new Vector3(c_offsetLimit * Settings.GrabOffset, 0f, 0f); + m_rightTarget = new GameObject("TargetRight").transform; + m_rightTarget.parent = m_root; + m_rightTarget.localPosition = Vector3.zero; m_rightTarget.localRotation = Quaternion.identity; - m_enabled = Settings.Enabled; + m_rightRotationTarget = new GameObject("RotationTarget").transform; + m_rightRotationTarget.parent = m_rightTarget; + m_rightRotationTarget.localPosition = Vector3.zero; + m_rightRotationTarget.localRotation = Quaternion.identity; Settings.OnEnabledChanged.AddListener(this.OnEnabledChanged); Settings.OnGrabOffsetChanged.AddListener(this.OnGrabOffsetChanged); @@ -86,25 +106,44 @@ void Start() GameEvents.OnAvatarClear.AddListener(this.OnAvatarClear); GameEvents.OnAvatarSetup.AddListener(this.OnAvatarSetup); GameEvents.OnAvatarReuse.AddListener(this.OnAvatarReuse); - GameEvents.OnPlayspaceScale.AddListener(this.OnPlayspaceScale); + GameEvents.OnIKScaling.AddListener(this.OnIKScaling); GameEvents.OnPickupGrab.AddListener(this.OnPickupGrab); GameEvents.OnPickupDrop.AddListener(this.OnPickupDrop); + + VRModeSwitchEvents.OnCompletedVRModeSwitch.AddListener(this.OnVRModeSwitch); } void OnDestroy() { + if(ms_instance == this) + ms_instance = null; + + if(m_disableTask != null) + StopCoroutine(m_disableTask); + m_disableTask = null; + RemoveArmIK(); - if(m_rootLeft != null) - Destroy(m_rootLeft); - m_rootLeft = null; + if(m_leftRotationTarget != null) + Destroy(m_leftRotationTarget.gameObject); + m_leftRotationTarget = null; + + if(m_leftTarget != null) + Destroy(m_leftTarget.gameObject); m_leftTarget = null; - if(m_rootRight != null) - Destroy(m_rootRight); - m_rootRight = null; + if(m_rightRotationTarget != null) + Destroy(m_rightRotationTarget.gameObject); + m_rightRotationTarget = null; + + if(m_rightTarget != null) + Destroy(m_rightTarget.gameObject); m_rightTarget = null; + if(m_root != null) + Destroy(m_root.gameObject); + m_root = null; + m_pickup = null; m_vrIK = null; @@ -116,13 +155,21 @@ void OnDestroy() GameEvents.OnAvatarClear.RemoveListener(this.OnAvatarClear); GameEvents.OnAvatarSetup.RemoveListener(this.OnAvatarSetup); GameEvents.OnAvatarReuse.RemoveListener(this.OnAvatarReuse); - GameEvents.OnPlayspaceScale.RemoveListener(this.OnPlayspaceScale); + GameEvents.OnIKScaling.AddListener(this.OnIKScaling); GameEvents.OnPickupGrab.RemoveListener(this.OnPickupGrab); GameEvents.OnPickupDrop.RemoveListener(this.OnPickupDrop); + + VRModeSwitchEvents.OnCompletedVRModeSwitch.RemoveListener(this.OnVRModeSwitch); } void Update() { + if((m_root != null) && (m_camera != null)) + { + m_root.position = m_camera.position; + m_root.rotation = m_camera.rotation; + } + if(!ReferenceEquals(m_pickup, null) && (m_pickup == null)) OnPickupDrop(m_pickup); @@ -130,205 +177,170 @@ void Update() { case HandState.Empty: { - if(Settings.HandsExtension && Input.GetKeyDown(c_leftKey)) - { + if(Settings.Enabled && Settings.HandsExtension && Input.GetKey(c_leftKey) && !ViewManager.Instance.IsAnyMenuOpen) m_leftHandState = HandState.Extended; - m_rootLeft.localPosition = new Vector3(0f, 0f, m_armLength * m_playspaceScale); - SetArmActive(Settings.LeadHand.Left, true); - } } break; case HandState.Extended: { - if(Input.GetKeyUp(c_leftKey)) - { + if(!Input.GetKey(c_leftKey)) m_leftHandState = HandState.Empty; - SetArmActive(Settings.LeadHand.Left, false); - } - } - break; - case HandState.Pickup: - { - if(m_pickup != null) - { - Matrix4x4 l_result = m_pickup.transform.GetMatrix() * m_offset; - m_rootLeft.position = l_result * ms_pointVector; - } } break; } - switch(m_rightHandState) { case HandState.Empty: { - if(Settings.HandsExtension && Input.GetKeyDown(c_rightKey)) - { + if(Settings.Enabled && Settings.HandsExtension && Input.GetKey(c_rightKey) && !ViewManager.Instance.IsAnyMenuOpen) m_rightHandState = HandState.Extended; - m_rootRight.localPosition = new Vector3(0f, 0f, m_armLength * m_playspaceScale); - SetArmActive(Settings.LeadHand.Right, true); - } } break; case HandState.Extended: { - if(Input.GetKeyUp(c_rightKey)) - { + if(!Input.GetKey(c_rightKey)) m_rightHandState = HandState.Empty; - SetArmActive(Settings.LeadHand.Right, false); - } } break; - case HandState.Pickup: + } + + m_handsWeights.x = Mathf.Clamp01(m_handsWeights.x + ((m_leftHandState != HandState.Empty) ? 1f : -1f) * Time.unscaledDeltaTime * Settings.ExtensionSpeed); + m_handsWeights.y = Mathf.Clamp01(m_handsWeights.y + ((m_rightHandState != HandState.Empty) ? 1f : -1f) * Time.unscaledDeltaTime * Settings.ExtensionSpeed); + + UpdateArmIK(m_armIKLeft, m_handsWeights.x); + UpdateArmIK(m_armIKRight, m_handsWeights.y); + + m_leftHandParameter?.SetValue(m_leftHandState != HandState.Empty); + m_rightHandParameter?.SetValue(m_rightHandState != HandState.Empty); + + if(m_leftHandState != HandState.Empty) + { + if(m_pickup != null) { - if(m_pickup != null) - { - Matrix4x4 l_result = m_pickup.transform.GetMatrix() * m_offset; - m_rootRight.position = l_result * ms_pointVector; - } + Matrix4x4 l_result = m_pickup.transform.GetMatrix() * m_offset; + m_leftTarget.position = l_result.GetPosition(); + m_leftTarget.rotation = l_result.rotation; + m_leftTarget.localPosition = Vector3.ClampMagnitude(m_leftTarget.localPosition, m_armsLength.x); + } + else + { + m_leftTarget.localPosition = new Vector3(0f, 0f, m_armsLength.x); + m_leftTarget.localRotation = Quaternion.identity; + } + } + if(m_rightHandState != HandState.Empty) + { + if(m_pickup != null) + { + Matrix4x4 l_result = m_pickup.transform.GetMatrix() * m_offset; + m_rightTarget.position = l_result.GetPosition(); + m_rightTarget.rotation = l_result.rotation; + m_rightTarget.localPosition = Vector3.ClampMagnitude(m_rightTarget.localPosition, m_armsLength.y); + } + else + { + m_rightTarget.localPosition = new Vector3(0f, 0f, m_armsLength.y); + m_rightTarget.localRotation = Quaternion.identity; } - break; + } + } + + void LateUpdate() + { + if((m_root != null) && (m_camera != null)) + { + m_root.position = m_camera.position; + m_root.rotation = m_camera.rotation; } } // VRIK updates void OnIKPreUpdate() { - if(m_enabled) + if(!Mathf.Approximately(m_handsWeights.x, 0f)) { - if(m_leftHandState != HandState.Empty) - { - m_vrIKInfo.m_leftHandTarget = m_vrIK.solver.leftArm.target; - m_vrIKInfo.m_armsWeights.x = m_vrIK.solver.leftArm.positionWeight; - m_vrIKInfo.m_armsWeights.y = m_vrIK.solver.leftArm.rotationWeight; + m_ikInfo.m_leftHandTarget = m_vrIK.solver.leftArm.target; + m_ikInfo.m_armsWeights.x = m_vrIK.solver.leftArm.positionWeight; + m_ikInfo.m_armsWeights.y = m_vrIK.solver.leftArm.rotationWeight; - m_vrIK.solver.leftArm.positionWeight = 1f; - m_vrIK.solver.leftArm.rotationWeight = 1f; - m_vrIK.solver.leftArm.target = m_leftTarget; - } - if(m_rightHandState != HandState.Empty) - { - m_vrIKInfo.m_rightHandTarget = m_vrIK.solver.rightArm.target; - m_vrIKInfo.m_armsWeights.z = m_vrIK.solver.rightArm.positionWeight; - m_vrIKInfo.m_armsWeights.w = m_vrIK.solver.rightArm.rotationWeight; + m_vrIK.solver.leftArm.positionWeight = m_handsWeights.x; + m_vrIK.solver.leftArm.rotationWeight = m_handsWeights.x; + m_vrIK.solver.leftArm.target = m_leftRotationTarget; + } + if(!Mathf.Approximately(m_handsWeights.y, 0f)) + { + m_ikInfo.m_rightHandTarget = m_vrIK.solver.rightArm.target; + m_ikInfo.m_armsWeights.z = m_vrIK.solver.rightArm.positionWeight; + m_ikInfo.m_armsWeights.w = m_vrIK.solver.rightArm.rotationWeight; - m_vrIK.solver.rightArm.positionWeight = 1f; - m_vrIK.solver.rightArm.rotationWeight = 1f; - m_vrIK.solver.rightArm.target = m_rightTarget; - } + m_vrIK.solver.rightArm.positionWeight = m_handsWeights.y; + m_vrIK.solver.rightArm.rotationWeight = m_handsWeights.y; + m_vrIK.solver.rightArm.target = m_rightRotationTarget; } } void OnIKPostUpdate() { - if(m_enabled) + if(!Mathf.Approximately(m_handsWeights.x, 0f)) { - if(m_leftHandState != HandState.Empty) - { - m_vrIK.solver.leftArm.target = m_vrIKInfo.m_leftHandTarget; - m_vrIK.solver.leftArm.positionWeight = m_vrIKInfo.m_armsWeights.x; - m_vrIK.solver.leftArm.rotationWeight = m_vrIKInfo.m_armsWeights.y; - } - if(m_rightHandState != HandState.Empty) - { - m_vrIK.solver.rightArm.target = m_vrIKInfo.m_rightHandTarget; - m_vrIK.solver.rightArm.positionWeight = m_vrIKInfo.m_armsWeights.z; - m_vrIK.solver.rightArm.rotationWeight = m_vrIKInfo.m_armsWeights.w; - } + m_vrIK.solver.leftArm.target = m_ikInfo.m_leftHandTarget; + m_vrIK.solver.leftArm.positionWeight = m_ikInfo.m_armsWeights.x; + m_vrIK.solver.leftArm.rotationWeight = m_ikInfo.m_armsWeights.y; + } + if(!Mathf.Approximately(m_handsWeights.y, 0f)) + { + m_vrIK.solver.rightArm.target = m_ikInfo.m_rightHandTarget; + m_vrIK.solver.rightArm.positionWeight = m_ikInfo.m_armsWeights.z; + m_vrIK.solver.rightArm.rotationWeight = m_ikInfo.m_armsWeights.w; } } // Settings void OnEnabledChanged(bool p_state) { - m_enabled = p_state; - if(p_state) { - if(m_leftHandState != HandState.Empty) - SetArmActive(Settings.LeadHand.Left, true); - if(m_rightHandState != HandState.Empty) - SetArmActive(Settings.LeadHand.Right, true); + if(this.enabled) + { + if(m_disableTask != null) + { + StopCoroutine(m_disableTask); + m_disableTask = null; + } + } + else + this.enabled = true; - OnHandsExtensionChanged(Settings.HandsExtension); + OnLeadingHandChanged(Settings.LeadingHand); } else - SetArmActive(Settings.LeadHand.Both, false, true); + { + m_leftHandState = HandState.Empty; + m_rightHandState = HandState.Empty; + + m_disableTask = StartCoroutine(WaitToDisable()); + } } void OnGrabOffsetChanged(float p_value) { - if(m_leftTarget != null) - m_leftTarget.localPosition = new Vector3(c_offsetLimit * m_playspaceScale * -p_value, 0f, 0f); - if(m_rightTarget != null) - m_rightTarget.localPosition = new Vector3(c_offsetLimit * m_playspaceScale * p_value, 0f, 0f); + if(m_leftRotationTarget != null) + m_leftRotationTarget.localPosition = new Vector3(-m_armsLength.z * p_value * 2f, 0f, 0f); + if(m_rightRotationTarget != null) + m_rightRotationTarget.localPosition = new Vector3(m_armsLength.w * p_value * 2f, 0f, 0f); } void OnLeadingHandChanged(Settings.LeadHand p_hand) { - if(m_pickup != null) - { - if(m_leftHandState == HandState.Pickup) - { - m_leftHandState = HandState.Empty; - SetArmActive(Settings.LeadHand.Left, false); - } - if(m_rightHandState == HandState.Pickup) - { - m_rightHandState = HandState.Empty; - SetArmActive(Settings.LeadHand.Right, false); - } - - switch(p_hand) - { - case Settings.LeadHand.Left: - m_leftHandState = HandState.Pickup; - break; - case Settings.LeadHand.Right: - m_rightHandState = HandState.Pickup; - break; - case Settings.LeadHand.Both: - { - m_leftHandState = HandState.Pickup; - m_rightHandState = HandState.Pickup; - } - break; - } - - SetArmActive(p_hand, true); - } + SetLeadingHandState((m_pickup != null) ? HandState.Pickup : HandState.Empty); + SetUnleadingHandState(HandState.Empty); } void OnHandsExtensionChanged(bool p_state) { - if(m_enabled) - { - if(p_state) - { - if((m_leftHandState == HandState.Empty) && Input.GetKey(c_leftKey)) - { - m_leftHandState = HandState.Extended; - SetArmActive(Settings.LeadHand.Left, true); - } - if((m_rightHandState == HandState.Empty) && Input.GetKey(c_rightKey)) - { - m_rightHandState = HandState.Extended; - SetArmActive(Settings.LeadHand.Right, true); - } - } - else - { - if(m_leftHandState == HandState.Extended) - { - m_leftHandState = HandState.Empty; - SetArmActive(Settings.LeadHand.Left, false); - } - if(m_rightHandState == HandState.Extended) - { - m_rightHandState = HandState.Empty; - SetArmActive(Settings.LeadHand.Right, false); - } - } - } + if(m_leftHandState == HandState.Extended) + m_leftHandState = HandState.Empty; + if(m_rightHandState == HandState.Extended) + m_rightHandState = HandState.Empty; } // Game events @@ -337,65 +349,81 @@ void OnAvatarClear() m_vrIK = null; m_armIKLeft = null; m_armIKRight = null; - m_armLength = 0f; + m_armsLength.Set(0f, 0f, 0f, 0f); m_leftHandParameter = null; m_rightHandParameter = null; } void OnAvatarSetup() { - m_inVR = Utils.IsInVR(); - m_vrIK = PlayerSetup.Instance._animator.GetComponent(); - - ReparentRoots(); + m_camera = PlayerSetup.Instance.GetActiveCamera().transform; if(PlayerSetup.Instance._animator.isHuman) { + m_vrIK = PlayerSetup.Instance._animator.GetComponent(); Utils.SetAvatarTPose(); - Transform l_leftHand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand); + Animator l_animator = PlayerSetup.Instance._animator; + Matrix4x4 l_avatarMatrixInv = l_animator.transform.GetMatrix().inverse; // Animator and avatar are on same game object + + Transform l_leftHand = l_animator.GetBoneTransform(HumanBodyBones.LeftHand); if(l_leftHand != null) - m_leftTarget.localRotation = ms_offsetLeft * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_leftHand.GetMatrix()).rotation; - Transform l_rightHand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand); + m_leftRotationTarget.localRotation = ms_offsetLeft * (l_avatarMatrixInv * l_leftHand.GetMatrix()).rotation; + Transform l_rightHand = l_animator.GetBoneTransform(HumanBodyBones.RightHand); if(l_rightHand != null) - m_rightTarget.localRotation = ms_offsetRight * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_rightHand.GetMatrix()).rotation; - - if(m_vrIK != null) + m_rightRotationTarget.localRotation = ms_offsetRight * (l_avatarMatrixInv * l_rightHand.GetMatrix()).rotation; + + m_armsLength.x = GetChainLength(new Transform[]{ + l_animator.GetBoneTransform(HumanBodyBones.LeftUpperArm), + l_animator.GetBoneTransform(HumanBodyBones.LeftLowerArm), + l_animator.GetBoneTransform(HumanBodyBones.LeftHand) + }); + m_armsLength.y = GetChainLength(new Transform[]{ + l_animator.GetBoneTransform(HumanBodyBones.RightUpperArm), + l_animator.GetBoneTransform(HumanBodyBones.RightLowerArm), + l_animator.GetBoneTransform(HumanBodyBones.RightHand) + }); + m_armsLength.z = Mathf.Abs((l_avatarMatrixInv * l_animator.GetBoneTransform(HumanBodyBones.LeftUpperArm).GetMatrix()).GetPosition().x); + m_armsLength.w = Mathf.Abs((l_avatarMatrixInv * l_animator.GetBoneTransform(HumanBodyBones.RightUpperArm).GetMatrix()).GetPosition().x); + + if(!Utils.IsInVR()) { - m_armLength = m_vrIK.solver.leftArm.mag * 1.25f; - m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreUpdate); - m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate); + if(m_vrIK != null) + { + m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreUpdate); + m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate); + } + else + SetupArmIK(); } - else if(!m_inVR) - SetupArmIK(); } m_leftHandParameter = new AvatarBoolParameter("LeftHandExtended", PlayerSetup.Instance.animatorManager); m_rightHandParameter = new AvatarBoolParameter("RightHandExtended", PlayerSetup.Instance.animatorManager); - OnEnabledChanged(m_enabled); + OnEnabledChanged(Settings.Enabled); + OnGrabOffsetChanged(Settings.GrabOffset); } void OnAvatarReuse() { // Old VRIK is destroyed by game - m_inVR = Utils.IsInVR(); m_vrIK = PlayerSetup.Instance._animator.GetComponent(); - ReparentRoots(); - - if(m_inVR) + if(Utils.IsInVR()) RemoveArmIK(); - - if(m_vrIK != null) + else { - m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreUpdate); - m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate); + if(m_vrIK != null) + { + m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreUpdate); + m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate); + } + else + SetupArmIK(); } - else if(!m_inVR) - SetupArmIK(); - OnEnabledChanged(m_enabled); + OnEnabledChanged(Settings.Enabled); } void OnPickupGrab(CVRPickupObject p_pickup, Vector3 p_hit) @@ -416,97 +444,82 @@ void OnPickupGrab(CVRPickupObject p_pickup, Vector3 p_hit) } } else - m_offset = m_pickup.transform.GetMatrix().inverse * Matrix4x4.Translate(p_hit); - - switch(Settings.LeadingHand) - { - case Settings.LeadHand.Left: - m_leftHandState = HandState.Pickup; - break; - case Settings.LeadHand.Right: - m_rightHandState = HandState.Pickup; - break; - case Settings.LeadHand.Both: - { - m_leftHandState = HandState.Pickup; - m_rightHandState = HandState.Pickup; - } - break; - } + m_offset = m_pickup.transform.GetMatrix().inverse * Matrix4x4.TRS(p_hit, m_camera.rotation, Vector3.one); - SetArmActive(Settings.LeadingHand, true); + if(Settings.Enabled) + OnLeadingHandChanged(Settings.LeadingHand); } } void OnPickupDrop(CVRPickupObject p_pickup) { - if(m_pickup == p_pickup) + if(ReferenceEquals(m_pickup, p_pickup) || (m_pickup == p_pickup)) { m_pickup = null; - switch(Settings.LeadingHand) - { - case Settings.LeadHand.Left: - m_leftHandState = HandState.Empty; - break; - case Settings.LeadHand.Right: - m_rightHandState = HandState.Empty; - break; - case Settings.LeadHand.Both: - { - m_leftHandState = HandState.Empty; - m_rightHandState = HandState.Empty; - } - break; - } - SetArmActive(Settings.LeadingHand, false); + + if(Settings.Enabled) + SetLeadingHandState(HandState.Empty); } } - void OnPlayspaceScale(float p_relation) + void OnIKScaling(float p_relation) { - m_playspaceScale = p_relation; - OnGrabOffsetChanged(Settings.GrabOffset); + if(m_root != null) + m_root.localScale = Vector3.one * p_relation; + } + + void OnVRModeSwitch(bool p_state) + { + try + { + m_camera = PlayerSetup.Instance.GetActiveCamera().transform; + this.enabled = !Utils.IsInVR(); + } + catch(System.Exception e) + { + MelonLoader.MelonLogger.Error(e); + } } // Arbitrary void SetupArmIK() { - Transform l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.UpperChest); + Animator l_animator = PlayerSetup.Instance._animator; + + Transform l_chest = l_animator.GetBoneTransform(HumanBodyBones.UpperChest); if(l_chest == null) - l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Chest); + l_chest = l_animator.GetBoneTransform(HumanBodyBones.Chest); if(l_chest == null) - l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Spine); + l_chest = l_animator.GetBoneTransform(HumanBodyBones.Spine); m_armIKLeft = PlayerSetup.Instance._avatar.AddComponent(); m_armIKLeft.solver.isLeft = true; m_armIKLeft.solver.SetChain( l_chest, - PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftShoulder), - PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftUpperArm), - PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftLowerArm), - PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand), - PlayerSetup.Instance._animator.transform + l_animator.GetBoneTransform(HumanBodyBones.LeftShoulder), + l_animator.GetBoneTransform(HumanBodyBones.LeftUpperArm), + l_animator.GetBoneTransform(HumanBodyBones.LeftLowerArm), + l_animator.GetBoneTransform(HumanBodyBones.LeftHand), + l_animator.transform ); - m_armIKLeft.solver.arm.target = m_leftTarget; + m_armIKLeft.solver.arm.target = m_leftRotationTarget; m_armIKLeft.solver.arm.positionWeight = 1f; m_armIKLeft.solver.arm.rotationWeight = 1f; m_armIKLeft.solver.IKPositionWeight = 0f; m_armIKLeft.solver.IKRotationWeight = 0f; m_armIKLeft.enabled = false; - m_armLength = m_armIKLeft.solver.arm.mag * 1.25f; - m_armIKRight = PlayerSetup.Instance._avatar.AddComponent(); m_armIKRight.solver.isLeft = false; m_armIKRight.solver.SetChain( l_chest, - PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightShoulder), - PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightUpperArm), - PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightLowerArm), - PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand), - PlayerSetup.Instance._animator.transform + l_animator.GetBoneTransform(HumanBodyBones.RightShoulder), + l_animator.GetBoneTransform(HumanBodyBones.RightUpperArm), + l_animator.GetBoneTransform(HumanBodyBones.RightLowerArm), + l_animator.GetBoneTransform(HumanBodyBones.RightHand), + l_animator.transform ); - m_armIKRight.solver.arm.target = m_rightTarget; + m_armIKRight.solver.arm.target = m_rightRotationTarget; m_armIKRight.solver.arm.positionWeight = 1f; m_armIKRight.solver.arm.rotationWeight = 1f; m_armIKRight.solver.IKPositionWeight = 0f; @@ -525,39 +538,66 @@ void RemoveArmIK() m_armIKRight = null; } - void SetArmActive(Settings.LeadHand p_hand, bool p_state, bool p_forced = false) + void UpdateArmIK(ArmIK p_ik, float p_weight) { - if(m_enabled || p_forced) + if(p_ik != null) { - if(((p_hand == Settings.LeadHand.Left) || (p_hand == Settings.LeadHand.Both)) && (m_armIKLeft != null)) - { - m_armIKLeft.enabled = m_enabled; - m_armIKLeft.solver.IKPositionWeight = (p_state ? 1f : 0f); - m_armIKLeft.solver.IKRotationWeight = (p_state ? 1f : 0f); - } - if(((p_hand == Settings.LeadHand.Right) || (p_hand == Settings.LeadHand.Both)) && (m_armIKRight != null)) + bool l_state = !Mathf.Approximately(p_weight, 0f); + p_ik.solver.IKPositionWeight = p_weight; + p_ik.solver.IKRotationWeight = p_weight; + p_ik.enabled = l_state; + } + } + + void SetLeadingHandState(HandState p_state) + { + switch(Settings.LeadingHand) + { + case Settings.LeadHand.Left: + m_leftHandState = p_state; + break; + case Settings.LeadHand.Right: + m_rightHandState = p_state; + break; + case Settings.LeadHand.Both: { - m_armIKRight.enabled = m_enabled; - m_armIKRight.solver.IKPositionWeight = (p_state ? 1f : 0f); - m_armIKRight.solver.IKRotationWeight = (p_state ? 1f : 0f); + m_leftHandState = p_state; + m_rightHandState = p_state; } - - if((p_hand == Settings.LeadHand.Left) || (p_hand == Settings.LeadHand.Both)) - m_leftHandParameter?.SetValue(p_state); - if((p_hand == Settings.LeadHand.Right) || (p_hand == Settings.LeadHand.Both)) - m_rightHandParameter?.SetValue(p_state); + break; + } + } + void SetUnleadingHandState(HandState p_state) + { + switch(Settings.LeadingHand) + { + case Settings.LeadHand.Left: + m_rightHandState = p_state; + break; + case Settings.LeadHand.Right: + m_leftHandState = p_state; + break; } } - void ReparentRoots() + IEnumerator WaitToDisable() { - m_rootLeft.parent = PlayerSetup.Instance.GetActiveCamera().transform; - m_rootLeft.localPosition = Vector3.zero; - m_rootLeft.localRotation = Quaternion.identity; + while(!Mathf.Approximately(m_handsWeights.x + m_handsWeights.y, 0f)) + yield return null; - m_rootRight.parent = PlayerSetup.Instance.GetActiveCamera().transform; - m_rootRight.localPosition = Vector3.zero; - m_rootRight.localRotation = Quaternion.identity; + this.enabled = false; + m_disableTask = null; + } + + static float GetChainLength(Transform[] p_chain) + { + float l_result = 0f; + for(int i = 0, j = p_chain.Length - 1; i < j; i++) + { + if((p_chain[i] != null) && (p_chain[i + 1] != null)) + l_result += Vector3.Distance(p_chain[i].position, p_chain[i + 1].position); + } + return l_result; } } } diff --git a/ml_pam/GameEvents.cs b/ml_pam/GameEvents.cs index 2baae54..8d53289 100644 --- a/ml_pam/GameEvents.cs +++ b/ml_pam/GameEvents.cs @@ -34,7 +34,7 @@ internal class GameEvent 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 OnPlayspaceScale = new GameEvent(); + public static readonly GameEvent OnIKScaling = new GameEvent(); public static readonly GameEvent OnPickupGrab = new GameEvent(); public static readonly GameEvent OnPickupDrop = new GameEvent(); @@ -61,9 +61,9 @@ internal static void Init(HarmonyLib.Harmony p_instance) ); p_instance.Patch( - typeof(PlayerSetup).GetMethod("SetPlaySpaceScale", BindingFlags.NonPublic | BindingFlags.Instance), + typeof(PlayerSetup).GetMethod("SetupIKScaling", BindingFlags.NonPublic | BindingFlags.Instance), null, - new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnPlayspaceScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupIKScaling_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); p_instance.Patch( @@ -120,11 +120,11 @@ static void OnAvatarReinitialize_Postfix() } } - static void OnPlayspaceScale_Postfix(float ____avatarScaleRelation) + static void OnSetupIKScaling_Postfix(ref UnityEngine.Vector3 ___scaleDifference) { try { - OnPlayspaceScale.Invoke(____avatarScaleRelation); + OnIKScaling.Invoke(1f + ___scaleDifference.y); } catch(Exception e) { diff --git a/ml_pam/Main.cs b/ml_pam/Main.cs index 441f5c3..efd426c 100644 --- a/ml_pam/Main.cs +++ b/ml_pam/Main.cs @@ -1,32 +1,34 @@ -using ABI_RC.Core.Player; +using UnityEngine; namespace ml_pam { public class PickupArmMovement : MelonLoader.MelonMod { - ArmMover m_localMover = null; + ArmMover m_mover = null; public override void OnInitializeMelon() { Settings.Init(); GameEvents.Init(HarmonyInstance); - MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); + MelonLoader.MelonCoroutines.Start(WaitForRootLogic()); } - System.Collections.IEnumerator WaitForLocalPlayer() + System.Collections.IEnumerator WaitForRootLogic() { - while(PlayerSetup.Instance == null) + while(ABI_RC.Core.RootLogic.Instance == null) + yield return null; + while(ABI_RC.Core.Player.PlayerSetup.Instance == null) yield return null; - m_localMover = PlayerSetup.Instance.gameObject.AddComponent(); + m_mover = new GameObject("[PickupArmMovement]").AddComponent(); } public override void OnDeinitializeMelon() { - if(m_localMover != null) - UnityEngine.Object.Destroy(m_localMover); - m_localMover = null; + if(m_mover != null) + Object.Destroy(m_mover.gameObject); + m_mover = null; } } } diff --git a/ml_pam/Properties/AssemblyInfo.cs b/ml_pam/Properties/AssemblyInfo.cs index 57e4d2c..56e479f 100644 --- a/ml_pam/Properties/AssemblyInfo.cs +++ b/ml_pam/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -[assembly: MelonLoader.MelonInfo(typeof(ml_pam.PickupArmMovement), "PickupArmMovement", "1.1.4", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_pam.PickupArmMovement), "PickupArmMovement", "1.2.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")] [assembly: MelonLoader.MelonPriority(1)] [assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] diff --git a/ml_pam/README.md b/ml_pam/README.md index a65f15a..2dffa6e 100644 --- a/ml_pam/README.md +++ b/ml_pam/README.md @@ -4,14 +4,15 @@ This mod adds arm tracking upon holding pickup in desktop mode. # Installation * Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader) * Get [latest release DLL](../../../releases/latest): - * Put `ml_pam.dll` in `Mods` folder of game + * Put `PickupArmMovement.dll` in `Mods` folder of game # Usage -Available mod's settings in `Settings - Interactions - Pickup Arm Movement`: +Available mod's settings in `Settings - Input & Key-Bindings - Pickup Arm Movement`: * **Enable hand movement:** enables/disables arm tracking; default value - `true`. * **Grab offset:** offset from pickup grab point; default value - `25`. * **Leading hand:** hand that will be extended when gragging pickup; available values: `Left`, `Right`, `Both`; default value - `Right`. * **Hands extension (Q\E):** extend left and right hand if `Q` and `E` keys are pressed; default value - `true`. +* **Hand extension speed::** smoothing speed multiplier between extended and animated hands; default value - `25`. Available animator boolean parameters: * **LeftHandExtended:`` indicates if left hand is extended. diff --git a/ml_pam/ResourcesHandler.cs b/ml_pam/ResourcesHandler.cs index 748dac3..ce6d86f 100644 --- a/ml_pam/ResourcesHandler.cs +++ b/ml_pam/ResourcesHandler.cs @@ -6,15 +6,16 @@ namespace ml_pam { static class ResourcesHandler { + readonly static string ms_namespace = typeof(ResourcesHandler).Namespace; + public static string GetEmbeddedResources(string p_name) { string l_result = ""; Assembly l_assembly = Assembly.GetExecutingAssembly(); - string l_assemblyName = l_assembly.GetName().Name; try { - Stream l_libraryStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name); + Stream l_libraryStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + p_name); StreamReader l_streadReader = new StreamReader(l_libraryStream); l_result = l_streadReader.ReadToEnd(); } diff --git a/ml_pam/Settings.cs b/ml_pam/Settings.cs index 222af5b..d7d5403 100644 --- a/ml_pam/Settings.cs +++ b/ml_pam/Settings.cs @@ -19,7 +19,8 @@ public enum ModSetting Enabled = 0, GrabOffset, LeadHand, - HandsExtension + HandsExtension, + ExtensionSpeed } public enum LeadHand { @@ -29,9 +30,10 @@ public enum LeadHand } public static bool Enabled { get; private set; } = true; - public static float GrabOffset { get; private set; } = 0.25f; + public static float GrabOffset { get; private set; } = 0.5f; public static LeadHand LeadingHand { get; private set; } = LeadHand.Right; public static bool HandsExtension { get; private set; } = true; + public static float ExtensionSpeed { get; private set; } = 10f; static MelonLoader.MelonPreferences_Category ms_category = null; static List ms_entries = null; @@ -40,6 +42,7 @@ public enum LeadHand public static readonly SettingEvent OnGrabOffsetChanged = new SettingEvent(); public static readonly SettingEvent OnLeadingHandChanged = new SettingEvent(); public static readonly SettingEvent OnHandsExtensionChanged = new SettingEvent(); + public static readonly SettingEvent OnExtensionSpeedChanged = new SettingEvent(); internal static void Init() { @@ -51,12 +54,14 @@ internal static void Init() ms_category.CreateEntry(ModSetting.GrabOffset.ToString(), (int)(GrabOffset * 100f)), ms_category.CreateEntry(ModSetting.LeadHand.ToString(), (int)LeadHand.Right), ms_category.CreateEntry(ModSetting.HandsExtension.ToString(), HandsExtension), + ms_category.CreateEntry(ModSetting.ExtensionSpeed.ToString(), (int)ExtensionSpeed), }; Enabled = (bool)ms_entries[(int)ModSetting.Enabled].BoxedValue; GrabOffset = (int)ms_entries[(int)ModSetting.GrabOffset].BoxedValue * 0.01f; LeadingHand = (LeadHand)(int)ms_entries[(int)ModSetting.LeadHand].BoxedValue; HandsExtension = (bool)ms_entries[(int)ModSetting.HandsExtension].BoxedValue; + ExtensionSpeed = Math.Clamp((int)ms_entries[(int)ModSetting.ExtensionSpeed].BoxedValue, 1f, 50f); MelonLoader.MelonCoroutines.Start(WaitMainMenuUi()); } @@ -72,6 +77,7 @@ static System.Collections.IEnumerator WaitMainMenuUi() ViewManager.Instance.gameMenuView.Listener.ReadyForBindings += () => { + ViewManager.Instance.gameMenuView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action(OnToggleUpdate)); ViewManager.Instance.gameMenuView.View.BindCall("OnSliderUpdate_" + ms_category.Identifier, new Action(OnSliderUpdate)); ViewManager.Instance.gameMenuView.View.BindCall("OnDropdownUpdate_" + ms_category.Identifier, new Action(OnDropdownUpdate)); @@ -131,6 +137,13 @@ static void OnSliderUpdate(string p_name, string p_value) OnGrabOffsetChanged.Invoke(GrabOffset); } break; + + case ModSetting.ExtensionSpeed: + { + ExtensionSpeed = l_value; + OnExtensionSpeedChanged.Invoke(ExtensionSpeed); + } + break; } ms_entries[(int)l_setting].BoxedValue = l_value; diff --git a/ml_pam/ml_pam.csproj b/ml_pam/ml_pam.csproj index 9854190..efa04d7 100644 --- a/ml_pam/ml_pam.csproj +++ b/ml_pam/ml_pam.csproj @@ -4,10 +4,11 @@ netstandard2.1 x64 PickupArmMovement - 1.1.4 + 1.2.0 SDraw - None + SDraw PickupArmMovement + PickupArmMovement diff --git a/ml_pam/resources/mod_menu.js b/ml_pam/resources/mod_menu.js index bd8a002..ba0e754 100644 --- a/ml_pam/resources/mod_menu.js +++ b/ml_pam/resources/mod_menu.js @@ -16,7 +16,7 @@
Grab offset:
-
+
@@ -33,8 +33,15 @@
+ +
+
Hand extension speed:
+
+
+
+
`; - document.getElementById('settings-interaction').appendChild(l_block); + document.getElementById('settings-input').appendChild(l_block); // Toggles for (let l_toggle of l_block.querySelectorAll('.inp_toggle')) diff --git a/ml_pin/Properties/AssemblyInfo.cs b/ml_pin/Properties/AssemblyInfo.cs index 8fb75ef..0b834b9 100644 --- a/ml_pin/Properties/AssemblyInfo.cs +++ b/ml_pin/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -[assembly: MelonLoader.MelonInfo(typeof(ml_pin.PlayersInstanceNotifier), "PlayersInstanceNotifier", "1.0.9", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_pin.PlayersInstanceNotifier), "PlayersInstanceNotifier", "1.1.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)] diff --git a/ml_pin/ResourcesHandler.cs b/ml_pin/ResourcesHandler.cs index 8a60dda..5865e11 100644 --- a/ml_pin/ResourcesHandler.cs +++ b/ml_pin/ResourcesHandler.cs @@ -8,6 +8,7 @@ namespace ml_pin static class ResourcesHandler { const string c_modName = "PlayersInstanceNotifier"; + readonly static string ms_namespace = typeof(ResourcesHandler).Namespace; static readonly List ms_audioResources = new List() { @@ -45,11 +46,10 @@ public static void ExtractAudioResources() static void ExtractAudioFile(string p_name, string p_path) { Assembly l_assembly = Assembly.GetExecutingAssembly(); - string l_assemblyName = l_assembly.GetName().Name; try { - Stream l_resourceStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name); + Stream l_resourceStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + p_name); Stream l_fileStream = File.Create(p_path); l_resourceStream.CopyTo(l_fileStream); l_fileStream.Flush(); @@ -66,11 +66,10 @@ public static string GetEmbeddedResource(string p_name) { string l_result = ""; Assembly l_assembly = Assembly.GetExecutingAssembly(); - string l_assemblyName = l_assembly.GetName().Name; try { - Stream l_libraryStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name); + Stream l_libraryStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + p_name); StreamReader l_streadReader = new StreamReader(l_libraryStream); l_result = l_streadReader.ReadToEnd(); } diff --git a/ml_pin/ml_pin.csproj b/ml_pin/ml_pin.csproj index e8d548c..5cd62d8 100644 --- a/ml_pin/ml_pin.csproj +++ b/ml_pin/ml_pin.csproj @@ -5,9 +5,9 @@ x64 PlayersInstanceNotifier SDraw - None + SDraw PlayersInstanceNotifier - 1.0.9 + 1.1.0 PlayersInstanceNotifier diff --git a/ml_pmc/Main.cs b/ml_pmc/Main.cs index c9180a8..bd10ea6 100644 --- a/ml_pmc/Main.cs +++ b/ml_pmc/Main.cs @@ -1,10 +1,11 @@ using ABI_RC.Core.Player; +using UnityEngine; namespace ml_pmc { public class PlayerMovementCopycat : MelonLoader.MelonMod { - PoseCopycat m_localCopycat = null; + PoseCopycat m_poseCopycat = null; public override void OnInitializeMelon() { @@ -17,9 +18,9 @@ public override void OnInitializeMelon() public override void OnDeinitializeMelon() { - if(m_localCopycat != null) - UnityEngine.Object.Destroy(m_localCopycat); - m_localCopycat = null; + if(m_poseCopycat != null) + Object.Destroy(m_poseCopycat.gameObject); + m_poseCopycat = null; } System.Collections.IEnumerator WaitForLocalPlayer() @@ -27,7 +28,7 @@ System.Collections.IEnumerator WaitForLocalPlayer() while(PlayerSetup.Instance == null) yield return null; - m_localCopycat = PlayerSetup.Instance.gameObject.AddComponent(); + m_poseCopycat = new GameObject("[PlayerMovementCopycat]").AddComponent(); } } } diff --git a/ml_pmc/PoseCopycat.cs b/ml_pmc/PoseCopycat.cs index 98a1daa..8ac5f94 100644 --- a/ml_pmc/PoseCopycat.cs +++ b/ml_pmc/PoseCopycat.cs @@ -10,7 +10,7 @@ namespace ml_pmc { [DisallowMultipleComponent] - public class PoseCopycat : MonoBehaviour + class PoseCopycat : MonoBehaviour { public class CopycatEvent { @@ -22,7 +22,7 @@ public class CopycatEvent static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f); - public static PoseCopycat Instance { get; private set; } = null; + static PoseCopycat ms_instance = null; internal static readonly CopycatEvent OnCopycatChanged = new CopycatEvent(); Animator m_animator = null; @@ -43,10 +43,14 @@ public class CopycatEvent void Awake() { - if((Instance != null) && (Instance != this)) - Object.Destroy(this); - else - Instance = this; + if(ms_instance != null) + { + DestroyImmediate(this); + return; + } + + ms_instance = this; + DontDestroyOnLoad(this); } void Start() @@ -60,8 +64,8 @@ void Start() } void OnDestroy() { - if(Instance == this) - Instance = null; + if(ms_instance == this) + ms_instance = null; m_poseHandler?.Dispose(); m_poseHandler = null; @@ -201,7 +205,7 @@ void Update() PlayerSetup.Instance.transform.rotation = l_result.rotation; } - if(Vector3.Distance(this.transform.position, m_puppetParser.transform.position) > m_distanceLimit) + if(Vector3.Distance(PlayerSetup.Instance.GetPlayerPosition(), m_puppetParser.transform.position) > m_distanceLimit) SetTarget(null); } else @@ -364,7 +368,7 @@ void OnLookAtIKPostUpdate() } // Arbitrary - public void SetTarget(PuppetMaster p_target) + void SetTarget(PuppetMaster p_target) { if(m_animator != null) { @@ -405,9 +409,6 @@ public void SetTarget(PuppetMaster p_target) } } - public bool IsActive() => m_active; - public bool IsFingerTrackingActive() => m_fingerTracking; - void OverrideIK() { if(!BodySystem.isCalibrating) diff --git a/ml_pmc/Properties/AssemblyInfo.cs b/ml_pmc/Properties/AssemblyInfo.cs index 7b6f461..75ba250 100644 --- a/ml_pmc/Properties/AssemblyInfo.cs +++ b/ml_pmc/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -[assembly: MelonLoader.MelonInfo(typeof(ml_pmc.PlayerMovementCopycat), "PlayerMovementCopycat", "1.0.8", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_pmc.PlayerMovementCopycat), "PlayerMovementCopycat", "1.1.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")] [assembly: MelonLoader.MelonPriority(3)] [assembly: MelonLoader.MelonAdditionalDependencies("BTKUILib")] diff --git a/ml_pmc/README.md b/ml_pmc/README.md index c70ac91..28005b7 100644 --- a/ml_pmc/README.md +++ b/ml_pmc/README.md @@ -5,7 +5,7 @@ Allows to copy pose, gestures and movement of your friends. * Install [BTKUILib](https://github.com/BTK-Development/BTKUILib) * Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader) * Get [latest release DLL](../../../releases/latest): - * Put `ml_pmc.dll` in `Mods` folder of game + * Put `PlayerMovementCopycat.dll` in `Mods` folder of game # Usage Available options in BTKUILib players list upon player selection: diff --git a/ml_pmc/ml_pmc.csproj b/ml_pmc/ml_pmc.csproj index 71fbc96..5c83c12 100644 --- a/ml_pmc/ml_pmc.csproj +++ b/ml_pmc/ml_pmc.csproj @@ -5,9 +5,10 @@ x64 PlayerMovementCopycat SDraw - None + SDraw PlayerMovementCopycat - 1.0.8 + 1.1.0 + PlayerMovementCopycat diff --git a/ml_prm/GameEvents.cs b/ml_prm/GameEvents.cs index cc67224..7fa87f2 100644 --- a/ml_prm/GameEvents.cs +++ b/ml_prm/GameEvents.cs @@ -248,6 +248,5 @@ static bool OnOffsetUpdate_Prefix() } return !ms_result.m_result; } - } } diff --git a/ml_prm/Main.cs b/ml_prm/Main.cs index 343c7f3..47bcc6d 100644 --- a/ml_prm/Main.cs +++ b/ml_prm/Main.cs @@ -42,14 +42,9 @@ System.Collections.IEnumerator WaitForRootLogic() System.Collections.IEnumerator WaitForWhitelist() { // Whitelist the toggle script - FieldInfo l_field = typeof(SharedFilter).GetField("_localComponentWhitelist", BindingFlags.NonPublic | BindingFlags.Static); - HashSet l_hashSet = l_field?.GetValue(null) as HashSet; - while(l_hashSet == null) - { - l_hashSet = l_field?.GetValue(null) as HashSet; + while(SharedFilter.LocalComponentWhitelist == null) yield return null; - } - l_hashSet.Add(typeof(RagdollToggle)); + SharedFilter.LocalComponentWhitelist.Add(typeof(RagdollToggle)); } } } diff --git a/ml_prm/ModUi.cs b/ml_prm/ModUi.cs index b6eff8f..6e0f9c3 100644 --- a/ml_prm/ModUi.cs +++ b/ml_prm/ModUi.cs @@ -43,6 +43,7 @@ enum UiIndex const string c_ragdollKeyTooltip = "Switch ragdoll mode with '{0}' key"; const string c_fallLimitTooltip = "Fall limit based on impact velocity

Current value corresponds to drop from {0} units with default gravity

"; + readonly static string ms_namespace = typeof(ModUi).Namespace; internal static readonly UiEvent OnSwitchChanged = new UiEvent(); static Page ms_page = null; @@ -345,7 +346,7 @@ static Stream GetIconStream(string p_name) { Assembly l_assembly = Assembly.GetExecutingAssembly(); string l_assemblyName = l_assembly.GetName().Name; - return l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name); + return l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + p_name); } static float GetDropHeight(float p_speed, float p_gravity = 9.8f) diff --git a/ml_prm/README.md b/ml_prm/README.md index 90c4f34..4d10d51 100644 --- a/ml_prm/README.md +++ b/ml_prm/README.md @@ -65,7 +65,7 @@ Now you can animate both parameters available: ![](.github/img_01.png) Note: In order to work the game object needs to be active and the component enabled. -# Mods Integration +# Mods integration You can use this mod's functions within your mod. To do this you need: * Add mod's dll as reference in your project * Access ragdoll controller with `ml_prm.RagdollController.Instance` @@ -75,9 +75,3 @@ Available methods: * ```void SwitchRagdoll()``` * ```void Ragdoll()``` * ```void Unragdoll()``` - -# Notes -* If ragdoll state is enabled during emote, remote players see whole emote playing while local player sees ragdolling. It's tied to how game handles remote players, currently can be prevented with (choose one): - * Renaming avatar emote animations to not have default name or containing `Emote` substring. - * Holding any movement key right after activating ragdoll state. - * Add transition from `Any state` to state with A-pose/T-pose animation and condition with `Ragdolled` parameter on main avatar's animator layer. diff --git a/ml_prm/RagdollController.cs b/ml_prm/RagdollController.cs index f5c9a59..9f5fcf7 100644 --- a/ml_prm/RagdollController.cs +++ b/ml_prm/RagdollController.cs @@ -26,8 +26,10 @@ public class RagdollController : MonoBehaviour bool m_applyHipsPosition = false; bool m_applyHipsRotation = false; + bool m_avatarReady = false; bool m_ragdolled = false; bool m_forcedSwitch = false; + Coroutine m_initTask = null; Transform m_puppet = null; Transform m_puppetRoot = null; @@ -36,10 +38,6 @@ public class RagdollController : MonoBehaviour readonly List> m_boneLinks = null; readonly List> m_jointAnchors = null; - bool m_avatarReady = false; - Coroutine m_initCoroutine = null; - Vector3 m_ragdollLastPos = Vector3.zero; - RagdollToggle m_avatarRagdollToggle = null; // Custom component available for editor AvatarBoolParameter m_ragdolledParameter = null; PhysicMaterial m_physicsMaterial = null; @@ -49,6 +47,11 @@ public class RagdollController : MonoBehaviour float m_groundedTime = 0f; float m_downTime = float.MinValue; + Vector3 m_lastRagdollPosition; + Vector3 m_lastSeatPositon; + Vector3 m_seatVelocity; + Plane m_playerPlane; + internal RagdollController() { m_ragdollBodyHandlers = new List(); @@ -59,10 +62,14 @@ internal RagdollController() // Unity events void Awake() { - if((Instance != null) && (Instance != this)) - Object.Destroy(this); - else - Instance = this; + if(Instance != null) + { + DestroyImmediate(this); + return; + } + + Instance = this; + DontDestroyOnLoad(this); } void Start() @@ -112,9 +119,9 @@ void OnDestroy() if(Instance == this) Instance = null; - if(m_initCoroutine != null) - StopCoroutine(m_initCoroutine); - m_initCoroutine = null; + if(m_initTask != null) + StopCoroutine(m_initTask); + m_initTask = null; if(m_puppet != null) Object.Destroy(m_puppet); @@ -160,7 +167,7 @@ void Update() { if(m_avatarReady) { - if(!m_ragdolled && Settings.FallDamage && !BetterBetterCharacterController.Instance.IsFlying()) + if(!m_ragdolled && Settings.FallDamage && !BetterBetterCharacterController.Instance.IsFlying() && !BetterBetterCharacterController.Instance.IsSitting()) { bool l_grounded = BetterBetterCharacterController.Instance.IsGrounded(); bool l_inWater = BetterBetterCharacterController.Instance.IsInWater(); @@ -170,6 +177,17 @@ void Update() m_inAir = !(l_grounded || l_inWater); } + if(!m_ragdolled && BetterBetterCharacterController.Instance.IsSitting()) // Those seats without velocity, smh + { + CVRSeat l_seat = BetterBetterCharacterController.Instance.GetCurrentSeat(); + if(l_seat != null) + { + Vector3 l_pos = l_seat.transform.position; + m_seatVelocity = (l_pos - m_lastSeatPositon) / Time.deltaTime; + m_lastSeatPositon = l_pos; + } + } + if(m_ragdolled) { BodySystem.TrackingPositionWeight = 0f; @@ -178,7 +196,7 @@ void Update() PlayerSetup.Instance.animatorManager.CancelEmote = true; } - if(!m_ragdolled && !m_reachedGround && (BetterBetterCharacterController.Instance.IsOnGround() || BetterBetterCharacterController.Instance.IsInWater())) + if(!m_ragdolled && !m_reachedGround && (BetterBetterCharacterController.Instance.IsOnGround() || BetterBetterCharacterController.Instance.IsInWater() || BetterBetterCharacterController.Instance.IsSitting())) { m_groundedTime += Time.unscaledDeltaTime; if(m_groundedTime >= 0.25f) @@ -210,9 +228,18 @@ void FixedUpdate() { if(m_avatarReady && m_ragdolled) { - Vector3 l_currentPos = m_puppetReferences.hips.position; - PlayerSetup.Instance.transform.position += (l_currentPos - m_ragdollLastPos); - m_ragdollLastPos = l_currentPos; + Vector3 l_diff = m_puppetReferences.hips.position - m_lastRagdollPosition; + m_playerPlane.SetNormalAndPosition(PlayerSetup.Instance.transform.rotation * Vector3.up, PlayerSetup.Instance.transform.position); + + PlayerSetup.Instance.transform.position += l_diff; + m_lastRagdollPosition = m_puppetReferences.hips.position; + + // Project on plane and fix our position if we under previous plane + if(m_playerPlane.GetDistanceToPoint(m_lastRagdollPosition) < 0f) + m_playerPlane.Flip(); + float l_distance = m_playerPlane.GetDistanceToPoint(PlayerSetup.Instance.transform.position); + if(l_distance < 0f) + PlayerSetup.Instance.transform.position = m_playerPlane.ClosestPointOnPlane(PlayerSetup.Instance.transform.position); } } @@ -242,10 +269,10 @@ void LateUpdate() // Game events void OnAvatarClear() { - if(m_initCoroutine != null) + if(m_initTask != null) { - StopCoroutine(m_initCoroutine); - m_initCoroutine = null; + StopCoroutine(m_initTask); + m_initTask = null; } if(m_ragdolled) @@ -365,7 +392,7 @@ void OnAvatarSetup() m_avatarRagdollToggle = PlayerSetup.Instance._avatar.GetComponentInChildren(true); m_ragdolledParameter = new AvatarBoolParameter("Ragdolled", PlayerSetup.Instance.animatorManager); - m_initCoroutine = StartCoroutine(WaitForBodyHandlers()); + m_initTask = StartCoroutine(WaitForBodyHandlers()); } } @@ -381,7 +408,7 @@ IEnumerator WaitForBodyHandlers() } m_avatarReady = true; - m_initCoroutine = null; + m_initTask = null; OnMovementDragChanged(Settings.MovementDrag); OnAngularDragChanged(Settings.AngularDrag); @@ -414,6 +441,8 @@ void OnAvatarScaling(float p_scaleDifference) void OnSeatPreSit(CVRSeat p_seat) { + m_lastSeatPositon = p_seat.transform.position; + if(!p_seat.occupied) { m_forcedSwitch = true; @@ -473,9 +502,8 @@ void OnPlayerTeleport(BetterBetterCharacterController.PlayerMoveOffset p_offset) if(m_avatarReady && m_ragdolled) { - Vector3 l_pos = m_hips.position; - m_puppetReferences.hips.position = l_pos; - m_ragdollLastPos = l_pos; + m_puppetReferences.hips.position = m_hips.position; + m_lastRagdollPosition = m_puppetReferences.hips.position; } } catch(System.Exception e) @@ -600,7 +628,7 @@ void OnFallDamageChanged(bool p_state) void OnGestureGrabChanged(bool p_state) { - if(m_avatarReady && m_ragdolled & !p_state) + if(m_avatarReady && m_ragdolled && !p_state) { foreach(var l_hanlder in m_ragdollBodyHandlers) l_hanlder.Detach(); @@ -622,13 +650,24 @@ public void Ragdoll() { if(m_avatarReady && !m_ragdolled && CanRagdoll()) { - Vector3 l_velocity = Vector3.ClampMagnitude(BetterBetterCharacterController.Instance.velocity * (WorldManager.IsSafeWorld() ? Settings.VelocityMultiplier : 1f), WorldManager.GetMovementLimit()); + Vector3 l_velocity = (BetterBetterCharacterController.Instance.IsSitting() ? m_seatVelocity : BetterBetterCharacterController.Instance.velocity); + l_velocity *= (WorldManager.IsSafeWorld() ? Settings.VelocityMultiplier : 1f); + l_velocity = Vector3.ClampMagnitude(l_velocity, WorldManager.GetMovementLimit()); if(Settings.ViewVelocity && WorldManager.IsSafeWorld()) { float l_mag = l_velocity.magnitude; l_velocity = PlayerSetup.Instance.GetActiveCamera().transform.forward * l_mag; } + Vector3 l_playerPos = PlayerSetup.Instance.transform.position; + Quaternion l_playerRot = PlayerSetup.Instance.transform.rotation; + bool l_wasSitting = BetterBetterCharacterController.Instance.IsSitting(); + if(BetterBetterCharacterController.Instance.IsSitting()) + { + BetterBetterCharacterController.Instance.SetSitting(false); + l_wasSitting = true; + } + if(BetterBetterCharacterController.Instance.IsFlying()) BetterBetterCharacterController.Instance.ChangeFlight(false, true); BetterBetterCharacterController.Instance.SetImmobilized(true); @@ -662,7 +701,12 @@ public void Ragdoll() l_handler.SetAngularVelocity(Vector3.zero); } - m_ragdollLastPos = m_puppetReferences.hips.position; + if(l_wasSitting) + { + PlayerSetup.Instance.transform.position = l_playerPos; + PlayerSetup.Instance.transform.rotation = l_playerRot; + } + m_lastRagdollPosition = m_puppetReferences.hips.position; m_downTime = 0f; m_ragdolled = true; @@ -675,12 +719,6 @@ public void Unragdoll() { BetterBetterCharacterController.Instance.TeleportPlayerTo(m_puppetReferences.hips.position, PlayerSetup.Instance.GetPlayerRotation().eulerAngles, false, false); TryRestoreMovement(); - if(!WorldManager.IsSafeWorld()) - { - Vector3 l_vec = BetterBetterCharacterController.Instance.GetVelocity(); - l_vec.y = Mathf.Clamp(l_vec.y, float.MinValue, 0f); - BetterBetterCharacterController.Instance.SetVelocity(l_vec); - } BodySystem.TrackingPositionWeight = 1f; IKSystem.Instance.applyOriginalHipPosition = m_applyHipsPosition; IKSystem.Instance.applyOriginalHipRotation = m_applyHipsRotation; @@ -725,7 +763,6 @@ bool CanRagdoll() bool l_result = m_reachedGround; l_result &= !BodySystem.isCalibrating; - l_result &= !BetterBetterCharacterController.Instance.IsSitting(); l_result &= ((CombatSystem.Instance == null) || !CombatSystem.Instance.isDown); return (l_result || m_forcedSwitch); } diff --git a/ml_prm/RemoteGesturesManager.cs b/ml_prm/RemoteGesturesManager.cs index 28851d4..02f54df 100644 --- a/ml_prm/RemoteGesturesManager.cs +++ b/ml_prm/RemoteGesturesManager.cs @@ -22,6 +22,7 @@ internal class GestureEvent public void RemoveListener(Action 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 OnGestureState = new GestureEvent(); class PlayerEntry @@ -32,6 +33,8 @@ class PlayerEntry public bool m_stateRight = false; } + static RemoteGesturesManager ms_instance = null; + readonly List m_entries = null; internal RemoteGesturesManager() @@ -39,10 +42,20 @@ internal RemoteGesturesManager() m_entries = new List(); } - void Start() + 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); @@ -50,6 +63,9 @@ void Start() void OnDestroy() { + if(ms_instance == this) + ms_instance = null; + m_entries.Clear(); CVRGameEventSystem.Player.OnJoinEntity.RemoveListener(OnRemotePlayerCreated); diff --git a/ml_prm/Utils.cs b/ml_prm/Utils.cs index b98c19b..c4fe775 100644 --- a/ml_prm/Utils.cs +++ b/ml_prm/Utils.cs @@ -8,6 +8,7 @@ using UnityEngine; using System.Linq; using ABI_RC.Systems.IK.SubSystems; +using ABI_RC.Core.InteractionSystem; namespace ml_prm { @@ -17,6 +18,7 @@ static class Utils static readonly FieldInfo ms_referencePoints = typeof(PhysicsInfluencer).GetField("_referencePoints", BindingFlags.NonPublic | BindingFlags.Instance); static readonly FieldInfo ms_influencerTouchingVolumes = typeof(PhysicsInfluencer).GetField("_touchingVolumes", BindingFlags.NonPublic | BindingFlags.Instance); static readonly FieldInfo ms_influencerSubmergedColliders = typeof(PhysicsInfluencer).GetField("_submergedColliders", BindingFlags.NonPublic | BindingFlags.Instance); + static readonly FieldInfo ms_lastCVRSeat = typeof(BetterBetterCharacterController).GetField("_lastCvrSeat", BindingFlags.NonPublic | BindingFlags.Instance); public static void ClearFluidVolumes(this BetterBetterCharacterController p_instance) => (ms_touchingVolumes.GetValue(p_instance) as List)?.Clear(); @@ -58,5 +60,9 @@ public static bool IsRightGrabPointerActive(this PuppetMaster p_source) l_result |= ((FingerSystem.GetCurlNormalized(p_source._playerAvatarMovementDataCurrent.RightMiddle1Stretched) >= 0.5f) && (FingerSystem.GetCurlNormalized(p_source._playerAvatarMovementDataCurrent.RightMiddle2Stretched) >= 0.5f) && (FingerSystem.GetCurlNormalized(p_source._playerAvatarMovementDataCurrent.RightMiddle3Stretched) >= 0.5f)); return l_result; } + + public static CVRSeat GetCurrentSeat(this BetterBetterCharacterController p_instance) => (ms_lastCVRSeat?.GetValue(p_instance) as CVRSeat); + + public static bool IsInRange(float p_value, float p_min, float p_max) => ((p_min <= p_value) && (p_value <= p_max)); } } diff --git a/ml_prm/WorldManager.cs b/ml_prm/WorldManager.cs index 53097ae..7de13d9 100644 --- a/ml_prm/WorldManager.cs +++ b/ml_prm/WorldManager.cs @@ -1,5 +1,6 @@ using ABI.CCK.Components; using ABI_RC.Systems.GameEventSystem; +using System; using UnityEngine; namespace ml_prm @@ -22,18 +23,25 @@ internal static void DeInit() static void OnWorldLoad(string p_id) { - ms_safeWorld = ((CVRWorld.Instance != null) && CVRWorld.Instance.allowFlying); - ms_movementLimit = 1f; + try + { + ms_safeWorld = ((CVRWorld.Instance != null) && CVRWorld.Instance.allowFlying); + ms_movementLimit = 1f; - GameObject l_restrictObj = GameObject.Find("[RagdollRestriction]"); - ms_restrictedWorld = ((l_restrictObj == null) ? false : (l_restrictObj.scene.name != "DontDestroyOnLoad")); + GameObject l_restrictObj = GameObject.Find("[RagdollRestriction]"); + ms_restrictedWorld = ((l_restrictObj == null) ? false : (l_restrictObj.scene.name != "DontDestroyOnLoad")); - if(CVRWorld.Instance != null) + if(CVRWorld.Instance != null) + { + ms_movementLimit = CVRWorld.Instance.baseMovementSpeed; + ms_movementLimit *= CVRWorld.Instance.sprintMultiplier; + ms_movementLimit *= CVRWorld.Instance.inAirMovementMultiplier; + ms_movementLimit *= CVRWorld.Instance.flyMultiplier; + } + } + catch(Exception e) { - ms_movementLimit = CVRWorld.Instance.baseMovementSpeed; - ms_movementLimit *= CVRWorld.Instance.sprintMultiplier; - ms_movementLimit *= CVRWorld.Instance.inAirMovementMultiplier; - ms_movementLimit *= CVRWorld.Instance.flyMultiplier; + MelonLoader.MelonLogger.Error(e); } } diff --git a/ml_vei/Properties/AssemblyInfo.cs b/ml_vei/Properties/AssemblyInfo.cs index 2ca1605..5a2f8a6 100644 --- a/ml_vei/Properties/AssemblyInfo.cs +++ b/ml_vei/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -[assembly: MelonLoader.MelonInfo(typeof(ml_vei.ViveExtendedInput), "ViveExtendedInput", "1.0.5", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_vei.ViveExtendedInput), "ViveExtendedInput", "1.1.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)] diff --git a/ml_vei/README.md b/ml_vei/README.md index 0386c1c..2f9b2fb 100644 --- a/ml_vei/README.md +++ b/ml_vei/README.md @@ -1,5 +1,5 @@ # Vive Extended Input -This mod changes input behaviour for Vive controllers. +This mod adds few changes of input behaviour for Vive controllers. # Installation * Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader) diff --git a/ml_vei/ResourcesHandler.cs b/ml_vei/ResourcesHandler.cs index dc85942..f7b0e08 100644 --- a/ml_vei/ResourcesHandler.cs +++ b/ml_vei/ResourcesHandler.cs @@ -6,15 +6,16 @@ namespace ml_vei { static class ResourcesHandler { + readonly static string ms_namespace = typeof(ResourcesHandler).Namespace; + public static string GetEmbeddedResource(string p_name) { string l_result = ""; Assembly l_assembly = Assembly.GetExecutingAssembly(); - string l_assemblyName = l_assembly.GetName().Name; try { - Stream l_libraryStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name); + Stream l_libraryStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + p_name); StreamReader l_streadReader = new StreamReader(l_libraryStream); l_result = l_streadReader.ReadToEnd(); } diff --git a/ml_vei/ml_vei.csproj b/ml_vei/ml_vei.csproj index 11c9315..27ea5cd 100644 --- a/ml_vei/ml_vei.csproj +++ b/ml_vei/ml_vei.csproj @@ -4,7 +4,7 @@ netstandard2.1 x64 ViveExtendedInput - 1.0.5 + 1.1.0 SDraw SDraw ViveExtendedInput