diff --git a/ml_amt/AvatarParameter.cs b/ml_amt/AvatarParameter.cs index 0430be6..5307c70 100644 --- a/ml_amt/AvatarParameter.cs +++ b/ml_amt/AvatarParameter.cs @@ -8,7 +8,6 @@ namespace ml_amt { public enum ParameterType { - GroundedRaw, Moving } @@ -42,10 +41,6 @@ namespace ml_amt { switch(m_type) { - case ParameterType.GroundedRaw: - SetBoolean(p_tweaker.GetGroundedRaw()); - break; - case ParameterType.Moving: SetBoolean(p_tweaker.GetMoving()); break; diff --git a/ml_amt/Main.cs b/ml_amt/Main.cs index 7e73e3d..ff51ec3 100644 --- a/ml_amt/Main.cs +++ b/ml_amt/Main.cs @@ -1,4 +1,5 @@ using ABI_RC.Core.Player; +using ABI_RC.Systems.IK; using ABI_RC.Systems.IK.SubSystems; using System; using System.Collections; @@ -30,9 +31,9 @@ namespace ml_amt new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); HarmonyInstance.Patch( - typeof(BodySystem).GetMethod(nameof(BodySystem.Calibrate)), + typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public), null, - new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnCalibrate_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); HarmonyInstance.Patch( typeof(PlayerSetup).GetMethod("SetPlaySpaceScale", BindingFlags.NonPublic | BindingFlags.Instance), @@ -89,17 +90,17 @@ namespace ml_amt } } - static void OnCalibrate_Postfix() => ms_instance?.OnCalibrate(); - void OnCalibrate() + static void OnAvatarReinitialize_Postfix() => ms_instance?.OnAvatarReinitialize(); + void OnAvatarReinitialize() { try { if(m_localTweaker != null) - m_localTweaker.OnCalibrate(); + m_localTweaker.OnAvatarReinitialize(); } - catch(Exception l_exception) + catch(System.Exception e) { - MelonLoader.MelonLogger.Error(l_exception); + MelonLoader.MelonLogger.Error(e); } } diff --git a/ml_amt/MotionTweaker.cs b/ml_amt/MotionTweaker.cs index cdc9e72..2ac9cee 100644 --- a/ml_amt/MotionTweaker.cs +++ b/ml_amt/MotionTweaker.cs @@ -1,7 +1,7 @@ using ABI_RC.Core.Player; using ABI_RC.Systems.IK; using ABI_RC.Systems.IK.SubSystems; -using ABI_RC.Systems.MovementSystem; +using ABI_RC.Systems.Movement; using RootMotion.FinalIK; using System.Collections.Generic; using UnityEngine; @@ -28,11 +28,9 @@ namespace ml_amt int m_locomotionLayer = 0; float m_avatarScale = 1f; Vector3 m_locomotionOffset = Vector3.zero; // Original locomotion offset - bool m_inVR = false; bool m_avatarReady = false; bool m_grounded = false; - bool m_groundedRaw = false; bool m_moving = false; bool m_locomotionOverride = false; @@ -56,8 +54,6 @@ namespace ml_amt // Unity events void Start() { - m_inVR = Utils.IsInVR(); - SetCrouchLimit(Settings.CrouchLimit); SetProneLimit(Settings.ProneLimit); SetIKOverrideFly(Settings.IKOverrideFly); @@ -90,9 +86,8 @@ namespace ml_amt { if(m_avatarReady) { - m_grounded = MovementSystem.Instance.IsGrounded(); - m_groundedRaw = MovementSystem.Instance.IsGroundedRaw(); - m_moving = !Mathf.Approximately(MovementSystem.Instance.movementVector.magnitude, 0f); + m_grounded = BetterBetterCharacterController.Instance.IsGrounded(); + m_moving = BetterBetterCharacterController.Instance.IsMoving(); UpdateIKLimits(); @@ -103,11 +98,8 @@ namespace ml_amt m_emoteActive = (l_animState.tagHash == ms_emoteHash); } - if(m_parameters.Count > 0) - { - foreach(AvatarParameter l_param in m_parameters) - l_param.Update(this); - } + foreach(AvatarParameter l_param in m_parameters) + l_param.Update(this); } } @@ -117,7 +109,6 @@ namespace ml_amt m_vrIk = null; m_locomotionLayer = -1; m_grounded = false; - m_groundedRaw = false; m_avatarReady = false; m_avatarScale = 1f; m_locomotionOffset = Vector3.zero; @@ -128,19 +119,17 @@ namespace ml_amt m_ikLimits = null; m_parameters.Clear(); - PlayerSetup.Instance.avatarCrouchLimit = Mathf.Clamp01(Settings.CrouchLimit); - PlayerSetup.Instance.avatarProneLimit = Mathf.Clamp01(Settings.ProneLimit); + BetterBetterCharacterController.Instance.avatarCrouchLimit = Mathf.Clamp01(Settings.CrouchLimit); + BetterBetterCharacterController.Instance.avatarProneLimit = Mathf.Clamp01(Settings.ProneLimit); } internal void OnSetupAvatar() { - m_inVR = Utils.IsInVR(); m_vrIk = PlayerSetup.Instance._avatar.GetComponent(); m_locomotionLayer = PlayerSetup.Instance._animator.GetLayerIndex("Locomotion/Emotes"); m_avatarScale = Mathf.Abs(PlayerSetup.Instance._avatar.transform.localScale.y); // Parse animator parameters - m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.GroundedRaw, PlayerSetup.Instance.animatorManager)); m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.Moving, PlayerSetup.Instance.animatorManager)); m_parameters.RemoveAll(p => !p.IsValid()); @@ -181,34 +170,25 @@ namespace ml_amt m_avatarReady = true; } - internal void OnCalibrate() - { - if(m_avatarReady && (m_vrIk != null) && (m_vrIk.solver.spine.pelvisTarget != null) && (m_vrIk.solver.leftLeg.target == null) && (m_vrIk.solver.rightLeg.target == null)) - { - // Do not consider 4PT as FBT (!!!) - m_vrIk.solver.spine.bodyPosStiffness = 0.55f; - m_vrIk.solver.spine.bodyRotStiffness = 0.1f; - m_vrIk.solver.spine.neckStiffness = 0.5f; - m_vrIk.solver.spine.chestClampWeight = 0.55f; - m_vrIk.solver.spine.moveBodyBackWhenCrouching = 0.5f; - m_vrIk.solver.spine.maxRootAngle = 25f; - m_vrIk.fixTransforms = false; - - BodySystem.isCalibratedAsFullBody = false; - BodySystem.TrackingLeftLegEnabled = false; - BodySystem.TrackingRightLegEnabled = false; - BodySystem.TrackingLocomotionEnabled = true; - - IKSystem.Instance.applyOriginalHipRotation = true; - } - } - internal void OnPlayspaceScale() { if((m_vrIk != null) && Settings.MassCenter) m_vrIk.solver.locomotion.offset = m_massCenter * GetRelativeScale(); } + internal void OnAvatarReinitialize() + { + // Old VRIK is destroyed by game + m_vrIk = PlayerSetup.Instance._animator.GetComponent(); + if(m_vrIk != null) + { + m_vrIk.solver.locomotion.offset = (Settings.MassCenter ? m_massCenter : m_locomotionOffset); + + m_vrIk.onPreSolverUpdate.AddListener(this.OnIKPreUpdate); + m_vrIk.onPostSolverUpdate.AddListener(this.OnIKPostUpdate); + } + } + // IK events void OnIKPreUpdate() { @@ -225,21 +205,20 @@ namespace ml_amt if(!BodySystem.isCalibratedAsFullBody) { - if(PlayerSetup.Instance.avatarUpright <= PlayerSetup.Instance.avatarCrouchLimit) + if(BetterBetterCharacterController.Instance.AvatarUpright <= BetterBetterCharacterController.Instance.avatarCrouchLimit) { m_vrIk.solver.leftLeg.useAnimatedBendNormal = true; m_vrIk.solver.rightLeg.useAnimatedBendNormal = true; l_locomotionOverride = true; } - - if(m_ikOverrideFly && MovementSystem.Instance.flying) + if(m_ikOverrideFly && BetterBetterCharacterController.Instance.IsFlying()) { m_vrIk.solver.locomotion.weight = 0f; m_vrIk.solver.leftLeg.useAnimatedBendNormal = true; m_vrIk.solver.rightLeg.useAnimatedBendNormal = true; l_locomotionOverride = true; } - if(m_ikOverrideJump && !m_grounded && !MovementSystem.Instance.flying) + if(m_ikOverrideJump && !m_grounded && !BetterBetterCharacterController.Instance.IsFlying()) { m_vrIk.solver.locomotion.weight = 0f; m_vrIk.solver.leftLeg.useAnimatedBendNormal = true; @@ -266,12 +245,12 @@ namespace ml_amt internal void SetCrouchLimit(float p_value) { if(m_ikLimits == null) - PlayerSetup.Instance.avatarCrouchLimit = Mathf.Clamp01(p_value); + BetterBetterCharacterController.Instance.avatarCrouchLimit = Mathf.Clamp01(p_value); } internal void SetProneLimit(float p_value) { if(m_ikLimits == null) - PlayerSetup.Instance.avatarProneLimit = Mathf.Clamp01(p_value); + BetterBetterCharacterController.Instance.avatarProneLimit = Mathf.Clamp01(p_value); } internal void SetIKOverrideFly(bool p_state) { @@ -302,14 +281,12 @@ namespace ml_amt if(m_ikLimits != null) { Vector3 l_values = m_ikLimits.localPosition; - PlayerSetup.Instance.avatarCrouchLimit = Mathf.Clamp01(l_values.x); - PlayerSetup.Instance.avatarProneLimit = Mathf.Clamp01(l_values.y); + BetterBetterCharacterController.Instance.avatarCrouchLimit = Mathf.Clamp01(l_values.x); + BetterBetterCharacterController.Instance.avatarProneLimit = Mathf.Clamp01(l_values.y); } } // Parameters access - public float GetUpright() => PlayerSetup.Instance.avatarUpright; - public bool GetGroundedRaw() => m_groundedRaw; public bool GetMoving() => m_moving; } } diff --git a/ml_amt/Properties/AssemblyInfo.cs b/ml_amt/Properties/AssemblyInfo.cs index 89aeb24..4273301 100644 --- a/ml_amt/Properties/AssemblyInfo.cs +++ b/ml_amt/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.3.6", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.3.7-ex", "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_amt/Utils.cs b/ml_amt/Utils.cs index d6d28b5..e9aca84 100644 --- a/ml_amt/Utils.cs +++ b/ml_amt/Utils.cs @@ -1,6 +1,6 @@ using ABI.CCK.Components; +using ABI_RC.Core.Savior; using ABI_RC.Core.UI; -using ABI_RC.Systems.MovementSystem; using RootMotion.FinalIK; using System.Reflection; using UnityEngine; @@ -9,14 +9,10 @@ namespace ml_amt { static class Utils { - static readonly FieldInfo ms_grounded = typeof(MovementSystem).GetField("_isGrounded", BindingFlags.NonPublic | BindingFlags.Instance); - static readonly FieldInfo ms_groundedRaw = typeof(MovementSystem).GetField("_isGroundedRaw", BindingFlags.NonPublic | BindingFlags.Instance); static readonly FieldInfo ms_hasToes = typeof(IKSolverVR).GetField("hasToes", BindingFlags.NonPublic | BindingFlags.Instance); static readonly FieldInfo ms_view = typeof(CohtmlControlledViewWrapper).GetField("_view", BindingFlags.NonPublic | BindingFlags.Instance); - public static bool IsInVR() => ((ABI_RC.Core.Savior.CheckVR.Instance != null) && ABI_RC.Core.Savior.CheckVR.Instance.hasVrDeviceLoaded); - - public static bool IsGroundedRaw(this MovementSystem p_instance) => (bool)ms_groundedRaw.GetValue(MovementSystem.Instance); + public static bool IsInVR() => ((MetaPort.Instance != null) && MetaPort.Instance.isUsingVr); public static bool HasToes(this IKSolverVR p_instance) => (bool)ms_hasToes.GetValue(p_instance); diff --git a/ml_amt/ml_amt.csproj b/ml_amt/ml_amt.csproj index 2292594..2d26d8b 100644 --- a/ml_amt/ml_amt.csproj +++ b/ml_amt/ml_amt.csproj @@ -6,7 +6,7 @@ None AvatarMotionTweaker AvatarMotionTweaker - 1.3.6 + 1.3.7 x64 ml_amt @@ -63,6 +63,11 @@ false false + + D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\ECM2.dll + false + false + D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\MelonLoader.dll false diff --git a/ml_asl/Main.cs b/ml_asl/Main.cs index 66f77d0..968e458 100644 --- a/ml_asl/Main.cs +++ b/ml_asl/Main.cs @@ -18,7 +18,7 @@ namespace ml_asl static void OnPlayerAvatarMovementDataUpdate_Postfix(ref PlayerSetup __instance, PlayerAvatarMovementData ____playerAvatarMovementData) { - if(Settings.Enabled && (__instance.eyeMovement != null)) + if(Settings.Enabled && (__instance.EyeMovementController != null)) ____playerAvatarMovementData.EyeTrackingOverride = true; } } diff --git a/ml_asl/Properties/AssemblyInfo.cs b/ml_asl/Properties/AssemblyInfo.cs index 641578e..fcbf161 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.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_asl.AvatarSyncedLook), "AvatarSyncedLook", "1.0.1-ex", "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/ml_asl.csproj b/ml_asl/ml_asl.csproj index 0fc712e..2e5e075 100644 --- a/ml_asl/ml_asl.csproj +++ b/ml_asl/ml_asl.csproj @@ -7,6 +7,7 @@ SDraw None AvatarSyncedLook + 1.0.1 diff --git a/ml_dht/DataParser.cs b/ml_dht/DataParser.cs new file mode 100644 index 0000000..abcceaf --- /dev/null +++ b/ml_dht/DataParser.cs @@ -0,0 +1,29 @@ +namespace ml_dht +{ + class DataParser + { + MemoryMapReader m_mapReader = null; + byte[] m_buffer = null; + TrackingData m_trackingData; + + public DataParser() + { + m_buffer = new byte[1024]; + m_mapReader = new MemoryMapReader(); + m_mapReader.Open("head/data"); + } + ~DataParser() + { + m_mapReader.Close(); + m_mapReader = null; + } + + public void Update() + { + if(m_mapReader.Read(ref m_buffer)) + m_trackingData = TrackingData.ToObject(m_buffer); + } + + public ref TrackingData GetLatestTrackingData() => ref m_trackingData; + } +} diff --git a/ml_dht/HeadTracked.cs b/ml_dht/HeadTracked.cs index dc27209..ab2a265 100644 --- a/ml_dht/HeadTracked.cs +++ b/ml_dht/HeadTracked.cs @@ -1,6 +1,10 @@ using ABI.CCK.Components; 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; @@ -25,10 +29,22 @@ namespace ml_dht Quaternion m_headRotation; Vector2 m_gazeDirection; float m_blinkProgress = 0f; + LipData_v2 m_lipData; + bool m_lipDataSent = false; Quaternion m_bindRotation; Quaternion m_lastHeadRotation; + internal HeadTracked() + { + m_lipData = new LipData_v2(); + m_lipData.frame = 0; + m_lipData.time = 0; + m_lipData.image = IntPtr.Zero; + m_lipData.prediction_data = new PredictionData_v2(); + m_lipData.prediction_data.blend_shape_weight = new float[(int)LipShape_v2.Max]; + } + // Unity events void Start() { @@ -48,6 +64,12 @@ namespace ml_dht Settings.SmoothingChange -= this.SetSmoothing; } + void Update() + { + if(m_lipDataSent) + m_lipDataSent = false; + } + // Tracking updates public void UpdateTrackingData(ref TrackingData p_data) { @@ -55,6 +77,12 @@ namespace ml_dht m_headRotation.Set(p_data.m_headRotationX, p_data.m_headRotationY * (Settings.Mirrored ? -1f : 1f), p_data.m_headRotationZ * (Settings.Mirrored ? -1f : 1f), p_data.m_headRotationW); m_gazeDirection.Set(Settings.Mirrored ? (1f - p_data.m_gazeX) : p_data.m_gazeX, p_data.m_gazeY); m_blinkProgress = p_data.m_blink; + + float l_weight = Mathf.Clamp01(Mathf.InverseLerp(0.25f, 1f, Mathf.Abs(p_data.m_mouthShape))); + m_lipData.prediction_data.blend_shape_weight[(int)LipShape_v2.Jaw_Open] = p_data.m_mouthOpen; + m_lipData.prediction_data.blend_shape_weight[(int)LipShape_v2.Mouth_Pout] = ((p_data.m_mouthShape > 0f) ? l_weight : 0f); + m_lipData.prediction_data.blend_shape_weight[(int)LipShape_v2.Mouth_Smile_Left] = ((p_data.m_mouthShape < 0f) ? l_weight : 0f); + m_lipData.prediction_data.blend_shape_weight[(int)LipShape_v2.Mouth_Smile_Right] = ((p_data.m_mouthShape < 0f) ? l_weight : 0f); } void OnLookIKPostUpdate() @@ -80,7 +108,7 @@ namespace ml_dht m_bindRotation = (m_avatarDescriptor.transform.GetMatrix().inverse * m_headBone.GetMatrix()).rotation; if(m_lookIK != null) - m_lookIK.solver.OnPostUpdate += this.OnLookIKPostUpdate; + m_lookIK.onPostSolverUpdate.AddListener(this.OnLookIKPostUpdate); } internal void OnAvatarClear() @@ -91,8 +119,15 @@ namespace ml_dht m_lastHeadRotation = Quaternion.identity; m_bindRotation = Quaternion.identity; } + internal void OnAvatarReinitialize() + { + m_camera = PlayerSetup.Instance.GetActiveCamera().transform; + m_lookIK = PlayerSetup.Instance._avatar.GetComponent(); + if(m_lookIK != null) + m_lookIK.onPostSolverUpdate.AddListener(this.OnLookIKPostUpdate); + } - internal void OnEyeControllerUpdate(CVREyeController p_component) + internal void OnEyeControllerUpdate(EyeMovementController p_component) { if(m_enabled) { @@ -112,6 +147,24 @@ namespace ml_dht } } + internal bool UpdateFaceTracking(CVRFaceTracking p_component) + { + bool l_result = false; + if(m_enabled && Settings.FaceTracking) + { + if(!m_lipDataSent) + { + FaceTrackingManager.Instance.SubmitNewFacialData(m_lipData); + m_lipDataSent = true; + } + p_component.LipSyncWasUpdated = true; + p_component.UpdateShapesLocal_Private(); + + l_result = true; + } + return l_result; + } + // Settings void SetEnabled(bool p_state) { diff --git a/ml_dht/Main.cs b/ml_dht/Main.cs index beeec86..c701136 100644 --- a/ml_dht/Main.cs +++ b/ml_dht/Main.cs @@ -1,6 +1,8 @@ +using ABI.CCK.Components; using ABI_RC.Core.Player; +using ABI_RC.Core.Player.EyeMovement; using ABI_RC.Core.Savior; -using ABI_RC.Systems.FaceTracking; +using ABI_RC.Systems.IK; using System.Reflection; namespace ml_dht @@ -9,7 +11,7 @@ namespace ml_dht { static DesktopHeadTracking ms_instance = null; - TrackingModule m_trackingModule = null; + DataParser m_dataParser = null; HeadTracked m_localTracked = null; public override void OnInitializeMelon() @@ -19,8 +21,6 @@ namespace ml_dht Settings.Init(); - m_trackingModule = new TrackingModule(); - // Patches HarmonyInstance.Patch( typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)), @@ -32,6 +32,11 @@ namespace ml_dht null, new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); + HarmonyInstance.Patch( + typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public), + null, + new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + ); MelonLoader.MelonCoroutines.Start(WaitForInstances()); } @@ -44,15 +49,19 @@ namespace ml_dht while(PlayerSetup.Instance == null) yield return null; + m_dataParser = new DataParser(); m_localTracked = PlayerSetup.Instance.gameObject.AddComponent(); - FaceTrackingManager.Instance.RegisterModule(m_trackingModule); // If you think it's a joke to put patch here, go on, try to put it in OnInitializeMelon, you melon :> HarmonyInstance.Patch( - typeof(CVREyeController).GetMethod("Update", BindingFlags.Instance | BindingFlags.NonPublic), + typeof(EyeMovementController).GetMethod("Update", BindingFlags.Instance | BindingFlags.NonPublic), null, new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnEyeControllerUpdate_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); + HarmonyInstance.Patch( + typeof(CVRFaceTracking).GetMethod("UpdateLocalData", BindingFlags.Instance | BindingFlags.NonPublic), + new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnFaceTrackingLocalUpdate_Prefix), BindingFlags.Static | BindingFlags.NonPublic)) + ); } public override void OnDeinitializeMelon() @@ -60,17 +69,17 @@ namespace ml_dht if(ms_instance == this) ms_instance = null; - m_trackingModule = null; + m_dataParser = null; m_localTracked = null; } public override void OnUpdate() { - if(Settings.Enabled && (m_trackingModule != null)) + if(Settings.Enabled && (m_dataParser != null)) { - m_trackingModule.Update(); + m_dataParser.Update(); if(m_localTracked != null) - m_localTracked.UpdateTrackingData(ref m_trackingModule.GetLatestTrackingData()); + m_localTracked.UpdateTrackingData(ref m_dataParser.GetLatestTrackingData()); } } @@ -102,12 +111,26 @@ namespace ml_dht } } - static void OnEyeControllerUpdate_Postfix(ref CVREyeController __instance) => ms_instance?.OnEyeControllerUpdate(__instance); - void OnEyeControllerUpdate(CVREyeController p_component) + static void OnAvatarReinitialize_Postfix() => ms_instance?.OnAvatarReinitialize(); + void OnAvatarReinitialize() { try { - if(p_component.isLocal && (m_localTracked != null)) + if(m_localTracked != null) + m_localTracked.OnAvatarReinitialize(); + } + catch(System.Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } + + static void OnEyeControllerUpdate_Postfix(ref EyeMovementController __instance) => ms_instance?.OnEyeControllerUpdate(__instance); + void OnEyeControllerUpdate(EyeMovementController p_component) + { + try + { + if(p_component.IsLocal && (m_localTracked != null)) m_localTracked.OnEyeControllerUpdate(p_component); } catch(System.Exception e) @@ -115,5 +138,18 @@ namespace ml_dht MelonLoader.MelonLogger.Error(e); } } + + static bool OnFaceTrackingLocalUpdate_Prefix(ref CVRFaceTracking __instance) + { + bool? l_result = ms_instance?.OnFaceTrackingLocalUpdate(__instance); + return l_result.GetValueOrDefault(true); + } + bool OnFaceTrackingLocalUpdate(CVRFaceTracking p_component) + { + bool l_result = true; + if(p_component.UseFacialTracking && (m_localTracked != null)) + l_result = !m_localTracked.UpdateFaceTracking(p_component); + return l_result; + } } } \ No newline at end of file diff --git a/ml_dht/Properties/AssemblyInfo.cs b/ml_dht/Properties/AssemblyInfo.cs index dbe24dc..7b7e58e 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.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_dht.DesktopHeadTracking), "DesktopHeadTracking", "1.2.1-ex", "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 7057fd6..1b6065b 100644 --- a/ml_dht/README.md +++ b/ml_dht/README.md @@ -21,7 +21,6 @@ Available mod's settings in `Settings - Implementation - Desktop Head Tracking`: * **Use head tracking:** enables head tracking; default value - `true`. * **Use eyes tracking:** enables eyes tracking; default value - `true`. * **Use face tracking:** enables mouth shapes tracking; default value - `true`. - * **Note:** You need to enable desktop tracking of `Vive Face tracking` in `Settings - Implementation` menu page. * **Note:** Your avatar should have configured `CVR Face Tracking` component. * **Use blinking:** uses blinking from data; default value - `true`. * **Mirrored movement:** mirrors movement and gaze along 0YZ plane; default value - `false`. diff --git a/ml_dht/TrackingModule.cs b/ml_dht/TrackingModule.cs deleted file mode 100644 index 01d1f5c..0000000 --- a/ml_dht/TrackingModule.cs +++ /dev/null @@ -1,70 +0,0 @@ -using ABI_RC.Systems.FaceTracking; -using System; -using UnityEngine; -using ViveSR.anipal.Lip; - -namespace ml_dht -{ - class TrackingModule : ITrackingModule - { - bool m_registered = false; - bool m_activeAsModule = false; - MemoryMapReader m_mapReader = null; - byte[] m_buffer = null; - TrackingData m_trackingData; - LipData_v2 m_lipData; - - public TrackingModule() - { - m_lipData = new LipData_v2(); - m_lipData.frame = 0; - m_lipData.time = 0; - m_lipData.image = IntPtr.Zero; - m_lipData.prediction_data = new PredictionData_v2(); - m_lipData.prediction_data.blend_shape_weight = new float[(int)LipShape_v2.Max]; - - m_buffer = new byte[1024]; - m_mapReader = new MemoryMapReader(); - m_mapReader.Open("head/data"); - } - ~TrackingModule() - { - m_mapReader.Close(); - m_mapReader = null; - } - - public (bool, bool) Initialize(bool useEye, bool useLip) - { - m_registered = true; - m_activeAsModule = true; - return (false, true); - } - - public void Shutdown() - { - m_activeAsModule = false; - } - - public bool IsEyeDataAvailable() => false; - public bool IsLipDataAvailable() => true; - - internal void Update() - { - if(m_mapReader.Read(ref m_buffer)) - { - m_trackingData = TrackingData.ToObject(m_buffer); - - float l_weight = Mathf.Clamp01(Mathf.InverseLerp(0.25f, 1f, Mathf.Abs(m_trackingData.m_mouthShape))); - m_lipData.prediction_data.blend_shape_weight[(int)LipShape_v2.Jaw_Open] = m_trackingData.m_mouthOpen; - m_lipData.prediction_data.blend_shape_weight[(int)LipShape_v2.Mouth_Pout] = ((m_trackingData.m_mouthShape > 0f) ? l_weight : 0f); - m_lipData.prediction_data.blend_shape_weight[(int)LipShape_v2.Mouth_Smile_Left] = ((m_trackingData.m_mouthShape < 0f) ? l_weight : 0f); - m_lipData.prediction_data.blend_shape_weight[(int)LipShape_v2.Mouth_Smile_Right] = ((m_trackingData.m_mouthShape < 0f) ? l_weight : 0f); - - if(m_registered && m_activeAsModule && Settings.FaceTracking) - FaceTrackingManager.Instance.SubmitNewFacialData(m_lipData); - } - } - - internal ref TrackingData GetLatestTrackingData() => ref m_trackingData; - } -} diff --git a/ml_dht/Utils.cs b/ml_dht/Utils.cs index d835fca..e3cff3c 100644 --- a/ml_dht/Utils.cs +++ b/ml_dht/Utils.cs @@ -1,4 +1,5 @@ -using ABI_RC.Core.UI; +using ABI.CCK.Components; +using ABI_RC.Core.UI; using System.Reflection; using UnityEngine; @@ -6,10 +7,14 @@ namespace ml_dht { static class Utils { + static readonly object[] ms_emptyArray = new object[0]; 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); static public void ExecuteScript(this CohtmlControlledViewWrapper p_instance, string p_script) => ((cohtml.Net.View)ms_view.GetValue(p_instance)).ExecuteScript(p_script); + static public void UpdateShapesLocal_Private(this CVRFaceTracking p_instance) => ms_updateShapesLocal?.Invoke(p_instance, ms_emptyArray); + 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_dht/ml_dht.csproj b/ml_dht/ml_dht.csproj index fb08a1e..85d58d2 100644 --- a/ml_dht/ml_dht.csproj +++ b/ml_dht/ml_dht.csproj @@ -6,7 +6,7 @@ SDraw None DesktopHeadTracking - 1.2.0 + 1.2.1 x64 diff --git a/ml_lme/LeapHand.cs b/ml_lme/LeapHand.cs new file mode 100644 index 0000000..23f15b1 --- /dev/null +++ b/ml_lme/LeapHand.cs @@ -0,0 +1,129 @@ +using UnityEngine; + +namespace ml_lme +{ + class LeapHand + { + public enum FingerBone + { + ThumbMetacarpal = 0, + ThumbProximal, + ThumbIntermediate, + ThumbDistal, + IndexMetacarpal, + IndexProximal, + IndexIntermediate, + IndexDistal, + MiddleMetacarpal, + MiddleProximal, + MiddleIntermediate, + MiddleDistal, + RingMetacarpal, + RingProximal, + RingIntermediate, + RingDistal, + PinkyMetacarpal, + PinkyProximal, + PinkyIntermediate, + PinkyDistal + }; + + readonly Transform m_root = null; + readonly Transform m_wrist = null; + readonly GameObject m_mesh = null; + readonly Transform[] m_fingersBones = null; + readonly Quaternion[] m_initialRotations = null; + + public LeapHand(Transform p_root, bool p_left) + { + m_fingersBones = new Transform[20]; + m_initialRotations = new Quaternion[20]; + + m_root = p_root; + if(m_root != null) + { + m_mesh = m_root.Find(p_left ? "GenericHandL" : "GenericHandR")?.gameObject; + m_wrist = m_root.Find(p_left ? "LeftHand/Wrist" : "RightHand/Wrist"); + if(m_wrist != null) + { + m_fingersBones[0] = null; // Actual thumb-meta, look at Leap Motion docs, dummy, it's zero point + m_fingersBones[1] = m_wrist.Find("thumb_meta"); + m_fingersBones[2] = m_wrist.Find("thumb_meta/thumb_a"); + m_fingersBones[3] = m_wrist.Find("thumb_meta/thumb_a/thumb_b"); + + m_fingersBones[4] = m_wrist.Find("index_meta"); + m_fingersBones[5] = m_wrist.Find("index_meta/index_a"); + m_fingersBones[6] = m_wrist.Find("index_meta/index_a/index_b"); + m_fingersBones[7] = m_wrist.Find("index_meta/index_a/index_b/index_c"); + + m_fingersBones[8] = m_wrist.Find("middle_meta"); + m_fingersBones[9] = m_wrist.Find("middle_meta/middle_a"); + m_fingersBones[10] = m_wrist.Find("middle_meta/middle_a/middle_b"); + m_fingersBones[11] = m_wrist.Find("middle_meta/middle_a/middle_b/middle_c"); + + m_fingersBones[12] = m_wrist.Find("ring_meta"); + m_fingersBones[13] = m_wrist.Find("ring_meta/ring_a"); + m_fingersBones[14] = m_wrist.Find("ring_meta/ring_a/ring_b"); + m_fingersBones[15] = m_wrist.Find("ring_meta/ring_a/ring_b/ring_c"); + + m_fingersBones[16] = m_wrist.Find("pinky_meta"); + m_fingersBones[17] = m_wrist.Find("pinky_meta/pinky_a"); + m_fingersBones[18] = m_wrist.Find("pinky_meta/pinky_a/pinky_b"); + m_fingersBones[19] = m_wrist.Find("pinky_meta/pinky_a/pinky_b/pinky_c"); + } + } + + for(int i = 0; i < 20; i++) + { + if(m_fingersBones[i] != null) + m_initialRotations[i] = m_fingersBones[i].localRotation; + } + } + + public void Update(LeapParser.HandData p_data) + { + if(m_wrist != null) + { + m_wrist.position = p_data.m_position; + m_wrist.rotation = p_data.m_rotation; + + for(int i = 0; i < 20; i++) + { + if(m_fingersBones[i] != null) + { + //m_fingers[i].position = p_data.m_fingerPosition[i]; + m_fingersBones[i].rotation = p_data.m_fingerRotation[i]; + } + } + + m_wrist.localPosition = Vector3.zero; + m_wrist.localRotation = Quaternion.identity; + } + } + + public void Reset() + { + if(m_wrist != null) + { + m_wrist.localPosition = Vector3.zero; + m_wrist.localRotation = Quaternion.identity; + } + + for(int i = 0; i < 20; i++) + { + if(m_fingersBones[i] != null) + m_fingersBones[i].localRotation = m_initialRotations[i]; + } + } + + public Transform GetRoot() => m_root; + public Transform GetWrist() => m_wrist; + public Transform GetFingersBone(FingerBone p_bone) => m_fingersBones[(int)p_bone]; + + public void SetMeshActive(bool p_state) + { + if(m_mesh != null) + m_mesh.SetActive(p_state); + } + } +} diff --git a/ml_lme/LeapInput.cs b/ml_lme/LeapInput.cs index 7836502..8a31b3b 100644 --- a/ml_lme/LeapInput.cs +++ b/ml_lme/LeapInput.cs @@ -1,8 +1,10 @@ -using ABI_RC.Core.InteractionSystem; +using ABI.CCK.Components; +using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.Player; using ABI_RC.Core.Savior; using ABI_RC.Systems.IK; using ABI_RC.Systems.InputManagement; +using ABI_RC.Systems.VRModeSwitch; using System.Collections; using UnityEngine; @@ -32,13 +34,15 @@ namespace ml_lme m_inVR = Utils.IsInVR(); - m_handRayLeft = LeapTracking.Instance.GetLeftHand().gameObject.AddComponent(); + m_handRayLeft = LeapTracking.Instance.GetLeftHand().GetRoot().gameObject.AddComponent(); m_handRayLeft.hand = true; - m_handRayLeft.generalMask = -1485; + m_handRayLeft.generalMask = -269; m_handRayLeft.isInteractionRay = true; m_handRayLeft.triggerGazeEvents = false; m_handRayLeft.holderRoot = m_handRayLeft.gameObject; m_handRayLeft.attachmentDistance = 0f; + m_handRayLeft.uiMask = 32; + m_handRayLeft.isDesktopRay = !m_inVR; m_lineLeft = m_handRayLeft.gameObject.AddComponent(); m_lineLeft.endWidth = 1f; @@ -52,13 +56,15 @@ namespace ml_lme m_lineLeft.receiveShadows = false; m_handRayLeft.lineRenderer = m_lineLeft; - m_handRayRight = LeapTracking.Instance.GetRightHand().gameObject.AddComponent(); + m_handRayRight = LeapTracking.Instance.GetRightHand().GetRoot().gameObject.AddComponent(); m_handRayRight.hand = false; - m_handRayRight.generalMask = -1485; + m_handRayRight.generalMask = -269; m_handRayRight.isInteractionRay = true; m_handRayRight.triggerGazeEvents = false; m_handRayRight.holderRoot = m_handRayRight.gameObject; m_handRayRight.attachmentDistance = 0f; + m_handRayRight.uiMask = 32; + m_handRayRight.isDesktopRay = !m_inVR; m_lineRight = m_handRayRight.gameObject.AddComponent(); m_lineRight.endWidth = 1f; @@ -72,6 +78,9 @@ namespace ml_lme m_lineRight.receiveShadows = false; m_handRayRight.lineRenderer = m_lineRight; + m_handRayLeft.otherRay = m_handRayRight; + m_handRayRight.otherRay = m_handRayLeft; + Settings.EnabledChange += this.OnEnableChange; Settings.InteractionChange += this.OnInteractionChange; Settings.GesturesChange += this.OnGesturesChange; @@ -84,6 +93,9 @@ namespace ml_lme MelonLoader.MelonCoroutines.Start(WaitForSettings()); MelonLoader.MelonCoroutines.Start(WaitForMaterial()); + + VRModeSwitchEvents.OnInitializeXR.AddListener(OnModeSwitch); + VRModeSwitchEvents.OnDeinitializeXR.AddListener(OnModeSwitch); } IEnumerator WaitForSettings() @@ -108,8 +120,13 @@ namespace ml_lme m_lineLeft.material = PlayerSetup.Instance.vrRayLeft.lineRenderer.material; m_lineLeft.gameObject.layer = PlayerSetup.Instance.vrRayLeft.gameObject.layer; + m_handRayLeft.highlightMaterial = PlayerSetup.Instance.vrRayLeft.highlightMaterial; + m_handRayLeft.SetVRActive(m_inVR); + m_lineRight.material = PlayerSetup.Instance.vrRayLeft.lineRenderer.material; m_lineRight.gameObject.layer = PlayerSetup.Instance.vrRayLeft.gameObject.layer; + m_handRayRight.highlightMaterial = PlayerSetup.Instance.vrRayLeft.highlightMaterial; + m_handRayRight.SetVRActive(m_inVR); } public override void ModuleDestroyed() @@ -138,6 +155,8 @@ namespace ml_lme Settings.FingersOnlyChange -= this.OnFingersOnlyChange; MetaPort.Instance.settings.settingBoolChanged.RemoveListener(this.OnGameSettingBoolChange); + VRModeSwitchEvents.OnInitializeXR.RemoveListener(OnModeSwitch); + VRModeSwitchEvents.OnDeinitializeXR.RemoveListener(OnModeSwitch); } public override void UpdateInput() @@ -157,36 +176,36 @@ namespace ml_lme base._inputManager.gestureLeftRaw = 0f; // Finger Point & Finger Gun - if((base._inputManager.fingerCurlLeftIndex < 0.2f) && (base._inputManager.fingerCurlLeftMiddle > 0.75f) && - (base._inputManager.fingerCurlLeftRing > 0.75f) && (base._inputManager.fingerCurlLeftPinky > 0.75f)) + if((base._inputManager.fingerFullCurlNormalizedLeftIndex < 0.2f) && (base._inputManager.fingerFullCurlNormalizedLeftMiddle > 0.75f) && + (base._inputManager.fingerFullCurlNormalizedLeftRing > 0.75f) && (base._inputManager.fingerFullCurlNormalizedLeftPinky > 0.75f)) { - base._inputManager.gestureLeftRaw = (base._inputManager.fingerCurlLeftThumb >= 0.5f) ? 4f : 3f; + base._inputManager.gestureLeftRaw = (base._inputManager.fingerFullCurlNormalizedLeftThumb >= 0.5f) ? 4f : 3f; } // Peace Sign - if((base._inputManager.fingerCurlLeftIndex < 0.2f) && (base._inputManager.fingerCurlLeftMiddle < 0.2f) && - (base._inputManager.fingerCurlLeftRing > 0.75f) && (base._inputManager.fingerCurlLeftPinky > 0.75f)) + if((base._inputManager.fingerFullCurlNormalizedLeftIndex < 0.2f) && (base._inputManager.fingerFullCurlNormalizedLeftMiddle < 0.2f) && + (base._inputManager.fingerFullCurlNormalizedLeftRing > 0.75f) && (base._inputManager.fingerFullCurlNormalizedLeftPinky > 0.75f)) { base._inputManager.gestureLeftRaw = 5f; } // Rock and Roll - if((base._inputManager.fingerCurlLeftIndex < 0.2f) && (base._inputManager.fingerCurlLeftMiddle > 0.75f) && - (base._inputManager.fingerCurlLeftRing > 0.75f) && (base._inputManager.fingerCurlLeftPinky < 0.5f)) + if((base._inputManager.fingerFullCurlNormalizedLeftIndex < 0.2f) && (base._inputManager.fingerFullCurlNormalizedLeftMiddle > 0.75f) && + (base._inputManager.fingerFullCurlNormalizedLeftRing > 0.75f) && (base._inputManager.fingerFullCurlNormalizedLeftPinky < 0.5f)) { base._inputManager.gestureLeftRaw = 6f; } // Fist & Thumbs Up - if((base._inputManager.fingerCurlLeftIndex > 0.5f) && (base._inputManager.fingerCurlLeftMiddle > 0.5f) && - (base._inputManager.fingerCurlLeftRing > 0.5f) && (base._inputManager.fingerCurlLeftPinky > 0.5f)) + if((base._inputManager.fingerFullCurlNormalizedLeftIndex > 0.5f) && (base._inputManager.fingerFullCurlNormalizedLeftMiddle > 0.5f) && + (base._inputManager.fingerFullCurlNormalizedLeftRing > 0.5f) && (base._inputManager.fingerFullCurlNormalizedLeftPinky > 0.5f)) { - base._inputManager.gestureLeftRaw = (base._inputManager.fingerCurlLeftThumb >= 0.5f) ? ((l_data.m_leftHand.m_grabStrength - 0.5f) * 2f) : 2f; + base._inputManager.gestureLeftRaw = (base._inputManager.fingerFullCurlNormalizedLeftThumb >= 0.5f) ? ((l_data.m_leftHand.m_grabStrength - 0.5f) * 2f) : 2f; } // Open Hand - if((base._inputManager.fingerCurlLeftIndex < 0.2f) && (base._inputManager.fingerCurlLeftMiddle < 0.2f) && - (base._inputManager.fingerCurlLeftRing < 0.2f) && (base._inputManager.fingerCurlLeftPinky < 0.2f)) + if((base._inputManager.fingerFullCurlNormalizedLeftIndex < 0.2f) && (base._inputManager.fingerFullCurlNormalizedLeftMiddle < 0.2f) && + (base._inputManager.fingerFullCurlNormalizedLeftRing < 0.2f) && (base._inputManager.fingerFullCurlNormalizedLeftPinky < 0.2f)) { base._inputManager.gestureLeftRaw = -1f; } @@ -217,36 +236,36 @@ namespace ml_lme base._inputManager.gestureRightRaw = 0f; // Finger Point & Finger Gun - if((base._inputManager.fingerCurlRightIndex < 0.2f) && (base._inputManager.fingerCurlRightMiddle > 0.75f) && - (base._inputManager.fingerCurlRightRing > 0.75f) && (base._inputManager.fingerCurlRightPinky > 0.75f)) + if((base._inputManager.fingerFullCurlNormalizedRightIndex < 0.2f) && (base._inputManager.fingerFullCurlNormalizedRightMiddle > 0.75f) && + (base._inputManager.fingerFullCurlNormalizedRightRing > 0.75f) && (base._inputManager.fingerFullCurlNormalizedRightPinky > 0.75f)) { - base._inputManager.gestureRightRaw = (base._inputManager.fingerCurlRightThumb >= 0.5f) ? 4f : 3f; + base._inputManager.gestureRightRaw = (base._inputManager.fingerFullCurlNormalizedRightThumb >= 0.5f) ? 4f : 3f; } // Peace Sign - if((base._inputManager.fingerCurlRightIndex < 0.2f) && (base._inputManager.fingerCurlRightMiddle < 0.2f) && - (base._inputManager.fingerCurlRightRing > 0.75f) && (base._inputManager.fingerCurlRightPinky > 0.75f)) + if((base._inputManager.fingerFullCurlNormalizedRightIndex < 0.2f) && (base._inputManager.fingerFullCurlNormalizedRightMiddle < 0.2f) && + (base._inputManager.fingerFullCurlNormalizedRightRing > 0.75f) && (base._inputManager.fingerFullCurlNormalizedRightPinky > 0.75f)) { base._inputManager.gestureRightRaw = 5f; } // Rock and Roll - if((base._inputManager.fingerCurlRightIndex < 0.2f) && (base._inputManager.fingerCurlRightMiddle > 0.75f) && - (base._inputManager.fingerCurlRightRing > 0.75f) && (base._inputManager.fingerCurlRightPinky < 0.5f)) + if((base._inputManager.fingerFullCurlNormalizedRightIndex < 0.2f) && (base._inputManager.fingerFullCurlNormalizedRightMiddle > 0.75f) && + (base._inputManager.fingerFullCurlNormalizedRightRing > 0.75f) && (base._inputManager.fingerFullCurlNormalizedRightPinky < 0.5f)) { base._inputManager.gestureRightRaw = 6f; } // Fist & Thumbs Up - if((base._inputManager.fingerCurlRightIndex > 0.5f) && (base._inputManager.fingerCurlRightMiddle > 0.5f) && - (base._inputManager.fingerCurlRightRing > 0.5f) && (base._inputManager.fingerCurlRightPinky > 0.5f)) + if((base._inputManager.fingerFullCurlNormalizedRightIndex > 0.5f) && (base._inputManager.fingerFullCurlNormalizedRightMiddle > 0.5f) && + (base._inputManager.fingerFullCurlNormalizedRightRing > 0.5f) && (base._inputManager.fingerFullCurlNormalizedRightPinky > 0.5f)) { - base._inputManager.gestureRightRaw = (base._inputManager.fingerCurlRightThumb >= 0.5f) ? ((l_data.m_rightHand.m_grabStrength - 0.5f) * 2f) : 2f; + base._inputManager.gestureRightRaw = (base._inputManager.fingerFullCurlNormalizedRightThumb >= 0.5f) ? ((l_data.m_rightHand.m_grabStrength - 0.5f) * 2f) : 2f; } // Open Hand - if((base._inputManager.fingerCurlRightIndex < 0.2f) && (base._inputManager.fingerCurlRightMiddle < 0.2f) && - (base._inputManager.fingerCurlRightRing < 0.2f) && (base._inputManager.fingerCurlRightPinky < 0.2f)) + if((base._inputManager.fingerFullCurlNormalizedRightIndex < 0.2f) && (base._inputManager.fingerFullCurlNormalizedRightMiddle < 0.2f) && + (base._inputManager.fingerFullCurlNormalizedRightRing < 0.2f) && (base._inputManager.fingerFullCurlNormalizedRightPinky < 0.2f)) { base._inputManager.gestureRightRaw = -1f; } @@ -279,7 +298,7 @@ namespace ml_lme { LeapParser.LeapData l_data = LeapManager.Instance.GetLatestData(); - if(m_handVisibleLeft && (!m_inVR || !Utils.IsLeftHandTracked()) && !Settings.FingersOnly) + if(m_handVisibleLeft && !Settings.FingersOnly) { float l_strength = l_data.m_leftHand.m_grabStrength; @@ -307,7 +326,7 @@ namespace ml_lme } } - if(m_handVisibleRight && (!m_inVR || !Utils.IsRightHandTracked()) && !Settings.FingersOnly) + if(m_handVisibleRight && !Settings.FingersOnly) { float l_strength = l_data.m_rightHand.m_grabStrength; @@ -335,8 +354,8 @@ namespace ml_lme } } - ToggleHandRay(m_handVisibleLeft && (!m_inVR || !Utils.IsLeftHandTracked()) && !Settings.FingersOnly, true); - ToggleHandRay(m_handVisibleRight && (!m_inVR || !Utils.IsRightHandTracked()) && !Settings.FingersOnly, false); + ToggleHandRay(m_handVisibleLeft && !Settings.FingersOnly, true); + ToggleHandRay(m_handVisibleRight && !Settings.FingersOnly, false); } } @@ -402,47 +421,116 @@ namespace ml_lme } // Game events - internal void OnAvatarSetup() - { - m_inVR = Utils.IsInVR(); - } - internal void OnRayScale(float p_scale) { m_handRayLeft.SetRayScale(p_scale); m_handRayRight.SetRayScale(p_scale); } + internal void OnPickupGrab(CVRPickupObject p_pickup) + { + if(p_pickup.gripType == CVRPickupObject.GripType.Origin) + { + if(p_pickup._controllerRay == m_handRayLeft) + { + m_handRayLeft.attachmentPoint.localPosition = Vector3.zero; + m_handRayLeft.attachmentPoint.localRotation = Quaternion.Euler(0f, 0f, 270f); + } + if(p_pickup._controllerRay == m_handRayRight) + { + m_handRayRight.attachmentPoint.localPosition = Vector3.zero; + m_handRayRight.attachmentPoint.localRotation = Quaternion.Euler(0f, 0f, 90f); + } + } + } + + void OnModeSwitch() + { + 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); + } + + OnEnableChange(Settings.Enabled); + } + // Arbitrary void SetFingersInput(LeapParser.HandData p_hand, bool p_left) { - // Game has spreads in range of [0;1], but mod now operates in range of [-1;1] - // So spreads will be normalized towards game's range if(p_left) { - base._inputManager.fingerCurlLeftThumb = p_hand.m_bends[0]; - base._inputManager.fingerCurlLeftIndex = p_hand.m_bends[1]; - base._inputManager.fingerCurlLeftMiddle = p_hand.m_bends[2]; - base._inputManager.fingerCurlLeftRing = p_hand.m_bends[3]; - base._inputManager.fingerCurlLeftPinky = p_hand.m_bends[4]; - base._inputManager.fingerSpreadLeftThumb = 1f - (p_hand.m_spreads[0] * 0.5f + 0.5f); - base._inputManager.fingerSpreadLeftIndex = 1f - (p_hand.m_spreads[1] * 0.5f + 0.5f); - base._inputManager.fingerSpreadLeftMiddle = 1f - (p_hand.m_spreads[2] * 0.5f + 0.5f); - base._inputManager.fingerSpreadLeftRing = 1f - (p_hand.m_spreads[3] * 0.5f + 0.5f); - base._inputManager.fingerSpreadLeftPinky = 1f - (p_hand.m_spreads[4] * 0.5f + 0.5f); + base._inputManager.finger1StretchedLeftThumb = LeapTracked.ms_lastLeftFingerBones[0]; + base._inputManager.finger2StretchedLeftThumb = LeapTracked.ms_lastLeftFingerBones[1]; + base._inputManager.finger3StretchedLeftThumb = LeapTracked.ms_lastLeftFingerBones[2]; + base._inputManager.fingerSpreadLeftThumb = LeapTracked.ms_lastLeftFingerBones[3]; + + base._inputManager.finger1StretchedLeftIndex = LeapTracked.ms_lastLeftFingerBones[4]; + base._inputManager.finger2StretchedLeftIndex = LeapTracked.ms_lastLeftFingerBones[5]; + base._inputManager.finger3StretchedLeftIndex = LeapTracked.ms_lastLeftFingerBones[6]; + base._inputManager.fingerSpreadLeftIndex = LeapTracked.ms_lastLeftFingerBones[7]; + + base._inputManager.finger1StretchedLeftMiddle = LeapTracked.ms_lastLeftFingerBones[8]; + base._inputManager.finger2StretchedLeftMiddle = LeapTracked.ms_lastLeftFingerBones[9]; + base._inputManager.finger3StretchedLeftMiddle = LeapTracked.ms_lastLeftFingerBones[10]; + base._inputManager.fingerSpreadLeftMiddle = LeapTracked.ms_lastLeftFingerBones[11]; + + base._inputManager.finger1StretchedLeftRing = LeapTracked.ms_lastLeftFingerBones[12]; + base._inputManager.finger2StretchedLeftRing = LeapTracked.ms_lastLeftFingerBones[13]; + base._inputManager.finger3StretchedLeftRing = LeapTracked.ms_lastLeftFingerBones[14]; + base._inputManager.fingerSpreadLeftRing = LeapTracked.ms_lastLeftFingerBones[15]; + + base._inputManager.finger1StretchedLeftPinky = LeapTracked.ms_lastLeftFingerBones[16]; + base._inputManager.finger2StretchedLeftPinky = LeapTracked.ms_lastLeftFingerBones[17]; + base._inputManager.finger3StretchedLeftPinky = LeapTracked.ms_lastLeftFingerBones[18]; + base._inputManager.fingerSpreadLeftPinky = LeapTracked.ms_lastLeftFingerBones[19]; + + base._inputManager.fingerFullCurlNormalizedLeftThumb = p_hand.m_bends[0]; + base._inputManager.fingerFullCurlNormalizedLeftIndex = p_hand.m_bends[1]; + base._inputManager.fingerFullCurlNormalizedLeftMiddle = p_hand.m_bends[2]; + base._inputManager.fingerFullCurlNormalizedLeftRing = p_hand.m_bends[3]; + base._inputManager.fingerFullCurlNormalizedLeftPinky = p_hand.m_bends[4]; } else { - base._inputManager.fingerCurlRightThumb = p_hand.m_bends[0]; - base._inputManager.fingerCurlRightIndex = p_hand.m_bends[1]; - base._inputManager.fingerCurlRightMiddle = p_hand.m_bends[2]; - base._inputManager.fingerCurlRightRing = p_hand.m_bends[3]; - base._inputManager.fingerCurlRightPinky = p_hand.m_bends[4]; - base._inputManager.fingerSpreadRightThumb = 1f - (p_hand.m_spreads[0] * 0.5f + 0.5f); - base._inputManager.fingerSpreadRightIndex = 1f - (p_hand.m_spreads[1] * 0.5f + 0.5f); - base._inputManager.fingerSpreadRightMiddle = 1f - (p_hand.m_spreads[2] * 0.5f + 0.5f); - base._inputManager.fingerSpreadRightRing = 1f - (p_hand.m_spreads[3] * 0.5f + 0.5f); - base._inputManager.fingerSpreadRightPinky = 1f - (p_hand.m_spreads[4] * 0.5f + 0.5f); + base._inputManager.finger1StretchedRightThumb = LeapTracked.ms_lastRightFingerBones[0]; + base._inputManager.finger2StretchedRightThumb = LeapTracked.ms_lastRightFingerBones[1]; + base._inputManager.finger3StretchedRightThumb = LeapTracked.ms_lastRightFingerBones[2]; + base._inputManager.fingerSpreadRightThumb = LeapTracked.ms_lastRightFingerBones[3]; + + base._inputManager.finger1StretchedRightIndex = LeapTracked.ms_lastRightFingerBones[4]; + base._inputManager.finger2StretchedRightIndex = LeapTracked.ms_lastRightFingerBones[5]; + base._inputManager.finger3StretchedRightIndex = LeapTracked.ms_lastRightFingerBones[6]; + base._inputManager.fingerSpreadRightIndex = LeapTracked.ms_lastRightFingerBones[7]; + + base._inputManager.finger1StretchedRightMiddle = LeapTracked.ms_lastRightFingerBones[8]; + base._inputManager.finger2StretchedRightMiddle = LeapTracked.ms_lastRightFingerBones[9]; + base._inputManager.finger3StretchedRightMiddle = LeapTracked.ms_lastRightFingerBones[10]; + base._inputManager.fingerSpreadRightMiddle = LeapTracked.ms_lastRightFingerBones[11]; + + base._inputManager.finger1StretchedRightRing = LeapTracked.ms_lastRightFingerBones[12]; + base._inputManager.finger2StretchedRightRing = LeapTracked.ms_lastRightFingerBones[13]; + base._inputManager.finger3StretchedRightRing = LeapTracked.ms_lastRightFingerBones[14]; + base._inputManager.fingerSpreadRightRing = LeapTracked.ms_lastRightFingerBones[15]; + + base._inputManager.finger1StretchedRightPinky = LeapTracked.ms_lastRightFingerBones[16]; + base._inputManager.finger2StretchedRightPinky = LeapTracked.ms_lastRightFingerBones[17]; + base._inputManager.finger3StretchedRightPinky = LeapTracked.ms_lastRightFingerBones[18]; + base._inputManager.fingerSpreadRightPinky = LeapTracked.ms_lastRightFingerBones[19]; + + base._inputManager.fingerFullCurlNormalizedRightThumb = p_hand.m_bends[0]; + base._inputManager.fingerFullCurlNormalizedRightIndex = p_hand.m_bends[1]; + base._inputManager.fingerFullCurlNormalizedRightMiddle = p_hand.m_bends[2]; + base._inputManager.fingerFullCurlNormalizedRightRing = p_hand.m_bends[3]; + base._inputManager.fingerFullCurlNormalizedRightPinky = p_hand.m_bends[4]; } } @@ -450,29 +538,69 @@ namespace ml_lme { if(p_left) { - base._inputManager.fingerCurlLeftThumb = 0f; - base._inputManager.fingerCurlLeftIndex = 0f; - base._inputManager.fingerCurlLeftMiddle = 0f; - base._inputManager.fingerCurlLeftRing = 0f; - base._inputManager.fingerCurlLeftPinky = 0f; - base._inputManager.fingerSpreadLeftThumb = 0.5f; - base._inputManager.fingerSpreadLeftIndex = 0.5f; - base._inputManager.fingerSpreadLeftMiddle = 0.5f; - base._inputManager.fingerSpreadLeftRing = 0.5f; - base._inputManager.fingerSpreadLeftPinky = 0.5f; + base._inputManager.finger1StretchedLeftThumb = -0.5f; + base._inputManager.finger2StretchedLeftThumb = 0.7f; + base._inputManager.finger3StretchedLeftThumb = 0.7f; + base._inputManager.fingerSpreadLeftThumb = 0f; + + base._inputManager.finger1StretchedLeftIndex = 0.5f; + base._inputManager.finger2StretchedLeftIndex = 0.7f; + base._inputManager.finger3StretchedLeftIndex = 0.7f; + base._inputManager.fingerSpreadLeftIndex = 0f; + + base._inputManager.finger1StretchedLeftMiddle = 0.5f; + base._inputManager.finger2StretchedLeftMiddle = 0.7f; + base._inputManager.finger3StretchedLeftMiddle = 0.7f; + base._inputManager.fingerSpreadLeftMiddle = 0f; + + base._inputManager.finger1StretchedLeftRing = 0.5f; + base._inputManager.finger2StretchedLeftRing = 0.7f; + base._inputManager.finger3StretchedLeftRing = 0.7f; + base._inputManager.fingerSpreadLeftRing = 0f; + + base._inputManager.finger1StretchedLeftPinky = 0.5f; + base._inputManager.finger2StretchedLeftPinky = 0.7f; + base._inputManager.finger3StretchedLeftPinky = 0.7f; + base._inputManager.fingerSpreadLeftPinky = 0f; + + base._inputManager.fingerFullCurlNormalizedLeftThumb = 0f; + base._inputManager.fingerFullCurlNormalizedLeftIndex = 0f; + base._inputManager.fingerFullCurlNormalizedLeftMiddle = 0f; + base._inputManager.fingerFullCurlNormalizedLeftRing = 0f; + base._inputManager.fingerFullCurlNormalizedLeftPinky = 0f; } else { - base._inputManager.fingerCurlRightThumb = 0f; - base._inputManager.fingerCurlRightIndex = 0f; - base._inputManager.fingerCurlRightMiddle = 0f; - base._inputManager.fingerCurlRightRing = 0f; - base._inputManager.fingerCurlRightPinky = 0f; - base._inputManager.fingerSpreadRightThumb = 0.5f; - base._inputManager.fingerSpreadRightIndex = 0.5f; - base._inputManager.fingerSpreadRightMiddle = 0.5f; - base._inputManager.fingerSpreadRightRing = 0.5f; - base._inputManager.fingerSpreadRightPinky = 0.5f; + base._inputManager.finger1StretchedRightThumb = -0.5f; + base._inputManager.finger2StretchedRightThumb = 0.7f; + base._inputManager.finger3StretchedRightThumb = 0.7f; + base._inputManager.fingerSpreadRightThumb = 0f; + + base._inputManager.finger1StretchedRightIndex = 0.5f; + base._inputManager.finger2StretchedRightIndex = 0.7f; + base._inputManager.finger3StretchedRightIndex = 0.7f; + base._inputManager.fingerSpreadRightIndex = 0f; + + base._inputManager.finger1StretchedRightMiddle = 0.5f; + base._inputManager.finger2StretchedRightMiddle = 0.7f; + base._inputManager.finger3StretchedRightMiddle = 0.7f; + base._inputManager.fingerSpreadRightMiddle = 0f; + + base._inputManager.finger1StretchedRightRing = 0.5f; + base._inputManager.finger2StretchedRightRing = 0.7f; + base._inputManager.finger3StretchedRightRing = 0.7f; + base._inputManager.fingerSpreadRightRing = 0f; + + base._inputManager.finger1StretchedRightPinky = 0.5f; + base._inputManager.finger2StretchedRightPinky = 0.7f; + base._inputManager.finger3StretchedRightPinky = 0.7f; + base._inputManager.fingerSpreadRightPinky = 0f; + + base._inputManager.fingerFullCurlNormalizedRightThumb = 0f; + base._inputManager.fingerFullCurlNormalizedRightIndex = 0f; + base._inputManager.fingerFullCurlNormalizedRightMiddle = 0f; + base._inputManager.fingerFullCurlNormalizedRightRing = 0f; + base._inputManager.fingerFullCurlNormalizedRightPinky = 0f; } } diff --git a/ml_lme/LeapManager.cs b/ml_lme/LeapManager.cs index 6d0918a..e6a3eab 100644 --- a/ml_lme/LeapManager.cs +++ b/ml_lme/LeapManager.cs @@ -1,216 +1,226 @@ -using ABI_RC.Core.Player; -using ABI_RC.Systems.InputManagement; -using System.Collections; -using UnityEngine; - -namespace ml_lme -{ - [DisallowMultipleComponent] - class LeapManager : MonoBehaviour - { - public static LeapManager Instance { get; private set; } = null; - - Leap.Controller m_leapController = null; - LeapParser.LeapData m_leapData = null; - - LeapTracking m_leapTracking = null; - LeapTracked m_leapTracked = null; - LeapInput m_leapInput = null; - - void Awake() - { - if(Instance == null) - Instance = this; - - m_leapController = new Leap.Controller(); - m_leapData = new LeapParser.LeapData(); - - DontDestroyOnLoad(this); - - m_leapController.Device += this.OnLeapDeviceInitialized; - m_leapController.DeviceFailure += this.OnLeapDeviceFailure; - m_leapController.DeviceLost += this.OnLeapDeviceLost; - m_leapController.Connect += this.OnLeapServiceConnect; - m_leapController.Disconnect += this.OnLeapServiceDisconnect; - - Settings.EnabledChange += this.OnEnableChange; - Settings.TrackingModeChange += this.OnTrackingModeChange; - - m_leapTracking = new GameObject("[LeapTrackingRoot]").AddComponent(); - m_leapTracking.transform.parent = this.transform; - - OnEnableChange(Settings.Enabled); - OnTrackingModeChange(Settings.TrackingMode); - - MelonLoader.MelonCoroutines.Start(WaitForObjects()); - } - - void OnDestroy() - { - if(Instance == this) - Instance = null; - - m_leapController.StopConnection(); - m_leapController.Device -= this.OnLeapDeviceInitialized; - m_leapController.DeviceFailure -= this.OnLeapDeviceFailure; - m_leapController.DeviceLost -= this.OnLeapDeviceLost; - m_leapController.Connect -= this.OnLeapServiceConnect; - m_leapController.Disconnect -= this.OnLeapServiceDisconnect; - m_leapController.Dispose(); - m_leapController = null; - - if(m_leapTracking != null) - Object.Destroy(m_leapTracking); - m_leapTracking = null; - - if(m_leapTracked != null) - Object.Destroy(m_leapTracked); - m_leapTracked = null; - - if(m_leapInput != null) - { - if(CVRInputManager.Instance != null) - CVRInputManager.Instance.DestroyInputModule(m_leapInput); - else - m_leapInput.ModuleDestroyed(); - } - m_leapInput = null; - - Settings.EnabledChange -= this.OnEnableChange; - Settings.TrackingModeChange -= this.OnTrackingModeChange; - } - - IEnumerator WaitForObjects() - { - while(CVRInputManager.Instance == null) - yield return null; - - while(PlayerSetup.Instance == null) - yield return null; - - while(LeapTracking.Instance == null) - yield return null; - - m_leapInput = new LeapInput(); - CVRInputManager.Instance.AddInputModule(m_leapInput); - - m_leapTracked = PlayerSetup.Instance.gameObject.AddComponent(); - } - - void Update() - { - if(Settings.Enabled) - { - m_leapData.Reset(); - - if(m_leapController.IsConnected) - { - Leap.Frame l_frame = m_leapController.Frame(); - LeapParser.ParseFrame(l_frame, m_leapData); - } - } - } - - public LeapParser.LeapData GetLatestData() => m_leapData; - - // Device events - void OnLeapDeviceInitialized(object p_sender, Leap.DeviceEventArgs p_args) - { - if(Settings.Enabled) - { - m_leapController.SubscribeToDeviceEvents(p_args.Device); - UpdateDeviceTrackingMode(); - } - - Utils.ShowHUDNotification("Leap Motion Extension", "Device initialized"); - } - - void OnLeapDeviceFailure(object p_sender, Leap.DeviceFailureEventArgs p_args) - { - Utils.ShowHUDNotification("Leap Motion Extension", "Device failure", "Code " + p_args.ErrorCode + ": " + p_args.ErrorMessage); - } - - void OnLeapDeviceLost(object p_sender, Leap.DeviceEventArgs p_args) - { - m_leapController.UnsubscribeFromDeviceEvents(p_args.Device); - - Utils.ShowHUDNotification("Leap Motion Extension", "Device lost"); - } - - void OnLeapServiceConnect(object p_sender, Leap.ConnectionEventArgs p_args) - { - Utils.ShowHUDNotification("Leap Motion Extension", "Service connected"); - } - - void OnLeapServiceDisconnect(object p_sender, Leap.ConnectionLostEventArgs p_args) - { - Utils.ShowHUDNotification("Leap Motion Extension", "Service disconnected"); - } - - // Settings - void OnEnableChange(bool p_state) - { - if(p_state) - { - m_leapController.StartConnection(); - UpdateDeviceTrackingMode(); - } - else - m_leapController.StopConnection(); - } - - void OnTrackingModeChange(Settings.LeapTrackingMode p_mode) - { - if(Settings.Enabled) - UpdateDeviceTrackingMode(); - } - - // Game events - internal void OnAvatarClear() - { - if(m_leapTracking != null) - m_leapTracking.OnAvatarClear(); - if(m_leapTracked != null) - m_leapTracked.OnAvatarClear(); - } - - internal void OnAvatarSetup() - { - if(m_leapTracking != null) - m_leapTracking.OnAvatarSetup(); - - m_leapInput?.OnAvatarSetup(); - - if(m_leapTracked != null) - m_leapTracked.OnAvatarSetup(); - } - - internal void OnRayScale(float p_scale) - { - m_leapInput?.OnRayScale(p_scale); - } - - internal void OnPlayspaceScale(float p_relation) - { - if(m_leapTracking != null) - m_leapTracking.OnPlayspaceScale(p_relation); - } - - // Arbitrary - void UpdateDeviceTrackingMode() - { - m_leapController.ClearPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_SCREENTOP, null); - m_leapController.ClearPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_HMD, null); - - switch(Settings.TrackingMode) - { - case Settings.LeapTrackingMode.Screentop: - m_leapController.SetPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_SCREENTOP, null); - break; - case Settings.LeapTrackingMode.HMD: - m_leapController.SetPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_HMD, null); - break; - } - } - } -} +using ABI.CCK.Components; +using ABI_RC.Core.Player; +using ABI_RC.Systems.InputManagement; +using System.Collections; +using UnityEngine; + +namespace ml_lme +{ + [DisallowMultipleComponent] + class LeapManager : MonoBehaviour + { + public static LeapManager Instance { get; private set; } = null; + + Leap.Controller m_leapController = null; + LeapParser.LeapData m_leapData = null; + + LeapTracking m_leapTracking = null; + LeapTracked m_leapTracked = null; + LeapInput m_leapInput = null; + + void Awake() + { + if(Instance == null) + Instance = this; + + m_leapController = new Leap.Controller(); + m_leapData = new LeapParser.LeapData(); + + DontDestroyOnLoad(this); + + m_leapController.Device += this.OnLeapDeviceInitialized; + m_leapController.DeviceFailure += this.OnLeapDeviceFailure; + m_leapController.DeviceLost += this.OnLeapDeviceLost; + m_leapController.Connect += this.OnLeapServiceConnect; + m_leapController.Disconnect += this.OnLeapServiceDisconnect; + + Settings.EnabledChange += this.OnEnableChange; + Settings.TrackingModeChange += this.OnTrackingModeChange; + + m_leapTracking = new GameObject("[LeapTrackingRoot]").AddComponent(); + m_leapTracking.transform.parent = this.transform; + + OnEnableChange(Settings.Enabled); + OnTrackingModeChange(Settings.TrackingMode); + + MelonLoader.MelonCoroutines.Start(WaitForObjects()); + } + + void OnDestroy() + { + if(Instance == this) + Instance = null; + + m_leapController.StopConnection(); + m_leapController.Device -= this.OnLeapDeviceInitialized; + m_leapController.DeviceFailure -= this.OnLeapDeviceFailure; + m_leapController.DeviceLost -= this.OnLeapDeviceLost; + m_leapController.Connect -= this.OnLeapServiceConnect; + m_leapController.Disconnect -= this.OnLeapServiceDisconnect; + m_leapController.Dispose(); + m_leapController = null; + + if(m_leapTracking != null) + Object.Destroy(m_leapTracking); + m_leapTracking = null; + + if(m_leapTracked != null) + Object.Destroy(m_leapTracked); + m_leapTracked = null; + + if(m_leapInput != null) + { + if(CVRInputManager.Instance != null) + CVRInputManager.Instance.DestroyInputModule(m_leapInput); + else + m_leapInput.ModuleDestroyed(); + } + m_leapInput = null; + + Settings.EnabledChange -= this.OnEnableChange; + Settings.TrackingModeChange -= this.OnTrackingModeChange; + } + + IEnumerator WaitForObjects() + { + while(CVRInputManager.Instance == null) + yield return null; + + while(PlayerSetup.Instance == null) + yield return null; + + while(LeapTracking.Instance == null) + yield return null; + + m_leapInput = new LeapInput(); + CVRInputManager.Instance.AddInputModule(m_leapInput); + + m_leapTracked = PlayerSetup.Instance.gameObject.AddComponent(); + } + + void Update() + { + if(Settings.Enabled) + { + m_leapData.Reset(); + + if(m_leapController.IsConnected) + { + Leap.Frame l_frame = m_leapController.Frame(); + LeapParser.ParseFrame(l_frame, m_leapData); + } + } + } + + public LeapParser.LeapData GetLatestData() => m_leapData; + + // Device events + void OnLeapDeviceInitialized(object p_sender, Leap.DeviceEventArgs p_args) + { + if(Settings.Enabled) + { + m_leapController.SubscribeToDeviceEvents(p_args.Device); + UpdateDeviceTrackingMode(); + } + + Utils.ShowHUDNotification("Leap Motion Extension", "Device initialized"); + } + + void OnLeapDeviceFailure(object p_sender, Leap.DeviceFailureEventArgs p_args) + { + Utils.ShowHUDNotification("Leap Motion Extension", "Device failure", "Code " + p_args.ErrorCode + ": " + p_args.ErrorMessage); + } + + void OnLeapDeviceLost(object p_sender, Leap.DeviceEventArgs p_args) + { + m_leapController.UnsubscribeFromDeviceEvents(p_args.Device); + + Utils.ShowHUDNotification("Leap Motion Extension", "Device lost"); + } + + void OnLeapServiceConnect(object p_sender, Leap.ConnectionEventArgs p_args) + { + Utils.ShowHUDNotification("Leap Motion Extension", "Service connected"); + } + + void OnLeapServiceDisconnect(object p_sender, Leap.ConnectionLostEventArgs p_args) + { + Utils.ShowHUDNotification("Leap Motion Extension", "Service disconnected"); + } + + // Settings + void OnEnableChange(bool p_state) + { + if(p_state) + { + m_leapController.StartConnection(); + UpdateDeviceTrackingMode(); + } + else + m_leapController.StopConnection(); + } + + void OnTrackingModeChange(Settings.LeapTrackingMode p_mode) + { + if(Settings.Enabled) + UpdateDeviceTrackingMode(); + } + + // Game events + internal void OnAvatarClear() + { + if(m_leapTracking != null) + m_leapTracking.OnAvatarClear(); + if(m_leapTracked != null) + m_leapTracked.OnAvatarClear(); + } + + internal void OnAvatarSetup() + { + if(m_leapTracking != null) + m_leapTracking.OnAvatarSetup(); + + if(m_leapTracked != null) + m_leapTracked.OnAvatarSetup(); + } + + internal void OnAvatarReinitialize() + { + if(m_leapTracked != null) + m_leapTracked.OnAvatarReinitialize(); + } + + internal void OnRayScale(float p_scale) + { + m_leapInput?.OnRayScale(p_scale); + } + + internal void OnPlayspaceScale(float p_relation) + { + if(m_leapTracking != null) + m_leapTracking.OnPlayspaceScale(p_relation); + } + + internal void OnPickupGrab(CVRPickupObject p_pickup) + { + m_leapInput?.OnPickupGrab(p_pickup); + } + + // Arbitrary + void UpdateDeviceTrackingMode() + { + m_leapController.ClearPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_SCREENTOP, null); + m_leapController.ClearPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_HMD, null); + + switch(Settings.TrackingMode) + { + case Settings.LeapTrackingMode.Screentop: + m_leapController.SetPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_SCREENTOP, null); + break; + case Settings.LeapTrackingMode.HMD: + m_leapController.SetPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_HMD, null); + break; + } + } + } +} diff --git a/ml_lme/LeapTracked.cs b/ml_lme/LeapTracked.cs index 09b0cb4..9d73b23 100644 --- a/ml_lme/LeapTracked.cs +++ b/ml_lme/LeapTracked.cs @@ -1,12 +1,14 @@ using ABI_RC.Core.Player; using ABI_RC.Systems.IK; using RootMotion.FinalIK; -using System.Reflection; +using System.Collections; +using System.Collections.Generic; using UnityEngine; namespace ml_lme { [DisallowMultipleComponent] + [DefaultExecutionOrder(999999)] class LeapTracked : MonoBehaviour { struct IKInfo @@ -19,18 +21,64 @@ namespace ml_lme public Transform m_rightElbowTarget; } - static readonly float[] ms_tposeMuscles = typeof(ABI_RC.Systems.IK.SubSystems.BodySystem).GetField("TPoseMuscles", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null) as float[]; + struct FingerBoneInfo + { + public LeapHand.FingerBone m_bone; + public Transform m_targetBone; + public Transform m_sourceBone; + public Quaternion m_offset; + } + static readonly Quaternion ms_offsetLeft = Quaternion.Euler(0f, 90f, 0f); static readonly Quaternion ms_offsetRight = Quaternion.Euler(0f, 270f, 0f); + static readonly (HumanBodyBones, LeapHand.FingerBone, bool)[] ms_fingerBonesLinks = + { + (HumanBodyBones.LeftThumbProximal, LeapHand.FingerBone.ThumbProximal, true), + (HumanBodyBones.LeftThumbIntermediate, LeapHand.FingerBone.ThumbIntermediate, true), + (HumanBodyBones.LeftThumbDistal, LeapHand.FingerBone.ThumbDistal, true), + (HumanBodyBones.LeftIndexProximal, LeapHand.FingerBone.IndexProximal, true), + (HumanBodyBones.LeftIndexIntermediate, LeapHand.FingerBone.IndexIntermediate, true), + (HumanBodyBones.LeftIndexDistal, LeapHand.FingerBone.IndexDistal, true), + (HumanBodyBones.LeftMiddleProximal, LeapHand.FingerBone.MiddleProximal, true), + (HumanBodyBones.LeftMiddleIntermediate, LeapHand.FingerBone.MiddleIntermediate, true), + (HumanBodyBones.LeftMiddleDistal, LeapHand.FingerBone.MiddleDistal, true), + (HumanBodyBones.LeftRingProximal, LeapHand.FingerBone.RingProximal, true), + (HumanBodyBones.LeftRingIntermediate, LeapHand.FingerBone.RingIntermediate, true), + (HumanBodyBones.LeftRingDistal, LeapHand.FingerBone.RingDistal, true), + (HumanBodyBones.LeftLittleProximal, LeapHand.FingerBone.PinkyProximal, true), + (HumanBodyBones.LeftLittleIntermediate, LeapHand.FingerBone.PinkyIntermediate, true), + (HumanBodyBones.LeftLittleDistal, LeapHand.FingerBone.PinkyDistal, true), + + (HumanBodyBones.RightThumbProximal, LeapHand.FingerBone.ThumbProximal, false), + (HumanBodyBones.RightThumbIntermediate, LeapHand.FingerBone.ThumbIntermediate, false), + (HumanBodyBones.RightThumbDistal, LeapHand.FingerBone.ThumbDistal, false), + (HumanBodyBones.RightIndexProximal, LeapHand.FingerBone.IndexProximal, false), + (HumanBodyBones.RightIndexIntermediate, LeapHand.FingerBone.IndexIntermediate, false), + (HumanBodyBones.RightIndexDistal, LeapHand.FingerBone.IndexDistal, false), + (HumanBodyBones.RightMiddleProximal, LeapHand.FingerBone.MiddleProximal, false), + (HumanBodyBones.RightMiddleIntermediate, LeapHand.FingerBone.MiddleIntermediate, false), + (HumanBodyBones.RightMiddleDistal, LeapHand.FingerBone.MiddleDistal, false), + (HumanBodyBones.RightRingProximal, LeapHand.FingerBone.RingProximal, false), + (HumanBodyBones.RightRingIntermediate, LeapHand.FingerBone.RingIntermediate, false), + (HumanBodyBones.RightRingDistal, LeapHand.FingerBone.RingDistal, false), + (HumanBodyBones.RightLittleProximal, LeapHand.FingerBone.PinkyProximal, false), + (HumanBodyBones.RightLittleIntermediate, LeapHand.FingerBone.PinkyIntermediate, false), + (HumanBodyBones.RightLittleDistal, LeapHand.FingerBone.PinkyDistal, false), + }; + + public static readonly float[] ms_lastLeftFingerBones = new float[20]; + public static readonly float[] ms_lastRightFingerBones = new float[20]; + bool m_inVR = false; VRIK m_vrIK = null; - Transform m_hips = null; bool m_enabled = true; bool m_fingersOnly = false; bool m_trackElbows = true; + Transform m_leftHand = null; + Transform m_rightHand = null; IKInfo m_vrIKInfo; ArmIK m_leftArmIK = null; ArmIK m_rightArmIK = null; @@ -41,18 +89,30 @@ namespace ml_lme bool m_leftTargetActive = false; // VRIK only bool m_rightTargetActive = false; // VRIK only + readonly List m_leftFingerBones = null; + readonly List m_rightFingerBones = null; + + Quaternion m_leftWristOffset; + Quaternion m_rightWristOffset; + + internal LeapTracked() + { + m_leftFingerBones = new List(); + m_rightFingerBones = new List(); + } + // Unity events void Start() { m_inVR = Utils.IsInVR(); m_leftHandTarget = new GameObject("RotationTarget").transform; - m_leftHandTarget.parent = LeapTracking.Instance.GetLeftHand(); + m_leftHandTarget.parent = LeapTracking.Instance.GetLeftHand().GetRoot(); m_leftHandTarget.localPosition = Vector3.zero; m_leftHandTarget.localRotation = Quaternion.identity; m_rightHandTarget = new GameObject("RotationTarget").transform; - m_rightHandTarget.parent = LeapTracking.Instance.GetRightHand(); + m_rightHandTarget.parent = LeapTracking.Instance.GetRightHand().GetRoot(); m_rightHandTarget.localPosition = Vector3.zero; m_rightHandTarget.localRotation = Quaternion.identity; @@ -67,13 +127,7 @@ namespace ml_lme void OnDestroy() { - if(m_leftArmIK != null) - Destroy(m_leftArmIK); - m_leftArmIK = null; - - if(m_rightArmIK != null) - Destroy(m_rightArmIK); - m_rightArmIK = null; + RemoveArmIK(); if(m_leftHandTarget != null) Destroy(m_leftHandTarget); @@ -122,19 +176,47 @@ namespace ml_lme void LateUpdate() { - if(m_enabled && !m_inVR && (m_poseHandler != null)) + if(m_enabled && (m_poseHandler != null)) { LeapParser.LeapData l_data = LeapManager.Instance.GetLatestData(); - - Vector3 l_hipsLocalPos = m_hips.localPosition; - Quaternion l_hipsLocalRot = m_hips.localRotation; + if(l_data.m_leftHand.m_present) + { + Transform l_leapWrist = LeapTracking.Instance.GetLeftHand().GetWrist(); + Quaternion l_turnBack = (m_leftHand.rotation * m_leftWristOffset) * Quaternion.Inverse(l_leapWrist.rotation); + foreach(var l_info in m_leftFingerBones) + l_info.m_targetBone.rotation = l_turnBack * (l_info.m_sourceBone.rotation * l_info.m_offset); + } + if(l_data.m_rightHand.m_present) + { + Transform l_leapWrist = LeapTracking.Instance.GetRightHand().GetWrist(); + Quaternion l_turnBack = (m_rightHand.rotation * m_rightWristOffset) * Quaternion.Inverse(l_leapWrist.rotation); + foreach(var l_info in m_rightFingerBones) + l_info.m_targetBone.rotation = l_turnBack * (l_info.m_sourceBone.rotation * l_info.m_offset); + } m_poseHandler.GetHumanPose(ref m_pose); - UpdateFingers(l_data); - m_poseHandler.SetHumanPose(ref m_pose); - - m_hips.localPosition = l_hipsLocalPos; - m_hips.localRotation = l_hipsLocalRot; + if(l_data.m_leftHand.m_present) + { + for(int i = 0; i < 5; i++) + { + int l_offset = i * 4; + ms_lastLeftFingerBones[l_offset] = m_pose.muscles[(int)MuscleIndex.LeftThumb1Stretched + l_offset]; + ms_lastLeftFingerBones[l_offset + 1] = m_pose.muscles[(int)MuscleIndex.LeftThumb2Stretched + l_offset]; + ms_lastLeftFingerBones[l_offset + 2] = m_pose.muscles[(int)MuscleIndex.LeftThumb3Stretched + l_offset]; + ms_lastLeftFingerBones[l_offset + 3] = m_pose.muscles[(int)MuscleIndex.LeftThumbSpread + l_offset]; + } + } + if(l_data.m_rightHand.m_present) + { + for(int i = 0; i < 5; i++) + { + int l_offset = i * 4; + ms_lastRightFingerBones[l_offset] = m_pose.muscles[(int)MuscleIndex.RightThumb1Stretched + l_offset]; + ms_lastRightFingerBones[l_offset + 1] = m_pose.muscles[(int)MuscleIndex.RightThumb2Stretched + l_offset]; + ms_lastRightFingerBones[l_offset + 2] = m_pose.muscles[(int)MuscleIndex.RightThumb3Stretched + l_offset]; + ms_lastRightFingerBones[l_offset + 3] = m_pose.muscles[(int)MuscleIndex.RightThumbSpread + l_offset]; + } + } } } @@ -142,20 +224,26 @@ namespace ml_lme internal void OnAvatarClear() { m_vrIK = null; - m_hips = null; m_leftArmIK = null; m_rightArmIK = null; m_leftTargetActive = false; m_rightTargetActive = false; - if(!m_inVR) - m_poseHandler?.Dispose(); + m_poseHandler?.Dispose(); m_poseHandler = null; m_leftHandTarget.localPosition = Vector3.zero; m_leftHandTarget.localRotation = Quaternion.identity; m_rightHandTarget.localPosition = Vector3.zero; m_rightHandTarget.localRotation = Quaternion.identity; + + m_leftFingerBones.Clear(); + m_rightFingerBones.Clear(); + + m_leftHand = null; + m_rightHand = null; + m_leftWristOffset = Quaternion.identity; + m_rightWristOffset = Quaternion.identity; } internal void OnAvatarSetup() @@ -165,84 +253,53 @@ namespace ml_lme if(PlayerSetup.Instance._animator.isHuman) { - Vector3 l_hipsPos = Vector3.zero; - m_hips = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Hips); - if(m_hips != null) - l_hipsPos = m_hips.localPosition; + m_poseHandler = new HumanPoseHandler(PlayerSetup.Instance._animator.avatar, PlayerSetup.Instance._animator.transform); + m_poseHandler.GetHumanPose(ref m_pose); - if(!m_inVR) + if(m_inVR) { - // Force desktop avatar into T-Pose - m_poseHandler = new HumanPoseHandler(PlayerSetup.Instance._animator.avatar, PlayerSetup.Instance._avatar.transform); - m_poseHandler.GetHumanPose(ref m_pose); - - HumanPose l_tPose = new HumanPose - { - bodyPosition = m_pose.bodyPosition, - bodyRotation = m_pose.bodyRotation, - muscles = new float[m_pose.muscles.Length] - }; - for(int i = 0; i < l_tPose.muscles.Length; i++) - l_tPose.muscles[i] = ms_tposeMuscles[i]; - m_poseHandler.SetHumanPose(ref l_tPose); - } - - Transform l_hand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand); - if(l_hand != null) - m_leftHandTarget.localRotation = ms_offsetLeft * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_hand.GetMatrix()).rotation; - - l_hand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand); - if(l_hand != null) - m_rightHandTarget.localRotation = ms_offsetRight * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_hand.GetMatrix()).rotation; - - if(m_vrIK == null) - { - Transform l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.UpperChest); - if(l_chest == null) - l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Chest); - if(l_chest == null) - l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Spine); - - m_leftArmIK = PlayerSetup.Instance._avatar.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 - ); - 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_rightArmIK = PlayerSetup.Instance._avatar.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 - ); - 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_poseHandler?.SetHumanPose(ref m_pose); + PlayerSetup.Instance._avatar.transform.localPosition = Vector3.zero; + PlayerSetup.Instance._avatar.transform.localRotation = Quaternion.identity; } else - { - m_vrIK.solver.OnPreUpdate += this.OnIKPreUpdate; - m_vrIK.solver.OnPostUpdate += this.OnIKPostUpdate; - } + PoseHelper.ForceTPose(PlayerSetup.Instance._animator); - if(m_hips != null) - m_hips.localPosition = l_hipsPos; + m_leftHand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand); + m_leftHandTarget.localRotation = ms_offsetLeft * (Quaternion.Inverse(PlayerSetup.Instance._avatar.transform.rotation) * m_leftHand.rotation); + + m_rightHand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand); + m_rightHandTarget.localRotation = ms_offsetRight * (Quaternion.Inverse(PlayerSetup.Instance._avatar.transform.rotation) * m_rightHand.rotation); + + ParseFingersBones(); + + if(m_vrIK != null) + { + m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreUpdate); + m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate); + } + else + SetupArmIK(); + } + } + + internal void OnAvatarReinitialize() + { + // Old VRIK is destroyed by game + m_inVR = Utils.IsInVR(); + m_vrIK = PlayerSetup.Instance._animator.GetComponent(); + + if(m_inVR) + RemoveArmIK(); + + if(m_vrIK != null) + { + m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreUpdate); + m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate); + } + else + { + PoseHelper.ForceTPose(PlayerSetup.Instance._animator); + SetupArmIK(); } } @@ -335,6 +392,56 @@ namespace ml_lme m_rightTargetActive = false; } + void SetupArmIK() + { + Transform l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.UpperChest); + if(l_chest == null) + l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Chest); + if(l_chest == null) + l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Spine); + + m_leftArmIK = PlayerSetup.Instance._avatar.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 + ); + 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_rightArmIK = PlayerSetup.Instance._avatar.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 + ); + 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); + } + + void RemoveArmIK() + { + if(m_leftArmIK != null) + Object.Destroy(m_leftArmIK); + m_leftArmIK = null; + + if(m_rightArmIK != null) + Object.Destroy(m_rightArmIK); + m_rightArmIK = null; + } + void RefreshArmIK() { if((m_leftArmIK != null) && (m_rightArmIK != null)) @@ -344,69 +451,33 @@ namespace ml_lme } } - void UpdateFingers(LeapParser.LeapData p_data) + void ParseFingersBones() { - if(p_data.m_leftHand.m_present) + LeapTracking.Instance.GetLeftHand().Reset(); + LeapTracking.Instance.GetLeftHand().GetWrist().rotation = PlayerSetup.Instance.transform.rotation * ms_offsetRight; // Weird, but that's how it works + m_leftWristOffset = Quaternion.Inverse(m_leftHand.rotation) * LeapTracking.Instance.GetLeftHand().GetWrist().rotation; + + LeapTracking.Instance.GetRightHand().Reset(); + LeapTracking.Instance.GetRightHand().GetWrist().rotation = PlayerSetup.Instance.transform.rotation * ms_offsetLeft; // Weird, but that's how it works + m_rightWristOffset = Quaternion.Inverse(m_rightHand.rotation) * LeapTracking.Instance.GetRightHand().GetWrist().rotation; + + foreach(var l_link in ms_fingerBonesLinks) { - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb1Stretched, -0.5f - p_data.m_leftHand.m_bends[0]); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb2Stretched, 0.7f - p_data.m_leftHand.m_bends[0] * 2f); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb3Stretched, 0.7f - p_data.m_leftHand.m_bends[0] * 2f); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumbSpread, -p_data.m_leftHand.m_spreads[0]); + Transform l_transform = PlayerSetup.Instance._animator.GetBoneTransform(l_link.Item1); + if(l_transform != null) + { + FingerBoneInfo l_info = new FingerBoneInfo(); + l_info.m_bone = l_link.Item2; + l_info.m_targetBone = l_transform; + l_info.m_sourceBone = (l_link.Item3 ? LeapTracking.Instance.GetLeftHand().GetFingersBone(l_link.Item2) : LeapTracking.Instance.GetRightHand().GetFingersBone(l_link.Item2)); + l_info.m_offset = Quaternion.Inverse(l_info.m_sourceBone.rotation) * l_info.m_targetBone.rotation; - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex1Stretched, 0.5f - p_data.m_leftHand.m_bends[1]); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex2Stretched, 0.7f - p_data.m_leftHand.m_bends[1] * 2f); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex3Stretched, 0.7f - p_data.m_leftHand.m_bends[1] * 2f); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndexSpread, p_data.m_leftHand.m_spreads[1]); - - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle1Stretched, 0.5f - p_data.m_leftHand.m_bends[2]); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle2Stretched, 0.7f - p_data.m_leftHand.m_bends[2] * 2f); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle3Stretched, 0.7f - p_data.m_leftHand.m_bends[2] * 2f); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddleSpread, p_data.m_leftHand.m_spreads[2]); - - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing1Stretched, 0.5f - p_data.m_leftHand.m_bends[3]); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing2Stretched, 0.7f - p_data.m_leftHand.m_bends[3] * 2f); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing3Stretched, 0.7f - p_data.m_leftHand.m_bends[3] * 2f); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRingSpread, -p_data.m_leftHand.m_spreads[3]); - - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle1Stretched, 0.5f - p_data.m_leftHand.m_bends[4]); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle2Stretched, 0.7f - p_data.m_leftHand.m_bends[4] * 2f); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle3Stretched, 0.7f - p_data.m_leftHand.m_bends[4] * 2f); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittleSpread, -p_data.m_leftHand.m_spreads[4]); + if(l_link.Item3) + m_leftFingerBones.Add(l_info); + else + m_rightFingerBones.Add(l_info); + } } - - if(p_data.m_rightHand.m_present) - { - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb1Stretched, -0.5f - p_data.m_rightHand.m_bends[0]); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb2Stretched, 0.7f - p_data.m_rightHand.m_bends[0] * 2f); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb3Stretched, 0.7f - p_data.m_rightHand.m_bends[0] * 2f); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumbSpread, -p_data.m_rightHand.m_spreads[0]); - - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex1Stretched, 0.5f - p_data.m_rightHand.m_bends[1]); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex2Stretched, 0.7f - p_data.m_rightHand.m_bends[1] * 2f); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex3Stretched, 0.7f - p_data.m_rightHand.m_bends[1] * 2f); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndexSpread, p_data.m_rightHand.m_spreads[1]); - - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle1Stretched, 0.5f - p_data.m_rightHand.m_bends[2]); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle2Stretched, 0.7f - p_data.m_rightHand.m_bends[2] * 2f); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle3Stretched, 0.7f - p_data.m_rightHand.m_bends[2] * 2f); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddleSpread, p_data.m_rightHand.m_spreads[2]); - - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing1Stretched, 0.5f - p_data.m_rightHand.m_bends[3]); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing2Stretched, 0.7f - p_data.m_rightHand.m_bends[3] * 2f); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing3Stretched, 0.7f - p_data.m_rightHand.m_bends[3] * 2f); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRingSpread, -p_data.m_rightHand.m_spreads[3]); - - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle1Stretched, 0.5f - p_data.m_rightHand.m_bends[4]); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle2Stretched, 0.7f - p_data.m_rightHand.m_bends[4] * 2f); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle3Stretched, 0.7f - p_data.m_rightHand.m_bends[4] * 2f); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittleSpread, -p_data.m_rightHand.m_spreads[4]); - } - } - - static void UpdatePoseMuscle(ref HumanPose p_pose, int p_index, float p_value) - { - if(p_pose.muscles.Length > p_index) - p_pose.muscles[p_index] = p_value; } } } diff --git a/ml_lme/LeapTracking.cs b/ml_lme/LeapTracking.cs index 684c679..535805d 100644 --- a/ml_lme/LeapTracking.cs +++ b/ml_lme/LeapTracking.cs @@ -1,288 +1,280 @@ -using ABI_RC.Core.Player; -using System.Collections; -using UnityEngine; - -namespace ml_lme -{ - [DisallowMultipleComponent] - class LeapTracking : MonoBehaviour - { - public static LeapTracking Instance { get; private set; } = null; - static Quaternion ms_dummyRotation = Quaternion.identity; - 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; - - GameObject m_leapHandLeft = null; - GameObject m_leapHandRight = null; - GameObject m_leapElbowLeft = null; - GameObject m_leapElbowRight = null; - GameObject m_leapControllerModel = null; - GameObject m_visualHands = null; - VisualHand m_visualHandLeft = null; - VisualHand m_visualHandRight = null; - - float m_scaleRelation = 1f; - - void Start() - { - if(Instance == null) - Instance = this; - - m_inVR = Utils.IsInVR(); - - m_leapHandLeft = new GameObject("LeapHandLeft"); - m_leapHandLeft.transform.parent = this.transform; - m_leapHandLeft.transform.localPosition = Vector3.zero; - m_leapHandLeft.transform.localRotation = Quaternion.identity; - - m_leapHandRight = new GameObject("LeapHandRight"); - m_leapHandRight.transform.parent = this.transform; - m_leapHandRight.transform.localPosition = Vector3.zero; - m_leapHandRight.transform.localRotation = Quaternion.identity; - - m_leapElbowLeft = new GameObject("LeapElbowLeft"); - m_leapElbowLeft.transform.parent = this.transform; - m_leapElbowLeft.transform.localPosition = Vector3.zero; - m_leapElbowLeft.transform.localRotation = Quaternion.identity; - - m_leapElbowRight = new GameObject("LeapElbowRight"); - m_leapElbowRight.transform.parent = this.transform; - m_leapElbowRight.transform.localPosition = Vector3.zero; - m_leapElbowRight.transform.localRotation = Quaternion.identity; - - m_leapControllerModel = AssetsHandler.GetAsset("assets/models/leapmotion/leap_motion_1_0.obj"); - if(m_leapControllerModel != null) - { - m_leapControllerModel.name = "LeapModel"; - m_leapControllerModel.transform.parent = this.transform; - m_leapControllerModel.transform.localPosition = Vector3.zero; - m_leapControllerModel.transform.localRotation = Quaternion.identity; - } - - m_visualHands = AssetsHandler.GetAsset("assets/models/hands/leaphands.prefab"); - if(m_visualHands != null) - { - m_visualHands.name = "VisualHands"; - m_visualHands.transform.parent = this.transform; - m_visualHands.transform.localPosition = Vector3.zero; - m_visualHands.transform.localRotation = Quaternion.identity; - - m_visualHandLeft = new VisualHand(m_visualHands.transform.Find("HandL"), true); - m_visualHandRight = new VisualHand(m_visualHands.transform.Find("HandR"), false); - } - - Settings.DesktopOffsetChange += this.OnDesktopOffsetChange; - Settings.ModelVisibilityChange += this.OnModelVisibilityChange; - Settings.VisualHandsChange += this.OnVisualHandsChange; - Settings.TrackingModeChange += this.OnTrackingModeChange; - Settings.RootAngleChange += this.OnRootAngleChange; - Settings.HeadAttachChange += this.OnHeadAttachChange; - Settings.HeadOffsetChange += this.OnHeadOffsetChange; - - MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); - - OnModelVisibilityChange(Settings.ModelVisibility); - OnVisualHandsChange(Settings.VisualHands); - OnTrackingModeChange(Settings.TrackingMode); - OnRootAngleChange(Settings.RootAngle); - } - - IEnumerator WaitForLocalPlayer() - { - while(PlayerSetup.Instance == null) - yield return null; - - OnHeadAttachChange(Settings.HeadAttach); - } - - void OnDestroy() - { - if(Instance == this) - Instance = null; - - if(m_leapHandLeft != null) - Object.Destroy(m_leapHandLeft); - m_leapHandLeft = null; - - if(m_leapHandRight != null) - Object.Destroy(m_leapHandRight); - m_leapHandRight = null; - - if(m_leapElbowLeft != null) - Object.Destroy(m_leapElbowLeft); - m_leapElbowLeft = null; - - if(m_leapElbowRight != null) - Object.Destroy(m_leapElbowRight); - m_leapElbowRight = null; - - if(m_leapControllerModel != null) - Object.Destroy(m_leapControllerModel); - m_leapControllerModel = null; - - if(m_visualHands != null) - Object.Destroy(m_visualHands); - m_visualHands = null; - - m_visualHandLeft = null; - m_visualHandRight = null; - - Settings.DesktopOffsetChange -= this.OnDesktopOffsetChange; - Settings.ModelVisibilityChange -= this.OnModelVisibilityChange; - Settings.VisualHandsChange -= this.OnVisualHandsChange; - Settings.TrackingModeChange -= this.OnTrackingModeChange; - Settings.RootAngleChange -= this.OnRootAngleChange; - Settings.HeadAttachChange -= this.OnHeadAttachChange; - Settings.HeadOffsetChange -= this.OnHeadOffsetChange; - } - - void Update() - { - if(Settings.Enabled) - { - LeapParser.LeapData l_data = LeapManager.Instance.GetLatestData(); - - if(l_data.m_leftHand.m_present) - { - OrientationAdjustment(ref l_data.m_leftHand.m_position, ref l_data.m_leftHand.m_rotation, Settings.TrackingMode); - for(int i = 0; i < 20; i++) - OrientationAdjustment(ref l_data.m_leftHand.m_fingerPosition[i], ref l_data.m_leftHand.m_fingerRotation[i], Settings.TrackingMode); - - m_leapHandLeft.transform.localPosition = l_data.m_leftHand.m_position; - m_leapHandLeft.transform.localRotation = l_data.m_leftHand.m_rotation; - - OrientationAdjustment(ref l_data.m_leftHand.m_elbowPosition, ref ms_dummyRotation, Settings.TrackingMode); - m_leapElbowLeft.transform.localPosition = l_data.m_leftHand.m_elbowPosition; - - if(Settings.VisualHands) - m_visualHandLeft?.Update(l_data.m_leftHand); - } - - if(l_data.m_rightHand.m_present) - { - OrientationAdjustment(ref l_data.m_rightHand.m_position, ref l_data.m_rightHand.m_rotation, Settings.TrackingMode); - for(int i = 0; i < 20; i++) - OrientationAdjustment(ref l_data.m_rightHand.m_fingerPosition[i], ref l_data.m_rightHand.m_fingerRotation[i], Settings.TrackingMode); - - m_leapHandRight.transform.localPosition = l_data.m_rightHand.m_position; - m_leapHandRight.transform.localRotation = l_data.m_rightHand.m_rotation; - - OrientationAdjustment(ref l_data.m_rightHand.m_elbowPosition, ref ms_dummyRotation, Settings.TrackingMode); - m_leapElbowRight.transform.localPosition = l_data.m_rightHand.m_elbowPosition; - - if(Settings.VisualHands) - m_visualHandRight?.Update(l_data.m_rightHand); - } - } - } - - public Transform GetLeftHand() => m_leapHandLeft.transform; - public Transform GetRightHand() => m_leapHandRight.transform; - public Transform GetLeftElbow() => m_leapElbowLeft.transform; - public Transform GetRightElbow() => m_leapElbowRight.transform; - - // Settings - void OnDesktopOffsetChange(Vector3 p_offset) - { - if(!Settings.HeadAttach) - this.transform.localPosition = p_offset * (!m_inVR ? m_scaleRelation : 1f); - } - - void OnModelVisibilityChange(bool p_state) - { - m_leapControllerModel.SetActive(p_state); - } - - void OnVisualHandsChange(bool p_state) - { - m_visualHands.SetActive(p_state); - } - - void OnTrackingModeChange(Settings.LeapTrackingMode p_mode) - { - switch(p_mode) - { - case Settings.LeapTrackingMode.Screentop: - m_leapControllerModel.transform.localRotation = Quaternion.Euler(0f, 0f, 180f); - break; - case Settings.LeapTrackingMode.Desktop: - m_leapControllerModel.transform.localRotation = Quaternion.identity; - break; - case Settings.LeapTrackingMode.HMD: - m_leapControllerModel.transform.localRotation = Quaternion.Euler(270f, 180f, 0f); - break; - } - } - - void OnRootAngleChange(Vector3 p_angle) - { - this.transform.localRotation = Quaternion.Euler(p_angle); - } - - void OnHeadAttachChange(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); - } - - void OnHeadOffsetChange(Vector3 p_offset) - { - if(Settings.HeadAttach) - this.transform.localPosition = p_offset * (!m_inVR ? m_scaleRelation : 1f); - } - - // Game events - internal void OnAvatarClear() - { - m_scaleRelation = 1f; - OnHeadAttachChange(Settings.HeadAttach); - } - - internal void OnAvatarSetup() - { - m_inVR = Utils.IsInVR(); - OnHeadAttachChange(Settings.HeadAttach); - } - - internal void OnPlayspaceScale(float p_relation) - { - m_scaleRelation = p_relation; - OnHeadAttachChange(Settings.HeadAttach); - } - - static void OrientationAdjustment(ref Vector3 p_pos, ref Quaternion p_rot, Settings.LeapTrackingMode p_mode) - { - switch(p_mode) - { - case Settings.LeapTrackingMode.Screentop: - { - p_pos.x *= -1f; - p_pos.y *= -1f; - p_rot = (ms_screentopRotation * p_rot); - } - break; - - case Settings.LeapTrackingMode.HMD: - { - p_pos.x *= -1f; - Utils.Swap(ref p_pos.y, ref p_pos.z); - p_rot = (ms_hmdRotation * p_rot); - } - break; - } - } - } -} +using ABI_RC.Core.Player; +using ABI_RC.Systems.VRModeSwitch; +using System.Collections; +using UnityEngine; + +namespace ml_lme +{ + [DisallowMultipleComponent] + class LeapTracking : MonoBehaviour + { + public static LeapTracking Instance { get; private set; } = null; + static Quaternion ms_dummyRotation = Quaternion.identity; + 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; + + GameObject m_leapHands = null; + LeapHand m_leapHandLeft = null; + LeapHand m_leapHandRight = null; + GameObject m_leapElbowLeft = null; + GameObject m_leapElbowRight = null; + GameObject m_leapControllerModel = null; + + float m_scaleRelation = 1f; + + void Start() + { + if(Instance == null) + Instance = this; + + m_inVR = Utils.IsInVR(); + + m_leapElbowLeft = new GameObject("LeapElbowLeft"); + m_leapElbowLeft.transform.parent = this.transform; + m_leapElbowLeft.transform.localPosition = Vector3.zero; + m_leapElbowLeft.transform.localRotation = Quaternion.identity; + + m_leapElbowRight = new GameObject("LeapElbowRight"); + m_leapElbowRight.transform.parent = this.transform; + m_leapElbowRight.transform.localPosition = Vector3.zero; + m_leapElbowRight.transform.localRotation = Quaternion.identity; + + m_leapControllerModel = AssetsHandler.GetAsset("assets/models/leapmotion/leap_motion_1_0.obj"); + if(m_leapControllerModel != null) + { + m_leapControllerModel.name = "LeapModel"; + m_leapControllerModel.transform.parent = this.transform; + m_leapControllerModel.transform.localPosition = Vector3.zero; + m_leapControllerModel.transform.localRotation = Quaternion.identity; + } + + m_leapHands = AssetsHandler.GetAsset("assets/models/leaphands/leaphands.prefab"); + if(m_leapHands != null) + { + m_leapHands.name = "LeapHands"; + m_leapHands.transform.parent = this.transform; + m_leapHands.transform.localPosition = Vector3.zero; + m_leapHands.transform.localRotation = Quaternion.identity; + + m_leapHandLeft = new LeapHand(m_leapHands.transform.Find("HandL"), true); + m_leapHandRight = new LeapHand(m_leapHands.transform.Find("HandR"), false); + } + + Settings.DesktopOffsetChange += this.OnDesktopOffsetChange; + Settings.ModelVisibilityChange += this.OnModelVisibilityChange; + Settings.VisualHandsChange += this.OnVisualHandsChange; + Settings.TrackingModeChange += this.OnTrackingModeChange; + Settings.RootAngleChange += this.OnRootAngleChange; + Settings.HeadAttachChange += this.OnHeadAttachChange; + Settings.HeadOffsetChange += this.OnHeadOffsetChange; + + MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); + + OnModelVisibilityChange(Settings.ModelVisibility); + OnVisualHandsChange(Settings.VisualHands); + OnTrackingModeChange(Settings.TrackingMode); + OnRootAngleChange(Settings.RootAngle); + + VRModeSwitchEvents.OnInitializeXR.AddListener(this.OnModeSwitch); + VRModeSwitchEvents.OnDeinitializeXR.AddListener(this.OnModeSwitch); + } + + IEnumerator WaitForLocalPlayer() + { + while(PlayerSetup.Instance == null) + yield return null; + + OnHeadAttachChange(Settings.HeadAttach); + } + + void OnDestroy() + { + if(Instance == this) + Instance = null; + + if(m_leapHands != null) + Object.Destroy(m_leapHands); + m_leapHands = null; + m_leapHandLeft = null; + m_leapHandRight = null; + + if(m_leapElbowLeft != null) + Object.Destroy(m_leapElbowLeft); + m_leapElbowLeft = null; + + if(m_leapElbowRight != null) + Object.Destroy(m_leapElbowRight); + m_leapElbowRight = null; + + if(m_leapControllerModel != null) + Object.Destroy(m_leapControllerModel); + m_leapControllerModel = null; + + Settings.DesktopOffsetChange -= this.OnDesktopOffsetChange; + Settings.ModelVisibilityChange -= this.OnModelVisibilityChange; + Settings.VisualHandsChange -= this.OnVisualHandsChange; + Settings.TrackingModeChange -= this.OnTrackingModeChange; + Settings.RootAngleChange -= this.OnRootAngleChange; + Settings.HeadAttachChange -= this.OnHeadAttachChange; + Settings.HeadOffsetChange -= this.OnHeadOffsetChange; + + VRModeSwitchEvents.OnInitializeXR.RemoveListener(this.OnModeSwitch); + VRModeSwitchEvents.OnDeinitializeXR.RemoveListener(this.OnModeSwitch); + } + + void Update() + { + if(Settings.Enabled) + { + LeapParser.LeapData l_data = LeapManager.Instance.GetLatestData(); + + if(l_data.m_leftHand.m_present) + { + OrientationAdjustment(ref l_data.m_leftHand.m_position, ref l_data.m_leftHand.m_rotation, Settings.TrackingMode); + for(int i = 0; i < 20; i++) + OrientationAdjustment(ref l_data.m_leftHand.m_fingerPosition[i], ref l_data.m_leftHand.m_fingerRotation[i], Settings.TrackingMode); + + m_leapHandLeft.GetRoot().localPosition = l_data.m_leftHand.m_position; + m_leapHandLeft.GetRoot().localRotation = l_data.m_leftHand.m_rotation; + + OrientationAdjustment(ref l_data.m_leftHand.m_elbowPosition, ref ms_dummyRotation, Settings.TrackingMode); + m_leapElbowLeft.transform.localPosition = l_data.m_leftHand.m_elbowPosition; + + m_leapHandLeft?.Update(l_data.m_leftHand); + } + + if(l_data.m_rightHand.m_present) + { + OrientationAdjustment(ref l_data.m_rightHand.m_position, ref l_data.m_rightHand.m_rotation, Settings.TrackingMode); + for(int i = 0; i < 20; i++) + OrientationAdjustment(ref l_data.m_rightHand.m_fingerPosition[i], ref l_data.m_rightHand.m_fingerRotation[i], Settings.TrackingMode); + + m_leapHandRight.GetRoot().localPosition = l_data.m_rightHand.m_position; + m_leapHandRight.GetRoot().localRotation = l_data.m_rightHand.m_rotation; + + OrientationAdjustment(ref l_data.m_rightHand.m_elbowPosition, ref ms_dummyRotation, Settings.TrackingMode); + m_leapElbowRight.transform.localPosition = l_data.m_rightHand.m_elbowPosition; + + m_leapHandRight?.Update(l_data.m_rightHand); + } + } + } + + public LeapHand GetLeftHand() => m_leapHandLeft; + public LeapHand GetRightHand() => m_leapHandRight; + public Transform GetLeftElbow() => m_leapElbowLeft.transform; + public Transform GetRightElbow() => m_leapElbowRight.transform; + + // Settings + void OnDesktopOffsetChange(Vector3 p_offset) + { + if(!Settings.HeadAttach) + this.transform.localPosition = p_offset * (!m_inVR ? m_scaleRelation : 1f); + } + + void OnModelVisibilityChange(bool p_state) + { + m_leapControllerModel.SetActive(p_state); + } + + void OnVisualHandsChange(bool p_state) + { + m_leapHandLeft?.SetMeshActive(p_state); + m_leapHandRight?.SetMeshActive(p_state); + } + + void OnTrackingModeChange(Settings.LeapTrackingMode p_mode) + { + switch(p_mode) + { + case Settings.LeapTrackingMode.Screentop: + m_leapControllerModel.transform.localRotation = Quaternion.Euler(0f, 0f, 180f); + break; + case Settings.LeapTrackingMode.Desktop: + m_leapControllerModel.transform.localRotation = Quaternion.identity; + break; + case Settings.LeapTrackingMode.HMD: + m_leapControllerModel.transform.localRotation = Quaternion.Euler(270f, 180f, 0f); + break; + } + } + + void OnRootAngleChange(Vector3 p_angle) + { + this.transform.localRotation = Quaternion.Euler(p_angle); + } + + void OnHeadAttachChange(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); + } + + void OnHeadOffsetChange(Vector3 p_offset) + { + if(Settings.HeadAttach) + this.transform.localPosition = p_offset * (!m_inVR ? m_scaleRelation : 1f); + } + + // Game events + internal void OnAvatarClear() + { + m_scaleRelation = 1f; + OnHeadAttachChange(Settings.HeadAttach); + } + + internal void OnAvatarSetup() + { + m_inVR = Utils.IsInVR(); + OnHeadAttachChange(Settings.HeadAttach); + } + + internal void OnPlayspaceScale(float p_relation) + { + m_scaleRelation = p_relation; + OnHeadAttachChange(Settings.HeadAttach); + } + + void OnModeSwitch() + { + m_inVR = Utils.IsInVR(); + OnHeadAttachChange(Settings.HeadAttach); + } + + // Utils + static void OrientationAdjustment(ref Vector3 p_pos, ref Quaternion p_rot, Settings.LeapTrackingMode p_mode) + { + switch(p_mode) + { + case Settings.LeapTrackingMode.Screentop: + { + p_pos.x *= -1f; + p_pos.y *= -1f; + p_rot = (ms_screentopRotation * p_rot); + } + break; + + case Settings.LeapTrackingMode.HMD: + { + p_pos.x *= -1f; + Utils.Swap(ref p_pos.y, ref p_pos.z); + p_rot = (ms_hmdRotation * p_rot); + } + break; + } + } + } +} diff --git a/ml_lme/Main.cs b/ml_lme/Main.cs index d317b77..5ee3cc0 100644 --- a/ml_lme/Main.cs +++ b/ml_lme/Main.cs @@ -1,4 +1,6 @@ -using ABI_RC.Core.Player; +using ABI.CCK.Components; +using ABI_RC.Core.Player; +using ABI_RC.Systems.IK; using System.Collections; using System.Reflection; using UnityEngine; @@ -32,6 +34,11 @@ namespace ml_lme null, new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); + HarmonyInstance.Patch( + typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public), + null, + new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + ); HarmonyInstance.Patch( typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetControllerRayScale)), null, @@ -42,6 +49,12 @@ namespace ml_lme null, new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnPlayspaceScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); + HarmonyInstance.Patch( + + typeof(CVRPickupObject).GetMethod(nameof(CVRPickupObject.Grab), BindingFlags.Public | BindingFlags.Instance), + null, + new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnPickupGrab_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + ); ModSupporter.Init(); MelonLoader.MelonCoroutines.Start(WaitForRootLogic()); @@ -94,6 +107,20 @@ namespace ml_lme } } + static void OnAvatarReinitialize_Postfix() => ms_instance?.OnAvatarReinitialize(); + void OnAvatarReinitialize() + { + try + { + if(m_leapManager != null) + m_leapManager.OnAvatarReinitialize(); + } + catch(System.Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } + static void OnRayScale_Postfix(float __0) => ms_instance?.OnRayScale(__0); void OnRayScale(float p_scale) { @@ -121,5 +148,19 @@ namespace ml_lme MelonLoader.MelonLogger.Error(e); } } + + static void OnPickupGrab_Postfix(ref CVRPickupObject __instance) => ms_instance?.OnPickupGrab(__instance); + void OnPickupGrab(CVRPickupObject p_pickup) + { + try + { + if(m_leapManager != null) + m_leapManager.OnPickupGrab(p_pickup); + } + catch(System.Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } } } diff --git a/ml_lme/PoseHelper.cs b/ml_lme/PoseHelper.cs new file mode 100644 index 0000000..4dbf3e7 --- /dev/null +++ b/ml_lme/PoseHelper.cs @@ -0,0 +1,26 @@ +using UnityEngine; +using ABI_RC.Systems.IK; + +namespace ml_lme +{ + static class PoseHelper + { + public static void ForceTPose(Animator p_animator) + { + if(p_animator.isHuman) + { + HumanPoseHandler l_handler = new HumanPoseHandler(p_animator.avatar, p_animator.transform); + HumanPose l_pose = new HumanPose(); + l_handler.GetHumanPose(ref l_pose); + + for(int i=0, j = Mathf.Min(l_pose.muscles.Length,MusclePoses.TPoseMuscles.Length); i < j; i++) + l_pose.muscles[i] = MusclePoses.TPoseMuscles[i]; + + l_pose.bodyPosition = Vector3.up; + l_pose.bodyRotation = Quaternion.identity; + l_handler.SetHumanPose(ref l_pose); + l_handler.Dispose(); + } + } + } +} diff --git a/ml_lme/Properties/AssemblyInfo.cs b/ml_lme/Properties/AssemblyInfo.cs index b802899..2a759ab 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.4.5", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.4.6-ex", "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/Settings.cs b/ml_lme/Settings.cs index 5c6b94c..e93faf5 100644 --- a/ml_lme/Settings.cs +++ b/ml_lme/Settings.cs @@ -1,346 +1,346 @@ -using ABI_RC.Core.InteractionSystem; -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace ml_lme -{ - static class Settings - { - public enum LeapTrackingMode - { - Screentop = 0, - Desktop, - HMD - } - - enum ModSetting - { - Enabled, - DesktopX, - DesktopY, - DesktopZ, - FingersOnly, - Model, - Mode, - AngleX, - AngleY, - AngleZ, - Head, - HeadX, - HeadY, - HeadZ, - TrackElbows, - Interaction, - Gestures, - InteractThreadhold, - GripThreadhold, - VisualHands - }; - - public static bool Enabled { get; private set; } = false; - public static Vector3 DesktopOffset { get; private set; } = new Vector3(0f, -0.45f, 0.3f); - public static bool FingersOnly { get; private set; } = false; - public static bool ModelVisibility { get; private set; } = false; - public static LeapTrackingMode TrackingMode { get; private set; } = LeapTrackingMode.Desktop; - public static Vector3 RootAngle { get; private set; } = Vector3.zero; - public static bool HeadAttach { get; private set; } = false; - public static Vector3 HeadOffset { get; private set; } = new Vector3(0f, -0.3f, 0.15f); - public static bool TrackElbows { get; private set; } = true; - public static bool Interaction { get; private set; } = true; - public static bool Gestures { get; private set; } = false; - public static float InteractThreadhold { get; private set; } = 0.8f; - public static float GripThreadhold { get; private set; } = 0.4f; - public static bool VisualHands { get; private set; } = false; - - static MelonLoader.MelonPreferences_Category ms_category = null; - static List ms_entries = null; - - static public event Action EnabledChange; - static public event Action DesktopOffsetChange; - static public event Action FingersOnlyChange; - static public event Action ModelVisibilityChange; - static public event Action TrackingModeChange; - static public event Action RootAngleChange; - static public event Action HeadAttachChange; - static public event Action HeadOffsetChange; - static public event Action TrackElbowsChange; - static public event Action InteractionChange; - static public event Action GesturesChange; - static public event Action InteractThreadholdChange; - static public event Action GripThreadholdChange; - static public event Action VisualHandsChange; - - internal static void Init() - { - ms_category = MelonLoader.MelonPreferences.CreateCategory("LME", null, true); - - ms_entries = new List() - { - ms_category.CreateEntry(ModSetting.Enabled.ToString(), Enabled), - ms_category.CreateEntry(ModSetting.DesktopX.ToString(), (int)(DesktopOffset.x * 100f)), - ms_category.CreateEntry(ModSetting.DesktopY.ToString(), (int)(DesktopOffset.y * 100f)), - ms_category.CreateEntry(ModSetting.DesktopZ.ToString(), (int)(DesktopOffset.z * 100f)), - ms_category.CreateEntry(ModSetting.FingersOnly.ToString(), FingersOnly), - ms_category.CreateEntry(ModSetting.Model.ToString(), ModelVisibility), - ms_category.CreateEntry(ModSetting.Mode.ToString(), (int)TrackingMode), - ms_category.CreateEntry(ModSetting.AngleX.ToString(), (int)(RootAngle.x * 100f)), - ms_category.CreateEntry(ModSetting.AngleY.ToString(), (int)(RootAngle.y * 100f)), - ms_category.CreateEntry(ModSetting.AngleZ.ToString(), (int)(RootAngle.z * 100f)), - ms_category.CreateEntry(ModSetting.Head.ToString(), HeadAttach), - ms_category.CreateEntry(ModSetting.HeadX.ToString(), (int)(HeadOffset.x * 100f)), - ms_category.CreateEntry(ModSetting.HeadY.ToString(), (int)(HeadOffset.y * 100f)), - ms_category.CreateEntry(ModSetting.HeadZ.ToString(), (int)(HeadOffset.z * 100f)), - ms_category.CreateEntry(ModSetting.TrackElbows.ToString(), TrackElbows), - ms_category.CreateEntry(ModSetting.Interaction.ToString(), Interaction), - ms_category.CreateEntry(ModSetting.Gestures.ToString(), Gestures), - ms_category.CreateEntry(ModSetting.InteractThreadhold.ToString(), (int)(InteractThreadhold * 100f)), - ms_category.CreateEntry(ModSetting.GripThreadhold.ToString(), (int)(GripThreadhold * 100f)), - ms_category.CreateEntry(ModSetting.VisualHands.ToString(), VisualHands) - }; - - Load(); - - MelonLoader.MelonCoroutines.Start(WaitMainMenuUi()); - } - - static System.Collections.IEnumerator WaitMainMenuUi() - { - while(ViewManager.Instance == null) - yield return null; - while(ViewManager.Instance.gameMenuView == null) - yield return null; - while(ViewManager.Instance.gameMenuView.Listener == null) - yield return null; - - 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)); - }; - ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) => - { - ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mods_extension.js")); - ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mod_menu.js")); - foreach(var l_entry in ms_entries) - ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString()); - }; - } - - static void Load() - { - Enabled = (bool)ms_entries[(int)ModSetting.Enabled].BoxedValue; - DesktopOffset = new Vector3( - (int)ms_entries[(int)ModSetting.DesktopX].BoxedValue, - (int)ms_entries[(int)ModSetting.DesktopY].BoxedValue, - (int)ms_entries[(int)ModSetting.DesktopZ].BoxedValue - ) * 0.01f; - FingersOnly = (bool)ms_entries[(int)ModSetting.FingersOnly].BoxedValue; - ModelVisibility = (bool)ms_entries[(int)ModSetting.Model].BoxedValue; - TrackingMode = (LeapTrackingMode)(int)ms_entries[(int)ModSetting.Mode].BoxedValue; - RootAngle = new Vector3( - (int)ms_entries[(int)ModSetting.AngleX].BoxedValue, - (int)ms_entries[(int)ModSetting.AngleY].BoxedValue, - (int)ms_entries[(int)ModSetting.AngleZ].BoxedValue - ); - HeadAttach = (bool)ms_entries[(int)ModSetting.Head].BoxedValue; - HeadOffset = new Vector3( - (int)ms_entries[(int)ModSetting.HeadX].BoxedValue, - (int)ms_entries[(int)ModSetting.HeadY].BoxedValue, - (int)ms_entries[(int)ModSetting.HeadZ].BoxedValue - ) * 0.01f; - TrackElbows = (bool)ms_entries[(int)ModSetting.TrackElbows].BoxedValue; - Interaction = (bool)ms_entries[(int)ModSetting.Interaction].BoxedValue; - Gestures = (bool)ms_entries[(int)ModSetting.Gestures].BoxedValue; - InteractThreadhold = (int)ms_entries[(int)ModSetting.InteractThreadhold].BoxedValue * 0.01f; - GripThreadhold = (int)ms_entries[(int)ModSetting.GripThreadhold].BoxedValue * 0.01f; - VisualHands = (bool)ms_entries[(int)ModSetting.VisualHands].BoxedValue; - } - - static void OnToggleUpdate(string p_name, string p_value) - { - if(Enum.TryParse(p_name, out ModSetting l_setting)) - { - switch(l_setting) - { - case ModSetting.Enabled: - { - Enabled = bool.Parse(p_value); - EnabledChange?.Invoke(Enabled); - } - break; - - case ModSetting.FingersOnly: - { - FingersOnly = bool.Parse(p_value); - FingersOnlyChange?.Invoke(FingersOnly); - } - break; - - case ModSetting.Model: - { - ModelVisibility = bool.Parse(p_value); - ModelVisibilityChange?.Invoke(ModelVisibility); - } - break; - - case ModSetting.Head: - { - HeadAttach = bool.Parse(p_value); - HeadAttachChange?.Invoke(HeadAttach); - } - break; - - case ModSetting.TrackElbows: - { - TrackElbows = bool.Parse(p_value); - TrackElbowsChange?.Invoke(TrackElbows); - } - break; - - case ModSetting.Interaction: - { - Interaction = bool.Parse(p_value); - InteractionChange?.Invoke(Interaction); - } - break; - - case ModSetting.Gestures: - { - Gestures = bool.Parse(p_value); - GesturesChange?.Invoke(Gestures); - } - break; - - case ModSetting.VisualHands: - { - VisualHands = bool.Parse(p_value); - VisualHandsChange?.Invoke(VisualHands); - } - break; - } - - ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); - } - } - - static void OnSliderUpdate(string p_name, string p_value) - { - if(Enum.TryParse(p_name, out ModSetting l_setting)) - { - switch(l_setting) - { - case ModSetting.DesktopX: - { - Vector3 l_current = DesktopOffset; - l_current.x = int.Parse(p_value) * 0.01f; - DesktopOffset = l_current; - DesktopOffsetChange?.Invoke(l_current); - } - break; - case ModSetting.DesktopY: - { - Vector3 l_current = DesktopOffset; - l_current.y = int.Parse(p_value) * 0.01f; - DesktopOffset = l_current; - DesktopOffsetChange?.Invoke(l_current); - } - break; - case ModSetting.DesktopZ: - { - Vector3 l_current = DesktopOffset; - l_current.z = int.Parse(p_value) * 0.01f; - DesktopOffset = l_current; - DesktopOffsetChange?.Invoke(l_current); - } - break; - - case ModSetting.AngleX: - { - Vector3 l_current = RootAngle; - l_current.x = int.Parse(p_value); - RootAngle = l_current; - RootAngleChange?.Invoke(l_current); - } - break; - - case ModSetting.AngleY: - { - Vector3 l_current = RootAngle; - l_current.y = int.Parse(p_value); - RootAngle = l_current; - RootAngleChange?.Invoke(l_current); - } - break; - - case ModSetting.AngleZ: - { - Vector3 l_current = RootAngle; - l_current.z = int.Parse(p_value); - RootAngle = l_current; - RootAngleChange?.Invoke(l_current); - } - break; - - case ModSetting.HeadX: - { - Vector3 l_current = HeadOffset; - l_current.x = int.Parse(p_value) * 0.01f; - HeadOffset = l_current; - HeadOffsetChange?.Invoke(l_current); - } - break; - case ModSetting.HeadY: - { - Vector3 l_current = HeadOffset; - l_current.y = int.Parse(p_value) * 0.01f; - HeadOffset = l_current; - HeadOffsetChange?.Invoke(l_current); - } - break; - case ModSetting.HeadZ: - { - Vector3 l_current = HeadOffset; - l_current.z = int.Parse(p_value) * 0.01f; - HeadOffset = l_current; - HeadOffsetChange?.Invoke(l_current); - } - break; - case ModSetting.InteractThreadhold: - { - InteractThreadhold = int.Parse(p_value) * 0.01f; - InteractThreadholdChange?.Invoke(InteractThreadhold); - } - break; - case ModSetting.GripThreadhold: - { - GripThreadhold = int.Parse(p_value) * 0.01f; - GripThreadholdChange?.Invoke(GripThreadhold); - } - break; - } - - ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); - } - } - - static void OnDropdownUpdate(string p_name, string p_value) - { - if(Enum.TryParse(p_name, out ModSetting l_setting)) - { - switch(l_setting) - { - case ModSetting.Mode: - { - TrackingMode = (LeapTrackingMode)int.Parse(p_value); - TrackingModeChange?.Invoke(TrackingMode); - } - break; - } - - ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); - } - } - } -} +using ABI_RC.Core.InteractionSystem; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace ml_lme +{ + static class Settings + { + public enum LeapTrackingMode + { + Screentop = 0, + Desktop, + HMD + } + + enum ModSetting + { + Enabled, + DesktopX, + DesktopY, + DesktopZ, + FingersOnly, + Model, + Mode, + AngleX, + AngleY, + AngleZ, + Head, + HeadX, + HeadY, + HeadZ, + TrackElbows, + Interaction, + Gestures, + InteractThreadhold, + GripThreadhold, + VisualHands + }; + + public static bool Enabled { get; private set; } = false; + public static Vector3 DesktopOffset { get; private set; } = new Vector3(0f, -0.45f, 0.3f); + public static bool FingersOnly { get; private set; } = false; + public static bool ModelVisibility { get; private set; } = false; + public static LeapTrackingMode TrackingMode { get; private set; } = LeapTrackingMode.Desktop; + public static Vector3 RootAngle { get; private set; } = Vector3.zero; + public static bool HeadAttach { get; private set; } = false; + public static Vector3 HeadOffset { get; private set; } = new Vector3(0f, -0.3f, 0.15f); + public static bool TrackElbows { get; private set; } = true; + public static bool Interaction { get; private set; } = true; + public static bool Gestures { get; private set; } = false; + public static float InteractThreadhold { get; private set; } = 0.8f; + public static float GripThreadhold { get; private set; } = 0.4f; + public static bool VisualHands { get; private set; } = false; + + static MelonLoader.MelonPreferences_Category ms_category = null; + static List ms_entries = null; + + static public event Action EnabledChange; + static public event Action DesktopOffsetChange; + static public event Action FingersOnlyChange; + static public event Action ModelVisibilityChange; + static public event Action TrackingModeChange; + static public event Action RootAngleChange; + static public event Action HeadAttachChange; + static public event Action HeadOffsetChange; + static public event Action TrackElbowsChange; + static public event Action InteractionChange; + static public event Action GesturesChange; + static public event Action InteractThreadholdChange; + static public event Action GripThreadholdChange; + static public event Action VisualHandsChange; + + internal static void Init() + { + ms_category = MelonLoader.MelonPreferences.CreateCategory("LME", null, true); + + ms_entries = new List() + { + ms_category.CreateEntry(ModSetting.Enabled.ToString(), Enabled), + ms_category.CreateEntry(ModSetting.DesktopX.ToString(), (int)(DesktopOffset.x * 100f)), + ms_category.CreateEntry(ModSetting.DesktopY.ToString(), (int)(DesktopOffset.y * 100f)), + ms_category.CreateEntry(ModSetting.DesktopZ.ToString(), (int)(DesktopOffset.z * 100f)), + ms_category.CreateEntry(ModSetting.FingersOnly.ToString(), FingersOnly), + ms_category.CreateEntry(ModSetting.Model.ToString(), ModelVisibility), + ms_category.CreateEntry(ModSetting.Mode.ToString(), (int)TrackingMode), + ms_category.CreateEntry(ModSetting.AngleX.ToString(), (int)(RootAngle.x * 100f)), + ms_category.CreateEntry(ModSetting.AngleY.ToString(), (int)(RootAngle.y * 100f)), + ms_category.CreateEntry(ModSetting.AngleZ.ToString(), (int)(RootAngle.z * 100f)), + ms_category.CreateEntry(ModSetting.Head.ToString(), HeadAttach), + ms_category.CreateEntry(ModSetting.HeadX.ToString(), (int)(HeadOffset.x * 100f)), + ms_category.CreateEntry(ModSetting.HeadY.ToString(), (int)(HeadOffset.y * 100f)), + ms_category.CreateEntry(ModSetting.HeadZ.ToString(), (int)(HeadOffset.z * 100f)), + ms_category.CreateEntry(ModSetting.TrackElbows.ToString(), TrackElbows), + ms_category.CreateEntry(ModSetting.Interaction.ToString(), Interaction), + ms_category.CreateEntry(ModSetting.Gestures.ToString(), Gestures), + ms_category.CreateEntry(ModSetting.InteractThreadhold.ToString(), (int)(InteractThreadhold * 100f)), + ms_category.CreateEntry(ModSetting.GripThreadhold.ToString(), (int)(GripThreadhold * 100f)), + ms_category.CreateEntry(ModSetting.VisualHands.ToString(), VisualHands) + }; + + Load(); + + MelonLoader.MelonCoroutines.Start(WaitMainMenuUi()); + } + + static System.Collections.IEnumerator WaitMainMenuUi() + { + while(ViewManager.Instance == null) + yield return null; + while(ViewManager.Instance.gameMenuView == null) + yield return null; + while(ViewManager.Instance.gameMenuView.Listener == null) + yield return null; + + 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)); + }; + ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) => + { + ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mods_extension.js")); + ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mod_menu.js")); + foreach(var l_entry in ms_entries) + ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString()); + }; + } + + static void Load() + { + Enabled = (bool)ms_entries[(int)ModSetting.Enabled].BoxedValue; + DesktopOffset = new Vector3( + (int)ms_entries[(int)ModSetting.DesktopX].BoxedValue, + (int)ms_entries[(int)ModSetting.DesktopY].BoxedValue, + (int)ms_entries[(int)ModSetting.DesktopZ].BoxedValue + ) * 0.01f; + FingersOnly = (bool)ms_entries[(int)ModSetting.FingersOnly].BoxedValue; + ModelVisibility = (bool)ms_entries[(int)ModSetting.Model].BoxedValue; + TrackingMode = (LeapTrackingMode)(int)ms_entries[(int)ModSetting.Mode].BoxedValue; + RootAngle = new Vector3( + (int)ms_entries[(int)ModSetting.AngleX].BoxedValue, + (int)ms_entries[(int)ModSetting.AngleY].BoxedValue, + (int)ms_entries[(int)ModSetting.AngleZ].BoxedValue + ); + HeadAttach = (bool)ms_entries[(int)ModSetting.Head].BoxedValue; + HeadOffset = new Vector3( + (int)ms_entries[(int)ModSetting.HeadX].BoxedValue, + (int)ms_entries[(int)ModSetting.HeadY].BoxedValue, + (int)ms_entries[(int)ModSetting.HeadZ].BoxedValue + ) * 0.01f; + TrackElbows = (bool)ms_entries[(int)ModSetting.TrackElbows].BoxedValue; + Interaction = (bool)ms_entries[(int)ModSetting.Interaction].BoxedValue; + Gestures = (bool)ms_entries[(int)ModSetting.Gestures].BoxedValue; + InteractThreadhold = (int)ms_entries[(int)ModSetting.InteractThreadhold].BoxedValue * 0.01f; + GripThreadhold = (int)ms_entries[(int)ModSetting.GripThreadhold].BoxedValue * 0.01f; + VisualHands = (bool)ms_entries[(int)ModSetting.VisualHands].BoxedValue; + } + + static void OnToggleUpdate(string p_name, string p_value) + { + if(Enum.TryParse(p_name, out ModSetting l_setting)) + { + switch(l_setting) + { + case ModSetting.Enabled: + { + Enabled = bool.Parse(p_value); + EnabledChange?.Invoke(Enabled); + } + break; + + case ModSetting.FingersOnly: + { + FingersOnly = bool.Parse(p_value); + FingersOnlyChange?.Invoke(FingersOnly); + } + break; + + case ModSetting.Model: + { + ModelVisibility = bool.Parse(p_value); + ModelVisibilityChange?.Invoke(ModelVisibility); + } + break; + + case ModSetting.Head: + { + HeadAttach = bool.Parse(p_value); + HeadAttachChange?.Invoke(HeadAttach); + } + break; + + case ModSetting.TrackElbows: + { + TrackElbows = bool.Parse(p_value); + TrackElbowsChange?.Invoke(TrackElbows); + } + break; + + case ModSetting.Interaction: + { + Interaction = bool.Parse(p_value); + InteractionChange?.Invoke(Interaction); + } + break; + + case ModSetting.Gestures: + { + Gestures = bool.Parse(p_value); + GesturesChange?.Invoke(Gestures); + } + break; + + case ModSetting.VisualHands: + { + VisualHands = bool.Parse(p_value); + VisualHandsChange?.Invoke(VisualHands); + } + break; + } + + ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); + } + } + + static void OnSliderUpdate(string p_name, string p_value) + { + if(Enum.TryParse(p_name, out ModSetting l_setting)) + { + switch(l_setting) + { + case ModSetting.DesktopX: + { + Vector3 l_current = DesktopOffset; + l_current.x = int.Parse(p_value) * 0.01f; + DesktopOffset = l_current; + DesktopOffsetChange?.Invoke(l_current); + } + break; + case ModSetting.DesktopY: + { + Vector3 l_current = DesktopOffset; + l_current.y = int.Parse(p_value) * 0.01f; + DesktopOffset = l_current; + DesktopOffsetChange?.Invoke(l_current); + } + break; + case ModSetting.DesktopZ: + { + Vector3 l_current = DesktopOffset; + l_current.z = int.Parse(p_value) * 0.01f; + DesktopOffset = l_current; + DesktopOffsetChange?.Invoke(l_current); + } + break; + + case ModSetting.AngleX: + { + Vector3 l_current = RootAngle; + l_current.x = int.Parse(p_value); + RootAngle = l_current; + RootAngleChange?.Invoke(l_current); + } + break; + + case ModSetting.AngleY: + { + Vector3 l_current = RootAngle; + l_current.y = int.Parse(p_value); + RootAngle = l_current; + RootAngleChange?.Invoke(l_current); + } + break; + + case ModSetting.AngleZ: + { + Vector3 l_current = RootAngle; + l_current.z = int.Parse(p_value); + RootAngle = l_current; + RootAngleChange?.Invoke(l_current); + } + break; + + case ModSetting.HeadX: + { + Vector3 l_current = HeadOffset; + l_current.x = int.Parse(p_value) * 0.01f; + HeadOffset = l_current; + HeadOffsetChange?.Invoke(l_current); + } + break; + case ModSetting.HeadY: + { + Vector3 l_current = HeadOffset; + l_current.y = int.Parse(p_value) * 0.01f; + HeadOffset = l_current; + HeadOffsetChange?.Invoke(l_current); + } + break; + case ModSetting.HeadZ: + { + Vector3 l_current = HeadOffset; + l_current.z = int.Parse(p_value) * 0.01f; + HeadOffset = l_current; + HeadOffsetChange?.Invoke(l_current); + } + break; + case ModSetting.InteractThreadhold: + { + InteractThreadhold = int.Parse(p_value) * 0.01f; + InteractThreadholdChange?.Invoke(InteractThreadhold); + } + break; + case ModSetting.GripThreadhold: + { + GripThreadhold = int.Parse(p_value) * 0.01f; + GripThreadholdChange?.Invoke(GripThreadhold); + } + break; + } + + ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); + } + } + + static void OnDropdownUpdate(string p_name, string p_value) + { + if(Enum.TryParse(p_name, out ModSetting l_setting)) + { + switch(l_setting) + { + case ModSetting.Mode: + { + TrackingMode = (LeapTrackingMode)int.Parse(p_value); + TrackingModeChange?.Invoke(TrackingMode); + } + break; + } + + ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); + } + } + } +} diff --git a/ml_lme/Utils.cs b/ml_lme/Utils.cs index a3888db..1cb14f3 100644 --- a/ml_lme/Utils.cs +++ b/ml_lme/Utils.cs @@ -1,6 +1,8 @@ -using ABI_RC.Core.Savior; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Savior; using ABI_RC.Core.UI; using ABI_RC.Systems.InputManagement; +using System.Collections.Generic; using System.Reflection; using UnityEngine; @@ -9,8 +11,10 @@ namespace ml_lme static class Utils { static readonly FieldInfo ms_view = typeof(CohtmlControlledViewWrapper).GetField("_view", BindingFlags.NonPublic | BindingFlags.Instance); + static readonly FieldInfo ms_vrActive = typeof(ControllerRay).GetField("vrActive", BindingFlags.NonPublic | BindingFlags.Instance); + static readonly FieldInfo ms_inputModules = typeof(CVRInputManager).GetField("_inputModules", BindingFlags.NonPublic | BindingFlags.Instance); - public static bool IsInVR() => ((CheckVR.Instance != null) && CheckVR.Instance.hasVrDeviceLoaded); + public static bool IsInVR() => ((MetaPort.Instance != null) && MetaPort.Instance.isUsingVr); public static bool AreKnucklesInUse() => ((CVRInputManager.Instance._leftController == ABI_RC.Systems.InputManagement.XR.eXRControllerType.Index) || (CVRInputManager.Instance._rightController == ABI_RC.Systems.InputManagement.XR.eXRControllerType.Index)); public static bool IsLeftHandTracked() => (CVRInputManager.Instance._leftController != ABI_RC.Systems.InputManagement.XR.eXRControllerType.None); public static bool IsRightHandTracked() => (CVRInputManager.Instance._rightController != ABI_RC.Systems.InputManagement.XR.eXRControllerType.None); @@ -31,6 +35,20 @@ namespace ml_lme } } + public static void SetVRActive(this ControllerRay p_instance, bool p_state) => ms_vrActive?.SetValue(p_instance, p_state); + + public static void SetModuleAsLast(this CVRInputManager p_instance, CVRInputModule p_module) + { + List l_modules = ms_inputModules.GetValue(p_instance) as List; + int l_lastIndex = l_modules.Count - 1; + int l_index = l_modules.FindIndex(p => p == p_module); + if((l_index != -1) && (l_index != l_lastIndex)) + { + l_modules[l_index] = l_modules[l_lastIndex]; + l_modules[l_lastIndex] = p_module; + } + } + static public void ExecuteScript(this CohtmlControlledViewWrapper p_instance, string p_script) => ((cohtml.Net.View)ms_view.GetValue(p_instance)).ExecuteScript(p_script); public static void Swap(ref T lhs, ref T rhs) diff --git a/ml_lme/VisualHand.cs b/ml_lme/VisualHand.cs deleted file mode 100644 index e9453f2..0000000 --- a/ml_lme/VisualHand.cs +++ /dev/null @@ -1,68 +0,0 @@ -using UnityEngine; - -namespace ml_lme -{ - class VisualHand - { - readonly Transform m_wrist = null; - readonly Transform[] m_fingers = null; - - public VisualHand(Transform p_root, bool p_left) - { - if(p_root != null) - { - m_wrist = p_root.Find(p_left ? "LeftHand/Wrist" : "RightHand/Wrist"); - if(m_wrist != null) - { - m_fingers = new Transform[20]; - - m_fingers[0] = null; // Actual thumb-meta, look at Leap Motion docs, dummy - m_fingers[1] = m_wrist.Find("thumb_meta"); - m_fingers[2] = m_wrist.Find("thumb_meta/thumb_a"); - m_fingers[3] = m_wrist.Find("thumb_meta/thumb_a/thumb_b"); - - m_fingers[4] = m_wrist.Find("index_meta"); - m_fingers[5] = m_wrist.Find("index_meta/index_a"); - m_fingers[6] = m_wrist.Find("index_meta/index_a/index_b"); - m_fingers[7] = m_wrist.Find("index_meta/index_a/index_b/index_c"); - - m_fingers[8] = m_wrist.Find("middle_meta"); - m_fingers[9] = m_wrist.Find("middle_meta/middle_a"); - m_fingers[10] = m_wrist.Find("middle_meta/middle_a/middle_b"); - m_fingers[11] = m_wrist.Find("middle_meta/middle_a/middle_b/middle_c"); - - m_fingers[12] = m_wrist.Find("ring_meta"); - m_fingers[13] = m_wrist.Find("ring_meta/ring_a"); - m_fingers[14] = m_wrist.Find("ring_meta/ring_a/ring_b"); - m_fingers[15] = m_wrist.Find("ring_meta/ring_a/ring_b/ring_c"); - - m_fingers[16] = m_wrist.Find("pinky_meta"); - m_fingers[17] = m_wrist.Find("pinky_meta/pinky_a"); - m_fingers[18] = m_wrist.Find("pinky_meta/pinky_a/pinky_b"); - m_fingers[19] = m_wrist.Find("pinky_meta/pinky_a/pinky_b/pinky_c"); - } - } - } - - public void Update(LeapParser.HandData p_data) - { - if(m_wrist != null) - { - m_wrist.position = p_data.m_position; - m_wrist.rotation = p_data.m_rotation; - - for(int i = 0; i < 20; i++) - { - if(m_fingers[i] != null) - { - //m_fingers[i].position = p_data.m_fingerPosition[i]; - m_fingers[i].rotation = p_data.m_fingerRotation[i]; - } - } - - m_wrist.localPosition = p_data.m_position; - m_wrist.localRotation = p_data.m_rotation; - } - } - } -} diff --git a/ml_lme/ml_lme.csproj b/ml_lme/ml_lme.csproj index 793413b..2d70ed7 100644 --- a/ml_lme/ml_lme.csproj +++ b/ml_lme/ml_lme.csproj @@ -4,15 +4,15 @@ netstandard2.1 x64 LeapMotionExtension - 1.4.5 + 1.4.6 SDraw None LeapMotionExtension - none - false + embedded + true diff --git a/ml_lme/resources/leapmotion_hands.asset b/ml_lme/resources/leapmotion_hands.asset index e7f9e7a..4fc9276 100644 Binary files a/ml_lme/resources/leapmotion_hands.asset and b/ml_lme/resources/leapmotion_hands.asset differ diff --git a/ml_lme/resources/mod_menu.js b/ml_lme/resources/mod_menu.js index 235c5b4..dadaee1 100644 --- a/ml_lme/resources/mod_menu.js +++ b/ml_lme/resources/mod_menu.js @@ -1,162 +1,162 @@ -{ - let l_block = document.createElement('div'); - l_block.innerHTML = ` -
-
Leap Motion tracking
-
-
- -
-
Enable tracking:
-
-
-
-
- -
-
Tracking mode:
-
-
-
-
- -
-
Desktop offset X:
-
-
-
-
- -
-
Desktop offset Y:
-
-
-
-
- -
-
Desktop offset Z:
-
-
-
-
- -
-
Attach to head:
-
- -
-
- -
-
Head offset X:
-
-
-
-
- -
-
Head offset Y:
-
-
-
-
- -
-
Head offset Z:
-
-
-
-
- -
-
Offset angle X:
-
-
-
-
- -
-
Offset angle Y:
-
-
-
-
- -
-
Offset angle Z:
-
-
-
-
- -
-
Track elbows:
-
-
-
-
- -
-
Fingers tracking only:
-
-
-
-
- -
-
Model visibility:
-
-
-
-
- -
-
Visualize hands:
-
-
-
-
- -
-
Interaction input:
-
-
-
-
- -
-
Recognize gestures:
-
-
-
-
- -
-
Interact gesture threadhold:
-
-
-
-
- -
-
Grip gesture threadhold:
-
-
-
-
- `; - document.getElementById('settings-implementation').appendChild(l_block); - - // Toggles - for (let l_toggle of l_block.querySelectorAll('.inp_toggle')) - modsExtension.addSetting('LME', l_toggle.id, modsExtension.createToggle(l_toggle, 'OnToggleUpdate_LME')); - - // Sliders - for (let l_slider of l_block.querySelectorAll('.inp_slider')) - modsExtension.addSetting('LME', l_slider.id, modsExtension.createSlider(l_slider, 'OnSliderUpdate_LME')); - - // Dropdowns - for (let l_dropdown of l_block.querySelectorAll('.inp_dropdown')) - modsExtension.addSetting('LME', l_dropdown.id, modsExtension.createDropdown(l_dropdown, 'OnDropdownUpdate_LME')); -} +{ + let l_block = document.createElement('div'); + l_block.innerHTML = ` +
+
Leap Motion tracking
+
+
+ +
+
Enable tracking:
+
+
+
+
+ +
+
Tracking mode:
+
+
+
+
+ +
+
Desktop offset X:
+
+
+
+
+ +
+
Desktop offset Y:
+
+
+
+
+ +
+
Desktop offset Z:
+
+
+
+
+ +
+
Attach to head:
+
+ +
+
+ +
+
Head offset X:
+
+
+
+
+ +
+
Head offset Y:
+
+
+
+
+ +
+
Head offset Z:
+
+
+
+
+ +
+
Offset angle X:
+
+
+
+
+ +
+
Offset angle Y:
+
+
+
+
+ +
+
Offset angle Z:
+
+
+
+
+ +
+
Track elbows:
+
+
+
+
+ +
+
Fingers tracking only:
+
+
+
+
+ +
+
Model visibility:
+
+
+
+
+ +
+
Visualize hands:
+
+
+
+
+ +
+
Interaction input:
+
+
+
+
+ +
+
Recognize gestures:
+
+
+
+
+ +
+
Interact gesture threadhold:
+
+
+
+
+ +
+
Grip gesture threadhold:
+
+
+
+
+ `; + document.getElementById('settings-implementation').appendChild(l_block); + + // Toggles + for (let l_toggle of l_block.querySelectorAll('.inp_toggle')) + modsExtension.addSetting('LME', l_toggle.id, modsExtension.createToggle(l_toggle, 'OnToggleUpdate_LME')); + + // Sliders + for (let l_slider of l_block.querySelectorAll('.inp_slider')) + modsExtension.addSetting('LME', l_slider.id, modsExtension.createSlider(l_slider, 'OnSliderUpdate_LME')); + + // Dropdowns + for (let l_dropdown of l_block.querySelectorAll('.inp_dropdown')) + modsExtension.addSetting('LME', l_dropdown.id, modsExtension.createDropdown(l_dropdown, 'OnDropdownUpdate_LME')); +} diff --git a/ml_lme/vendor/LeapCSharp/Arm.cs b/ml_lme/vendor/LeapCSharp/Arm.cs index 03ff19f..7f89f59 100644 --- a/ml_lme/vendor/LeapCSharp/Arm.cs +++ b/ml_lme/vendor/LeapCSharp/Arm.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/Bone.cs b/ml_lme/vendor/LeapCSharp/Bone.cs index dfee543..2922bf5 100644 --- a/ml_lme/vendor/LeapCSharp/Bone.cs +++ b/ml_lme/vendor/LeapCSharp/Bone.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/CSharpExtensions.cs b/ml_lme/vendor/LeapCSharp/CSharpExtensions.cs index c229bc6..d2f1efc 100644 --- a/ml_lme/vendor/LeapCSharp/CSharpExtensions.cs +++ b/ml_lme/vendor/LeapCSharp/CSharpExtensions.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/CircularObjectBuffer.cs b/ml_lme/vendor/LeapCSharp/CircularObjectBuffer.cs index 173d65d..1949b05 100644 --- a/ml_lme/vendor/LeapCSharp/CircularObjectBuffer.cs +++ b/ml_lme/vendor/LeapCSharp/CircularObjectBuffer.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/Config.cs b/ml_lme/vendor/LeapCSharp/Config.cs index 1042050..7981ef8 100644 --- a/ml_lme/vendor/LeapCSharp/Config.cs +++ b/ml_lme/vendor/LeapCSharp/Config.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/Connection.cs b/ml_lme/vendor/LeapCSharp/Connection.cs index 8395348..871165e 100644 --- a/ml_lme/vendor/LeapCSharp/Connection.cs +++ b/ml_lme/vendor/LeapCSharp/Connection.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/Controller.cs b/ml_lme/vendor/LeapCSharp/Controller.cs index 33a8578..801794b 100644 --- a/ml_lme/vendor/LeapCSharp/Controller.cs +++ b/ml_lme/vendor/LeapCSharp/Controller.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/CopyFromLeapCExtensions.cs b/ml_lme/vendor/LeapCSharp/CopyFromLeapCExtensions.cs index a398f2c..19ed17c 100644 --- a/ml_lme/vendor/LeapCSharp/CopyFromLeapCExtensions.cs +++ b/ml_lme/vendor/LeapCSharp/CopyFromLeapCExtensions.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/CopyFromOtherExtensions.cs b/ml_lme/vendor/LeapCSharp/CopyFromOtherExtensions.cs index ca91ea9..a1eed49 100644 --- a/ml_lme/vendor/LeapCSharp/CopyFromOtherExtensions.cs +++ b/ml_lme/vendor/LeapCSharp/CopyFromOtherExtensions.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/Device.cs b/ml_lme/vendor/LeapCSharp/Device.cs index 753fab6..1ec4285 100644 --- a/ml_lme/vendor/LeapCSharp/Device.cs +++ b/ml_lme/vendor/LeapCSharp/Device.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/DeviceList.cs b/ml_lme/vendor/LeapCSharp/DeviceList.cs index 69bf84d..40e95b6 100644 --- a/ml_lme/vendor/LeapCSharp/DeviceList.cs +++ b/ml_lme/vendor/LeapCSharp/DeviceList.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/DistortionData.cs b/ml_lme/vendor/LeapCSharp/DistortionData.cs index 99630ec..9ccd98a 100644 --- a/ml_lme/vendor/LeapCSharp/DistortionData.cs +++ b/ml_lme/vendor/LeapCSharp/DistortionData.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/Events.cs b/ml_lme/vendor/LeapCSharp/Events.cs index c4df171..c7b12d3 100644 --- a/ml_lme/vendor/LeapCSharp/Events.cs +++ b/ml_lme/vendor/LeapCSharp/Events.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/FailedDevice.cs b/ml_lme/vendor/LeapCSharp/FailedDevice.cs index 020794e..cde7380 100644 --- a/ml_lme/vendor/LeapCSharp/FailedDevice.cs +++ b/ml_lme/vendor/LeapCSharp/FailedDevice.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/FailedDeviceList.cs b/ml_lme/vendor/LeapCSharp/FailedDeviceList.cs index 1562dae..306f4d4 100644 --- a/ml_lme/vendor/LeapCSharp/FailedDeviceList.cs +++ b/ml_lme/vendor/LeapCSharp/FailedDeviceList.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/Finger.cs b/ml_lme/vendor/LeapCSharp/Finger.cs index 2f46fa4..ccdad62 100644 --- a/ml_lme/vendor/LeapCSharp/Finger.cs +++ b/ml_lme/vendor/LeapCSharp/Finger.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/Frame.cs b/ml_lme/vendor/LeapCSharp/Frame.cs index dd1513b..65f751f 100644 --- a/ml_lme/vendor/LeapCSharp/Frame.cs +++ b/ml_lme/vendor/LeapCSharp/Frame.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/Hand.cs b/ml_lme/vendor/LeapCSharp/Hand.cs index 16cee65..e7c036d 100644 --- a/ml_lme/vendor/LeapCSharp/Hand.cs +++ b/ml_lme/vendor/LeapCSharp/Hand.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/IController.cs b/ml_lme/vendor/LeapCSharp/IController.cs index 95c8990..19167bf 100644 --- a/ml_lme/vendor/LeapCSharp/IController.cs +++ b/ml_lme/vendor/LeapCSharp/IController.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/Image.cs b/ml_lme/vendor/LeapCSharp/Image.cs index f10f215..73f033f 100644 --- a/ml_lme/vendor/LeapCSharp/Image.cs +++ b/ml_lme/vendor/LeapCSharp/Image.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/ImageData.cs b/ml_lme/vendor/LeapCSharp/ImageData.cs index f258317..1182e90 100644 --- a/ml_lme/vendor/LeapCSharp/ImageData.cs +++ b/ml_lme/vendor/LeapCSharp/ImageData.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/LeapC.cs b/ml_lme/vendor/LeapCSharp/LeapC.cs index 1295577..e13f95d 100644 --- a/ml_lme/vendor/LeapCSharp/LeapC.cs +++ b/ml_lme/vendor/LeapCSharp/LeapC.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/LeapTransform.cs b/ml_lme/vendor/LeapCSharp/LeapTransform.cs index 9ccfcfa..1c308a4 100644 --- a/ml_lme/vendor/LeapCSharp/LeapTransform.cs +++ b/ml_lme/vendor/LeapCSharp/LeapTransform.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/Logger.cs b/ml_lme/vendor/LeapCSharp/Logger.cs index 720a013..1bf97a2 100644 --- a/ml_lme/vendor/LeapCSharp/Logger.cs +++ b/ml_lme/vendor/LeapCSharp/Logger.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/MemoryManager.cs b/ml_lme/vendor/LeapCSharp/MemoryManager.cs index d490dbb..3c47710 100644 --- a/ml_lme/vendor/LeapCSharp/MemoryManager.cs +++ b/ml_lme/vendor/LeapCSharp/MemoryManager.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/MessageSeverity.cs b/ml_lme/vendor/LeapCSharp/MessageSeverity.cs index 75e135a..daa4081 100644 --- a/ml_lme/vendor/LeapCSharp/MessageSeverity.cs +++ b/ml_lme/vendor/LeapCSharp/MessageSeverity.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/PointMapping.cs b/ml_lme/vendor/LeapCSharp/PointMapping.cs index 63cae94..e62d137 100644 --- a/ml_lme/vendor/LeapCSharp/PointMapping.cs +++ b/ml_lme/vendor/LeapCSharp/PointMapping.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/StructMarshal.cs b/ml_lme/vendor/LeapCSharp/StructMarshal.cs index b1458d7..a1baafd 100644 --- a/ml_lme/vendor/LeapCSharp/StructMarshal.cs +++ b/ml_lme/vendor/LeapCSharp/StructMarshal.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_lme/vendor/LeapCSharp/TransformExtensions.cs b/ml_lme/vendor/LeapCSharp/TransformExtensions.cs index 49575dc..90d97c9 100644 --- a/ml_lme/vendor/LeapCSharp/TransformExtensions.cs +++ b/ml_lme/vendor/LeapCSharp/TransformExtensions.cs @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) Ultraleap, Inc. 2011-2023. * + * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * diff --git a/ml_pam/ArmMover.cs b/ml_pam/ArmMover.cs index 9431725..7aa119c 100644 --- a/ml_pam/ArmMover.cs +++ b/ml_pam/ArmMover.cs @@ -83,13 +83,7 @@ namespace ml_pam void OnDestroy() { - if(m_armIKLeft != null) - Destroy(m_armIKLeft); - m_armIKLeft = null; - - if(m_armIKRight != null) - Destroy(m_armIKRight); - m_armIKRight = null; + RemoveArmIK(); if(m_rootLeft != null) Destroy(m_rootLeft); @@ -331,26 +325,15 @@ namespace ml_pam internal void OnAvatarSetup() { - // Recheck if user could switch to VR - if(m_inVR != Utils.IsInVR()) - { - m_rootLeft.parent = PlayerSetup.Instance.GetActiveCamera().transform; - m_rootLeft.localPosition = Vector3.zero; - m_rootLeft.localRotation = Quaternion.identity; - - m_rootRight.parent = PlayerSetup.Instance.GetActiveCamera().transform; - m_rootRight.localPosition = Vector3.zero; - m_rootRight.localRotation = Quaternion.identity; - } m_inVR = Utils.IsInVR(); + m_vrIK = PlayerSetup.Instance._animator.GetComponent(); - if(!m_inVR && PlayerSetup.Instance._animator.isHuman) + ReparentRoots(); + + if(PlayerSetup.Instance._animator.isHuman) { - m_vrIK = PlayerSetup.Instance._animator.GetComponent(); - - TPoseHelper l_tpHelper = new TPoseHelper(); - l_tpHelper.Assign(PlayerSetup.Instance._animator); - l_tpHelper.Apply(); + if(!m_inVR) + PoseHelper.ForceTPose(PlayerSetup.Instance._animator); Transform l_leftHand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand); if(l_leftHand != null) @@ -359,64 +342,41 @@ namespace ml_pam if(l_rightHand != null) m_rightTarget.localRotation = ms_offsetRight * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_rightHand.GetMatrix()).rotation; - if(m_vrIK == null) - { - Transform l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.UpperChest); - if(l_chest == null) - l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Chest); - if(l_chest == null) - l_chest = PlayerSetup.Instance._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), - l_leftHand, - PlayerSetup.Instance._animator.transform - ); - m_armIKLeft.solver.arm.target = m_leftTarget; - 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), - l_rightHand, - PlayerSetup.Instance._animator.transform - ); - m_armIKRight.solver.arm.target = m_rightTarget; - m_armIKRight.solver.arm.positionWeight = 1f; - m_armIKRight.solver.arm.rotationWeight = 1f; - m_armIKRight.solver.IKPositionWeight = 0f; - m_armIKRight.solver.IKRotationWeight = 0f; - m_armIKRight.enabled = false; - } - else + if(m_vrIK != null) { m_armLength = m_vrIK.solver.leftArm.mag * 1.25f; - m_vrIK.solver.OnPreUpdate += this.OnIKPreUpdate; - m_vrIK.solver.OnPostUpdate += this.OnIKPostUpdate; + m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreUpdate); + m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate); } - - l_tpHelper.Restore(); - l_tpHelper.Unassign(); + else if(!m_inVR) + SetupArmIK(); } SetEnabled(m_enabled); } + internal void OnAvatarReinitialize() + { + // Old VRIK is destroyed by game + m_inVR = Utils.IsInVR(); + m_vrIK = PlayerSetup.Instance._animator.GetComponent(); + + ReparentRoots(); + + if(m_inVR) + RemoveArmIK(); + + if(m_vrIK != null) + { + m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreUpdate); + m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate); + } + else if(!m_inVR) + SetupArmIK(); + + SetEnabled(m_enabled); + } + internal void OnPickupGrab(CVRPickupObject p_pickup, ControllerRay p_ray, Vector3 p_hit) { if(p_ray == ViewManager.Instance.desktopControllerRay) @@ -488,6 +448,62 @@ namespace ml_pam } // Arbitrary + void SetupArmIK() + { + Transform l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.UpperChest); + if(l_chest == null) + l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Chest); + if(l_chest == null) + l_chest = PlayerSetup.Instance._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 + ); + m_armIKLeft.solver.arm.target = m_leftTarget; + 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 + ); + m_armIKRight.solver.arm.target = m_rightTarget; + m_armIKRight.solver.arm.positionWeight = 1f; + m_armIKRight.solver.arm.rotationWeight = 1f; + m_armIKRight.solver.IKPositionWeight = 0f; + m_armIKRight.solver.IKRotationWeight = 0f; + m_armIKRight.enabled = false; + } + + void RemoveArmIK() + { + if(m_armIKLeft != null) + Object.Destroy(m_armIKLeft); + m_armIKLeft = null; + + if(m_armIKRight != null) + Object.Destroy(m_armIKRight); + m_armIKRight = null; + } + void SetArmActive(Settings.LeadHand p_hand, bool p_state, bool p_forced = false) { if(m_enabled || p_forced) @@ -506,5 +522,16 @@ namespace ml_pam } } } + + void ReparentRoots() + { + m_rootLeft.parent = PlayerSetup.Instance.GetActiveCamera().transform; + m_rootLeft.localPosition = Vector3.zero; + m_rootLeft.localRotation = Quaternion.identity; + + m_rootRight.parent = PlayerSetup.Instance.GetActiveCamera().transform; + m_rootRight.localPosition = Vector3.zero; + m_rootRight.localRotation = Quaternion.identity; + } } } diff --git a/ml_pam/Main.cs b/ml_pam/Main.cs index 9ad1bc5..b6e17a9 100644 --- a/ml_pam/Main.cs +++ b/ml_pam/Main.cs @@ -1,6 +1,7 @@ using ABI.CCK.Components; using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.Player; +using ABI_RC.Systems.IK; using System; using System.Reflection; using UnityEngine; @@ -30,6 +31,11 @@ namespace ml_pam null, new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); + HarmonyInstance.Patch( + typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public), + null, + new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + ); HarmonyInstance.Patch( typeof(CVRPickupObject).GetMethod(nameof(CVRPickupObject.Grab)), null, @@ -95,6 +101,20 @@ namespace ml_pam } } + static void OnAvatarReinitialize_Postfix() => ms_instance?.OnAvatarReinitialize(); + void OnAvatarReinitialize() + { + try + { + if(m_localMover != null) + m_localMover.OnAvatarReinitialize(); + } + catch(System.Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } + static void OnCVRPickupObjectGrab_Postfix(ref CVRPickupObject __instance, ControllerRay __1, Vector3 __2) => ms_instance?.OnCVRPickupObjectGrab(__instance, __1, __2); void OnCVRPickupObjectGrab(CVRPickupObject p_pickup, ControllerRay p_ray, Vector3 p_hit) { diff --git a/ml_pam/PoseHelper.cs b/ml_pam/PoseHelper.cs new file mode 100644 index 0000000..ecf871f --- /dev/null +++ b/ml_pam/PoseHelper.cs @@ -0,0 +1,26 @@ +using UnityEngine; +using ABI_RC.Systems.IK; + +namespace ml_pam +{ + static class PoseHelper + { + public static void ForceTPose(Animator p_animator) + { + if(p_animator.isHuman) + { + HumanPoseHandler l_handler = new HumanPoseHandler(p_animator.avatar, p_animator.transform); + HumanPose l_pose = new HumanPose(); + l_handler.GetHumanPose(ref l_pose); + + for(int i = 0, j = Mathf.Min(l_pose.muscles.Length, MusclePoses.TPoseMuscles.Length); i < j; i++) + l_pose.muscles[i] = MusclePoses.TPoseMuscles[i]; + + l_pose.bodyPosition = Vector3.up; + l_pose.bodyRotation = Quaternion.identity; + l_handler.SetHumanPose(ref l_pose); + l_handler.Dispose(); + } + } + } +} diff --git a/ml_pam/Properties/AssemblyInfo.cs b/ml_pam/Properties/AssemblyInfo.cs index ebe5a6f..9bd9a57 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.0.9", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_pam.PickupArmMovement), "PickupArmMovement", "1.1.0-ex", "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/TPoseHelper.cs b/ml_pam/TPoseHelper.cs deleted file mode 100644 index 49e9e6f..0000000 --- a/ml_pam/TPoseHelper.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.Reflection; -using UnityEngine; -using ABI_RC.Systems.IK.SubSystems; - -namespace ml_pam -{ - class TPoseHelper - { - static readonly float[] ms_tposeMuscles = typeof(BodySystem).GetField("TPoseMuscles", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null) as float[]; - - HumanPoseHandler m_poseHandler = null; - HumanPose m_oldPose; - HumanPose m_newPose; - Vector3 m_hipsLocalPos = Vector3.zero; - Transform m_hips = null; - - public void Assign(Animator p_animator) - { - if(m_poseHandler != null) - { - m_poseHandler = new HumanPoseHandler(p_animator.avatar, p_animator.transform); - m_hips = p_animator.GetBoneTransform(HumanBodyBones.Hips); - } - } - - public void Unassign() - { - m_poseHandler?.Dispose(); - m_poseHandler = null; - m_oldPose = new HumanPose(); - m_newPose = new HumanPose(); - m_hips = null; - m_hipsLocalPos = Vector3.zero; - } - - public void Apply() - { - if(m_hips != null) - m_hipsLocalPos = m_hips.localPosition; - - if(m_poseHandler != null) - { - m_poseHandler.GetHumanPose(ref m_oldPose); - m_newPose.bodyPosition = m_oldPose.bodyPosition; - m_newPose.bodyRotation = m_oldPose.bodyRotation; - m_newPose.muscles = new float[m_oldPose.muscles.Length]; - for(int i = 0, j = m_newPose.muscles.Length; i < j; i++) - m_newPose.muscles[i] = ms_tposeMuscles[i]; - - m_poseHandler.SetHumanPose(ref m_newPose); - } - } - - public void Restore() - { - if(m_poseHandler != null) - m_poseHandler.SetHumanPose(ref m_oldPose); - - if(m_hips != null) - m_hips.localPosition = m_hipsLocalPos; - } - } -} diff --git a/ml_pam/Utils.cs b/ml_pam/Utils.cs index d8d76c4..ec4513b 100644 --- a/ml_pam/Utils.cs +++ b/ml_pam/Utils.cs @@ -1,4 +1,5 @@ -using ABI_RC.Core.UI; +using ABI_RC.Core.Savior; +using ABI_RC.Core.UI; using System.Reflection; using UnityEngine; @@ -8,7 +9,7 @@ namespace ml_pam { static readonly FieldInfo ms_view = typeof(CohtmlControlledViewWrapper).GetField("_view", BindingFlags.NonPublic | BindingFlags.Instance); - public static bool IsInVR() => ((ABI_RC.Core.Savior.CheckVR.Instance != null) && ABI_RC.Core.Savior.CheckVR.Instance.hasVrDeviceLoaded); + public static bool IsInVR() => ((MetaPort.Instance != null) && MetaPort.Instance.isUsingVr); static public void ExecuteScript(this CohtmlControlledViewWrapper p_instance, string p_script) => ((cohtml.Net.View)ms_view.GetValue(p_instance)).ExecuteScript(p_script); diff --git a/ml_pam/ml_pam.csproj b/ml_pam/ml_pam.csproj index 901ce8b..37228e9 100644 --- a/ml_pam/ml_pam.csproj +++ b/ml_pam/ml_pam.csproj @@ -4,7 +4,7 @@ netstandard2.1 x64 PickupArmMovement - 1.0.9 + 1.1.0 SDraw None PickupArmMovement diff --git a/ml_pin/Main.cs b/ml_pin/Main.cs index f89d611..59f5c03 100644 --- a/ml_pin/Main.cs +++ b/ml_pin/Main.cs @@ -41,25 +41,28 @@ namespace ml_pin { try { - bool l_isFriend = Friends.FriendsWith(p_player.ownerId); - bool l_notify = false; - - switch(Settings.NotifyType) + if(p_player != null) // This happens sometimes, no idea why { - case Settings.NotificationType.None: - l_notify = false; - break; - case Settings.NotificationType.Friends: - l_notify = (l_isFriend && ShouldNotifyInCurrentInstance()); - break; - case Settings.NotificationType.All: - l_notify = ShouldNotifyInCurrentInstance(); - break; - } - l_notify |= (l_isFriend && Settings.FriendsAlways); + bool l_isFriend = Friends.FriendsWith(p_player.ownerId); + bool l_notify = false; - if(l_notify) - m_soundManager?.PlaySound(l_isFriend ? SoundManager.SoundType.FriendJoin : SoundManager.SoundType.PlayerJoin); + switch(Settings.NotifyType) + { + case Settings.NotificationType.None: + l_notify = false; + break; + case Settings.NotificationType.Friends: + l_notify = (l_isFriend && ShouldNotifyInCurrentInstance()); + break; + case Settings.NotificationType.All: + l_notify = ShouldNotifyInCurrentInstance(); + break; + } + l_notify |= (l_isFriend && Settings.FriendsAlways); + + if(l_notify) + m_soundManager?.PlaySound(l_isFriend ? SoundManager.SoundType.FriendJoin : SoundManager.SoundType.PlayerJoin); + } } catch(Exception e) { @@ -70,25 +73,28 @@ namespace ml_pin { try { - bool l_isFriend = Friends.FriendsWith(p_player.ownerId); - bool l_notify = false; - - switch(Settings.NotifyType) + if(p_player != null) // This happens sometimes, no idea why { - case Settings.NotificationType.None: - l_notify = false; - break; - case Settings.NotificationType.Friends: - l_notify = (l_isFriend && ShouldNotifyInCurrentInstance()); - break; - case Settings.NotificationType.All: - l_notify = ShouldNotifyInCurrentInstance(); - break; - } - l_notify |= (l_isFriend && Settings.FriendsAlways); + bool l_isFriend = Friends.FriendsWith(p_player.ownerId); + bool l_notify = false; - if(l_notify) - m_soundManager?.PlaySound(l_isFriend ? SoundManager.SoundType.FriendLeave : SoundManager.SoundType.PlayerLeave); + switch(Settings.NotifyType) + { + case Settings.NotificationType.None: + l_notify = false; + break; + case Settings.NotificationType.Friends: + l_notify = (l_isFriend && ShouldNotifyInCurrentInstance()); + break; + case Settings.NotificationType.All: + l_notify = ShouldNotifyInCurrentInstance(); + break; + } + l_notify |= (l_isFriend && Settings.FriendsAlways); + + if(l_notify) + m_soundManager?.PlaySound(l_isFriend ? SoundManager.SoundType.FriendLeave : SoundManager.SoundType.PlayerLeave); + } } catch(Exception e) { diff --git a/ml_pin/Properties/AssemblyInfo.cs b/ml_pin/Properties/AssemblyInfo.cs index 99b7e2a..67b4925 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.1", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_pin.PlayersInstanceNotifier), "PlayersInstanceNotifier", "1.0.2-ex", "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/ml_pin.csproj b/ml_pin/ml_pin.csproj index 150b487..9228213 100644 --- a/ml_pin/ml_pin.csproj +++ b/ml_pin/ml_pin.csproj @@ -7,7 +7,7 @@ SDraw None PlayersInstanceNotifier - 1.0.1 + 1.0.2 diff --git a/ml_pmc/Main.cs b/ml_pmc/Main.cs index d660e2c..0274988 100644 --- a/ml_pmc/Main.cs +++ b/ml_pmc/Main.cs @@ -1,137 +1,171 @@ -using ABI_RC.Core.Networking.IO.Social; -using ABI_RC.Core.Player; -using ABI_RC.Systems.MovementSystem; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using UnityEngine; - -namespace ml_pmc -{ - public class PlayerMovementCopycat : MelonLoader.MelonMod - { - static PlayerMovementCopycat ms_instance = null; - - PoseCopycat m_localCopycat = null; - - public override void OnInitializeMelon() - { - if(ms_instance == null) - ms_instance = this; - - Settings.Init(); - ModUi.Init(); - - HarmonyInstance.Patch( - typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)), - null, - new HarmonyLib.HarmonyMethod(typeof(PlayerMovementCopycat).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.NonPublic | BindingFlags.Static)) - ); - HarmonyInstance.Patch( - typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)), - null, - new HarmonyLib.HarmonyMethod(typeof(PlayerMovementCopycat).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) - ); - - MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); - } - - public override void OnDeinitializeMelon() - { - if(ms_instance == this) - ms_instance = null; - - ModUi.CopySwitch -= this.OnTargetSelect; - - if(m_localCopycat != null) - UnityEngine.Object.Destroy(m_localCopycat); - m_localCopycat = null; - } - - System.Collections.IEnumerator WaitForLocalPlayer() - { - while(PlayerSetup.Instance == null) - yield return null; - - m_localCopycat = PlayerSetup.Instance.gameObject.AddComponent(); - ModUi.CopySwitch += this.OnTargetSelect; - } - - void OnTargetSelect(string p_id) - { - if(m_localCopycat != null) - { - if(m_localCopycat.IsActive()) - m_localCopycat.SetTarget(null); - else - { - if(Friends.FriendsWith(p_id)) - { - if(CVRPlayerManager.Instance.GetPlayerPuppetMaster(p_id, out PuppetMaster l_puppetMaster)) - { - if(IsInSight(MovementSystem.Instance.proxyCollider, l_puppetMaster.GetComponent(), Utils.GetWorldMovementLimit())) - m_localCopycat.SetTarget(l_puppetMaster); - else - ModUi.ShowAlert("Selected player is too far away or obstructed"); - } - else - ModUi.ShowAlert("Selected player isn't connected or ready yet"); - } - else - ModUi.ShowAlert("Selected player isn't your friend"); - } - } - } - - static bool IsInSight(CapsuleCollider p_source, CapsuleCollider p_target, float p_limit) - { - bool l_result = false; - if((p_source != null) && (p_target != null)) - { - Ray l_ray = new Ray(); - l_ray.origin = p_source.bounds.center; - l_ray.direction = p_target.bounds.center - l_ray.origin; - List l_hits = Physics.RaycastAll(l_ray, p_limit).ToList(); - if(l_hits.Count > 0) - { - l_hits.RemoveAll(hit => hit.collider.gameObject.layer == LayerMask.NameToLayer("UI Internal")); // Somehow layer mask in RaycastAll just ignores players entirely - l_hits.RemoveAll(hit => hit.collider.gameObject.layer == LayerMask.NameToLayer("PlayerLocal")); - l_hits.RemoveAll(hit => hit.collider.gameObject.layer == LayerMask.NameToLayer("PlayerClone")); - l_hits.Sort((a, b) => ((a.distance < b.distance) ? -1 : 1)); - l_result = (l_hits.First().collider.gameObject.transform.root == p_target.transform.root); - } - } - return l_result; - } - - // Patches - static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear(); - void OnAvatarClear() - { - try - { - if(m_localCopycat != null) - m_localCopycat.OnAvatarClear(); - } - catch(Exception e) - { - MelonLoader.MelonLogger.Error(e); - } - } - - static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar(); - void OnSetupAvatar() - { - try - { - if(m_localCopycat != null) - m_localCopycat.OnAvatarSetup(); - } - catch(Exception e) - { - MelonLoader.MelonLogger.Error(e); - } - } - } -} +using ABI_RC.Core.Networking.IO.Social; +using ABI_RC.Core.Player; +using ABI_RC.Systems.IK; +using ABI_RC.Systems.Movement; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEngine; + +namespace ml_pmc +{ + public class PlayerMovementCopycat : MelonLoader.MelonMod + { + static PlayerMovementCopycat ms_instance = null; + + PoseCopycat m_localCopycat = null; + + public override void OnInitializeMelon() + { + if(ms_instance == null) + ms_instance = this; + + Settings.Init(); + ModUi.Init(); + + HarmonyInstance.Patch( + typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)), + null, + new HarmonyLib.HarmonyMethod(typeof(PlayerMovementCopycat).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.NonPublic | BindingFlags.Static)) + ); + HarmonyInstance.Patch( + typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)), + null, + new HarmonyLib.HarmonyMethod(typeof(PlayerMovementCopycat).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + ); + HarmonyInstance.Patch( + typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public), + new HarmonyLib.HarmonyMethod(typeof(PlayerMovementCopycat).GetMethod(nameof(OnAvatarReinitialize_Prefix), BindingFlags.Static | BindingFlags.NonPublic)), + new HarmonyLib.HarmonyMethod(typeof(PlayerMovementCopycat).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + ); + + MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); + } + + public override void OnDeinitializeMelon() + { + if(ms_instance == this) + ms_instance = null; + + ModUi.CopySwitch -= this.OnTargetSelect; + + if(m_localCopycat != null) + UnityEngine.Object.Destroy(m_localCopycat); + m_localCopycat = null; + } + + System.Collections.IEnumerator WaitForLocalPlayer() + { + while(PlayerSetup.Instance == null) + yield return null; + + m_localCopycat = PlayerSetup.Instance.gameObject.AddComponent(); + ModUi.CopySwitch += this.OnTargetSelect; + } + + void OnTargetSelect(string p_id) + { + if(m_localCopycat != null) + { + if(m_localCopycat.IsActive()) + m_localCopycat.SetTarget(null); + else + { + if(Friends.FriendsWith(p_id)) + { + if(CVRPlayerManager.Instance.GetPlayerPuppetMaster(p_id, out PuppetMaster l_puppetMaster)) + { + if(IsInSight(BetterBetterCharacterController.Instance.KinematicTriggerProxy.Collider, l_puppetMaster.GetComponent(), Utils.GetWorldMovementLimit())) + m_localCopycat.SetTarget(l_puppetMaster); + else + ModUi.ShowAlert("Selected player is too far away or obstructed"); + } + else + ModUi.ShowAlert("Selected player isn't connected or ready yet"); + } + else + ModUi.ShowAlert("Selected player isn't your friend"); + } + } + } + + static bool IsInSight(CapsuleCollider p_source, CapsuleCollider p_target, float p_limit) + { + bool l_result = false; + if((p_source != null) && (p_target != null)) + { + Ray l_ray = new Ray(); + l_ray.origin = p_source.bounds.center; + l_ray.direction = p_target.bounds.center - l_ray.origin; + List l_hits = Physics.RaycastAll(l_ray, p_limit).ToList(); + if(l_hits.Count > 0) + { + l_hits.RemoveAll(hit => hit.collider.gameObject.layer == LayerMask.NameToLayer("UI Internal")); // Somehow layer mask in RaycastAll just ignores players entirely + l_hits.RemoveAll(hit => hit.collider.gameObject.layer == LayerMask.NameToLayer("PlayerLocal")); + l_hits.RemoveAll(hit => hit.collider.gameObject.layer == LayerMask.NameToLayer("PlayerClone")); + l_hits.Sort((a, b) => ((a.distance < b.distance) ? -1 : 1)); + l_result = (l_hits.First().collider.gameObject.transform.root == p_target.transform.root); + } + } + return l_result; + } + + // Patches + static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear(); + void OnAvatarClear() + { + try + { + if(m_localCopycat != null) + m_localCopycat.OnAvatarClear(); + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } + + static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar(); + void OnSetupAvatar() + { + try + { + if(m_localCopycat != null) + m_localCopycat.OnAvatarSetup(); + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } + + static void OnAvatarReinitialize_Prefix() => ms_instance?.OnPreAvatarReinitialize(); + void OnPreAvatarReinitialize() + { + try + { + if(m_localCopycat != null) + m_localCopycat.OnPreAvatarReinitialize(); + } + catch(System.Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } + + static void OnAvatarReinitialize_Postfix() => ms_instance?.OnPostAvatarReinitialize(); + void OnPostAvatarReinitialize() + { + try + { + if(m_localCopycat != null) + m_localCopycat.OnPostAvatarReinitialize(); + } + catch(System.Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } + } +} diff --git a/ml_pmc/PoseCopycat.cs b/ml_pmc/PoseCopycat.cs index 16a4ece..3ccfeaa 100644 --- a/ml_pmc/PoseCopycat.cs +++ b/ml_pmc/PoseCopycat.cs @@ -1,342 +1,440 @@ -using ABI_RC.Core.Player; -using ABI_RC.Systems.IK; -using ABI_RC.Systems.IK.SubSystems; -using ABI_RC.Systems.InputManagement; -using ABI_RC.Systems.MovementSystem; -using RootMotion.FinalIK; -using UnityEngine; - -namespace ml_pmc -{ - [DisallowMultipleComponent] - public class PoseCopycat : MonoBehaviour - { - static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f); - - static public PoseCopycat Instance { get; private set; } = null; - static internal System.Action OnActivityChange; - - Animator m_animator = null; - VRIK m_vrIk = null; - float m_ikWeight = 1f; - LookAtIK m_lookAtIk = null; - float m_lookIkWeight = 1f; - bool m_sitting = false; - bool m_inVr = false; - - bool m_active = false; - float m_distanceLimit = float.MaxValue; - bool m_fingerTracking = false; - - HumanPoseHandler m_poseHandler = null; - HumanPose m_pose; - PuppetParser m_puppetParser = null; - - void Start() - { - if(Instance == null) - Instance = this; - } - void OnDestroy() - { - if(Instance == this) - Instance = null; - - m_poseHandler?.Dispose(); - m_poseHandler = null; - - if(m_puppetParser != null) - Object.Destroy(m_puppetParser); - m_puppetParser = null; - - m_animator = null; - m_vrIk = null; - m_lookAtIk = null; - } - - // Unity events - void Update() - { - m_sitting = (MovementSystem.Instance.lastSeat != null); - - if(m_active) - { - if(m_puppetParser != null) - { - OverrideIK(); - - bool l_mirror = Settings.MirrorPose; - - if(Settings.Gestures) - { - CVRInputManager.Instance.gestureLeft = (l_mirror ? m_puppetParser.GetRightGesture() : m_puppetParser.GetLeftGesture()); - CVRInputManager.Instance.gestureRight = (l_mirror ? m_puppetParser.GetLeftGesture() : m_puppetParser.GetRightGesture()); - } - - if(m_puppetParser.HasFingerTracking()) - { - m_fingerTracking = true; - - CVRInputManager.Instance.individualFingerTracking = true; - IKSystem.Instance.FingerSystem.controlActive = true; - - ref readonly float[] l_curls = ref m_puppetParser.GetFingerCurls(); - ref readonly float[] l_spreads = ref m_puppetParser.GetFingerSpreads(); - - CVRInputManager.Instance.fingerCurlLeftThumb = l_curls[l_mirror ? 5 : 0]; - CVRInputManager.Instance.fingerCurlLeftIndex = l_curls[l_mirror ? 6 : 1]; - CVRInputManager.Instance.fingerCurlLeftMiddle = l_curls[l_mirror ? 7 : 2]; - CVRInputManager.Instance.fingerCurlLeftRing = l_curls[l_mirror ? 8 : 3]; - CVRInputManager.Instance.fingerCurlLeftPinky = l_curls[l_mirror ? 9 : 4]; - CVRInputManager.Instance.fingerCurlRightThumb = l_curls[l_mirror ? 0 : 5]; - CVRInputManager.Instance.fingerCurlRightIndex = l_curls[l_mirror ? 1 : 6]; - CVRInputManager.Instance.fingerCurlRightMiddle = l_curls[l_mirror ? 2 : 7]; - CVRInputManager.Instance.fingerCurlRightRing = l_curls[l_mirror ? 3 : 8]; - CVRInputManager.Instance.fingerCurlRightPinky = l_curls[l_mirror ? 4 : 9]; - - CVRInputManager.Instance.fingerSpreadLeftThumb = l_spreads[l_mirror ? 5 : 0]; - CVRInputManager.Instance.fingerSpreadLeftIndex = l_spreads[l_mirror ? 6 : 1]; - CVRInputManager.Instance.fingerSpreadLeftMiddle = l_spreads[l_mirror ? 7 : 2]; - CVRInputManager.Instance.fingerSpreadLeftRing = l_spreads[l_mirror ? 8 : 3]; - CVRInputManager.Instance.fingerSpreadLeftPinky = l_spreads[l_mirror ? 9 : 4]; - CVRInputManager.Instance.fingerSpreadRightThumb = l_spreads[l_mirror ? 0 : 5]; - CVRInputManager.Instance.fingerSpreadRightIndex = l_spreads[l_mirror ? 1 : 6]; - CVRInputManager.Instance.fingerSpreadRightMiddle = l_spreads[l_mirror ? 2 : 7]; - CVRInputManager.Instance.fingerSpreadRightRing = l_spreads[l_mirror ? 3 : 8]; - CVRInputManager.Instance.fingerSpreadRightPinky = l_spreads[l_mirror ? 4 : 9]; - } - else - { - if(m_fingerTracking) - { - RestoreFingerTracking(); - m_fingerTracking = false; - } - } - - Matrix4x4 l_offset = m_puppetParser.GetLastOffset(); - Vector3 l_pos = l_offset * ms_pointVector; - Quaternion l_rot = l_offset.rotation; - - l_pos.y = 0f; - if(Settings.MirrorPosition) - l_pos.x *= -1f; - l_pos = Vector3.ClampMagnitude(l_pos, m_distanceLimit); - - l_rot = Quaternion.Euler(0f, l_rot.eulerAngles.y * (Settings.MirrorRotation ? -1f : 1f), 0f); - - Matrix4x4 l_result = PlayerSetup.Instance.transform.GetMatrix() * Matrix4x4.TRS(l_pos, l_rot, Vector3.one); - - if(Settings.Position && !m_sitting && !m_puppetParser.IsSitting() && Utils.IsWorldSafe() && Utils.IsCombatSafe()) - PlayerSetup.Instance.transform.position = l_result * ms_pointVector; - - if(Settings.Rotation && !m_sitting && !m_puppetParser.IsSitting() && Utils.IsCombatSafe()) - { - if(m_inVr) - { - Vector3 l_avatarPos = PlayerSetup.Instance._avatar.transform.position; - PlayerSetup.Instance.transform.rotation = l_result.rotation; - Vector3 l_dif = l_avatarPos - PlayerSetup.Instance._avatar.transform.position; - PlayerSetup.Instance.transform.position += l_dif; - } - else - PlayerSetup.Instance.transform.rotation = l_result.rotation; - } - - if(Vector3.Distance(this.transform.position, m_puppetParser.transform.position) > m_distanceLimit) - SetTarget(null); - } - else - SetTarget(null); - } - } - - void LateUpdate() - { - if(m_active && (m_animator != null) && (m_puppetParser != null)) - { - OverrideIK(); - - m_puppetParser.GetPose().CopyTo(ref m_pose); - - if(Settings.MirrorPose) - Utils.MirrorPose(ref m_pose); - - m_poseHandler.SetHumanPose(ref m_pose); - } - } - - // Patches - internal void OnAvatarClear() - { - if(m_active) - { - RestoreIK(); - RestoreFingerTracking(); - OnActivityChange?.Invoke(false); - } - m_active = false; - - m_inVr = Utils.IsInVR(); - - if(m_puppetParser != null) - Object.Destroy(m_puppetParser); - m_puppetParser = null; - - m_animator = null; - m_vrIk = null; - m_lookAtIk = null; - - m_poseHandler?.Dispose(); - m_poseHandler = null; - - m_distanceLimit = float.MaxValue; - m_fingerTracking = false; - m_pose = new HumanPose(); - } - internal void OnAvatarSetup() - { - m_animator = PlayerSetup.Instance._animator; - m_vrIk = PlayerSetup.Instance._avatar.GetComponent(); - m_lookAtIk = PlayerSetup.Instance._avatar.GetComponent(); - - if((m_animator != null) && m_animator.isHuman) - { - m_poseHandler = new HumanPoseHandler(m_animator.avatar, m_animator.transform); - m_poseHandler.GetHumanPose(ref m_pose); - - if(m_vrIk != null) - { - m_vrIk.onPreSolverUpdate.AddListener(this.OnVRIKPreUpdate); - m_vrIk.onPostSolverUpdate.AddListener(this.OnVRIKPostUpdate); - } - - if(m_lookAtIk != null) - { - m_lookAtIk.onPreSolverUpdate.AddListener(this.OnLookAtIKPreUpdate); - m_lookAtIk.onPostSolverUpdate.AddListener(this.OnLookAtIKPostUpdate); - } - } - else - m_animator = null; - } - - // IK updates - void OnVRIKPreUpdate() - { - if(m_active) - { - m_ikWeight = m_vrIk.solver.IKPositionWeight; - m_vrIk.solver.IKPositionWeight = 0f; - } - } - void OnVRIKPostUpdate() - { - if(m_active) - m_vrIk.solver.IKPositionWeight = m_ikWeight; - } - - void OnLookAtIKPreUpdate() - { - if(m_active && !Settings.LookAtMix) - { - m_lookIkWeight = m_lookAtIk.solver.IKPositionWeight; - m_lookAtIk.solver.IKPositionWeight = 0f; - } - } - void OnLookAtIKPostUpdate() - { - if(m_active && !Settings.LookAtMix) - m_lookAtIk.solver.IKPositionWeight = m_lookIkWeight; - } - - // Arbitrary - public void SetTarget(PuppetMaster p_target) - { - if(m_animator != null) - { - if(!m_active) - { - if((p_target != null) && (p_target.animatorManager != null) && (p_target.animatorManager.animator != null) && p_target.animatorManager.animator.isHuman) - { - m_puppetParser = p_target.animatorManager.animator.gameObject.AddComponent(); - m_puppetParser.m_puppetMaster = p_target; - m_distanceLimit = Utils.GetWorldMovementLimit(); - - m_active = true; - OnActivityChange?.Invoke(m_active); - } - } - else - { - if(p_target == null) - { - if(m_puppetParser != null) - Object.Destroy(m_puppetParser); - m_puppetParser = null; - - if(!m_sitting) - { - Quaternion l_rot = PlayerSetup.Instance.transform.rotation; - PlayerSetup.Instance.transform.rotation = Quaternion.Euler(0f, l_rot.eulerAngles.y, 0f); - } - - RestoreIK(); - RestoreFingerTracking(); - m_fingerTracking = false; - - m_active = false; - OnActivityChange?.Invoke(m_active); - } - } - } - } - - public bool IsActive() => m_active; - public bool IsFingerTrackingActive() => m_fingerTracking; - - void OverrideIK() - { - if(!BodySystem.isCalibrating) - BodySystem.TrackingPositionWeight = 0f; - } - void RestoreIK() - { - if(!BodySystem.isCalibrating) - BodySystem.TrackingPositionWeight = 1f; - - if(m_vrIk != null) - m_vrIk.solver.Reset(); - } - void RestoreFingerTracking() - { - CVRInputManager.Instance.individualFingerTracking = (m_inVr && Utils.AreKnucklesInUse() && !CVRInputManager._moduleXR.GestureToggleValue); - IKSystem.Instance.FingerSystem.controlActive = CVRInputManager.Instance.individualFingerTracking; - - if(!CVRInputManager.Instance.individualFingerTracking) - { - CVRInputManager.Instance.fingerCurlLeftThumb = 0f; - CVRInputManager.Instance.fingerCurlLeftIndex = 0f; - CVRInputManager.Instance.fingerCurlLeftMiddle = 0f; - CVRInputManager.Instance.fingerCurlLeftRing = 0f; - CVRInputManager.Instance.fingerCurlLeftPinky = 0f; - CVRInputManager.Instance.fingerCurlRightThumb = 0f; - CVRInputManager.Instance.fingerCurlRightIndex = 0f; - CVRInputManager.Instance.fingerCurlRightMiddle = 0f; - CVRInputManager.Instance.fingerCurlRightRing = 0f; - CVRInputManager.Instance.fingerCurlRightPinky = 0f; - - CVRInputManager.Instance.fingerSpreadLeftThumb = 0.5f; - CVRInputManager.Instance.fingerSpreadLeftIndex = 0.5f; - CVRInputManager.Instance.fingerSpreadLeftMiddle = 0.5f; - CVRInputManager.Instance.fingerSpreadLeftRing = 0.5f; - CVRInputManager.Instance.fingerSpreadLeftPinky = 0.5f; - CVRInputManager.Instance.fingerSpreadRightThumb = 0.5f; - CVRInputManager.Instance.fingerSpreadRightIndex = 0.5f; - CVRInputManager.Instance.fingerSpreadRightMiddle = 0.5f; - CVRInputManager.Instance.fingerSpreadRightRing = 0.5f; - CVRInputManager.Instance.fingerSpreadRightPinky = 0.5f; - } - } - } -} +using ABI_RC.Core.Player; +using ABI_RC.Systems.IK; +using ABI_RC.Systems.IK.SubSystems; +using ABI_RC.Systems.InputManagement; +using ABI_RC.Systems.Movement; +using ABI_RC.Systems.VRModeSwitch; +using RootMotion.FinalIK; +using UnityEngine; + +namespace ml_pmc +{ + [DisallowMultipleComponent] + public class PoseCopycat : MonoBehaviour + { + static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f); + + static public PoseCopycat Instance { get; private set; } = null; + static internal System.Action OnActivityChange; + + Animator m_animator = null; + VRIK m_vrIk = null; + float m_ikWeight = 1f; + LookAtIK m_lookAtIk = null; + float m_lookIkWeight = 1f; + bool m_sitting = false; + bool m_inVr = false; + + bool m_active = false; + float m_distanceLimit = float.MaxValue; + bool m_fingerTracking = false; + + HumanPoseHandler m_poseHandler = null; + HumanPose m_pose; + PuppetParser m_puppetParser = null; + + void Start() + { + if(Instance == null) + Instance = this; + } + void OnDestroy() + { + if(Instance == this) + Instance = null; + + m_poseHandler?.Dispose(); + m_poseHandler = null; + + if(m_puppetParser != null) + Object.Destroy(m_puppetParser); + m_puppetParser = null; + + m_animator = null; + m_vrIk = null; + m_lookAtIk = null; + } + + // Unity events + void Update() + { + m_sitting = BetterBetterCharacterController.Instance.IsSitting(); + + if(m_active) + { + if(m_puppetParser != null) + { + OverrideIK(); + + bool l_mirror = Settings.MirrorPose; + + if(Settings.Gestures) + { + CVRInputManager.Instance.gestureLeft = (l_mirror ? m_puppetParser.GetRightGesture() : m_puppetParser.GetLeftGesture()); + CVRInputManager.Instance.gestureRight = (l_mirror ? m_puppetParser.GetLeftGesture() : m_puppetParser.GetRightGesture()); + } + + if(m_puppetParser.HasFingerTracking()) + { + m_fingerTracking = true; + + CVRInputManager.Instance.individualFingerTracking = true; + IKSystem.Instance.FingerSystem.controlActive = true; + + ref readonly float[] l_curls = ref m_puppetParser.GetFingerCurls(); + ref readonly float[] l_spreads = ref m_puppetParser.GetFingerSpreads(); + + // Left hand + CVRInputManager.Instance.finger1StretchedLeftThumb = l_curls[l_mirror ? 15 : 0]; + CVRInputManager.Instance.finger2StretchedLeftThumb = l_curls[l_mirror ? 16 : 1]; + CVRInputManager.Instance.finger3StretchedLeftThumb = l_curls[l_mirror ? 17 : 2]; + CVRInputManager.Instance.fingerSpreadLeftThumb = l_spreads[l_mirror ? 5 : 0]; + + CVRInputManager.Instance.finger1StretchedLeftIndex = l_curls[l_mirror ? 18 : 3]; + CVRInputManager.Instance.finger2StretchedLeftIndex = l_curls[l_mirror ? 19 : 4]; + CVRInputManager.Instance.finger3StretchedLeftIndex = l_curls[l_mirror ? 20 : 5]; + CVRInputManager.Instance.fingerSpreadLeftIndex = l_spreads[l_mirror ? 6 : 1]; + + CVRInputManager.Instance.finger1StretchedLeftMiddle = l_curls[l_mirror ? 21 : 6]; + CVRInputManager.Instance.finger2StretchedLeftMiddle = l_curls[l_mirror ? 22 : 7]; + CVRInputManager.Instance.finger3StretchedLeftMiddle = l_curls[l_mirror ? 23 : 8]; + CVRInputManager.Instance.fingerSpreadLeftMiddle = l_spreads[l_mirror ? 7 : 2]; + + CVRInputManager.Instance.finger1StretchedLeftRing = l_curls[l_mirror ? 24 : 9]; + CVRInputManager.Instance.finger2StretchedLeftRing = l_curls[l_mirror ? 25 : 10]; + CVRInputManager.Instance.finger3StretchedLeftRing = l_curls[l_mirror ? 26 : 11]; + CVRInputManager.Instance.fingerSpreadLeftRing = l_spreads[l_mirror ? 8 : 3]; + + CVRInputManager.Instance.finger1StretchedLeftPinky = l_curls[l_mirror ? 27 : 12]; + CVRInputManager.Instance.finger2StretchedLeftPinky = l_curls[l_mirror ? 28 : 13]; + CVRInputManager.Instance.finger3StretchedLeftPinky = l_curls[l_mirror ? 29 : 14]; + CVRInputManager.Instance.fingerSpreadLeftPinky = l_spreads[l_mirror ? 9 : 4]; + + // Right hand + CVRInputManager.Instance.finger1StretchedRightThumb = l_curls[l_mirror ? 0 : 15]; + CVRInputManager.Instance.finger2StretchedRightThumb = l_curls[l_mirror ? 1 : 16]; + CVRInputManager.Instance.finger3StretchedRightThumb = l_curls[l_mirror ? 2 : 17]; + CVRInputManager.Instance.fingerSpreadRightThumb = l_spreads[l_mirror ? 0 : 5]; + + CVRInputManager.Instance.finger1StretchedRightIndex = l_curls[l_mirror ? 3 : 18]; + CVRInputManager.Instance.finger2StretchedRightIndex = l_curls[l_mirror ? 4 : 19]; + CVRInputManager.Instance.finger3StretchedRightIndex = l_curls[l_mirror ? 5 : 20]; + CVRInputManager.Instance.fingerSpreadRightIndex = l_spreads[l_mirror ? 1 : 6]; + + CVRInputManager.Instance.finger1StretchedRightMiddle = l_curls[l_mirror ? 6 : 21]; + CVRInputManager.Instance.finger2StretchedRightMiddle = l_curls[l_mirror ? 7 : 22]; + CVRInputManager.Instance.finger3StretchedRightMiddle = l_curls[l_mirror ? 8 : 23]; + CVRInputManager.Instance.fingerSpreadRightMiddle = l_spreads[l_mirror ? 2 : 7]; + + CVRInputManager.Instance.finger1StretchedRightRing = l_curls[l_mirror ? 9 : 24]; + CVRInputManager.Instance.finger2StretchedRightRing = l_curls[l_mirror ? 10 : 25]; + CVRInputManager.Instance.finger3StretchedRightRing = l_curls[l_mirror ? 11 : 26]; + CVRInputManager.Instance.fingerSpreadRightRing = l_spreads[l_mirror ? 3 : 8]; + + CVRInputManager.Instance.finger1StretchedRightPinky = l_curls[l_mirror ? 12 : 27]; + CVRInputManager.Instance.finger2StretchedRightPinky = l_curls[l_mirror ? 13 : 28]; + CVRInputManager.Instance.finger3StretchedRightPinky = l_curls[l_mirror ? 14 : 29]; + CVRInputManager.Instance.fingerSpreadRightPinky = l_spreads[l_mirror ? 4 : 9]; + } + else + { + if(m_fingerTracking) + { + RestoreFingerTracking(); + m_fingerTracking = false; + } + } + + Matrix4x4 l_offset = m_puppetParser.GetLastOffset(); + Vector3 l_pos = l_offset * ms_pointVector; + Quaternion l_rot = l_offset.rotation; + + l_pos.y = 0f; + if(Settings.MirrorPosition) + l_pos.x *= -1f; + l_pos = Vector3.ClampMagnitude(l_pos, m_distanceLimit); + + l_rot = Quaternion.Euler(0f, l_rot.eulerAngles.y * (Settings.MirrorRotation ? -1f : 1f), 0f); + + Matrix4x4 l_result = PlayerSetup.Instance.transform.GetMatrix() * Matrix4x4.TRS(l_pos, l_rot, Vector3.one); + + if(Settings.Position && !m_sitting && !m_puppetParser.IsSitting() && Utils.IsWorldSafe() && Utils.IsCombatSafe()) + PlayerSetup.Instance.transform.position = l_result * ms_pointVector; + + if(Settings.Rotation && !m_sitting && !m_puppetParser.IsSitting() && Utils.IsCombatSafe()) + { + if(m_inVr) + { + Vector3 l_avatarPos = PlayerSetup.Instance._avatar.transform.position; + PlayerSetup.Instance.transform.rotation = l_result.rotation; + Vector3 l_dif = l_avatarPos - PlayerSetup.Instance._avatar.transform.position; + PlayerSetup.Instance.transform.position += l_dif; + } + else + PlayerSetup.Instance.transform.rotation = l_result.rotation; + } + + if(Vector3.Distance(this.transform.position, m_puppetParser.transform.position) > m_distanceLimit) + SetTarget(null); + } + else + SetTarget(null); + } + } + + void LateUpdate() + { + if(m_active && (m_animator != null) && (m_puppetParser != null)) + { + OverrideIK(); + + m_puppetParser.GetPose().CopyTo(ref m_pose); + + if(Settings.MirrorPose) + Utils.MirrorPose(ref m_pose); + + m_poseHandler.SetHumanPose(ref m_pose); + } + } + + // Patches + internal void OnAvatarClear() + { + if(m_active) + { + RestoreIK(); + RestoreFingerTracking(); + OnActivityChange?.Invoke(false); + } + m_active = false; + + if(m_puppetParser != null) + Object.Destroy(m_puppetParser); + m_puppetParser = null; + + m_animator = null; + m_vrIk = null; + m_lookAtIk = null; + + m_poseHandler?.Dispose(); + m_poseHandler = null; + + m_distanceLimit = float.MaxValue; + m_fingerTracking = false; + m_pose = new HumanPose(); + } + internal void OnAvatarSetup() + { + m_inVr = Utils.IsInVR(); + m_animator = PlayerSetup.Instance._animator; + m_vrIk = PlayerSetup.Instance._avatar.GetComponent(); + m_lookAtIk = PlayerSetup.Instance._avatar.GetComponent(); + + if((m_animator != null) && m_animator.isHuman) + { + m_poseHandler = new HumanPoseHandler(m_animator.avatar, m_animator.transform); + m_poseHandler.GetHumanPose(ref m_pose); + + if(m_vrIk != null) + { + m_vrIk.onPreSolverUpdate.AddListener(this.OnVRIKPreUpdate); + m_vrIk.onPostSolverUpdate.AddListener(this.OnVRIKPostUpdate); + } + + if(m_lookAtIk != null) + { + m_lookAtIk.onPreSolverUpdate.AddListener(this.OnLookAtIKPreUpdate); + m_lookAtIk.onPostSolverUpdate.AddListener(this.OnLookAtIKPostUpdate); + } + } + else + m_animator = null; + } + + internal void OnPreAvatarReinitialize() + { + if(m_active) + SetTarget(null); + } + internal void OnPostAvatarReinitialize() + { + m_inVr = Utils.IsInVR(); + + // Old VRIK and LookAtIK are destroyed by game + m_vrIk = PlayerSetup.Instance._avatar.GetComponent(); + m_lookAtIk = PlayerSetup.Instance._avatar.GetComponent(); + + if(m_vrIk != null) + { + m_vrIk.onPreSolverUpdate.AddListener(this.OnVRIKPreUpdate); + m_vrIk.onPostSolverUpdate.AddListener(this.OnVRIKPostUpdate); + } + + if(m_lookAtIk != null) + { + m_lookAtIk.onPreSolverUpdate.AddListener(this.OnLookAtIKPreUpdate); + m_lookAtIk.onPostSolverUpdate.AddListener(this.OnLookAtIKPostUpdate); + } + } + + // IK updates + void OnVRIKPreUpdate() + { + if(m_active) + { + m_ikWeight = m_vrIk.solver.IKPositionWeight; + m_vrIk.solver.IKPositionWeight = 0f; + } + } + void OnVRIKPostUpdate() + { + if(m_active) + m_vrIk.solver.IKPositionWeight = m_ikWeight; + } + + void OnLookAtIKPreUpdate() + { + if(m_active && !Settings.LookAtMix) + { + m_lookIkWeight = m_lookAtIk.solver.IKPositionWeight; + m_lookAtIk.solver.IKPositionWeight = 0f; + } + } + void OnLookAtIKPostUpdate() + { + if(m_active && !Settings.LookAtMix) + m_lookAtIk.solver.IKPositionWeight = m_lookIkWeight; + } + + // Arbitrary + public void SetTarget(PuppetMaster p_target) + { + if(m_animator != null) + { + if(!m_active) + { + if((p_target != null) && (p_target.animatorManager != null) && (p_target.animatorManager.animator != null) && p_target.animatorManager.animator.isHuman) + { + m_puppetParser = p_target.animatorManager.animator.gameObject.AddComponent(); + m_puppetParser.m_puppetMaster = p_target; + m_distanceLimit = Utils.GetWorldMovementLimit(); + + m_active = true; + OnActivityChange?.Invoke(m_active); + } + } + else + { + if(p_target == null) + { + if(m_puppetParser != null) + Object.Destroy(m_puppetParser); + m_puppetParser = null; + + if(!m_sitting) + { + Quaternion l_rot = PlayerSetup.Instance.transform.rotation; + PlayerSetup.Instance.transform.rotation = Quaternion.Euler(0f, l_rot.eulerAngles.y, 0f); + } + + RestoreIK(); + RestoreFingerTracking(); + m_fingerTracking = false; + + m_active = false; + OnActivityChange?.Invoke(m_active); + } + } + } + } + + public bool IsActive() => m_active; + public bool IsFingerTrackingActive() => m_fingerTracking; + + void OverrideIK() + { + if(!BodySystem.isCalibrating) + BodySystem.TrackingPositionWeight = 0f; + } + void RestoreIK() + { + if(!BodySystem.isCalibrating) + BodySystem.TrackingPositionWeight = 1f; + + if(m_vrIk != null) + m_vrIk.solver.Reset(); + } + void RestoreFingerTracking() + { + CVRInputManager.Instance.individualFingerTracking = (m_inVr && Utils.AreKnucklesInUse() && !CVRInputManager._moduleXR.GestureToggleValue); + IKSystem.Instance.FingerSystem.controlActive = CVRInputManager.Instance.individualFingerTracking; + + if(!CVRInputManager.Instance.individualFingerTracking) + { + // Left hand + CVRInputManager.Instance.finger1StretchedLeftThumb = -0.5f; + CVRInputManager.Instance.finger2StretchedLeftThumb = 0.7f; + CVRInputManager.Instance.finger3StretchedLeftThumb = 0.7f; + CVRInputManager.Instance.fingerSpreadLeftThumb = 0f; + + CVRInputManager.Instance.finger1StretchedLeftIndex = 0.5f; + CVRInputManager.Instance.finger2StretchedLeftIndex = 0.7f; + CVRInputManager.Instance.finger3StretchedLeftIndex = 0.7f; + CVRInputManager.Instance.fingerSpreadLeftIndex = 0f; + + CVRInputManager.Instance.finger1StretchedLeftMiddle = 0.5f; + CVRInputManager.Instance.finger2StretchedLeftMiddle = 0.7f; + CVRInputManager.Instance.finger3StretchedLeftMiddle = 0.7f; + CVRInputManager.Instance.fingerSpreadLeftMiddle = 0f; + + CVRInputManager.Instance.finger1StretchedLeftRing = 0.5f; + CVRInputManager.Instance.finger2StretchedLeftRing = 0.7f; + CVRInputManager.Instance.finger3StretchedLeftRing = 0.7f; + CVRInputManager.Instance.fingerSpreadLeftRing = 0f; + + CVRInputManager.Instance.finger1StretchedLeftPinky = 0.5f; + CVRInputManager.Instance.finger2StretchedLeftPinky = 0.7f; + CVRInputManager.Instance.finger3StretchedLeftPinky = 0.7f; + CVRInputManager.Instance.fingerSpreadLeftPinky = 0f; + + CVRInputManager.Instance.fingerFullCurlNormalizedLeftThumb = 0f; + CVRInputManager.Instance.fingerFullCurlNormalizedLeftIndex = 0f; + CVRInputManager.Instance.fingerFullCurlNormalizedLeftMiddle = 0f; + CVRInputManager.Instance.fingerFullCurlNormalizedLeftRing = 0f; + CVRInputManager.Instance.fingerFullCurlNormalizedLeftPinky = 0f; + + // Right hand + CVRInputManager.Instance.finger1StretchedRightThumb = -0.5f; + CVRInputManager.Instance.finger2StretchedRightThumb = 0.7f; + CVRInputManager.Instance.finger3StretchedRightThumb = 0.7f; + CVRInputManager.Instance.fingerSpreadRightThumb = 0f; + + CVRInputManager.Instance.finger1StretchedRightIndex = 0.5f; + CVRInputManager.Instance.finger2StretchedRightIndex = 0.7f; + CVRInputManager.Instance.finger3StretchedRightIndex = 0.7f; + CVRInputManager.Instance.fingerSpreadRightIndex = 0f; + + CVRInputManager.Instance.finger1StretchedRightMiddle = 0.5f; + CVRInputManager.Instance.finger2StretchedRightMiddle = 0.7f; + CVRInputManager.Instance.finger3StretchedRightMiddle = 0.7f; + CVRInputManager.Instance.fingerSpreadRightMiddle = 0f; + + CVRInputManager.Instance.finger1StretchedRightRing = 0.5f; + CVRInputManager.Instance.finger2StretchedRightRing = 0.7f; + CVRInputManager.Instance.finger3StretchedRightRing = 0.7f; + CVRInputManager.Instance.fingerSpreadRightRing = 0f; + + CVRInputManager.Instance.finger1StretchedRightPinky = 0.5f; + CVRInputManager.Instance.finger2StretchedRightPinky = 0.7f; + CVRInputManager.Instance.finger3StretchedRightPinky = 0.7f; + CVRInputManager.Instance.fingerSpreadRightPinky = 0f; + + CVRInputManager.Instance.fingerFullCurlNormalizedRightThumb = 0f; + CVRInputManager.Instance.fingerFullCurlNormalizedRightIndex = 0f; + CVRInputManager.Instance.fingerFullCurlNormalizedRightMiddle = 0f; + CVRInputManager.Instance.fingerFullCurlNormalizedRightRing = 0f; + CVRInputManager.Instance.fingerFullCurlNormalizedRightPinky = 0f; + } + } + } +} diff --git a/ml_pmc/Properties/AssemblyInfo.cs b/ml_pmc/Properties/AssemblyInfo.cs index d97b88d..518b369 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.4", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_pmc.PlayerMovementCopycat), "PlayerMovementCopycat", "1.0.5-ex", "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/PuppetParser.cs b/ml_pmc/PuppetParser.cs index fece340..046a798 100644 --- a/ml_pmc/PuppetParser.cs +++ b/ml_pmc/PuppetParser.cs @@ -1,108 +1,136 @@ -using ABI_RC.Core.Player; -using UnityEngine; - -namespace ml_pmc -{ - [DisallowMultipleComponent] - class PuppetParser : MonoBehaviour - { - internal PuppetMaster m_puppetMaster = null; - Animator m_animator = null; - AnimatorCullingMode m_cullMode; - - HumanPoseHandler m_poseHandler = null; - HumanPose m_pose; - - Matrix4x4 m_matrix = Matrix4x4.identity; - Matrix4x4 m_offset = Matrix4x4.identity; - - bool m_sitting = false; - float m_leftGesture = 0f; - float m_rightGesture = 0f; - bool m_fingerTracking = false; - readonly float[] m_fingerCurls = null; - readonly float[] m_fingerSpreads = null; - - internal PuppetParser() - { - m_fingerCurls = new float[10]; - m_fingerSpreads = new float[10]; - } - - // Unity events - void Start() - { - m_animator = this.GetComponent(); - m_cullMode = m_animator.cullingMode; - m_animator.cullingMode = AnimatorCullingMode.AlwaysAnimate; - m_poseHandler = new HumanPoseHandler(m_animator.avatar, m_animator.transform); - m_poseHandler.GetHumanPose(ref m_pose); - m_matrix = this.transform.GetMatrix(); - } - - void OnDestroy() - { - m_puppetMaster = null; - if(m_animator != null) - m_animator.cullingMode = m_cullMode; - m_animator = null; - - m_poseHandler?.Dispose(); - m_poseHandler = null; - } - - void Update() - { - if(m_puppetMaster != null) - { - m_sitting = m_puppetMaster.PlayerAvatarMovementDataInput.AnimatorSitting; - m_leftGesture = m_puppetMaster.PlayerAvatarMovementDataInput.AnimatorGestureLeft; - m_rightGesture = m_puppetMaster.PlayerAvatarMovementDataInput.AnimatorGestureRight; - m_fingerTracking = m_puppetMaster.PlayerAvatarMovementDataInput.IndexUseIndividualFingers; - if(m_fingerTracking) - { - m_fingerCurls[0] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftThumbCurl; - m_fingerCurls[1] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftIndexCurl; - m_fingerCurls[2] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftMiddleCurl; - m_fingerCurls[3] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftRingCurl; - m_fingerCurls[4] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftPinkyCurl; - m_fingerCurls[5] = m_puppetMaster.PlayerAvatarMovementDataInput.RightThumbCurl; - m_fingerCurls[6] = m_puppetMaster.PlayerAvatarMovementDataInput.RightIndexCurl; - m_fingerCurls[7] = m_puppetMaster.PlayerAvatarMovementDataInput.RightMiddleCurl; - m_fingerCurls[8] = m_puppetMaster.PlayerAvatarMovementDataInput.RightRingCurl; - m_fingerCurls[9] = m_puppetMaster.PlayerAvatarMovementDataInput.RightPinkyCurl; - - m_fingerSpreads[0] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftThumbSpread; - m_fingerSpreads[1] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftIndexSpread; - m_fingerSpreads[2] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftMiddleSpread; - m_fingerSpreads[3] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftRingSpread; - m_fingerSpreads[4] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftPinkySpread; - m_fingerSpreads[5] = m_puppetMaster.PlayerAvatarMovementDataInput.RightThumbSpread; - m_fingerSpreads[6] = m_puppetMaster.PlayerAvatarMovementDataInput.RightIndexSpread; - m_fingerSpreads[7] = m_puppetMaster.PlayerAvatarMovementDataInput.RightMiddleSpread; - m_fingerSpreads[8] = m_puppetMaster.PlayerAvatarMovementDataInput.RightRingSpread; - m_fingerSpreads[9] = m_puppetMaster.PlayerAvatarMovementDataInput.RightPinkySpread; - } - - Matrix4x4 l_current = this.transform.GetMatrix(); - m_offset = m_matrix.inverse * l_current; - m_matrix = l_current; - } - } - - void LateUpdate() - { - if((m_animator != null) && (m_poseHandler != null)) - m_poseHandler.GetHumanPose(ref m_pose); - } - - public ref HumanPose GetPose() => ref m_pose; - public ref Matrix4x4 GetLastOffset() => ref m_offset; - public bool IsSitting() => m_sitting; - public float GetLeftGesture() => m_leftGesture; - public float GetRightGesture() => m_rightGesture; - public bool HasFingerTracking() => m_fingerTracking; - public ref readonly float[] GetFingerCurls() => ref m_fingerCurls; - public ref readonly float[] GetFingerSpreads() => ref m_fingerSpreads; - } -} +using ABI_RC.Core.Player; +using UnityEngine; + +namespace ml_pmc +{ + [DisallowMultipleComponent] + class PuppetParser : MonoBehaviour + { + internal PuppetMaster m_puppetMaster = null; + Animator m_animator = null; + AnimatorCullingMode m_cullMode; + + HumanPoseHandler m_poseHandler = null; + HumanPose m_pose; + + Matrix4x4 m_matrix = Matrix4x4.identity; + Matrix4x4 m_offset = Matrix4x4.identity; + + bool m_sitting = false; + float m_leftGesture = 0f; + float m_rightGesture = 0f; + bool m_fingerTracking = false; + readonly float[] m_fingerCurls = null; + readonly float[] m_fingerSpreads = null; + + internal PuppetParser() + { + m_fingerCurls = new float[30]; + m_fingerSpreads = new float[10]; + } + + // Unity events + void Start() + { + m_animator = this.GetComponent(); + m_cullMode = m_animator.cullingMode; + m_animator.cullingMode = AnimatorCullingMode.AlwaysAnimate; + m_poseHandler = new HumanPoseHandler(m_animator.avatar, m_animator.transform); + m_poseHandler.GetHumanPose(ref m_pose); + m_matrix = this.transform.GetMatrix(); + } + + void OnDestroy() + { + m_puppetMaster = null; + if(m_animator != null) + m_animator.cullingMode = m_cullMode; + m_animator = null; + + m_poseHandler?.Dispose(); + m_poseHandler = null; + } + + void Update() + { + if(m_puppetMaster != null) + { + m_sitting = m_puppetMaster.PlayerAvatarMovementDataInput.AnimatorSitting; + m_leftGesture = m_puppetMaster.PlayerAvatarMovementDataInput.AnimatorGestureLeft; + m_rightGesture = m_puppetMaster.PlayerAvatarMovementDataInput.AnimatorGestureRight; + m_fingerTracking = m_puppetMaster.PlayerAvatarMovementDataInput.UseIndividualFingers; + if(m_fingerTracking) + { + m_fingerCurls[0] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftThumb1Stretched; + m_fingerCurls[1] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftThumb2Stretched; + m_fingerCurls[2] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftThumb3Stretched; + m_fingerSpreads[0] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftThumbSpread; + + m_fingerCurls[3] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftIndex1Stretched; + m_fingerCurls[4] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftIndex2Stretched; + m_fingerCurls[5] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftIndex3Stretched; + m_fingerSpreads[1] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftIndexSpread; + + m_fingerCurls[6] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftMiddle1Stretched; + m_fingerCurls[7] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftMiddle2Stretched; + m_fingerCurls[8] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftMiddle3Stretched; + m_fingerSpreads[2] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftMiddleSpread; + + m_fingerCurls[9] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftRing1Stretched; + m_fingerCurls[10] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftRing2Stretched; + m_fingerCurls[11] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftRing3Stretched; + m_fingerSpreads[3] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftRingSpread; + + m_fingerCurls[12] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftPinky1Stretched; + m_fingerCurls[13] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftPinky2Stretched; + m_fingerCurls[14] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftPinky3Stretched; + m_fingerSpreads[4] = m_puppetMaster.PlayerAvatarMovementDataInput.LeftPinkySpread; + + m_fingerCurls[15] = m_puppetMaster.PlayerAvatarMovementDataInput.RightThumb1Stretched; + m_fingerCurls[16] = m_puppetMaster.PlayerAvatarMovementDataInput.RightThumb2Stretched; + m_fingerCurls[17] = m_puppetMaster.PlayerAvatarMovementDataInput.RightThumb3Stretched; + m_fingerSpreads[5] = m_puppetMaster.PlayerAvatarMovementDataInput.RightThumbSpread; + + m_fingerCurls[18] = m_puppetMaster.PlayerAvatarMovementDataInput.RightIndex1Stretched; + m_fingerCurls[19] = m_puppetMaster.PlayerAvatarMovementDataInput.RightIndex2Stretched; + m_fingerCurls[20] = m_puppetMaster.PlayerAvatarMovementDataInput.RightIndex3Stretched; + m_fingerSpreads[6] = m_puppetMaster.PlayerAvatarMovementDataInput.RightIndexSpread; + + m_fingerCurls[21] = m_puppetMaster.PlayerAvatarMovementDataInput.RightMiddle1Stretched; + m_fingerCurls[22] = m_puppetMaster.PlayerAvatarMovementDataInput.RightMiddle2Stretched; + m_fingerCurls[23] = m_puppetMaster.PlayerAvatarMovementDataInput.RightMiddle3Stretched; + m_fingerSpreads[7] = m_puppetMaster.PlayerAvatarMovementDataInput.RightMiddleSpread; + + m_fingerCurls[24] = m_puppetMaster.PlayerAvatarMovementDataInput.RightRing1Stretched; + m_fingerCurls[25] = m_puppetMaster.PlayerAvatarMovementDataInput.RightRing2Stretched; + m_fingerCurls[26] = m_puppetMaster.PlayerAvatarMovementDataInput.RightRing3Stretched; + m_fingerSpreads[8] = m_puppetMaster.PlayerAvatarMovementDataInput.RightRingSpread; + + m_fingerCurls[27] = m_puppetMaster.PlayerAvatarMovementDataInput.RightPinky1Stretched; + m_fingerCurls[28] = m_puppetMaster.PlayerAvatarMovementDataInput.RightPinky2Stretched; + m_fingerCurls[29] = m_puppetMaster.PlayerAvatarMovementDataInput.RightPinky3Stretched; + m_fingerSpreads[9] = m_puppetMaster.PlayerAvatarMovementDataInput.RightPinkySpread; + } + + Matrix4x4 l_current = this.transform.GetMatrix(); + m_offset = m_matrix.inverse * l_current; + m_matrix = l_current; + } + } + + void LateUpdate() + { + if((m_animator != null) && (m_poseHandler != null)) + m_poseHandler.GetHumanPose(ref m_pose); + } + + public ref HumanPose GetPose() => ref m_pose; + public ref Matrix4x4 GetLastOffset() => ref m_offset; + public bool IsSitting() => m_sitting; + public float GetLeftGesture() => m_leftGesture; + public float GetRightGesture() => m_rightGesture; + public bool HasFingerTracking() => m_fingerTracking; + public ref readonly float[] GetFingerCurls() => ref m_fingerCurls; + public ref readonly float[] GetFingerSpreads() => ref m_fingerSpreads; + } +} diff --git a/ml_pmc/Utils.cs b/ml_pmc/Utils.cs index c09cc09..0235eda 100644 --- a/ml_pmc/Utils.cs +++ b/ml_pmc/Utils.cs @@ -16,7 +16,7 @@ namespace ml_pmc }; static readonly int[] ms_centralMuscles = new int[] { 1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 18, 20 }; - public static bool IsInVR() => ((CheckVR.Instance != null) && CheckVR.Instance.hasVrDeviceLoaded); + public static bool IsInVR() => ((MetaPort.Instance != null) && MetaPort.Instance.isUsingVr); public static bool AreKnucklesInUse() => ((CVRInputManager.Instance._leftController == ABI_RC.Systems.InputManagement.XR.eXRControllerType.Index) || (CVRInputManager.Instance._rightController == ABI_RC.Systems.InputManagement.XR.eXRControllerType.Index)); public static bool IsWorldSafe() => ((CVRWorld.Instance != null) && CVRWorld.Instance.allowFlying); diff --git a/ml_pmc/ml_pmc.csproj b/ml_pmc/ml_pmc.csproj index 9be3650..75e32d0 100644 --- a/ml_pmc/ml_pmc.csproj +++ b/ml_pmc/ml_pmc.csproj @@ -7,7 +7,7 @@ SDraw None PlayerMovementCopycat - 1.0.4 + 1.0.5 @@ -45,6 +45,11 @@ false false
+ + D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\ECM2.dll + false + false + D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\MelonLoader.dll false diff --git a/ml_prm/GravityInfluencer.cs b/ml_prm/GravityInfluencer.cs new file mode 100644 index 0000000..183fb70 --- /dev/null +++ b/ml_prm/GravityInfluencer.cs @@ -0,0 +1,30 @@ +using ABI.CCK.Components; +using ABI_RC.Systems.Gravity; +using ABI_RC.Systems.Movement; +using UnityEngine; + +namespace ml_prm +{ + [DisallowMultipleComponent] + class GravityInfluencer : MonoBehaviour + { + Rigidbody m_rigidBody = null; + PhysicsInfluencer m_physicsInfluencer = null; + bool m_activeGravity = true; + + void Start() + { + m_rigidBody = this.GetComponent(); + m_physicsInfluencer = this.GetComponent(); + } + + void FixedUpdate() + { + m_rigidBody.useGravity = false; + if(m_activeGravity && ((m_physicsInfluencer == null) || !m_physicsInfluencer.enableInfluence || !m_physicsInfluencer.GetSubmerged())) + m_rigidBody.AddForce(BetterBetterCharacterController.Instance.GravityResult.AppliedGravity * m_rigidBody.mass); + } + + public void SetActiveGravity(bool p_state) => m_activeGravity = p_state; + } +} diff --git a/ml_prm/Main.cs b/ml_prm/Main.cs index f27879a..e26d045 100644 --- a/ml_prm/Main.cs +++ b/ml_prm/Main.cs @@ -4,8 +4,9 @@ using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.Player; using ABI_RC.Core.Util.AssetFiltering; using ABI_RC.Systems.Camera.VisualMods; +using ABI_RC.Systems.IK; using ABI_RC.Systems.IK.SubSystems; -using ABI_RC.Systems.MovementSystem; +using ABI_RC.Systems.Movement; using System; using System.Collections.Generic; using System.Linq; @@ -15,6 +16,8 @@ namespace ml_prm { public class PlayerRagdollMod : MelonLoader.MelonMod { + static readonly Type[] ms_teleportTypes = { typeof(UnityEngine.Vector3), typeof(bool), typeof(bool), typeof(UnityEngine.Quaternion?) }; + static PlayerRagdollMod ms_instance = null; RagdollController m_localController = null; @@ -37,6 +40,11 @@ namespace ml_prm null, new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); + HarmonyInstance.Patch( + typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public), + new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnAvatarReinitialize_Prefix), BindingFlags.Static | BindingFlags.NonPublic)), + new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + ); HarmonyInstance.Patch( typeof(PlayerSetup).GetMethod("SetupIKScaling", BindingFlags.NonPublic | BindingFlags.Instance), null, @@ -63,19 +71,13 @@ namespace ml_prm null ); HarmonyInstance.Patch( - typeof(MovementSystem).GetMethod(nameof(MovementSystem.ChangeFlight)), + typeof(BetterBetterCharacterController).GetMethod(nameof(BetterBetterCharacterController.ChangeFlight)), null, new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnChangeFlight_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); HarmonyInstance.Patch( - typeof(MovementSystem).GetMethod(nameof(MovementSystem.TeleportToPosRot)), - null, - new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnPlayerTeleport_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) - ); - HarmonyInstance.Patch( - typeof(DroneMode).GetMethod(nameof(DroneMode.Disable)), - null, - new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnDroneModeDisable_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + typeof(IKSystem).GetMethod("OnPreSolverUpdateActiveOffset", BindingFlags.Instance | BindingFlags.NonPublic), + new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnOffsetUpdate_Prefix), BindingFlags.Static | BindingFlags.NonPublic)) ); // Whitelist the toggle script @@ -140,6 +142,34 @@ namespace ml_prm } } + static void OnAvatarReinitialize_Prefix() => ms_instance?.OnPreAvatarReinitialize(); + void OnPreAvatarReinitialize() + { + try + { + if(m_localController != null) + m_localController.OnPreAvatarReinitialize(); + } + catch(System.Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } + + static void OnAvatarReinitialize_Postfix() => ms_instance?.OnPostAvatarReinitialize(); + void OnPostAvatarReinitialize() + { + try + { + if(m_localController != null) + m_localController.OnPostAvatarReinitialize(); + } + catch(System.Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } + static void OnSetupIKScaling_Postfix(ref UnityEngine.Vector3 ___scaleDifference) => ms_instance?.OnSetupIKScaling(___scaleDifference.y); void OnSetupIKScaling(float p_scaleDifference) { @@ -228,32 +258,20 @@ namespace ml_prm } } - static void OnPlayerTeleport_Postfix() => ms_instance?.OnPlayerTeleport(); - void OnPlayerTeleport() + static bool OnOffsetUpdate_Prefix(ref IKSystem __instance) => ms_instance.OnOffsetUpdate(__instance); + bool OnOffsetUpdate(IKSystem p_instance) { + bool l_result = true; try { if(m_localController != null) - m_localController.OnPlayerTeleport(); - } - catch(Exception e) - { - MelonLoader.MelonLogger.Error(e); - } - } - - static void OnDroneModeDisable_Postfix() => ms_instance?.OnDroneModeDisable(); - void OnDroneModeDisable() - { - try - { - if(m_localController != null) - m_localController.OnDroneModeDisable(); + l_result = !m_localController.ShoudlDisableHeadOffset(); } catch(Exception e) { MelonLoader.MelonLogger.Error(e); } + return l_result; } } } diff --git a/ml_prm/ModUi.cs b/ml_prm/ModUi.cs index b19f00f..98a36bb 100644 --- a/ml_prm/ModUi.cs +++ b/ml_prm/ModUi.cs @@ -90,19 +90,19 @@ namespace ml_prm ms_uiElements.Add(l_modCategory.AddToggle("Fall damage", "Enable ragdoll when falling from height", Settings.FallDamage)); (ms_uiElements[(int)UiIndex.FallDamage] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.FallDamage, state); - ms_uiElements.Add(l_modRoot.AddSlider("Velocity multiplier", "Velocity multiplier upon entering ragdoll state", Settings.VelocityMultiplier, 1f, 50f)); + ms_uiElements.Add(l_modCategory.AddSlider("Velocity multiplier", "Velocity multiplier upon entering ragdoll state", Settings.VelocityMultiplier, 1f, 50f)); (ms_uiElements[(int)UiIndex.VelocityMultiplier] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(UiIndex.VelocityMultiplier, value); - ms_uiElements.Add(l_modRoot.AddSlider("Movement drag", "Movement resistance", Settings.MovementDrag, 0f, 50f)); + ms_uiElements.Add(l_modCategory.AddSlider("Movement drag", "Movement resistance", Settings.MovementDrag, 0f, 50f)); (ms_uiElements[(int)UiIndex.MovementDrag] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(UiIndex.MovementDrag, value); - ms_uiElements.Add(l_modRoot.AddSlider("Angular movement drag", "Rotation movement resistance", Settings.AngularDrag, 0f, 50f)); + ms_uiElements.Add(l_modCategory.AddSlider("Angular movement drag", "Rotation movement resistance", Settings.AngularDrag, 0f, 50f)); (ms_uiElements[(int)UiIndex.AngularDrag] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(UiIndex.AngularDrag, value); - ms_uiElements.Add(l_modRoot.AddSlider("Recover delay (seconds)", "Recover delay for automatic recover", Settings.RecoverDelay, 1f, 10f)); + ms_uiElements.Add(l_modCategory.AddSlider("Recover delay (seconds)", "Recover delay for automatic recover", Settings.RecoverDelay, 1f, 10f)); (ms_uiElements[(int)UiIndex.RecoverDelay] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(UiIndex.RecoverDelay, value); - ms_uiElements.Add(l_modRoot.AddSlider("Fall limit", "Height limit for fall damage", Settings.FallLimit, 0f, 100f)); + ms_uiElements.Add(l_modCategory.AddSlider("Fall limit", "Height limit for fall damage", Settings.FallLimit, 0f, 100f)); (ms_uiElements[(int)UiIndex.FallLimit] as BTKUILib.UIObjects.Components.SliderFloat).OnValueUpdated += (value) => OnSliderUpdate(UiIndex.FallLimit, value); l_modCategory.AddButton("Reset settings", "", "Reset mod settings to default").OnPress += Reset; diff --git a/ml_prm/Properties/AssemblyInfo.cs b/ml_prm/Properties/AssemblyInfo.cs index f2a0605..3b540bd 100644 --- a/ml_prm/Properties/AssemblyInfo.cs +++ b/ml_prm/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.1.2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.1.3-ex", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")] [assembly: MelonLoader.MelonPriority(2)] [assembly: MelonLoader.MelonOptionalDependencies("BTKUILib")] diff --git a/ml_prm/RagdollController.cs b/ml_prm/RagdollController.cs index d476751..c1b3e9b 100644 --- a/ml_prm/RagdollController.cs +++ b/ml_prm/RagdollController.cs @@ -1,11 +1,10 @@ using ABI.CCK.Components; using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.Player; -using ABI_RC.Systems.Camera; using ABI_RC.Systems.IK; using ABI_RC.Systems.IK.SubSystems; using ABI_RC.Systems.InputManagement; -using ABI_RC.Systems.MovementSystem; +using ABI_RC.Systems.Movement; using RootMotion.Dynamics; using RootMotion.FinalIK; using System.Collections; @@ -21,6 +20,7 @@ namespace ml_prm public static RagdollController Instance { get; private set; } = null; + bool m_inVR = false; VRIK m_vrIK = null; bool m_applyHipsPosition = false; bool m_applyHipsRotation = false; @@ -36,12 +36,14 @@ namespace ml_prm readonly List> m_boneLinks = null; readonly List> m_jointAnchors = null; readonly List m_physicsInfluencers = null; + readonly List m_gravityInfluencers = null; bool m_avatarReady = false; Coroutine m_initCoroutine = null; Vector3 m_lastPosition = Vector3.zero; Vector3 m_velocity = Vector3.zero; Vector3 m_ragdollLastPos = Vector3.zero; + bool m_wasSwimming = false; RagdollToggle m_avatarRagdollToggle = null; RagdollTrigger m_ragdollTrigger = null; @@ -62,6 +64,7 @@ namespace ml_prm m_boneLinks = new List>(); m_jointAnchors = new List>(); m_physicsInfluencers = new List(); + m_gravityInfluencers = new List(); } // Unity events @@ -82,7 +85,7 @@ namespace ml_prm m_puppetRoot.localPosition = Vector3.zero; m_puppetRoot.localRotation = Quaternion.identity; - m_ragdollTrigger = MovementSystem.Instance.proxyCollider.gameObject.AddComponent(); + m_ragdollTrigger = BetterBetterCharacterController.Instance.NonKinematicProxy.gameObject.AddComponent(); m_ragdollTrigger.enabled = false; Settings.MovementDragChange += this.OnMovementDragChange; @@ -92,6 +95,8 @@ namespace ml_prm Settings.BouncinessChange += this.OnPhysicsMaterialChange; Settings.BuoyancyChange += this.OnBuoyancyChange; Settings.FallDamageChange += this.OnFallDamageChange; + + BetterBetterCharacterController.OnTeleport.AddListener(this.OnPlayerTeleport); } void OnDestroy() @@ -106,6 +111,7 @@ namespace ml_prm if(m_puppetRoot != null) Object.Destroy(m_puppetRoot); m_puppetRoot = null; + m_puppet = null; m_rigidBodies.Clear(); m_colliders.Clear(); @@ -129,14 +135,16 @@ namespace ml_prm Settings.BouncinessChange -= this.OnPhysicsMaterialChange; Settings.BuoyancyChange -= this.OnBuoyancyChange; Settings.FallDamageChange -= this.OnFallDamageChange; + + BetterBetterCharacterController.OnTeleport.RemoveListener(this.OnPlayerTeleport); } void Update() { - if(m_avatarReady && !m_enabled && Settings.FallDamage && !MovementSystem.Instance.flying) + if(m_avatarReady && !m_enabled && Settings.FallDamage && !BetterBetterCharacterController.Instance.IsFlying()) { - bool l_grounded = MovementSystem.Instance.IsGroundedRaw(); - bool l_inWater = MovementSystem.Instance.GetSubmerged(); + bool l_grounded = BetterBetterCharacterController.Instance.IsGrounded(); + bool l_inWater = BetterBetterCharacterController.Instance.IsInWater(); if(m_inAir && l_grounded && !l_inWater && (m_inAirDistance > Settings.FallLimit)) { m_inAirDistance = 0f; @@ -151,12 +159,6 @@ namespace ml_prm if(m_avatarReady && m_enabled) { m_inAirDistance = 0f; - - Vector3 l_dif = m_puppetReferences.hips.position - m_ragdollLastPos; - PlayerSetup.Instance.transform.position += l_dif; - m_puppetReferences.hips.position -= l_dif; - m_ragdollLastPos = m_puppetReferences.hips.position; - BodySystem.TrackingPositionWeight = 0f; } @@ -166,13 +168,13 @@ namespace ml_prm m_velocity = (m_velocity + (l_pos - m_lastPosition) / Time.deltaTime) * 0.5f; if(m_inAir) { - m_inAirDistance += (m_lastPosition - l_pos).y; + m_inAirDistance += (Quaternion.Inverse(PlayerSetup.Instance.transform.rotation) * (m_lastPosition - l_pos)).y; m_inAirDistance = Mathf.Clamp(m_inAirDistance, 0f, float.MaxValue); } m_lastPosition = l_pos; - if(!m_reachedGround && MovementSystem.Instance.IsGrounded()) + if(!m_reachedGround && BetterBetterCharacterController.Instance.IsOnGround()) { m_groundedTime += Time.deltaTime; if(m_groundedTime >= 0.25f) @@ -196,13 +198,24 @@ namespace ml_prm if((m_ragdollTrigger != null) && m_ragdollTrigger.GetStateWithReset() && m_avatarReady && !m_enabled && Settings.PointersReaction) SwitchRagdoll(); - if(Settings.Hotkey && Input.GetKeyDown(Settings.HotkeyKey) && !ViewManager.Instance.isGameMenuOpen()) + if(Settings.Hotkey && Input.GetKeyDown(Settings.HotkeyKey) && !ViewManager.Instance.IsAnyMenuOpen) SwitchRagdoll(); if(m_avatarReady && m_enabled && CVRInputManager.Instance.jump && Settings.JumpRecover) SwitchRagdoll(); } + void FixedUpdate() + { + if(m_avatarReady && m_enabled) + { + Vector3 l_dif = m_puppetReferences.hips.position - m_ragdollLastPos; + PlayerSetup.Instance.transform.position += l_dif; + m_puppetReferences.hips.position -= l_dif; + m_ragdollLastPos = m_puppetReferences.hips.position; + } + } + void LateUpdate() { if(m_avatarReady) @@ -223,6 +236,8 @@ namespace ml_prm // Game events internal void OnAvatarClear() { + m_inVR = Utils.IsInVR(); + if(m_initCoroutine != null) { StopCoroutine(m_initCoroutine); @@ -257,16 +272,20 @@ namespace ml_prm m_boneLinks.Clear(); m_jointAnchors.Clear(); m_physicsInfluencers.Clear(); + m_gravityInfluencers.Clear(); m_reachedGround = true; m_groundedTime = 0f; m_downTime = float.MinValue; m_puppetRoot.localScale = Vector3.one; m_inAir = false; m_inAirDistance = 0f; + m_wasSwimming = false; } internal void OnAvatarSetup() { + m_inVR = Utils.IsInVR(); + if(PlayerSetup.Instance._animator.isHuman) { BipedRagdollReferences l_avatarReferences = BipedRagdollReferences.FromAvatar(PlayerSetup.Instance._animator); @@ -322,9 +341,13 @@ namespace ml_prm l_body.isKinematic = true; l_body.angularDrag = Settings.AngularDrag; l_body.drag = (Utils.IsWorldSafe() ? Settings.MovementDrag : 1f); - l_body.useGravity = (!Utils.IsWorldSafe() || Settings.Gravity); + l_body.useGravity = false; l_body.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic; l_body.gameObject.layer = LayerMask.NameToLayer("PlayerLocal"); + + GravityInfluencer l_gravInfluencer = l_body.gameObject.AddComponent(); + l_gravInfluencer.SetActiveGravity((!Utils.IsWorldSafe() || Settings.Gravity)); + m_gravityInfluencers.Add(l_gravInfluencer); } CharacterJoint l_joint = l_puppetTransforms[i].GetComponent(); @@ -338,9 +361,12 @@ namespace ml_prm Collider l_collider = l_puppetTransforms[i].GetComponent(); if(l_collider != null) { - Physics.IgnoreCollision(l_collider, MovementSystem.Instance.controller, true); - Physics.IgnoreCollision(l_collider, MovementSystem.Instance.proxyCollider, true); - Physics.IgnoreCollision(l_collider, MovementSystem.Instance.forceCollider, true); + Physics.IgnoreCollision(l_collider, BetterBetterCharacterController.Instance.Collider, true); + Physics.IgnoreCollision(l_collider, BetterBetterCharacterController.Instance.KinematicTriggerProxy.Collider, true); + Physics.IgnoreCollision(l_collider, BetterBetterCharacterController.Instance.NonKinematicProxy.Collider, true); + Physics.IgnoreCollision(l_collider, BetterBetterCharacterController.Instance.SphereProxy.Collider, true); + BetterBetterCharacterController.Instance.IgnoreCollision(l_collider, true); + l_collider.sharedMaterial = m_physicsMaterial; l_collider.material = m_physicsMaterial; m_colliders.Add(l_collider); @@ -355,6 +381,7 @@ namespace ml_prm l_physicsInfluencer.fluidAngularDrag = 1f; l_physicsInfluencer.enableBuoyancy = true; l_physicsInfluencer.enableInfluence = false; + l_physicsInfluencer.forceAlignUpright = false; float mass = l_body.mass; l_physicsInfluencer.UpdateDensity(); l_body.mass = mass; @@ -402,6 +429,24 @@ namespace ml_prm OnAngularDragChange(Settings.AngularDrag); } + internal void OnPreAvatarReinitialize() + { + if(m_avatarReady && m_enabled) + { + m_forcedSwitch = true; + SwitchRagdoll(); + m_forcedSwitch = false; + } + } + internal void OnPostAvatarReinitialize() + { + m_inVR = Utils.IsInVR(); + m_vrIK = PlayerSetup.Instance._avatar.GetComponent(); + + if(m_vrIK != null) + m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate); + } + internal void OnAvatarScaling(float p_scaleDifference) { if(m_puppetRoot != null) @@ -460,7 +505,7 @@ namespace ml_prm internal void OnChangeFlight() { - if(m_avatarReady && m_enabled && MovementSystem.Instance.flying) + if(m_avatarReady && m_enabled && BetterBetterCharacterController.Instance.IsFlying()) { m_forcedSwitch = true; SwitchRagdoll(); @@ -470,21 +515,22 @@ namespace ml_prm } } - internal void OnPlayerTeleport() + void OnPlayerTeleport(BetterBetterCharacterController.PlayerMoveOffset p_offset) { - ResetStates(); + try + { + ResetStates(); - if(m_avatarReady && m_enabled) - m_ragdollLastPos = m_puppetReferences.hips.position; + if(m_avatarReady && m_enabled) + m_ragdollLastPos = m_puppetReferences.hips.position; + } + catch(System.Exception e) + { + MelonLoader.MelonLogger.Error(e); + } } - internal void OnDroneModeDisable() - { - if(m_avatarReady && m_enabled) - MovementSystem.Instance.canRot = false; - } - - // IK updates + // VRIK updates void OnIKPostUpdate() { if(!m_enabled) @@ -529,10 +575,10 @@ namespace ml_prm if(m_avatarReady) { bool l_gravity = (!Utils.IsWorldSafe() || p_state); - foreach(Rigidbody l_body in m_rigidBodies) - l_body.useGravity = l_gravity; foreach(PhysicsInfluencer l_influencer in m_physicsInfluencers) l_influencer.enabled = l_gravity; + foreach(GravityInfluencer l_influencer in m_gravityInfluencers) + l_influencer.SetActiveGravity(l_gravity); if(!l_gravity) { @@ -584,10 +630,12 @@ namespace ml_prm { if(CanRagdoll()) { - if(MovementSystem.Instance.flying) - MovementSystem.Instance.ChangeFlight(false); - MovementSystem.Instance.SetImmobilized(true); - MovementSystem.Instance.ClearFluidVolumes(); + m_wasSwimming = BetterBetterCharacterController.Instance.IsSwimming(); + + if(BetterBetterCharacterController.Instance.IsFlying()) + BetterBetterCharacterController.Instance.ChangeFlight(false,true); + BetterBetterCharacterController.Instance.SetImmobilized(true); + BetterBetterCharacterController.Instance.ClearFluidVolumes(); BodySystem.TrackingPositionWeight = 0f; m_applyHipsPosition = IKSystem.Instance.applyOriginalHipPosition; IKSystem.Instance.applyOriginalHipPosition = true; @@ -631,13 +679,13 @@ namespace ml_prm { if(CanUnragdoll()) { - MovementSystem.Instance.TeleportTo(m_puppetReferences.hips.position, new Vector3(0f, PlayerSetup.Instance.GetActiveCamera().transform.rotation.eulerAngles.y, 0f)); + BetterBetterCharacterController.Instance.TeleportPlayerTo(m_puppetReferences.hips.position, PlayerSetup.Instance.GetPlayerRotation().eulerAngles, false, false); TryRestoreMovement(); if(!Utils.IsWorldSafe()) { - Vector3 l_vec = MovementSystem.Instance.GetAppliedGravity(); + Vector3 l_vec = BetterBetterCharacterController.Instance.GetVelocity(); l_vec.y = Mathf.Clamp(l_vec.y, float.MinValue, 0f); - MovementSystem.Instance.SetAppliedGravity(l_vec); + BetterBetterCharacterController.Instance.SetVelocity(l_vec); } BodySystem.TrackingPositionWeight = 1f; IKSystem.Instance.applyOriginalHipPosition = m_applyHipsPosition; @@ -666,6 +714,10 @@ namespace ml_prm OnMovementDragChange(Settings.MovementDrag); OnAngularDragChange(Settings.AngularDrag); + // Restore movement if was ragdolled in water and left it + if(m_wasSwimming) + BetterBetterCharacterController.Instance.SetMovementMode(ECM2.Character.MovementMode.Swimming); + m_enabled = false; } } @@ -698,7 +750,7 @@ namespace ml_prm { bool l_result = m_reachedGround; l_result &= !BodySystem.isCalibrating; - l_result &= (MovementSystem.Instance.lastSeat == null); + l_result &= !BetterBetterCharacterController.Instance.IsSitting(); l_result &= ((CombatSystem.Instance == null) || !CombatSystem.Instance.isDown); return (l_result || m_forcedSwitch); } @@ -710,18 +762,19 @@ namespace ml_prm return (l_result || m_forcedSwitch); } + internal bool ShoudlDisableHeadOffset() + { + return (m_enabled && (m_vrIK != null)); + } + static void TryRestoreMovement() { bool l_state = true; l_state &= ((CombatSystem.Instance == null) || !CombatSystem.Instance.isDown); - l_state &= (MovementSystem.Instance.lastSeat == null); + l_state &= !BetterBetterCharacterController.Instance.IsSitting(); if(l_state) - { - MovementSystem.Instance.SetImmobilized(false); - if(PortableCamera.Instance.CheckModActive(typeof(ABI_RC.Systems.Camera.VisualMods.DroneMode))) - MovementSystem.Instance.canRot = false; - } + BetterBetterCharacterController.Instance.SetImmobilized(false); } } } diff --git a/ml_prm/Utils.cs b/ml_prm/Utils.cs index 909f656..41b3ba0 100644 --- a/ml_prm/Utils.cs +++ b/ml_prm/Utils.cs @@ -1,6 +1,6 @@ using ABI.CCK.Components; using ABI_RC.Core.Savior; -using ABI_RC.Systems.MovementSystem; +using ABI_RC.Systems.Movement; using System.Collections.Generic; using System.Reflection; using UnityEngine; @@ -9,14 +9,12 @@ namespace ml_prm { static class Utils { - static readonly FieldInfo ms_groundedRaw = typeof(MovementSystem).GetField("_isGroundedRaw", BindingFlags.NonPublic | BindingFlags.Instance); - static readonly FieldInfo ms_appliedGravity = typeof(MovementSystem).GetField("_appliedGravity", BindingFlags.NonPublic | BindingFlags.Instance); - static readonly FieldInfo ms_touchingVolumes = typeof(MovementSystem).GetField("_touchingVolumes", BindingFlags.NonPublic | BindingFlags.Instance); + static readonly FieldInfo ms_touchingVolumes = typeof(BetterBetterCharacterController).GetField("_currentlyTouchingFluidVolumes", BindingFlags.NonPublic | BindingFlags.Instance); 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); - public static bool IsInVR() => ((CheckVR.Instance != null) && CheckVR.Instance.hasVrDeviceLoaded); + public static bool IsInVR() => ((MetaPort.Instance != null) && MetaPort.Instance.isUsingVr); public static bool IsWorldSafe() => ((CVRWorld.Instance != null) && CVRWorld.Instance.allowFlying); public static float GetWorldMovementLimit() { @@ -31,10 +29,7 @@ namespace ml_prm return l_result; } - public static bool IsGroundedRaw(this MovementSystem p_instance) => (bool)ms_groundedRaw.GetValue(p_instance); - public static Vector3 GetAppliedGravity(this MovementSystem p_instance) => (Vector3)ms_appliedGravity.GetValue(p_instance); - public static void SetAppliedGravity(this MovementSystem p_instance, Vector3 p_vec) => ms_appliedGravity.SetValue(p_instance, p_vec); - public static void ClearFluidVolumes(this MovementSystem p_instance) => (ms_touchingVolumes.GetValue(p_instance) as List)?.Clear(); + public static void ClearFluidVolumes(this BetterBetterCharacterController p_instance) => (ms_touchingVolumes.GetValue(p_instance) as List)?.Clear(); public static void CopyGlobal(this Transform p_source, Transform p_target) { diff --git a/ml_prm/ml_prm.csproj b/ml_prm/ml_prm.csproj index 6c579ab..e84b7ac 100644 --- a/ml_prm/ml_prm.csproj +++ b/ml_prm/ml_prm.csproj @@ -4,7 +4,7 @@ netstandard2.1 x64 PlayerRagdollMod - 1.1.2 + 1.1.3 SDraw None PlayerRagdollMod @@ -41,6 +41,11 @@ false false + + D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\ECM2.dll + false + false + D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\MelonLoader.dll false diff --git a/ml_vei/Properties/AssemblyInfo.cs b/ml_vei/Properties/AssemblyInfo.cs index 73d71dd..1fb0b47 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.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_vei.ViveExtendedInput), "ViveExtendedInput", "1.0.1-ex", "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/ml_vei.csproj b/ml_vei/ml_vei.csproj index d55a724..ffd4ad5 100644 --- a/ml_vei/ml_vei.csproj +++ b/ml_vei/ml_vei.csproj @@ -4,7 +4,7 @@ netstandard2.1 x64 ViveExtendedInput - 1.0.0 + 1.0.1 SDraw None ViveExtendedInput