diff --git a/README.md b/README.md index de9850d..2d62003 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,6 @@ Merged set of MelonLoader mods for ChilloutVR. | Desktop Reticle Switch | ml_drs | 1.0.0 | Yes | Working | | Extended Game Notifications | ml_egn | 1.0.0 | Yes | Working | Four Point Tracking | ml_fpt | 1.0.9 | Retired | Deprecated | In-game feature since 2022r170 update -| Leap Motion Extension | ml_lme | 1.2.9 | Yes | Working | +| Leap Motion Extension | ml_lme | 1.3.0 | Yes, update review | Working | | Pickup Arm Movement | ml_pam | 1.0.0 | Yes | Working | | Server Connection Info | ml_sci | 1.0.2 | Retired | Retired | Superseded by `Extended Game Notifications` diff --git a/ml_amt/Main.cs b/ml_amt/Main.cs index 4444846..450a028 100644 --- a/ml_amt/Main.cs +++ b/ml_amt/Main.cs @@ -4,6 +4,7 @@ using ABI_RC.Systems.MovementSystem; using System.Reflection; using UnityEngine; +using System.Collections; namespace ml_amt { @@ -71,7 +72,7 @@ public override void OnInitializeMelon() MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); } - System.Collections.IEnumerator WaitForLocalPlayer() + IEnumerator WaitForLocalPlayer() { while(PlayerSetup.Instance == null) yield return null; diff --git a/ml_amt/MotionTweaker.cs b/ml_amt/MotionTweaker.cs index 1e7e4c2..c9077cd 100644 --- a/ml_amt/MotionTweaker.cs +++ b/ml_amt/MotionTweaker.cs @@ -66,7 +66,7 @@ enum PoseState readonly List m_parameters = null; - public MotionTweaker() + internal MotionTweaker() { m_parameters = new List(); } @@ -159,7 +159,7 @@ void Update() } } - public void OnAvatarClear() + internal void OnAvatarClear() { m_vrIk = null; m_locomotionLayer = -1; @@ -181,7 +181,7 @@ public void OnAvatarClear() m_parameters.Clear(); } - public void OnSetupAvatar() + internal void OnSetupAvatar() { m_isInVR = Utils.IsInVR(); m_vrIk = PlayerSetup.Instance._avatar.GetComponent(); @@ -239,7 +239,7 @@ public void OnSetupAvatar() m_avatarReady = true; } - public void OnCalibrate() + internal void OnCalibrate() { if(m_avatarReady && BodySystem.isCalibratedAsFullBody && BodySystem.enableHipTracking && !BodySystem.enableRightFootTracking && !BodySystem.enableLeftFootTracking && !BodySystem.enableLeftKneeTracking && !BodySystem.enableRightKneeTracking) { diff --git a/ml_amt/Settings.cs b/ml_amt/Settings.cs index 7eb0ea2..ed548c0 100644 --- a/ml_amt/Settings.cs +++ b/ml_amt/Settings.cs @@ -49,22 +49,24 @@ enum ModSetting static public event Action FollowHipsChange; static public event Action CollisionScaleChange; - public static void Init() + internal static void Init() { ms_category = MelonLoader.MelonPreferences.CreateCategory("AMT"); - ms_entries = new List(); - ms_entries.Add(ms_category.CreateEntry(ModSetting.IKOverrideCrouch.ToString(), true)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.CrouchLimit.ToString(), 65)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.IKOverrideProne.ToString(), true)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.ProneLimit.ToString(), 30)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.PoseTransitions.ToString(), true)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.AdjustedMovement.ToString(), true)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.IKOverrideFly.ToString(), true)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.IKOverrideJump.ToString(), true)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.DetectEmotes.ToString(), true)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.FollowHips.ToString(), true)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.CollisionScale.ToString(), true)); + ms_entries = new List() + { + ms_category.CreateEntry(ModSetting.IKOverrideCrouch.ToString(), true), + ms_category.CreateEntry(ModSetting.CrouchLimit.ToString(), 65), + ms_category.CreateEntry(ModSetting.IKOverrideProne.ToString(), true), + ms_category.CreateEntry(ModSetting.ProneLimit.ToString(), 30), + ms_category.CreateEntry(ModSetting.PoseTransitions.ToString(), true), + ms_category.CreateEntry(ModSetting.AdjustedMovement.ToString(), true), + ms_category.CreateEntry(ModSetting.IKOverrideFly.ToString(), true), + ms_category.CreateEntry(ModSetting.IKOverrideJump.ToString(), true), + ms_category.CreateEntry(ModSetting.DetectEmotes.ToString(), true), + ms_category.CreateEntry(ModSetting.FollowHips.ToString(), true), + ms_category.CreateEntry(ModSetting.CollisionScale.ToString(), true) + }; Load(); @@ -194,7 +196,7 @@ static void OnToggleUpdate(string p_name, string p_value) FollowHipsChange?.Invoke(ms_followHips); } break; - + case ModSetting.CollisionScale: { ms_collisionScale = bool.Parse(p_value); diff --git a/ml_dht/HeadTracked.cs b/ml_dht/HeadTracked.cs index df87e18..7282ed3 100644 --- a/ml_dht/HeadTracked.cs +++ b/ml_dht/HeadTracked.cs @@ -77,7 +77,7 @@ void OnLookIKPostUpdate() } } - public void OnEyeControllerUpdate(CVREyeController p_component) + internal void OnEyeControllerUpdate(CVREyeController p_component) { if(m_enabled) { @@ -99,7 +99,7 @@ public void OnEyeControllerUpdate(CVREyeController p_component) } } - public void OnFaceTrackingUpdate(CVRFaceTracking p_component) + internal void OnFaceTrackingUpdate(CVRFaceTracking p_component) { if(m_enabled && m_faceOverride) { @@ -117,7 +117,7 @@ public void OnFaceTrackingUpdate(CVRFaceTracking p_component) } } - public void OnSetupAvatar() + internal void OnSetupAvatar() { m_avatarDescriptor = PlayerSetup.Instance._avatar.GetComponent(); m_headBone = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Head); @@ -130,7 +130,7 @@ public void OnSetupAvatar() m_lookIK.solver.OnPostUpdate += this.OnLookIKPostUpdate; } - public void OnAvatarClear() + internal void OnAvatarClear() { m_avatarDescriptor = null; m_lookIK = null; diff --git a/ml_dht/Settings.cs b/ml_dht/Settings.cs index bb33b28..12057f2 100644 --- a/ml_dht/Settings.cs +++ b/ml_dht/Settings.cs @@ -17,7 +17,7 @@ enum ModSetting Smoothing, FaceOverride } - + static bool ms_enabled = false; static bool ms_headTracking = true; static bool ms_eyeTracking = true; @@ -25,10 +25,10 @@ enum ModSetting static bool ms_mirrored = false; static float ms_smoothing = 0.5f; static bool ms_faceOverride = true; - + static MelonLoader.MelonPreferences_Category ms_category = null; static List ms_entries = null; - + static public event Action EnabledChange; static public event Action HeadTrackingChange; static public event Action EyeTrackingChange; @@ -36,25 +36,27 @@ enum ModSetting static public event Action MirroredChange; static public event Action SmoothingChange; static public event Action FaceOverrideChange; - - public static void Init() + + internal static void Init() { ms_category = MelonLoader.MelonPreferences.CreateCategory("DHT"); - - ms_entries = new List(); - ms_entries.Add(ms_category.CreateEntry(ModSetting.Enabled.ToString(), false)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.HeadTracking.ToString(), false)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.EyeTracking.ToString(), true)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.Blinking.ToString(), true)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.Mirrored.ToString(), false)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.Smoothing.ToString(), 50)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.FaceOverride.ToString(), true)); - + + ms_entries = new List() + { + ms_category.CreateEntry(ModSetting.Enabled.ToString(), false), + ms_category.CreateEntry(ModSetting.HeadTracking.ToString(), false), + ms_category.CreateEntry(ModSetting.EyeTracking.ToString(), true), + ms_category.CreateEntry(ModSetting.Blinking.ToString(), true), + ms_category.CreateEntry(ModSetting.Mirrored.ToString(), false), + ms_category.CreateEntry(ModSetting.Smoothing.ToString(), 50), + ms_category.CreateEntry(ModSetting.FaceOverride.ToString(), true) + }; + Load(); MelonLoader.MelonCoroutines.Start(WaitMainMenuUi()); } - + static System.Collections.IEnumerator WaitMainMenuUi() { while(ViewManager.Instance == null) @@ -76,18 +78,18 @@ static System.Collections.IEnumerator WaitMainMenuUi() ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSettingDHT", l_entry.DisplayName, l_entry.GetValueAsString()); }; } - + static void Load() { ms_enabled = (bool)ms_entries[(int)ModSetting.Enabled].BoxedValue; - ms_headTracking = (bool)ms_entries[(int)ModSetting.HeadTracking].BoxedValue; - ms_eyeTracking = (bool)ms_entries[(int)ModSetting.EyeTracking].BoxedValue; - ms_blinking = (bool)ms_entries[(int)ModSetting.Blinking].BoxedValue; + ms_headTracking = (bool)ms_entries[(int)ModSetting.HeadTracking].BoxedValue; + ms_eyeTracking = (bool)ms_entries[(int)ModSetting.EyeTracking].BoxedValue; + ms_blinking = (bool)ms_entries[(int)ModSetting.Blinking].BoxedValue; ms_mirrored = (bool)ms_entries[(int)ModSetting.Mirrored].BoxedValue; ms_smoothing = ((int)ms_entries[(int)ModSetting.Smoothing].BoxedValue) * 0.01f; ms_faceOverride = (bool)ms_entries[(int)ModSetting.FaceOverride].BoxedValue; } - + static void OnSliderUpdate(string p_name, string p_value) { if(Enum.TryParse(p_name, out ModSetting l_setting)) @@ -105,7 +107,7 @@ static void OnSliderUpdate(string p_name, string p_value) ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); } } - + static void OnToggleUpdate(string p_name, string p_value) { if(Enum.TryParse(p_name, out ModSetting l_setting)) @@ -130,13 +132,15 @@ static void OnToggleUpdate(string p_name, string p_value) { ms_eyeTracking = bool.Parse(p_value); EyeTrackingChange?.Invoke(ms_eyeTracking); - } break; + } + break; case ModSetting.Blinking: { ms_blinking = bool.Parse(p_value); BlinkingChange?.Invoke(ms_blinking); - } break; + } + break; case ModSetting.Mirrored: { @@ -149,13 +153,14 @@ static void OnToggleUpdate(string p_name, string p_value) { ms_faceOverride = bool.Parse(p_value); FaceOverrideChange?.Invoke(ms_faceOverride); - } break; + } + break; } ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); } } - + public static bool Enabled { get => ms_enabled; diff --git a/ml_dht/ml_dht.csproj b/ml_dht/ml_dht.csproj index 76ca014..5093a18 100644 --- a/ml_dht/ml_dht.csproj +++ b/ml_dht/ml_dht.csproj @@ -88,6 +88,6 @@ - copy /y "$(TargetPath)" "C:\Games\Steam\common\ChilloutVR\Mods\" + copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\" \ No newline at end of file diff --git a/ml_dht/ml_dht.csproj.user b/ml_dht/ml_dht.csproj.user index 2539084..04df561 100644 --- a/ml_dht/ml_dht.csproj.user +++ b/ml_dht/ml_dht.csproj.user @@ -1,6 +1,6 @@  - C:\Games\Steam\common\ChilloutVR\MelonLoader\;C:\Games\Steam\common\ChilloutVR\ChilloutVR_Data\Managed\ + D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\;D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\ \ No newline at end of file diff --git a/ml_egn/Main.cs b/ml_egn/Main.cs index f250abd..7b90b53 100644 --- a/ml_egn/Main.cs +++ b/ml_egn/Main.cs @@ -59,7 +59,7 @@ static void OnPropSpawned() else { if(Utils.IsMenuOpened()) - ViewManager.Instance.TriggerAlert("Prop Error", "Not connected to live instance", -1, true); + Utils.ShowMenuAlert("Prop Error", "Not connected to live instance"); else Utils.ShowHUDNotification("(Local) Client", "Unable to spawn prop", "Not connected to live instance"); } @@ -70,7 +70,7 @@ static void OnPropSpawned() } } - static void OnGameNetworkConnectionClosed(object __0, DisconnectedEventArgs __1) + static void OnGameNetworkConnectionClosed(DisconnectedEventArgs __1) { try { diff --git a/ml_lme/GestureMatcher.cs b/ml_lme/GestureMatcher.cs index dbaa640..550af8f 100644 --- a/ml_lme/GestureMatcher.cs +++ b/ml_lme/GestureMatcher.cs @@ -14,100 +14,75 @@ static class GestureMatcher new Vector2(-10f, 25f) }; - public class GesturesData + public class HandData { - readonly public static int ms_handsCount = 2; - readonly public static int ms_fingersCount = 5; - - public bool[] m_handsPresenses = null; - public Vector3[] m_handsPositons = null; - public Quaternion[] m_handsRotations = null; - public Vector3[] m_elbowsPositions = null; - public float[] m_leftFingersBends = null; - public float[] m_leftFingersSpreads = null; - public float[] m_rightFingersBends = null; - public float[] m_rightFingersSpreads = null; - - public GesturesData() + public bool m_present = false; + public Vector3 m_position = Vector3.zero; + public Quaternion m_rotation = Quaternion.identity; + public Vector3 m_elbowPosition = Vector3.zero; + public readonly float[] m_spreads = null; + public readonly float[] m_bends = null; + public float m_grabStrength = 0f; + + public HandData() { - m_handsPresenses = new bool[ms_handsCount]; - m_handsPositons = new Vector3[ms_handsCount]; - m_handsRotations = new Quaternion[ms_handsCount]; - m_elbowsPositions = new Vector3[ms_handsCount]; - m_leftFingersBends = new float[ms_fingersCount]; - m_leftFingersSpreads = new float[ms_fingersCount]; - m_rightFingersBends = new float[ms_fingersCount]; - m_rightFingersSpreads = new float[ms_fingersCount]; + m_spreads = new float[5]; + m_bends = new float[5]; + } + + public void Reset() + { + m_present = false; + for(int i = 0; i < 5; i++) + { + m_bends[i] = 0f; + m_spreads[i] = 0f; + } + m_grabStrength = 0f; } } - public static void GetGestures(Leap.Frame p_frame, ref GesturesData p_data) + public class LeapData { - // Fill as default - for(int i = 0; i < GesturesData.ms_handsCount; i++) - p_data.m_handsPresenses[i] = false; - for(int i = 0; i < GesturesData.ms_fingersCount; i++) + public readonly HandData m_leftHand = null; + public readonly HandData m_rightHand = null; + + public LeapData() { - p_data.m_leftFingersBends[i] = 0f; - p_data.m_leftFingersSpreads[i] = 0f; - p_data.m_rightFingersBends[i] = 0f; - p_data.m_leftFingersSpreads[i] = 0f; + m_leftHand = new HandData(); + m_rightHand = new HandData(); } - // Fill hands data - foreach(Leap.Hand l_hand in p_frame.Hands) + public void Reset() { - int l_sideID = (l_hand.IsLeft ? 0 : 1); - if(!p_data.m_handsPresenses[l_sideID]) - { - p_data.m_handsPresenses[l_sideID] = true; - FillHandPosition(l_hand, ref p_data.m_handsPositons[l_sideID]); - FillHandRotation(l_hand, ref p_data.m_handsRotations[l_sideID]); - FillElbowPosition(l_hand, ref p_data.m_elbowsPositions[l_sideID]); - switch(l_sideID) - { - case 0: - { - FillFingerBends(l_hand, ref p_data.m_leftFingersBends); - FilFingerSpreads(l_hand, ref p_data.m_leftFingersSpreads); - } - break; - case 1: - { - FillFingerBends(l_hand, ref p_data.m_rightFingersBends); - FilFingerSpreads(l_hand, ref p_data.m_rightFingersSpreads); - } - break; - } - } + m_leftHand.Reset(); + m_rightHand.Reset(); } } - static void FillHandPosition(Leap.Hand p_hand, ref Vector3 p_pos) + public static void GetFrameData(Leap.Frame p_frame, LeapData p_data) { - // Unity's IK and FinalIK move hand bones to target, therefore - wrist - p_pos.x = p_hand.WristPosition.x; - p_pos.y = p_hand.WristPosition.y; - p_pos.z = p_hand.WristPosition.z; - } + p_data.Reset(); - static void FillHandRotation(Leap.Hand p_hand, ref Quaternion p_rot) - { - p_rot.x = p_hand.Rotation.x; - p_rot.y = p_hand.Rotation.y; - p_rot.z = p_hand.Rotation.z; - p_rot.w = p_hand.Rotation.w; + // Fill hands data + foreach(Leap.Hand l_hand in p_frame.Hands) + { + if(l_hand.IsLeft && !p_data.m_leftHand.m_present) + FillHandData(l_hand, p_data.m_leftHand); + if(l_hand.IsRight && !p_data.m_rightHand.m_present) + FillHandData(l_hand, p_data.m_rightHand); + } } - static void FillElbowPosition(Leap.Hand p_hand, ref Vector3 p_pos) + static void FillHandData(Leap.Hand p_hand, HandData p_data) { - p_pos.x = p_hand.Arm.ElbowPosition.x; - p_pos.y = p_hand.Arm.ElbowPosition.y; - p_pos.z = p_hand.Arm.ElbowPosition.z; - } + // Unity's IK and FinalIK move hand bones to target, therefore - wrist + p_data.m_present = true; + p_data.m_position.Set(p_hand.WristPosition.x, p_hand.WristPosition.y, p_hand.WristPosition.z); + p_data.m_rotation.Set(p_hand.Rotation.x, p_hand.Rotation.y, p_hand.Rotation.z, p_hand.Rotation.w); + p_data.m_elbowPosition.Set(p_hand.Arm.ElbowPosition.x, p_hand.Arm.ElbowPosition.y, p_hand.Arm.ElbowPosition.z); - static void FillFingerBends(Leap.Hand p_hand, ref float[] p_bends) - { + // Bends foreach(Leap.Finger l_finger in p_hand.Fingers) { Quaternion l_prevSegment = Quaternion.identity; @@ -132,12 +107,10 @@ static void FillFingerBends(Leap.Hand p_hand, ref float[] p_bends) l_angle += l_curAngle; } - p_bends[(int)l_finger.Type] = Mathf.InverseLerp(0f, (l_finger.Type == Leap.Finger.FingerType.TYPE_THUMB) ? 90f : 180f, l_angle); + p_data.m_bends[(int)l_finger.Type] = Mathf.InverseLerp(0f, (l_finger.Type == Leap.Finger.FingerType.TYPE_THUMB) ? 90f : 180f, l_angle); } - } - static void FilFingerSpreads(Leap.Hand p_hand, ref float[] p_spreads) - { + // Spreads foreach(Leap.Finger l_finger in p_hand.Fingers) { float l_angle = 0f; @@ -162,13 +135,15 @@ static void FilFingerSpreads(Leap.Hand p_hand, ref float[] p_spreads) if(l_finger.Type != Leap.Finger.FingerType.TYPE_THUMB) { if(l_angle < 0f) - p_spreads[(int)l_finger.Type] = 0.5f * Mathf.InverseLerp(ms_fingerLimits[(int)l_finger.Type].x, 0f, l_angle); + p_data.m_spreads[(int)l_finger.Type] = 0.5f * Mathf.InverseLerp(ms_fingerLimits[(int)l_finger.Type].x, 0f, l_angle); else - p_spreads[(int)l_finger.Type] = 0.5f + 0.5f * Mathf.InverseLerp(0f, ms_fingerLimits[(int)l_finger.Type].y, l_angle); + p_data.m_spreads[(int)l_finger.Type] = 0.5f + 0.5f * Mathf.InverseLerp(0f, ms_fingerLimits[(int)l_finger.Type].y, l_angle); } else - p_spreads[(int)l_finger.Type] = Mathf.InverseLerp(ms_fingerLimits[(int)l_finger.Type].x, ms_fingerLimits[(int)l_finger.Type].y, l_angle); + p_data.m_spreads[(int)l_finger.Type] = Mathf.InverseLerp(ms_fingerLimits[(int)l_finger.Type].x, ms_fingerLimits[(int)l_finger.Type].y, l_angle); } + + p_data.m_grabStrength = (p_data.m_bends[1] + p_data.m_bends[2] + p_data.m_bends[3] + p_data.m_bends[4]) * 0.25f; } } } diff --git a/ml_lme/LeapInput.cs b/ml_lme/LeapInput.cs new file mode 100644 index 0000000..b71875e --- /dev/null +++ b/ml_lme/LeapInput.cs @@ -0,0 +1,247 @@ +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using ABI_RC.Systems.IK; +using System.Collections; +using System.Reflection; +using UnityEngine; + +namespace ml_lme +{ + [DisallowMultipleComponent] + class LeapInput : CVRInputModule + { + static readonly FieldInfo ms_indexGestureToggle = typeof(InputModuleSteamVR).GetField("_steamVrIndexGestureToggleValue", BindingFlags.Instance | BindingFlags.NonPublic); + + CVRInputManager m_inputManager = null; + InputModuleSteamVR m_steamVrModule = null; + bool m_inVR = false; + + ControllerRay m_handRayLeft = null; + ControllerRay m_handRayRight = null; + LineRenderer m_lineLeft = null; + LineRenderer m_lineRight = null; + bool m_interactLeft = false; + bool m_interactRight = false; + bool m_gripLeft = false; + bool m_gripRight = false; + + public new void Start() + { + base.Start(); + + m_inputManager = CVRInputManager.Instance; // _inputManager is stripped out, cool beans + m_steamVrModule = this.GetComponent(); + m_inVR = Utils.IsInVR(); + + m_handRayLeft = LeapTracking.GetInstance().GetLeftHand().gameObject.AddComponent(); + m_handRayLeft.hand = true; + m_handRayLeft.generalMask = -1485; + m_handRayLeft.isInteractionRay = true; + m_handRayLeft.triggerGazeEvents = false; + m_handRayLeft.holderRoot = m_handRayLeft.gameObject; + + m_handRayRight = LeapTracking.GetInstance().GetRightHand().gameObject.AddComponent(); + m_handRayRight.hand = false; + m_handRayRight.generalMask = -1485; + m_handRayRight.isInteractionRay = true; + m_handRayRight.triggerGazeEvents = false; + m_handRayRight.holderRoot = m_handRayRight.gameObject; + + m_lineLeft = m_handRayLeft.gameObject.AddComponent(); + m_lineLeft.endWidth = 1f; + m_lineLeft.startWidth = 1f; + m_lineLeft.textureMode = LineTextureMode.Tile; + m_lineLeft.useWorldSpace = false; + m_lineLeft.widthMultiplier = 1f; + m_lineLeft.allowOcclusionWhenDynamic = false; + m_lineLeft.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; + m_lineLeft.enabled = false; + m_lineLeft.receiveShadows = false; + m_handRayLeft.lineRenderer = m_lineLeft; + + m_lineRight = m_handRayRight.gameObject.AddComponent(); + m_lineRight.endWidth = 1f; + m_lineRight.startWidth = 1f; + m_lineRight.textureMode = LineTextureMode.Tile; + m_lineRight.useWorldSpace = false; + m_lineRight.widthMultiplier = 1f; + m_lineRight.allowOcclusionWhenDynamic = false; + m_lineRight.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; + m_lineRight.enabled = false; + m_lineRight.receiveShadows = false; + m_handRayRight.lineRenderer = m_lineRight; + + Settings.EnabledChange += this.OnEnableChange; + Settings.InputChange += this.OnInputChange; + + OnEnableChange(Settings.Enabled); + OnInputChange(Settings.Input); + + MelonLoader.MelonCoroutines.Start(WaitForMaterial()); + } + + IEnumerator WaitForMaterial() + { + while(PlayerSetup.Instance == null) + yield return null; + while(PlayerSetup.Instance.leftRay == null) + yield return null; + while(PlayerSetup.Instance.leftRay.lineRenderer == null) + yield return null; + + m_lineLeft.material = PlayerSetup.Instance.leftRay.lineRenderer.material; + m_lineRight.material = PlayerSetup.Instance.leftRay.lineRenderer.material; + } + + void OnDestroy() + { + Settings.EnabledChange -= this.OnEnableChange; + Settings.InputChange -= this.OnInputChange; + } + + void Update() + { + GestureMatcher.LeapData l_data = LeapManager.GetInstance().GetLatestData(); + + if(Settings.Enabled) + { + if(l_data.m_leftHand.m_present) + SetFingersInput(l_data.m_leftHand, true); + if(l_data.m_rightHand.m_present) + SetFingersInput(l_data.m_rightHand, false); + } + + m_handRayLeft.enabled = (l_data.m_leftHand.m_present && (!m_inVR || (VRTrackerManager.Instance.leftHand == null) || !VRTrackerManager.Instance.leftHand.active || !Settings.FingersOnly)); + m_handRayRight.enabled = (l_data.m_rightHand.m_present && (!m_inVR || (VRTrackerManager.Instance.rightHand == null) || !VRTrackerManager.Instance.rightHand.active || !Settings.FingersOnly)); + } + + public override void UpdateInput() + { + if(Settings.Enabled && Settings.Input) + { + GestureMatcher.LeapData l_data = LeapManager.GetInstance().GetLatestData(); + + if(l_data.m_leftHand.m_present && (!m_inVR || (VRTrackerManager.Instance.leftHand == null) || !VRTrackerManager.Instance.leftHand.active || !Settings.FingersOnly)) + { + float l_strength = l_data.m_leftHand.m_grabStrength; + m_inputManager.interactLeftValue = l_strength; + if(m_interactLeft != (l_strength > Settings.HoldThreadhold)) + { + m_interactLeft = (l_strength > Settings.HoldThreadhold); + m_inputManager.interactLeftUp |= m_interactLeft; + m_inputManager.interactLeftDown |= m_interactLeft; + } + m_inputManager.gripLeftValue = 1f - l_strength; // Inversed + if(m_gripLeft != (l_strength < Settings.ReleaseThreadhold)) + { + m_gripLeft = (l_strength < Settings.ReleaseThreadhold); + m_inputManager.gripLeftUp |= m_gripLeft; + m_inputManager.gripLeftDown |= m_gripLeft; + } + } + + if(l_data.m_rightHand.m_present && (!m_inVR || (VRTrackerManager.Instance.rightHand == null) || !VRTrackerManager.Instance.rightHand.active || !Settings.FingersOnly)) + { + float l_strength = l_data.m_rightHand.m_grabStrength; + m_inputManager.interactRightValue = l_strength; + if(m_interactRight != (l_strength > Settings.HoldThreadhold)) + { + m_interactRight = (l_strength > Settings.HoldThreadhold); + m_inputManager.interactRightUp |= m_interactRight; + m_inputManager.interactRightDown |= m_interactRight; + } + m_inputManager.gripRightValue = 1f - l_strength; + if(m_gripRight != (l_strength < Settings.HoldThreadhold)) + { + m_gripRight = (l_strength < Settings.HoldThreadhold); + m_inputManager.gripRightUp |= m_gripRight; + m_inputManager.gripRightDown |= m_gripRight; + } + } + } + } + + // Settings changes + void OnEnableChange(bool p_state) + { + OnInputChange(p_state && Settings.Input); + UpdateFingerTracking(); + } + + void OnInputChange(bool p_state) + { + (m_handRayLeft as MonoBehaviour).enabled = (p_state && Settings.Enabled); + (m_handRayRight as MonoBehaviour).enabled = (p_state && Settings.Enabled); + m_lineLeft.enabled = (p_state && Settings.Enabled); + m_lineRight.enabled = (p_state && Settings.Enabled); + + if(!p_state) + { + m_handRayLeft.DropObject(true); + m_handRayLeft.ClearGrabbedObject(); + + m_handRayRight.DropObject(true); + m_handRayRight.ClearGrabbedObject(); + + m_interactLeft = false; + m_interactRight = false; + m_gripLeft = false; + m_gripRight = false; + } + } + + // Game events + internal void OnAvatarSetup() + { + m_inVR = Utils.IsInVR(); + UpdateFingerTracking(); + } + + internal void OnRayScale(float p_scale) + { + m_handRayLeft.SetRayScale(p_scale); + m_handRayRight.SetRayScale(p_scale); + } + + // Arbitrary + void UpdateFingerTracking() + { + m_inputManager.individualFingerTracking = (Settings.Enabled || (m_inVR && Utils.AreKnucklesInUse() && !(bool)ms_indexGestureToggle.GetValue(m_steamVrModule))); + IKSystem.Instance.FingerSystem.controlActive = m_inputManager.individualFingerTracking; + } + + void SetFingersInput(GestureMatcher.HandData p_hand, bool p_left) + { + m_inputManager.individualFingerTracking = true; + IKSystem.Instance.FingerSystem.controlActive = true; + + if(p_left) + { + m_inputManager.fingerCurlLeftThumb = p_hand.m_bends[0]; + m_inputManager.fingerCurlLeftIndex = p_hand.m_bends[1]; + m_inputManager.fingerCurlLeftMiddle = p_hand.m_bends[2]; + m_inputManager.fingerCurlLeftRing = p_hand.m_bends[3]; + m_inputManager.fingerCurlLeftPinky = p_hand.m_bends[4]; + IKSystem.Instance.FingerSystem.leftThumbCurl = p_hand.m_bends[0]; + IKSystem.Instance.FingerSystem.leftIndexCurl = p_hand.m_bends[1]; + IKSystem.Instance.FingerSystem.leftMiddleCurl = p_hand.m_bends[2]; + IKSystem.Instance.FingerSystem.leftRingCurl = p_hand.m_bends[3]; + IKSystem.Instance.FingerSystem.leftPinkyCurl = p_hand.m_bends[4]; + } + else + { + m_inputManager.fingerCurlRightThumb = p_hand.m_bends[0]; + m_inputManager.fingerCurlRightIndex = p_hand.m_bends[1]; + m_inputManager.fingerCurlRightMiddle = p_hand.m_bends[2]; + m_inputManager.fingerCurlRightRing = p_hand.m_bends[3]; + m_inputManager.fingerCurlRightPinky = p_hand.m_bends[4]; + IKSystem.Instance.FingerSystem.rightThumbCurl = p_hand.m_bends[0]; + IKSystem.Instance.FingerSystem.rightIndexCurl = p_hand.m_bends[1]; + IKSystem.Instance.FingerSystem.rightMiddleCurl = p_hand.m_bends[2]; + IKSystem.Instance.FingerSystem.rightRingCurl = p_hand.m_bends[3]; + IKSystem.Instance.FingerSystem.rightPinkyCurl = p_hand.m_bends[4]; + } + } + } +} diff --git a/ml_lme/LeapManager.cs b/ml_lme/LeapManager.cs new file mode 100644 index 0000000..33aa249 --- /dev/null +++ b/ml_lme/LeapManager.cs @@ -0,0 +1,204 @@ +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using System.Collections; +using UnityEngine; + +namespace ml_lme +{ + [DisallowMultipleComponent] + class LeapManager : MonoBehaviour + { + static LeapManager ms_instance = null; + + readonly Leap.Controller m_leapController = null; + readonly GestureMatcher.LeapData m_leapData = null; + + LeapTracking m_leapTracking = null; + LeapTracked m_leapTracked = null; + LeapInput m_leapInput = null; + + public static LeapManager GetInstance() => ms_instance; + + internal LeapManager() + { + m_leapController = new Leap.Controller(); + m_leapData = new GestureMatcher.LeapData(); + } + ~LeapManager() + { + m_leapController.StopConnection(); + m_leapController.Dispose(); + } + + void Start() + { + if(ms_instance == null) + ms_instance = this; + + 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; + + MelonLoader.MelonCoroutines.Start(WaitForInputManager()); + MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); + + OnEnableChange(Settings.Enabled); + OnTrackingModeChange(Settings.TrackingMode); + } + + void OnDestroy() + { + if(ms_instance == this) + ms_instance = null; + + 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; + } + + IEnumerator WaitForInputManager() + { + while(CVRInputManager.Instance == null) + yield return null; + + m_leapInput = CVRInputManager.Instance.gameObject.AddComponent(); + } + + IEnumerator WaitForLocalPlayer() + { + while(PlayerSetup.Instance == null) + yield return null; + + 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(); + GestureMatcher.GetFrameData(l_frame, m_leapData); + } + } + } + + public GestureMatcher.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_leapTracked != null) + m_leapTracked.OnAvatarClear(); + } + + internal void OnAvatarSetup() + { + if(m_leapTracking != null) + m_leapTracking.OnAvatarSetup(); + if(m_leapInput != null) + m_leapInput.OnAvatarSetup(); + if(m_leapTracked != null) + m_leapTracked.OnAvatarSetup(); + } + + internal void OnCalibrate() + { + if(m_leapTracked != null) + m_leapTracked.OnCalibrate(); + } + + internal void OnRayScale(float p_scale) + { + if(m_leapInput != null) + m_leapInput.OnRayScale(p_scale); + } + + // 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 ee1d0ae..167ba6d 100644 --- a/ml_lme/LeapTracked.cs +++ b/ml_lme/LeapTracked.cs @@ -1,5 +1,4 @@ using ABI_RC.Core.Player; -using ABI_RC.Core.Savior; using ABI_RC.Systems.IK; using RootMotion.FinalIK; using System.Reflection; @@ -11,20 +10,17 @@ namespace ml_lme class LeapTracked : MonoBehaviour { static readonly float[] ms_tposeMuscles = typeof(ABI_RC.Systems.IK.SubSystems.BodySystem).GetField("TPoseMuscles", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null) as float[]; - static readonly FieldInfo ms_indexGestureToggle = typeof(InputModuleSteamVR).GetField("_steamVrIndexGestureToggleValue", BindingFlags.Instance | BindingFlags.NonPublic); static readonly Quaternion ms_offsetLeft = Quaternion.Euler(0f, 0f, 270f); static readonly Quaternion ms_offsetRight = Quaternion.Euler(0f, 0f, 90f); static readonly Quaternion ms_offsetLeftDesktop = Quaternion.Euler(0f, 90f, 0f); static readonly Quaternion ms_offsetRightDesktop = Quaternion.Euler(0f, 270f, 0f); - InputModuleSteamVR m_steamVrModule = null; VRIK m_vrIK = null; Vector2 m_armsWeights = Vector2.zero; - bool m_isInVR = false; + bool m_inVR = false; Transform m_origElbowLeft = null; Transform m_origElbowRight = null; Transform m_hips = null; - Vector3 m_hipsLocal = Vector3.zero; bool m_enabled = true; bool m_fingersOnly = false; @@ -34,38 +30,32 @@ class LeapTracked : MonoBehaviour ArmIK m_rightIK = null; HumanPoseHandler m_poseHandler = null; HumanPose m_pose; - Transform m_leftHand = null; - Transform m_rightHand = null; Transform m_leftHandTarget = null; Transform m_rightHandTarget = null; - Transform m_leftElbow = null; - Transform m_rightElbow = null; bool m_leftTargetActive = false; bool m_rightTargetActive = false; void Start() { - m_steamVrModule = CVRInputManager.Instance.GetComponent(); - m_isInVR = Utils.IsInVR(); + m_inVR = Utils.IsInVR(); - if(m_leftHand != null) - { - m_leftHandTarget = new GameObject("RotationTarget").transform; - m_leftHandTarget.parent = m_leftHand; - m_leftHandTarget.localPosition = Vector3.zero; - m_leftHandTarget.localRotation = Quaternion.identity; - } - if(m_rightHand != null) - { - m_rightHandTarget = new GameObject("RotationTarget").transform; - m_rightHandTarget.parent = m_rightHand; - m_rightHandTarget.localPosition = Vector3.zero; - m_rightHandTarget.localRotation = Quaternion.identity; - } + m_leftHandTarget = new GameObject("RotationTarget").transform; + m_leftHandTarget.parent = LeapTracking.GetInstance().GetLeftHand(); + m_leftHandTarget.localPosition = Vector3.zero; + m_leftHandTarget.localRotation = Quaternion.identity; + + m_rightHandTarget = new GameObject("RotationTarget").transform; + m_rightHandTarget.parent = LeapTracking.GetInstance().GetRightHand(); + m_rightHandTarget.localPosition = Vector3.zero; + m_rightHandTarget.localRotation = Quaternion.identity; Settings.EnabledChange += this.SetEnabled; Settings.FingersOnlyChange += this.SetFingersOnly; Settings.TrackElbowsChange += this.SetTrackElbows; + + SetEnabled(Settings.Enabled); + SetFingersOnly(Settings.FingersOnly); + SetTrackElbows(Settings.TrackElbows); } void OnDestroy() @@ -75,17 +65,16 @@ void OnDestroy() Settings.TrackElbowsChange -= this.SetTrackElbows; } - public void SetEnabled(bool p_state) + void SetEnabled(bool p_state) { m_enabled = p_state; - RefreshFingersTracking(); RefreshArmIK(); if(!m_enabled || m_fingersOnly) RestoreVRIK(); } - public void SetFingersOnly(bool p_state) + void SetFingersOnly(bool p_state) { m_fingersOnly = p_state; @@ -94,7 +83,7 @@ public void SetFingersOnly(bool p_state) RestoreVRIK(); } - public void SetTrackElbows(bool p_state) + void SetTrackElbows(bool p_state) { m_trackElbows = p_state; @@ -107,190 +96,148 @@ public void SetTrackElbows(bool p_state) RestoreVRIK(); } - public void SetTransforms(Transform p_left, Transform p_right, Transform p_leftElbow, Transform p_rightElbow) - { - m_leftHand = p_left; - m_rightHand = p_right; - - m_leftElbow = p_leftElbow; - m_rightElbow = p_rightElbow; - } - - public void UpdateTracking(GestureMatcher.GesturesData p_data) + void Update() { if(m_enabled) { + GestureMatcher.LeapData l_data = LeapManager.GetInstance().GetLatestData(); + if((m_leftIK != null) && (m_rightIK != null)) { - m_leftIK.solver.IKPositionWeight = Mathf.Lerp(m_leftIK.solver.IKPositionWeight, (p_data.m_handsPresenses[0] && !m_fingersOnly) ? 1f : 0f, 0.25f); - m_leftIK.solver.IKRotationWeight = Mathf.Lerp(m_leftIK.solver.IKRotationWeight, (p_data.m_handsPresenses[0] && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_leftIK.solver.IKPositionWeight = Mathf.Lerp(m_leftIK.solver.IKPositionWeight, (l_data.m_leftHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_leftIK.solver.IKRotationWeight = Mathf.Lerp(m_leftIK.solver.IKRotationWeight, (l_data.m_leftHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); if(m_trackElbows) - m_leftIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_leftIK.solver.arm.bendGoalWeight, (p_data.m_handsPresenses[0] && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_leftIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_leftIK.solver.arm.bendGoalWeight, (l_data.m_leftHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); - m_rightIK.solver.IKPositionWeight = Mathf.Lerp(m_rightIK.solver.IKPositionWeight, (p_data.m_handsPresenses[1] && !m_fingersOnly) ? 1f : 0f, 0.25f); - m_rightIK.solver.IKRotationWeight = Mathf.Lerp(m_rightIK.solver.IKRotationWeight, (p_data.m_handsPresenses[1] && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_rightIK.solver.IKPositionWeight = Mathf.Lerp(m_rightIK.solver.IKPositionWeight, (l_data.m_rightHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_rightIK.solver.IKRotationWeight = Mathf.Lerp(m_rightIK.solver.IKRotationWeight, (l_data.m_rightHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); if(m_trackElbows) - m_rightIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_rightIK.solver.arm.bendGoalWeight, (p_data.m_handsPresenses[1] && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_rightIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_rightIK.solver.arm.bendGoalWeight, (l_data.m_rightHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f); } if((m_vrIK != null) && !m_fingersOnly) { - if(p_data.m_handsPresenses[0] && !m_leftTargetActive) + if(l_data.m_leftHand.m_present && !m_leftTargetActive) { m_vrIK.solver.leftArm.target = m_leftHandTarget; - m_vrIK.solver.leftArm.bendGoal = m_leftElbow; + m_vrIK.solver.leftArm.bendGoal = LeapTracking.GetInstance().GetLeftElbow(); m_vrIK.solver.leftArm.bendGoalWeight = (m_trackElbows ? 1f : 0f); m_leftTargetActive = true; } - if(!p_data.m_handsPresenses[0] && m_leftTargetActive) + if(!l_data.m_leftHand.m_present && m_leftTargetActive) { - m_vrIK.solver.leftArm.target = IKSystem.Instance.leftHandAnchor; + m_vrIK.solver.leftArm.target = (m_inVR ? IKSystem.Instance.leftHandAnchor : null); m_vrIK.solver.leftArm.bendGoal = m_origElbowLeft; m_vrIK.solver.leftArm.bendGoalWeight = ((m_origElbowLeft != null) ? 1f : 0f); m_leftTargetActive = false; } - if(p_data.m_handsPresenses[1] && !m_rightTargetActive) + if(l_data.m_rightHand.m_present && !m_rightTargetActive) { m_vrIK.solver.rightArm.target = m_rightHandTarget; - m_vrIK.solver.rightArm.bendGoal = m_rightElbow; + m_vrIK.solver.rightArm.bendGoal = LeapTracking.GetInstance().GetRightElbow(); m_vrIK.solver.rightArm.bendGoalWeight = (m_trackElbows ? 1f : 0f); m_rightTargetActive = true; } - if(!p_data.m_handsPresenses[1] && m_rightTargetActive) + if(!l_data.m_rightHand.m_present && m_rightTargetActive) { - m_vrIK.solver.rightArm.target = IKSystem.Instance.rightHandAnchor; + m_vrIK.solver.rightArm.target = (m_inVR ? IKSystem.Instance.rightHandAnchor : null); m_vrIK.solver.rightArm.bendGoal = m_origElbowRight; m_vrIK.solver.rightArm.bendGoalWeight = ((m_origElbowRight != null) ? 1f : 0f); m_rightTargetActive = false; } } - - if(p_data.m_handsPresenses[0]) - { - CVRInputManager.Instance.individualFingerTracking = true; - CVRInputManager.Instance.fingerCurlLeftThumb = p_data.m_leftFingersBends[0]; - CVRInputManager.Instance.fingerCurlLeftIndex = p_data.m_leftFingersBends[1]; - CVRInputManager.Instance.fingerCurlLeftMiddle = p_data.m_leftFingersBends[2]; - CVRInputManager.Instance.fingerCurlLeftRing = p_data.m_leftFingersBends[3]; - CVRInputManager.Instance.fingerCurlLeftPinky = p_data.m_leftFingersBends[4]; - - IKSystem.Instance.FingerSystem.controlActive = true; - IKSystem.Instance.FingerSystem.leftThumbCurl = p_data.m_leftFingersBends[0]; - IKSystem.Instance.FingerSystem.leftIndexCurl = p_data.m_leftFingersBends[1]; - IKSystem.Instance.FingerSystem.leftMiddleCurl = p_data.m_leftFingersBends[2]; - IKSystem.Instance.FingerSystem.leftRingCurl = p_data.m_leftFingersBends[3]; - IKSystem.Instance.FingerSystem.leftPinkyCurl = p_data.m_leftFingersBends[4]; - } - - if(p_data.m_handsPresenses[1]) - { - CVRInputManager.Instance.individualFingerTracking = true; - CVRInputManager.Instance.fingerCurlRightThumb = p_data.m_rightFingersBends[0]; - CVRInputManager.Instance.fingerCurlRightIndex = p_data.m_rightFingersBends[1]; - CVRInputManager.Instance.fingerCurlRightMiddle = p_data.m_rightFingersBends[2]; - CVRInputManager.Instance.fingerCurlRightRing = p_data.m_rightFingersBends[3]; - CVRInputManager.Instance.fingerCurlRightPinky = p_data.m_rightFingersBends[4]; - - IKSystem.Instance.FingerSystem.controlActive = true; - IKSystem.Instance.FingerSystem.rightThumbCurl = p_data.m_rightFingersBends[0]; - IKSystem.Instance.FingerSystem.rightIndexCurl = p_data.m_rightFingersBends[1]; - IKSystem.Instance.FingerSystem.rightMiddleCurl = p_data.m_rightFingersBends[2]; - IKSystem.Instance.FingerSystem.rightRingCurl = p_data.m_rightFingersBends[3]; - IKSystem.Instance.FingerSystem.rightPinkyCurl = p_data.m_rightFingersBends[4]; - } } } - public void UpdateTrackingLate(GestureMatcher.GesturesData p_data) + void LateUpdate() { - if(m_enabled && !m_isInVR && (m_poseHandler != null)) + if(m_enabled && !m_inVR && (m_poseHandler != null)) { - if(m_hips != null) - m_hipsLocal = m_hips.localPosition; + GestureMatcher.LeapData l_data = LeapManager.GetInstance().GetLatestData(); + + Vector3 l_hipsLocalPos = m_hips.localPosition; m_poseHandler.GetHumanPose(ref m_pose); - UpdateFingers(p_data); + UpdateFingers(l_data); m_poseHandler.SetHumanPose(ref m_pose); - if(m_hips != null) - m_hips.localPosition = m_hipsLocal; + m_hips.localPosition = l_hipsLocalPos; } } - void UpdateFingers(GestureMatcher.GesturesData p_data) + void UpdateFingers(GestureMatcher.LeapData p_data) { - if(p_data.m_handsPresenses[0]) + if(p_data.m_leftHand.m_present) { - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb1Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_leftFingersBends[0])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb2Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_leftFingersBends[0])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb3Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_leftFingersBends[0])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumbSpread, Mathf.Lerp(-1.5f, 1.0f, p_data.m_leftFingersSpreads[0])); // Ok - - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[1])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[1])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[1])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndexSpread, Mathf.Lerp(1f, -1f, p_data.m_leftFingersSpreads[1])); // Ok - - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[2])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[2])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[2])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddleSpread, Mathf.Lerp(2f, -2f, p_data.m_leftFingersSpreads[2])); - - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[3])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[3])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[3])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRingSpread, Mathf.Lerp(-2f, 2f, p_data.m_leftFingersSpreads[3])); - - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[4])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[4])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[4])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittleSpread, Mathf.Lerp(-0.5f, 1f, p_data.m_leftFingersSpreads[4])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb1Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_leftHand.m_bends[0])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb2Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_leftHand.m_bends[0])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb3Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_leftHand.m_bends[0])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumbSpread, Mathf.Lerp(-1.5f, 1.0f, p_data.m_leftHand.m_spreads[0])); // Ok + + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[1])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[1])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[1])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndexSpread, Mathf.Lerp(1f, -1f, p_data.m_leftHand.m_spreads[1])); // Ok + + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[2])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[2])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[2])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddleSpread, Mathf.Lerp(2f, -2f, p_data.m_leftHand.m_spreads[2])); + + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[3])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[3])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[3])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRingSpread, Mathf.Lerp(-2f, 2f, p_data.m_leftHand.m_spreads[3])); + + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[4])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[4])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[4])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittleSpread, Mathf.Lerp(-0.5f, 1f, p_data.m_leftHand.m_spreads[4])); } - if(p_data.m_handsPresenses[1]) + if(p_data.m_rightHand.m_present) { - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb1Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_rightFingersBends[0])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb2Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_rightFingersBends[0])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb3Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_rightFingersBends[0])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumbSpread, Mathf.Lerp(-1.5f, 1.0f, p_data.m_rightFingersSpreads[0])); // Ok - - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[1])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[1])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[1])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndexSpread, Mathf.Lerp(1f, -1f, p_data.m_rightFingersSpreads[1])); // Ok - - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[2])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[2])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[2])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddleSpread, Mathf.Lerp(2f, -2f, p_data.m_rightFingersSpreads[2])); - - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[3])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[3])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[3])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRingSpread, Mathf.Lerp(-2f, 2f, p_data.m_rightFingersSpreads[3])); - - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[4])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[4])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[4])); - UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittleSpread, Mathf.Lerp(-0.5f, 1f, p_data.m_rightFingersSpreads[4])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb1Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_rightHand.m_bends[0])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb2Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_rightHand.m_bends[0])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb3Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_rightHand.m_bends[0])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumbSpread, Mathf.Lerp(-1.5f, 1.0f, p_data.m_rightHand.m_spreads[0])); // Ok + + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[1])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[1])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[1])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndexSpread, Mathf.Lerp(1f, -1f, p_data.m_rightHand.m_spreads[1])); // Ok + + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[2])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[2])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[2])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddleSpread, Mathf.Lerp(2f, -2f, p_data.m_rightHand.m_spreads[2])); + + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[3])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[3])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[3])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRingSpread, Mathf.Lerp(-2f, 2f, p_data.m_rightHand.m_spreads[3])); + + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[4])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[4])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[4])); + UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittleSpread, Mathf.Lerp(-0.5f, 1f, p_data.m_rightHand.m_spreads[4])); } } - public void OnAvatarClear() + internal void OnAvatarClear() { m_vrIK = null; m_origElbowLeft = null; m_origElbowRight = null; m_hips = null; - m_hipsLocal = Vector3.zero; m_armsWeights = Vector2.zero; m_leftIK = null; m_rightIK = null; m_leftTargetActive = false; m_rightTargetActive = false; - if(!m_isInVR) + if(!m_inVR) m_poseHandler?.Dispose(); m_poseHandler = null; @@ -300,27 +247,27 @@ public void OnAvatarClear() m_rightHandTarget.localRotation = Quaternion.identity; } - public void OnSetupAvatar() + internal void OnAvatarSetup() { - m_isInVR = Utils.IsInVR(); + m_inVR = Utils.IsInVR(); m_vrIK = PlayerSetup.Instance._animator.GetComponent(); - RefreshFingersTracking(); - if(PlayerSetup.Instance._animator.isHuman) { m_hips = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Hips); - if(!m_isInVR) + 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(); - l_tPose.bodyPosition = m_pose.bodyPosition; - l_tPose.bodyRotation = m_pose.bodyRotation; - l_tPose.muscles = new float[m_pose.muscles.Length]; + 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); @@ -353,7 +300,7 @@ public void OnSetupAvatar() PlayerSetup.Instance._animator.transform ); m_leftIK.solver.arm.target = m_leftHandTarget; - m_leftIK.solver.arm.bendGoal = m_leftElbow; + m_leftIK.solver.arm.bendGoal = LeapTracking.GetInstance().GetLeftElbow(); m_leftIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f); m_leftIK.enabled = (m_enabled && !m_fingersOnly); @@ -368,7 +315,7 @@ public void OnSetupAvatar() PlayerSetup.Instance._animator.transform ); m_rightIK.solver.arm.target = m_rightHandTarget; - m_rightIK.solver.arm.bendGoal = m_rightElbow; + m_rightIK.solver.arm.bendGoal = LeapTracking.GetInstance().GetRightElbow(); m_rightIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f); m_rightIK.enabled = (m_enabled && !m_fingersOnly); @@ -382,7 +329,7 @@ public void OnSetupAvatar() } } - public void OnCalibrate() + internal void OnCalibrate() { if(m_vrIK != null) { @@ -421,14 +368,14 @@ void RestoreVRIK() { if(m_leftTargetActive) { - m_vrIK.solver.leftArm.target = IKSystem.Instance.leftHandAnchor; + m_vrIK.solver.leftArm.target = (m_inVR ? IKSystem.Instance.leftHandAnchor : null); m_vrIK.solver.leftArm.bendGoal = m_origElbowLeft; m_vrIK.solver.leftArm.bendGoalWeight = ((m_origElbowLeft != null) ? 1f : 0f); m_leftTargetActive = false; } if(m_rightTargetActive) { - m_vrIK.solver.rightArm.target = IKSystem.Instance.rightHandAnchor; + m_vrIK.solver.rightArm.target = (m_inVR ? IKSystem.Instance.rightHandAnchor : null); m_vrIK.solver.rightArm.bendGoal = m_origElbowRight; m_vrIK.solver.rightArm.bendGoalWeight = ((m_origElbowRight != null) ? 1f : 0f); m_rightTargetActive = false; @@ -445,12 +392,6 @@ void RefreshArmIK() } } - void RefreshFingersTracking() - { - CVRInputManager.Instance.individualFingerTracking = (m_enabled || (m_isInVR && Utils.AreKnucklesInUse() && !(bool)ms_indexGestureToggle.GetValue(m_steamVrModule))); - IKSystem.Instance.FingerSystem.controlActive = CVRInputManager.Instance.individualFingerTracking; - } - static void UpdatePoseMuscle(ref HumanPose p_pose, int p_index, float p_value) { if(p_pose.muscles.Length > p_index) diff --git a/ml_lme/LeapTracking.cs b/ml_lme/LeapTracking.cs new file mode 100644 index 0000000..bc71ac5 --- /dev/null +++ b/ml_lme/LeapTracking.cs @@ -0,0 +1,221 @@ +using ABI_RC.Core.Player; +using System.Collections; +using UnityEngine; + +namespace ml_lme +{ + [DisallowMultipleComponent] + class LeapTracking : MonoBehaviour + { + static LeapTracking ms_instance = null; + static Quaternion ms_identityRotation = Quaternion.identity; + + bool m_inVR = false; + + GameObject m_leapHandLeft = null; + GameObject m_leapHandRight = null; + GameObject m_leapElbowLeft = null; + GameObject m_leapElbowRight = null; + GameObject m_leapControllerModel = null; + + public static LeapTracking GetInstance() => ms_instance; + + void Start() + { + if(ms_instance == null) + ms_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; + } + + Settings.DesktopOffsetChange += this.OnDesktopOffsetChange; + Settings.ModelVisibilityChange += this.OnModelVisibilityChange; + Settings.TrackingModeChange += this.OnTrackingModeChange; + Settings.RootAngleChange += this.OnRootAngleChange; + Settings.HeadAttachChange += this.OnHeadAttachChange; + Settings.HeadOffsetChange += this.OnHeadOffsetChange; + + MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); + + OnModelVisibilityChange(Settings.ModelVisibility); + OnTrackingModeChange(Settings.TrackingMode); + OnRootAngleChange(Settings.RootAngle); + } + + IEnumerator WaitForLocalPlayer() + { + while(PlayerSetup.Instance == null) + yield return null; + + OnDesktopOffsetChange(Settings.DesktopOffset); + OnHeadAttachChange(Settings.HeadAttach); + OnHeadOffsetChange(Settings.HeadOffset); + } + + void OnDestroy() + { + if(ms_instance == this) + ms_instance = null; + + Settings.DesktopOffsetChange -= this.OnDesktopOffsetChange; + Settings.ModelVisibilityChange -= this.OnModelVisibilityChange; + Settings.TrackingModeChange -= this.OnTrackingModeChange; + Settings.RootAngleChange -= this.OnRootAngleChange; + Settings.HeadAttachChange -= this.OnHeadAttachChange; + Settings.HeadOffsetChange -= this.OnHeadOffsetChange; + } + + void Update() + { + if(Settings.Enabled) + { + GestureMatcher.LeapData l_data = LeapManager.GetInstance().GetLatestData(); + + if(l_data.m_leftHand.m_present) + { + Utils.LeapToUnity(ref l_data.m_leftHand.m_position, ref l_data.m_leftHand.m_rotation, Settings.TrackingMode); + m_leapHandLeft.transform.localPosition = l_data.m_leftHand.m_position; + m_leapHandLeft.transform.localRotation = l_data.m_leftHand.m_rotation; + + Utils.LeapToUnity(ref l_data.m_leftHand.m_elbowPosition, ref ms_identityRotation, Settings.TrackingMode); + m_leapElbowLeft.transform.localPosition = l_data.m_leftHand.m_elbowPosition; + } + + if(l_data.m_rightHand.m_present) + { + Utils.LeapToUnity(ref l_data.m_rightHand.m_position, ref l_data.m_rightHand.m_rotation, Settings.TrackingMode); + m_leapHandRight.transform.localPosition = l_data.m_rightHand.m_position; + m_leapHandRight.transform.localRotation = l_data.m_rightHand.m_rotation; + + Utils.LeapToUnity(ref l_data.m_rightHand.m_elbowPosition, ref ms_identityRotation, Settings.TrackingMode); + m_leapElbowRight.transform.localPosition = l_data.m_rightHand.m_elbowPosition; + } + } + } + + 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) + { + if(!m_inVR) + this.transform.localPosition = p_offset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; + else + this.transform.localPosition = p_offset; + } + } + + void OnModelVisibilityChange(bool p_state) + { + m_leapControllerModel.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(p_state) + { + if(!m_inVR) + { + this.transform.parent = PlayerSetup.Instance.desktopCamera.transform; + this.transform.localPosition = Settings.HeadOffset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; + this.transform.localScale = PlayerSetup.Instance.vrCameraRig.transform.localScale; + } + else + { + this.transform.parent = PlayerSetup.Instance.vrCamera.transform; + this.transform.localPosition = Settings.HeadOffset; + this.transform.localScale = Vector3.one; + } + } + else + { + if(!m_inVR) + { + this.transform.parent = PlayerSetup.Instance.desktopCameraRig.transform; + this.transform.localPosition = Settings.DesktopOffset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; + this.transform.localScale = PlayerSetup.Instance.vrCameraRig.transform.localScale; + } + else + { + this.transform.parent = PlayerSetup.Instance.vrCameraRig.transform; + this.transform.localPosition = Settings.DesktopOffset; + this.transform.localScale = Vector3.one; + } + } + + this.transform.localRotation = Quaternion.Euler(Settings.RootAngle); + } + + void OnHeadOffsetChange(Vector3 p_offset) + { + if(Settings.HeadAttach) + { + if(!m_inVR) + this.transform.localPosition = p_offset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; + else + this.transform.localPosition = p_offset; + } + } + + // Game events + internal void OnAvatarSetup() + { + m_inVR = Utils.IsInVR(); + OnHeadAttachChange(Settings.HeadAttach); + } + } +} diff --git a/ml_lme/Main.cs b/ml_lme/Main.cs index b441b9d..c520251 100644 --- a/ml_lme/Main.cs +++ b/ml_lme/Main.cs @@ -1,6 +1,6 @@ using ABI_RC.Core.Player; -using ABI_RC.Core.UI; using ABI_RC.Systems.IK.SubSystems; +using System.Collections; using System.Reflection; using UnityEngine; @@ -11,16 +11,7 @@ public class LeapMotionExtension : MelonLoader.MelonMod { static LeapMotionExtension ms_instance = null; - Leap.Controller m_leapController = null; - GestureMatcher.GesturesData m_gesturesData = null; - - GameObject m_leapTrackingRoot = null; - GameObject[] m_leapHands = null; - GameObject[] m_leapElbows = null; - GameObject m_leapControllerModel = null; - LeapTracked m_leapTracked = null; - - bool m_isInVR = false; + LeapManager m_leapManager = null; public override void OnInitializeMelon() { @@ -28,26 +19,8 @@ public override void OnInitializeMelon() ms_instance = this; DependenciesHandler.ExtractDependencies(); - Settings.Init(); - Settings.EnabledChange += this.OnEnableChange; - Settings.DesktopOffsetChange += this.OnDesktopOffsetChange; - Settings.ModelVisibilityChange += this.OnModelVisibilityChange; - Settings.TrackingModeChange += this.OnTrackingModeChange; - Settings.RootAngleChange += this.OnRootAngleChange; - Settings.HeadAttachChange += this.OnHeadAttachChange; - Settings.HeadOffsetChange += this.OnHeadOffsetChange; - - m_leapController = new Leap.Controller(); - 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_gesturesData = new GestureMatcher.GesturesData(); - m_leapHands = new GameObject[GestureMatcher.GesturesData.ms_handsCount]; - m_leapElbows = new GameObject[GestureMatcher.GesturesData.ms_handsCount]; + AssetsHandler.Load(); // Patches HarmonyInstance.Patch( @@ -65,280 +38,27 @@ public override void OnInitializeMelon() null, new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnCalibrate_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) ); + HarmonyInstance.Patch( + typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetControllerRayScale)), + null, + new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnRayScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + ); - MelonLoader.MelonCoroutines.Start(CreateTrackingObjects()); - } - - System.Collections.IEnumerator CreateTrackingObjects() - { - AssetsHandler.Load(); - - while(PlayerSetup.Instance == null) - yield return null; - while(PlayerSetup.Instance.desktopCameraRig == null) - yield return null; - while(PlayerSetup.Instance.desktopCamera == null) - yield return null; - while(PlayerSetup.Instance.vrCameraRig == null) - yield return null; - while(PlayerSetup.Instance.vrCamera == null) - yield return null; - - m_isInVR = Utils.IsInVR(); - - m_leapTrackingRoot = new GameObject("[LeapRoot]"); - - for(int i = 0; i < GestureMatcher.GesturesData.ms_handsCount; i++) - { - m_leapHands[i] = new GameObject("LeapHand" + i); - m_leapHands[i].transform.parent = m_leapTrackingRoot.transform; - m_leapHands[i].transform.localPosition = Vector3.zero; - m_leapHands[i].transform.localRotation = Quaternion.identity; - - m_leapElbows[i] = new GameObject("LeapElbow" + i); - m_leapElbows[i].transform.parent = m_leapTrackingRoot.transform; - m_leapElbows[i].transform.localPosition = Vector3.zero; - m_leapElbows[i].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 = m_leapTrackingRoot.transform; - m_leapControllerModel.transform.localPosition = Vector3.zero; - m_leapControllerModel.transform.localRotation = Quaternion.identity; - } - - // Player setup - m_leapTracked = PlayerSetup.Instance.gameObject.AddComponent(); - m_leapTracked.SetTransforms(m_leapHands[0].transform, m_leapHands[1].transform, m_leapElbows[0].transform, m_leapElbows[1].transform); - m_leapTracked.SetEnabled(Settings.Enabled); - m_leapTracked.SetTrackElbows(Settings.TrackElbows); - m_leapTracked.SetFingersOnly(Settings.FingersOnly); - - OnEnableChange(Settings.Enabled); - OnModelVisibilityChange(Settings.ModelVisibility); - OnTrackingModeChange(Settings.TrackingMode); - OnHeadAttachChange(Settings.HeadAttach); // Includes offsets and parenting + MelonLoader.MelonCoroutines.Start(WaitForRootLogic()); } public override void OnDeinitializeMelon() { if(ms_instance == this) ms_instance = null; - - m_leapController?.StopConnection(); - m_leapController?.Dispose(); - m_leapController = null; - - m_gesturesData = null; - } - - public override void OnUpdate() - { - if(Settings.Enabled) - { - for(int i = 0; i < GestureMatcher.GesturesData.ms_handsCount; i++) - m_gesturesData.m_handsPresenses[i] = false; - - if((m_leapController != null) && m_leapController.IsConnected) - { - Leap.Frame l_frame = m_leapController.Frame(); - if(l_frame != null) - { - GestureMatcher.GetGestures(l_frame, ref m_gesturesData); - - for(int i = 0; i < GestureMatcher.GesturesData.ms_handsCount; i++) - { - if((m_leapHands[i] != null) && m_gesturesData.m_handsPresenses[i]) - { - Vector3 l_pos = m_gesturesData.m_handsPositons[i]; - Quaternion l_rot = m_gesturesData.m_handsRotations[i]; - Utils.LeapToUnity(ref l_pos, ref l_rot, Settings.TrackingMode); - m_leapHands[i].transform.localPosition = l_pos; - m_leapHands[i].transform.localRotation = l_rot; - - l_pos = m_gesturesData.m_elbowsPositions[i]; - Utils.LeapToUnity(ref l_pos, ref l_rot, Settings.TrackingMode); - m_leapElbows[i].transform.localPosition = l_pos; - } - } - } - } - - if(m_leapTracked != null) - m_leapTracked.UpdateTracking(m_gesturesData); - } - } - - public override void OnLateUpdate() - { - if(Settings.Enabled && !m_isInVR && (m_leapTracked != null)) - m_leapTracked.UpdateTrackingLate(m_gesturesData); - } - - // Settings changes - void OnEnableChange(bool p_state) - { - if(p_state) - { - m_leapController?.StartConnection(); - UpdateDeviceTrackingMode(); - } - else - m_leapController?.StopConnection(); } - void OnDesktopOffsetChange(Vector3 p_offset) + IEnumerator WaitForRootLogic() { - if((m_leapTrackingRoot != null) && !Settings.HeadAttach) - { - if(!m_isInVR) - m_leapTrackingRoot.transform.localPosition = p_offset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; - else - m_leapTrackingRoot.transform.localPosition = p_offset; - } - } - - void OnModelVisibilityChange(bool p_state) - { - if(m_leapControllerModel != null) - m_leapControllerModel.SetActive(p_state); - } - - void OnTrackingModeChange(Settings.LeapTrackingMode p_mode) - { - if(Settings.Enabled) - UpdateDeviceTrackingMode(); - - if(m_leapControllerModel != null) - { - 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) - { - if(m_leapTrackingRoot != null) - m_leapTrackingRoot.transform.localRotation = Quaternion.Euler(p_angle); - } - - void OnHeadAttachChange(bool p_state) - { - if(m_leapTrackingRoot != null) - { - if(p_state) - { - if(!m_isInVR) - { - m_leapTrackingRoot.transform.parent = PlayerSetup.Instance.desktopCamera.transform; - m_leapTrackingRoot.transform.localPosition = Settings.HeadOffset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; - m_leapTrackingRoot.transform.localScale = PlayerSetup.Instance.vrCameraRig.transform.localScale; - } - else - { - m_leapTrackingRoot.transform.parent = PlayerSetup.Instance.vrCamera.transform; - m_leapTrackingRoot.transform.localPosition = Settings.HeadOffset; - m_leapTrackingRoot.transform.localScale = Vector3.one; - } - } - else - { - if(!m_isInVR) - { - m_leapTrackingRoot.transform.parent = PlayerSetup.Instance.desktopCameraRig.transform; - m_leapTrackingRoot.transform.localPosition = Settings.DesktopOffset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; - m_leapTrackingRoot.transform.localScale = PlayerSetup.Instance.vrCameraRig.transform.localScale; - } - else - { - m_leapTrackingRoot.transform.parent = PlayerSetup.Instance.vrCameraRig.transform; - m_leapTrackingRoot.transform.localPosition = Settings.DesktopOffset; - m_leapTrackingRoot.transform.localScale = Vector3.one; - } - } - - m_leapTrackingRoot.transform.localRotation = Quaternion.Euler(Settings.RootAngle); - } - } - - void OnHeadOffsetChange(Vector3 p_offset) - { - if((m_leapTrackingRoot != null) && Settings.HeadAttach) - { - if(!m_isInVR) - m_leapTrackingRoot.transform.localPosition = p_offset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; - else - m_leapTrackingRoot.transform.localPosition = p_offset; - } - } - - // Internal utility - 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; - } - } - - // Leap events - void OnLeapDeviceInitialized(object p_sender, Leap.DeviceEventArgs p_args) - { - if(Settings.Enabled) - { - m_leapController?.SubscribeToDeviceEvents(p_args.Device); - UpdateDeviceTrackingMode(); - } - - if(CohtmlHud.Instance != null) - CohtmlHud.Instance.ViewDropText("Leap Motion Extension", "Device initialized"); - } - - void OnLeapDeviceFailure(object p_sender, Leap.DeviceFailureEventArgs p_args) - { - if(CohtmlHud.Instance != null) - CohtmlHud.Instance.ViewDropText("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); + while(ABI_RC.Core.RootLogic.Instance == null) + yield return null; - if(CohtmlHud.Instance != null) - CohtmlHud.Instance.ViewDropText("Leap Motion Extension", "Device lost"); - } - - void OnLeapServiceConnect(object p_sender, Leap.ConnectionEventArgs p_args) - { - if(CohtmlHud.Instance != null) - CohtmlHud.Instance.ViewDropText("Leap Motion Extension", "Service connected"); - } - - void OnLeapServiceDisconnect(object p_sender, Leap.ConnectionLostEventArgs p_args) - { - if(CohtmlHud.Instance != null) - CohtmlHud.Instance.ViewDropText("Leap Motion Extension", "Service disconnected"); + m_leapManager = new GameObject("LeapMotionManager").AddComponent(); } // Patches @@ -347,8 +67,8 @@ void OnAvatarClear() { try { - if(m_leapTracked != null) - m_leapTracked.OnAvatarClear(); + if(m_leapManager != null) + m_leapManager.OnAvatarClear(); } catch(System.Exception e) { @@ -361,12 +81,8 @@ void OnSetupAvatar() { try { - m_isInVR = Utils.IsInVR(); - - if(m_leapTracked != null) - m_leapTracked.OnSetupAvatar(); - - OnHeadAttachChange(Settings.HeadAttach); + if(m_leapManager != null) + m_leapManager.OnAvatarSetup(); } catch(System.Exception e) { @@ -379,8 +95,22 @@ void OnCalibrate() { try { - if(m_leapTracked != null) - m_leapTracked.OnCalibrate(); + if(m_leapManager != null) + m_leapManager.OnCalibrate(); + } + catch(System.Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } + + static void OnRayScale_Postfix(float __0) => ms_instance?.OnRayScale(__0); + void OnRayScale(float p_scale) + { + try + { + if(m_leapManager != null) + m_leapManager.OnRayScale(p_scale); } catch(System.Exception e) { diff --git a/ml_lme/Properties/AssemblyInfo.cs b/ml_lme/Properties/AssemblyInfo.cs index ea10aad..095d7d8 100644 --- a/ml_lme/Properties/AssemblyInfo.cs +++ b/ml_lme/Properties/AssemblyInfo.cs @@ -1,10 +1,10 @@ using System.Reflection; [assembly: AssemblyTitle("LeapMotionExtension")] -[assembly: AssemblyVersion("1.2.9")] -[assembly: AssemblyFileVersion("1.2.9")] +[assembly: AssemblyVersion("1.3.0")] +[assembly: AssemblyFileVersion("1.3.0")] -[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.2.9", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.3.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")] [assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)] diff --git a/ml_lme/README.md b/ml_lme/README.md index f843f95..355b1f3 100644 --- a/ml_lme/README.md +++ b/ml_lme/README.md @@ -1,5 +1,5 @@ # Leap Motion Extension -This mod allows you to use your Leap Motion controller for hands and fingers visual tracking. +This mod allows you to use your Leap Motion controller for hands and fingers tracking. [![](.github/img_01.png)](https://youtu.be/nak1C8uibgc) @@ -21,3 +21,6 @@ Available mod's settings in `Settings - Implementation - Leap Motion Tracking`: * **Track elbows:** elbows tracking, works best in `Screentop` and `HMD` tracking modes, `true` by default. * **Fingers tracking only:** apply only fingers tracking, disabled by default. * **Model visibility:** show Leap Motion controller model, useful for tracking visualizing, disabled by default. +* **Interaction input:** enables in-game interactions (props, menu and etc.); `true` by default. + ** Note: Suggested to use with disabled `Settings - Input & Key-Bindings - Use grip to grab`. +* **Hold/Release gesture threadhold:** limits for interaction/grip activation based on hand gesture; 50 by default. diff --git a/ml_lme/Settings.cs b/ml_lme/Settings.cs index aa5fd79..a28f0a2 100644 --- a/ml_lme/Settings.cs +++ b/ml_lme/Settings.cs @@ -31,7 +31,10 @@ enum ModSetting HeadX, HeadY, HeadZ, - TrackElbows + TrackElbows, + Input, + HoldThreadhold, + ReleaseThreadhold }; static bool ms_enabled = false; @@ -43,6 +46,9 @@ enum ModSetting static bool ms_headAttach = false; static Vector3 ms_headOffset = new Vector3(0f, -0.3f, 0.15f); static bool ms_trackElbows = true; + static bool ms_input = true; + static float ms_holdThreadhold = 0.5f; + static float ms_releaseThreadhold = 0.5f; static MelonLoader.MelonPreferences_Category ms_category = null; static List ms_entries = null; @@ -56,27 +62,35 @@ enum ModSetting static public event Action HeadAttachChange; static public event Action HeadOffsetChange; static public event Action TrackElbowsChange; + static public event Action InputChange; + static public event Action HoldThreadholdChange; + static public event Action ReleaseThreadholdChange; - public static void Init() + internal static void Init() { ms_category = MelonLoader.MelonPreferences.CreateCategory("LME"); - ms_entries = new List(); - ms_entries.Add(ms_category.CreateEntry(ModSetting.Enabled.ToString(), ms_enabled)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.DesktopX.ToString(), 0)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.DesktopY.ToString(), -45)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.DesktopZ.ToString(), 30)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.FingersOnly.ToString(), ms_modelVisibility)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.Model.ToString(), ms_modelVisibility)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.Mode.ToString(), (int)ms_trackingMode)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.AngleX.ToString(), 0)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.AngleY.ToString(), 0)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.AngleZ.ToString(), 0)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.Head.ToString(), ms_headAttach)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.HeadX.ToString(), 0)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.HeadY.ToString(), -30)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.HeadZ.ToString(), 15)); - ms_entries.Add(ms_category.CreateEntry(ModSetting.TrackElbows.ToString(), true)); + ms_entries = new List() + { + ms_category.CreateEntry(ModSetting.Enabled.ToString(), ms_enabled), + ms_category.CreateEntry(ModSetting.DesktopX.ToString(), 0), + ms_category.CreateEntry(ModSetting.DesktopY.ToString(), -45), + ms_category.CreateEntry(ModSetting.DesktopZ.ToString(), 30), + ms_category.CreateEntry(ModSetting.FingersOnly.ToString(), ms_modelVisibility), + ms_category.CreateEntry(ModSetting.Model.ToString(), ms_modelVisibility), + ms_category.CreateEntry(ModSetting.Mode.ToString(), (int)ms_trackingMode), + ms_category.CreateEntry(ModSetting.AngleX.ToString(), 0), + ms_category.CreateEntry(ModSetting.AngleY.ToString(), 0), + ms_category.CreateEntry(ModSetting.AngleZ.ToString(), 0), + ms_category.CreateEntry(ModSetting.Head.ToString(), ms_headAttach), + ms_category.CreateEntry(ModSetting.HeadX.ToString(), 0), + ms_category.CreateEntry(ModSetting.HeadY.ToString(), -30), + ms_category.CreateEntry(ModSetting.HeadZ.ToString(), 15), + ms_category.CreateEntry(ModSetting.TrackElbows.ToString(), true), + ms_category.CreateEntry(ModSetting.Input.ToString(), true), + ms_category.CreateEntry(ModSetting.HoldThreadhold.ToString(), 50), + ms_category.CreateEntry(ModSetting.ReleaseThreadhold.ToString(), 50), + }; Load(); @@ -129,6 +143,9 @@ static void Load() (int)ms_entries[(int)ModSetting.HeadZ].BoxedValue ) * 0.01f; ms_trackElbows = (bool)ms_entries[(int)ModSetting.TrackElbows].BoxedValue; + ms_input = (bool)ms_entries[(int)ModSetting.Input].BoxedValue; + ms_holdThreadhold = (int)ms_entries[(int)ModSetting.HoldThreadhold].BoxedValue * 0.01f; + ms_releaseThreadhold = (int)ms_entries[(int)ModSetting.ReleaseThreadhold].BoxedValue * 0.01f; } static void OnToggleUpdate(string p_name, string p_value) @@ -171,6 +188,13 @@ static void OnToggleUpdate(string p_name, string p_value) TrackElbowsChange?.Invoke(ms_trackElbows); } break; + + case ModSetting.Input: + { + ms_input = bool.Parse(p_value); + InputChange?.Invoke(ms_input); + } + break; } ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); @@ -241,6 +265,18 @@ static void OnSliderUpdate(string p_name, string p_value) HeadOffsetChange?.Invoke(ms_headOffset); } break; + case ModSetting.HoldThreadhold: + { + ms_holdThreadhold = int.Parse(p_value) * 0.01f; + HoldThreadholdChange?.Invoke(ms_holdThreadhold); + } + break; + case ModSetting.ReleaseThreadhold: + { + ms_releaseThreadhold = int.Parse(p_value) * 0.01f; + ReleaseThreadholdChange?.Invoke(ms_releaseThreadhold); + } + break; } ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); @@ -301,5 +337,17 @@ public static bool TrackElbows { get => ms_trackElbows; } + public static bool Input + { + get => ms_input; + } + public static float HoldThreadhold + { + get => ms_holdThreadhold; + } + public static float ReleaseThreadhold + { + get => ms_releaseThreadhold; + } } } diff --git a/ml_lme/Utils.cs b/ml_lme/Utils.cs index bf493a4..1a05cef 100644 --- a/ml_lme/Utils.cs +++ b/ml_lme/Utils.cs @@ -1,4 +1,5 @@ using ABI_RC.Core.Player; +using ABI_RC.Core.UI; using System.Linq; using UnityEngine; @@ -8,7 +9,7 @@ static class Utils { static readonly Quaternion ms_hmdRotationFix = new Quaternion(0f, 0.7071068f, 0.7071068f, 0f); static readonly Quaternion ms_screentopRotationFix = new Quaternion(0f, 0f, -1f, 0f); - + public static bool AreKnucklesInUse() => PlayerSetup.Instance._trackerManager.trackerNames.Contains("knuckles"); public static bool IsInVR() => ((ABI_RC.Core.Savior.CheckVR.Instance != null) && ABI_RC.Core.Savior.CheckVR.Instance.hasVrDeviceLoaded); @@ -17,7 +18,18 @@ public static Matrix4x4 GetMatrix(this Transform p_transform, bool p_pos = true, { return Matrix4x4.TRS(p_pos ? p_transform.position : Vector3.zero, p_rot ? p_transform.rotation : Quaternion.identity, p_scl ? p_transform.lossyScale : Vector3.one); } - + + public static void ShowHUDNotification(string p_title, string p_message, string p_small = "", bool p_immediate = false) + { + if(CohtmlHud.Instance != null) + { + if(p_immediate) + CohtmlHud.Instance.ViewDropTextImmediate(p_title, p_message, p_small); + else + CohtmlHud.Instance.ViewDropText(p_title, p_message, p_small); + } + } + public static void LeapToUnity(ref Vector3 p_pos, ref Quaternion p_rot, Settings.LeapTrackingMode p_mode) { p_pos *= 0.001f; diff --git a/ml_lme/ml_lme.csproj b/ml_lme/ml_lme.csproj index d1fba4a..25fb3c8 100644 --- a/ml_lme/ml_lme.csproj +++ b/ml_lme/ml_lme.csproj @@ -84,7 +84,10 @@ + + + diff --git a/ml_lme/resources/menu.js b/ml_lme/resources/menu.js index bc1fb73..8b8cd52 100644 --- a/ml_lme/resources/menu.js +++ b/ml_lme/resources/menu.js @@ -384,6 +384,27 @@ function inp_dropdown_mod_lme(_obj, _callbackName) {
+ +
+
Interaction input:
+
+
+
+
+ +
+
Hold gesture threadhold:
+
+
+
+
+ +
+
Release gesture threadhold:
+
+
+
+
`; document.getElementById('settings-implementation').appendChild(l_block); diff --git a/ml_pam/ArmMover.cs b/ml_pam/ArmMover.cs index 3e1e584..d2fd112 100644 --- a/ml_pam/ArmMover.cs +++ b/ml_pam/ArmMover.cs @@ -4,6 +4,7 @@ namespace ml_pam { + [DisallowMultipleComponent] class ArmMover : MonoBehaviour { static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f);