diff --git a/ml_lme_cvr/AssetsHandler.cs b/ml_lme_cvr/AssetsHandler.cs new file mode 100644 index 0000000..3fc4ad2 --- /dev/null +++ b/ml_lme_cvr/AssetsHandler.cs @@ -0,0 +1,88 @@ +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using UnityEngine; + +namespace ml_lme_cvr +{ + static class AssetsHandler + { + static readonly List ms_assets = new List() + { + "leapmotion_controller.asset" + }; + + static Dictionary ms_loadedAssets = new Dictionary(); + static Dictionary ms_loadedObjects = new Dictionary(); + + public static void Load() + { + Assembly l_assembly = Assembly.GetExecutingAssembly(); + string l_assemblyName = l_assembly.GetName().Name; + + foreach(string l_assetName in ms_assets) + { + try + { + Stream l_assetStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + l_assetName); + if(l_assetStream != null) + { + MemoryStream l_memorySteam = new MemoryStream((int)l_assetStream.Length); + l_assetStream.CopyTo(l_memorySteam); + AssetBundle l_assetBundle = AssetBundle.LoadFromMemory(l_memorySteam.ToArray(), 0); + if(l_assetBundle != null) + { + l_assetBundle.hideFlags |= HideFlags.DontUnloadUnusedAsset; + ms_loadedAssets.Add(l_assetName, l_assetBundle); + } + else + MelonLoader.MelonLogger.Warning("Unable to load bundled '" + l_assetName + "' asset"); + } + else + MelonLoader.MelonLogger.Warning("Unable to get bundled '" + l_assetName + "' asset stream"); + } + catch(System.Exception e) + { + MelonLoader.MelonLogger.Warning("Unable to load bundled '" + l_assetName + "' asset, reason: " + e.Message); + } + } + } + + public static GameObject GetAsset(string p_name) + { + GameObject l_result = null; + if(ms_loadedObjects.ContainsKey(p_name)) + { + l_result = Object.Instantiate(ms_loadedObjects[p_name]); + l_result.SetActive(true); + l_result.hideFlags |= HideFlags.DontUnloadUnusedAsset; + } + else + { + foreach(var l_pair in ms_loadedAssets) + { + if(l_pair.Value.Contains(p_name)) + { + GameObject l_bundledObject = (GameObject)l_pair.Value.LoadAsset(p_name, typeof(GameObject)); + if(l_bundledObject != null) + { + ms_loadedObjects.Add(p_name, l_bundledObject); + l_result = Object.Instantiate(l_bundledObject); + l_result.SetActive(true); + l_result.hideFlags |= HideFlags.DontUnloadUnusedAsset; + } + break; + } + } + } + return l_result; + } + + public static void Unload() + { + foreach(var l_pair in ms_loadedAssets) + Object.Destroy(l_pair.Value); + ms_loadedAssets.Clear(); + } + } +} diff --git a/ml_lme_cvr/LeapIK.cs b/ml_lme_cvr/LeapIK.cs index fc5fdbe..76d8a20 100644 --- a/ml_lme_cvr/LeapIK.cs +++ b/ml_lme_cvr/LeapIK.cs @@ -13,6 +13,12 @@ namespace ml_lme_cvr Transform m_leftHand = null; Transform m_rightHand = null; + float m_leftHandWeight = 1f; + float m_rightHandWeight = 1f; + + bool m_leftHandVisible = false; + bool m_rightHandVisible = false; + void Start() { m_animator = this.GetComponent(); @@ -24,16 +30,18 @@ namespace ml_lme_cvr { if(m_leftHand != null) { - m_animator.SetIKPositionWeight(AvatarIKGoal.LeftHand, 1f); - m_animator.SetIKRotationWeight(AvatarIKGoal.LeftHand, 1f); + m_leftHandWeight = Mathf.Lerp(m_leftHandWeight, m_leftHandVisible ? 1f : 0f, 0.25f); + m_animator.SetIKPositionWeight(AvatarIKGoal.LeftHand, m_leftHandWeight); + m_animator.SetIKRotationWeight(AvatarIKGoal.LeftHand, m_leftHandWeight); m_animator.SetIKPosition(AvatarIKGoal.LeftHand, m_leftHand.position); m_animator.SetIKRotation(AvatarIKGoal.LeftHand, m_leftHand.rotation); } if(m_rightHand != null) { - m_animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 1f); - m_animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 1f); + m_rightHandWeight = Mathf.Lerp(m_rightHandWeight, m_rightHandVisible ? 1f : 0f, 0.25f); + m_animator.SetIKPositionWeight(AvatarIKGoal.RightHand, m_rightHandWeight); + m_animator.SetIKRotationWeight(AvatarIKGoal.RightHand, m_rightHandWeight); m_animator.SetIKPosition(AvatarIKGoal.RightHand, m_rightHand.position); m_animator.SetIKRotation(AvatarIKGoal.RightHand, m_rightHand.rotation); } @@ -49,5 +57,11 @@ namespace ml_lme_cvr m_leftHand = p_left; m_rightHand = p_right; } + + public void SetHandsVisibility(bool p_left, bool p_right) + { + m_leftHandVisible = p_left; + m_rightHandVisible = p_right; + } } } diff --git a/ml_lme_cvr/LeapTracked.cs b/ml_lme_cvr/LeapTracked.cs index add19e3..dba0f15 100644 --- a/ml_lme_cvr/LeapTracked.cs +++ b/ml_lme_cvr/LeapTracked.cs @@ -1,8 +1,10 @@ -using UnityEngine; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using UnityEngine; namespace ml_lme_cvr { - [RequireComponent(typeof(ABI_RC.Core.Player.IndexIK))] + [RequireComponent(typeof(IndexIK))] [DisallowMultipleComponent] class LeapTracked : MonoBehaviour { @@ -11,7 +13,8 @@ namespace ml_lme_cvr bool m_calibrated = false; Animator m_animator = null; - ABI_RC.Core.Player.IndexIK m_indexIK = null; + IndexIK m_indexIK = null; + LeapIK m_leapIK = null; Transform m_leftHand = null; Transform m_rightHand = null; @@ -26,7 +29,7 @@ namespace ml_lme_cvr m_indexIK.Recalibrate(); m_indexIK.activeControl = m_enabled; - ABI_RC.Core.Savior.CVRInputManager.Instance.individualFingerTracking = m_enabled; + CVRInputManager.Instance.individualFingerTracking = m_enabled; m_calibrated = true; } @@ -46,7 +49,7 @@ namespace ml_lme_cvr m_indexIK.Recalibrate(); m_calibrated = true; } - ABI_RC.Core.Savior.CVRInputManager.Instance.individualFingerTracking = true; + CVRInputManager.Instance.individualFingerTracking = true; } } else @@ -54,7 +57,7 @@ namespace ml_lme_cvr if((m_indexIK != null) && m_calibrated) { m_indexIK.activeControl = false; - ABI_RC.Core.Savior.CVRInputManager.Instance.individualFingerTracking = false; + CVRInputManager.Instance.individualFingerTracking = false; } } @@ -89,17 +92,13 @@ namespace ml_lme_cvr m_leapIK.SetHands(p_left, p_right); } - public void Reset() - { - m_calibrated = false; - m_animator = null; - m_leapIK = null; - } - public void UpdateTracking(GestureMatcher.GesturesData p_gesturesData) { if(m_enabled && (m_indexIK != null)) { + if(m_leapIK != null) + m_leapIK.SetHandsVisibility(p_gesturesData.m_handsPresenses[0], p_gesturesData.m_handsPresenses[1]); + if(p_gesturesData.m_handsPresenses[0]) { m_indexIK.leftThumbCurl = p_gesturesData.m_leftFingersBends[0]; @@ -108,13 +107,13 @@ namespace ml_lme_cvr m_indexIK.leftRingCurl = p_gesturesData.m_leftFingersBends[3]; m_indexIK.leftPinkyCurl = p_gesturesData.m_leftFingersBends[4]; - if(ABI_RC.Core.Savior.CVRInputManager.Instance != null) + if(CVRInputManager.Instance != null) { - ABI_RC.Core.Savior.CVRInputManager.Instance.fingerCurlLeftThumb = p_gesturesData.m_leftFingersBends[0]; - ABI_RC.Core.Savior.CVRInputManager.Instance.fingerCurlLeftIndex = p_gesturesData.m_leftFingersBends[1]; - ABI_RC.Core.Savior.CVRInputManager.Instance.fingerCurlLeftMiddle = p_gesturesData.m_leftFingersBends[2]; - ABI_RC.Core.Savior.CVRInputManager.Instance.fingerCurlLeftRing = p_gesturesData.m_leftFingersBends[3]; - ABI_RC.Core.Savior.CVRInputManager.Instance.fingerCurlLeftPinky = p_gesturesData.m_leftFingersBends[4]; + CVRInputManager.Instance.fingerCurlLeftThumb = p_gesturesData.m_leftFingersBends[0]; + CVRInputManager.Instance.fingerCurlLeftIndex = p_gesturesData.m_leftFingersBends[1]; + CVRInputManager.Instance.fingerCurlLeftMiddle = p_gesturesData.m_leftFingersBends[2]; + CVRInputManager.Instance.fingerCurlLeftRing = p_gesturesData.m_leftFingersBends[3]; + CVRInputManager.Instance.fingerCurlLeftPinky = p_gesturesData.m_leftFingersBends[4]; } } @@ -126,13 +125,13 @@ namespace ml_lme_cvr m_indexIK.rightRingCurl = p_gesturesData.m_rightFingersBends[3]; m_indexIK.rightPinkyCurl = p_gesturesData.m_rightFingersBends[4]; - if(ABI_RC.Core.Savior.CVRInputManager.Instance != null) + if(CVRInputManager.Instance != null) { - ABI_RC.Core.Savior.CVRInputManager.Instance.fingerCurlRightThumb = p_gesturesData.m_rightFingersBends[0]; - ABI_RC.Core.Savior.CVRInputManager.Instance.fingerCurlRightIndex = p_gesturesData.m_rightFingersBends[1]; - ABI_RC.Core.Savior.CVRInputManager.Instance.fingerCurlRightMiddle = p_gesturesData.m_rightFingersBends[2]; - ABI_RC.Core.Savior.CVRInputManager.Instance.fingerCurlRightRing = p_gesturesData.m_rightFingersBends[3]; - ABI_RC.Core.Savior.CVRInputManager.Instance.fingerCurlRightPinky = p_gesturesData.m_rightFingersBends[4]; + CVRInputManager.Instance.fingerCurlRightThumb = p_gesturesData.m_rightFingersBends[0]; + CVRInputManager.Instance.fingerCurlRightIndex = p_gesturesData.m_rightFingersBends[1]; + CVRInputManager.Instance.fingerCurlRightMiddle = p_gesturesData.m_rightFingersBends[2]; + CVRInputManager.Instance.fingerCurlRightRing = p_gesturesData.m_rightFingersBends[3]; + CVRInputManager.Instance.fingerCurlRightPinky = p_gesturesData.m_rightFingersBends[4]; } } } diff --git a/ml_lme_cvr/Main.cs b/ml_lme_cvr/Main.cs index 7a0ef5a..721e1c2 100644 --- a/ml_lme_cvr/Main.cs +++ b/ml_lme_cvr/Main.cs @@ -1,4 +1,5 @@ -using UnityEngine; +using ABI_RC.Core.Player; +using UnityEngine; namespace ml_lme_cvr { @@ -14,11 +15,9 @@ namespace ml_lme_cvr GameObject m_leapTrackingRoot = null; GameObject[] m_leapHands = null; + GameObject m_leapControllerModel = null; LeapTracked m_leapTracked = null; - Transform m_vrRig = null; - Transform m_desktopRig = null; - public override void OnApplicationStart() { ms_instance = this; @@ -29,6 +28,11 @@ namespace ml_lme_cvr Settings.EnabledChange += this.OnSettingsEnableChange; Settings.DesktopOffsetChange += this.OnSettingsDesktopOffsetChange; Settings.FingersOnlyChange += this.OnSettingsFingersOptionChange; + Settings.ModelVisibilityChange += this.OnSettingsModelVisibilityChange; + Settings.HmdModeChange += this.OnSettingsHmdModeChange; + Settings.RootAngleChange += this.OnSettingsRootAngleChange; + Settings.HeadAttachChange += this.OnSettingsHeadAttachChange; + Settings.HeadOffsetChange += this.OnSettingsHeadOffsetChange; m_leapController = new Leap.Controller(); m_gesturesData = new GestureMatcher.GesturesData(); @@ -37,7 +41,7 @@ namespace ml_lme_cvr // Patches HarmonyInstance.Patch( - typeof(ABI_RC.Core.Player.PlayerSetup).GetMethod(nameof(ABI_RC.Core.Player.PlayerSetup.SetupAvatar)), + typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)), null, new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnAvatarSetup), System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)) ); @@ -47,25 +51,20 @@ namespace ml_lme_cvr System.Collections.IEnumerator CreateTrackingObjects() { - while(ABI_RC.Core.Player.PlayerSetup.Instance == null) - yield return null; + AssetsHandler.Load(); - while(m_vrRig == null) - { - m_vrRig = ABI_RC.Core.Player.PlayerSetup.Instance.transform.Find("[CameraRigVR]"); + while(PlayerSetup.Instance == null) yield return null; - } - - while(m_desktopRig == null) - { - m_desktopRig = ABI_RC.Core.Player.PlayerSetup.Instance.transform.Find("[CameraRigDesktop]"); + 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_leapTrackingRoot = new GameObject("[LeapRoot]"); - m_leapTrackingRoot.transform.parent = m_desktopRig; - m_leapTrackingRoot.transform.localPosition = new Vector3(0f, -0.45637f, 0.35f); - m_leapTrackingRoot.transform.localRotation = Quaternion.identity; for(int i = 0; i < GestureMatcher.GesturesData.ms_handsCount; i++) { @@ -75,7 +74,22 @@ namespace ml_lme_cvr m_leapHands[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; + } + Settings.Reload(); + + OnSettingsEnableChange(); + OnSettingsFingersOptionChange(); + OnSettingsModelVisibilityChange(); + OnSettingsHmdModeChange(); + OnSettingsHeadAttachChange(); // Includes offsets and parenting } public override void OnUpdate() @@ -89,28 +103,33 @@ namespace ml_lme_cvr for(int i = 0; i < GestureMatcher.GesturesData.ms_handsCount; i++) { - if(m_gesturesData.m_handsPresenses[i] && (m_leapHands[i] != null)) + 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]; - ReorientateLeapToUnity(ref l_pos, ref l_rot, false); + ReorientateLeapToUnity(ref l_pos, ref l_rot, Settings.HmdMode); m_leapHands[i].transform.localPosition = l_pos; m_leapHands[i].transform.localRotation = l_rot; } } - - if(m_leapTracked != null) - m_leapTracked.UpdateTracking(m_gesturesData); } + + if(m_leapTracked != null) + m_leapTracked.UpdateTracking(m_gesturesData); } } + // Settings changes void OnSettingsEnableChange() { if(Settings.Enabled) { m_leapController.StartConnection(); - m_leapController.SetAndClearPolicy(Leap.Controller.PolicyFlag.POLICY_DEFAULT, Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_SCREENTOP | Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_HMD); + m_leapController.ClearPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_SCREENTOP); + if(Settings.HmdMode) + m_leapController.SetPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_HMD); + else + m_leapController.ClearPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_HMD); } else m_leapController.StopConnection(); @@ -121,10 +140,12 @@ namespace ml_lme_cvr void OnSettingsDesktopOffsetChange() { - if((m_leapTrackingRoot != null) && (m_vrRig != null)) + if((m_leapTrackingRoot != null) && !Settings.HeadAttach) { - m_leapTrackingRoot.transform.localPosition = new Vector3(Settings.DesktopOffsetX, Settings.DesktopOffsetY, Settings.DesktopOffsetZ) * m_vrRig.transform.localScale.x; - m_leapTrackingRoot.transform.localScale = m_vrRig.transform.localScale; + if(!PlayerSetup.Instance._inVr) + m_leapTrackingRoot.transform.localPosition = Settings.DesktopOffset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; + else + m_leapTrackingRoot.transform.localPosition = Settings.DesktopOffset; } } @@ -134,14 +155,92 @@ namespace ml_lme_cvr m_leapTracked.SetFingersOnly(Settings.FingersOnly); } - static void OnAvatarSetup(ref ABI_RC.Core.Player.PlayerSetup __instance) + void OnSettingsModelVisibilityChange() { - if(__instance != null && __instance == ABI_RC.Core.Player.PlayerSetup.Instance) + if(m_leapControllerModel != null) + m_leapControllerModel.SetActive(Settings.ModelVisibility); + } + + void OnSettingsHmdModeChange() + { + if(m_leapController != null) { - ms_instance?.OnLocalPlayerAvatarSetup(__instance._animator, __instance.GetComponent()); + m_leapController.ClearPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_SCREENTOP); + if(Settings.HmdMode) + m_leapController.SetPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_HMD); + else + m_leapController.ClearPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_HMD); + } + + if(m_leapControllerModel != null) + m_leapControllerModel.transform.localRotation = (Settings.HmdMode ? Quaternion.Euler(270f, 180f, 0f) : Quaternion.identity); + } + + void OnSettingsRootAngleChange() + { + if(m_leapTrackingRoot != null) + m_leapTrackingRoot.transform.localRotation = Quaternion.Euler(Settings.RootAngle, 0f, 0f); + } + + void OnSettingsHeadAttachChange() + { + if(m_leapTrackingRoot != null) + { + if(Settings.HeadAttach) + { + if(!PlayerSetup.Instance._inVr) + { + 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(!PlayerSetup.Instance._inVr) + { + 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, 0f, 0f); } } - void OnLocalPlayerAvatarSetup(Animator p_animator, ABI_RC.Core.Player.IndexIK p_indexIK) + + void OnSettingsHeadOffsetChange() + { + if((m_leapTrackingRoot != null) && Settings.HeadAttach) + { + if(!PlayerSetup.Instance._inVr) + m_leapTrackingRoot.transform.localPosition = Settings.HeadOffset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x; + else + m_leapTrackingRoot.transform.localPosition = Settings.HeadOffset; + } + } + + // Patches + static void OnAvatarSetup(ref PlayerSetup __instance) + { + if(__instance != null && __instance == PlayerSetup.Instance) + { + ms_instance?.OnLocalPlayerAvatarSetup(__instance._animator, __instance.GetComponent()); + } + } + void OnLocalPlayerAvatarSetup(Animator p_animator, IndexIK p_indexIK) { if(m_leapTracked != null) Object.DestroyImmediate(m_leapTracked); @@ -152,11 +251,7 @@ namespace ml_lme_cvr m_leapTracked.SetHands(m_leapHands[0].transform, m_leapHands[1].transform); m_leapTracked.SetFingersOnly(Settings.FingersOnly); - if((m_leapTrackingRoot != null) && (m_vrRig != null)) - { - m_leapTrackingRoot.transform.localPosition = new Vector3(Settings.DesktopOffsetX, Settings.DesktopOffsetY, Settings.DesktopOffsetZ) * m_vrRig.transform.localScale.x; - m_leapTrackingRoot.transform.localScale = m_vrRig.transform.localScale; - } + OnSettingsHeadAttachChange(); } static void ReorientateLeapToUnity(ref Vector3 p_pos, ref Quaternion p_rot, bool p_hmd) diff --git a/ml_lme_cvr/README.md b/ml_lme_cvr/README.md index 014aaba..b47e739 100644 --- a/ml_lme_cvr/README.md +++ b/ml_lme_cvr/README.md @@ -6,56 +6,16 @@ This mod allows you to use your Leap Motion controller for hands and fingers vis * Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader) * Get [latest release DLL](../../../releases/latest): * Put `ml_lme_cvr.dll` in `Mods` folder of game -* Add code section below in `\ChilloutVR_Data\StreamingAssets\Cohtml\UIResources\CVRTest\index.html` after div for `InteractionViveFaceTrackingStrength` menu item: -```html - -

Leap Motion tracking

-
-
Enable tracking:
-
-
-
-
- -
-
Desktop offset X:
-
-
-
-
- -
-
Desktop offset Y:
-
-
-
-
- -
-
Desktop offset Z:
-
-
-
-
- -
-
Fingers tracking only:
-
-
-
-
- -``` +* Add code from [this gist](https://gist.github.com/SDraw/543825b39cdabc3bc4fda358bc70247a) to `\ChilloutVR_Data\StreamingAssets\Cohtml\UIResources\CVRTest\index.html` after div for `InteractionViveFaceTrackingStrength` menu item (near line 1188) # Usage ## Settings Available mod's settings in `Settings - Implementation - Leap Motion Tracking`: * **Enable tracking:** enable hands tracking from Leap Motion data, disabled by default. +* **HMD mode:** force Leap Motion to use head-mounted orientation mode, disabled by default. * **Desktop offset X/Y/Z:** offset position for body attachment, (0, -45, 30) by default. +* **Attach to head:** attach hands transformation to head instead of body, disabled by default. +* **Head offset X/Y/Z:** offset position for head attachment (`Attach to head` is **`true`**), (0, -30, 15) by default. +* **Offset angle:** rotation around X axis, useful for neck mounts, 0 by default. * **Fingers tracking only:** apply only fingers tracking, disabled by default. - -# Notes -* Only desktop mode is implemented, VR mode is in development. -* Head attachment isn't implemented, in development. -* Root rotation isn't implemented, in development. -* Model visibility isn't implemented, in development. +* **Model visibility:** show Leap Motion controller model, useful for tracking visualizing, disabled by default. diff --git a/ml_lme_cvr/Settings.cs b/ml_lme_cvr/Settings.cs index fe42daf..0033ae6 100644 --- a/ml_lme_cvr/Settings.cs +++ b/ml_lme_cvr/Settings.cs @@ -1,4 +1,8 @@ -namespace ml_lme_cvr +using ABI_RC.Core.Savior; +using System; +using UnityEngine; + +namespace ml_lme_cvr { static class Settings { @@ -8,87 +12,186 @@ "InteractionLeapMotionTrackingDesktopX", "InteractionLeapMotionTrackingDesktopY", "InteractionLeapMotionTrackingDesktopZ", - "InteractionLeapMotionTrackingFingersOnly" + "InteractionLeapMotionTrackingFingersOnly", + "InteractionLeapMotionTrackingModel", + "InteractionLeapMotionTrackingHmd", + "InteractionLeapMotionTrackingAngle", + "InteractionLeapMotionTrackingHead", + "InteractionLeapMotionTrackingHeadX", + "InteractionLeapMotionTrackingHeadY", + "InteractionLeapMotionTrackingHeadZ" }; static bool ms_enabled = false; - static float ms_desktopOffsetX = 0f; - static float ms_desktopOffsetY = -0.45f; - static float ms_desktopOffsetZ = 0.3f; + static Vector3 ms_desktopOffset = new Vector3(0f, -0.45f, 0.3f); static bool ms_fingersOnly = false; + static bool ms_modelVisibility = false; + static bool ms_hmdMode = false; + static float ms_rootAngle = 0f; + static bool ms_headAttach = false; + static Vector3 ms_headOffset = new Vector3(0f, 0f, 0f); static bool ms_initialized = false; - static public event System.Action EnabledChange; - static public event System.Action DesktopOffsetChange; - static public event System.Action FingersOnlyChange; + static public event Action EnabledChange; + static public event Action DesktopOffsetChange; + static public event Action FingersOnlyChange; + static public event Action ModelVisibilityChange; + static public event Action HmdModeChange; + static public event Action RootAngleChange; + static public event Action HeadAttachChange; + static public event Action HeadOffsetChange; public static void Init(HarmonyLib.Harmony p_instance) { p_instance.Patch( - typeof(ABI_RC.Core.Savior.CVRSettings).GetMethod(nameof(ABI_RC.Core.Savior.CVRSettings.LoadSerializedSettings)), + typeof(CVRSettings).GetMethod(nameof(CVRSettings.LoadSerializedSettings)), new HarmonyLib.HarmonyMethod(typeof(Settings).GetMethod(nameof(BeforeSettingsLoad), System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)), null ); } - static void BeforeSettingsLoad(ref ABI_RC.Core.Savior.CVRSettings __instance) + static void BeforeSettingsLoad(ref CVRSettings __instance) { if(!ms_initialized && __instance != null) { var l_settings = HarmonyLib.Traverse.Create(__instance)?.Field("_settings")?.GetValue>(); if(l_settings != null) { - l_settings.Add(new ABI_RC.Core.Savior.CVRSettingsBool(ms_defaultSettings[0], false)); - l_settings.Add(new ABI_RC.Core.Savior.CVRSettingsInt(ms_defaultSettings[1], 0)); - l_settings.Add(new ABI_RC.Core.Savior.CVRSettingsInt(ms_defaultSettings[2], -45)); - l_settings.Add(new ABI_RC.Core.Savior.CVRSettingsInt(ms_defaultSettings[3], 30)); - l_settings.Add(new ABI_RC.Core.Savior.CVRSettingsBool(ms_defaultSettings[4], false)); + l_settings.Add(new CVRSettingsBool(ms_defaultSettings[0], false)); + l_settings.Add(new CVRSettingsInt(ms_defaultSettings[1], 0)); + l_settings.Add(new CVRSettingsInt(ms_defaultSettings[2], -45)); + l_settings.Add(new CVRSettingsInt(ms_defaultSettings[3], 30)); + l_settings.Add(new CVRSettingsBool(ms_defaultSettings[4], false)); + l_settings.Add(new CVRSettingsBool(ms_defaultSettings[5], false)); + l_settings.Add(new CVRSettingsBool(ms_defaultSettings[6], false)); + l_settings.Add(new CVRSettingsInt(ms_defaultSettings[7], 0)); + l_settings.Add(new CVRSettingsBool(ms_defaultSettings[8], false)); + l_settings.Add(new CVRSettingsInt(ms_defaultSettings[9], 0)); + l_settings.Add(new CVRSettingsInt(ms_defaultSettings[10], 0)); + l_settings.Add(new CVRSettingsInt(ms_defaultSettings[11], 0)); } // Changes events + + // Enable tracking __instance.settingBoolChanged.AddListener((name, value) => { if(name == ms_defaultSettings[0]) { - Settings.Reload(); + ms_enabled = value; EnabledChange?.Invoke(); } }); + // Desktop offsets __instance.settingIntChanged.AddListener((name, value) => { - for(int i=1; i <= 3; i++) + for(int i = 1; i <= 3; i++) { if(name == ms_defaultSettings[i]) { - Settings.Reload(); + ms_desktopOffset = new Vector3( + MetaPort.Instance.settings.GetSettingInt(ms_defaultSettings[1]), + MetaPort.Instance.settings.GetSettingInt(ms_defaultSettings[2]), + MetaPort.Instance.settings.GetSettingInt(ms_defaultSettings[3]) + ) * 0.01f; DesktopOffsetChange?.Invoke(); break; } } }); + // Fingers tracking only __instance.settingBoolChanged.AddListener((name, value) => { if(name == ms_defaultSettings[4]) { - Settings.Reload(); + ms_fingersOnly = value; FingersOnlyChange?.Invoke(); } }); + // Model visibility + __instance.settingBoolChanged.AddListener((name, value) => + { + if(name == ms_defaultSettings[5]) + { + ms_modelVisibility = value; + ModelVisibilityChange?.Invoke(); + } + }); + + // HMD mode + __instance.settingBoolChanged.AddListener((name, value) => + { + if(name == ms_defaultSettings[6]) + { + ms_hmdMode = value; + HmdModeChange?.Invoke(); + } + }); + + // Root angle + __instance.settingIntChanged.AddListener((name, value) => + { + if(name == ms_defaultSettings[7]) + { + ms_rootAngle = value; + RootAngleChange?.Invoke(); + } + }); + + // Head attach + __instance.settingBoolChanged.AddListener((name, value) => + { + if(name == ms_defaultSettings[8]) + { + ms_headAttach = value; + HeadAttachChange?.Invoke(); + } + }); + + // Head offset + __instance.settingIntChanged.AddListener((name, value) => + { + for(int i = 9; i <= 11; i++) + { + if(name == ms_defaultSettings[i]) + { + ms_headOffset = new Vector3( + MetaPort.Instance.settings.GetSettingInt(ms_defaultSettings[9]), + MetaPort.Instance.settings.GetSettingInt(ms_defaultSettings[10]), + MetaPort.Instance.settings.GetSettingInt(ms_defaultSettings[11]) + ) * 0.01f; + HeadOffsetChange?.Invoke(); + break; + } + } + }); + ms_initialized = true; } } static public void Reload() { - ms_enabled = ABI_RC.Core.Savior.MetaPort.Instance.settings.GetSettingsBool(ms_defaultSettings[0]); - ms_desktopOffsetX = ABI_RC.Core.Savior.MetaPort.Instance.settings.GetSettingInt(ms_defaultSettings[1]) * 0.01f; - ms_desktopOffsetY = ABI_RC.Core.Savior.MetaPort.Instance.settings.GetSettingInt(ms_defaultSettings[2]) * 0.01f; - ms_desktopOffsetZ = ABI_RC.Core.Savior.MetaPort.Instance.settings.GetSettingInt(ms_defaultSettings[3]) * 0.01f; - ms_fingersOnly = ABI_RC.Core.Savior.MetaPort.Instance.settings.GetSettingsBool(ms_defaultSettings[4]); + ms_enabled = MetaPort.Instance.settings.GetSettingsBool(ms_defaultSettings[0]); + ms_desktopOffset = new Vector3( + MetaPort.Instance.settings.GetSettingInt(ms_defaultSettings[1]), + MetaPort.Instance.settings.GetSettingInt(ms_defaultSettings[2]), + MetaPort.Instance.settings.GetSettingInt(ms_defaultSettings[3]) + ) * 0.01f; + ms_fingersOnly = MetaPort.Instance.settings.GetSettingsBool(ms_defaultSettings[4]); + ms_modelVisibility = MetaPort.Instance.settings.GetSettingsBool(ms_defaultSettings[5]); + ms_hmdMode = MetaPort.Instance.settings.GetSettingsBool(ms_defaultSettings[6]); + ms_rootAngle = MetaPort.Instance.settings.GetSettingInt(ms_defaultSettings[7]); + ms_headAttach = MetaPort.Instance.settings.GetSettingsBool(ms_defaultSettings[8]); + ms_headOffset = new Vector3( + MetaPort.Instance.settings.GetSettingInt(ms_defaultSettings[9]), + MetaPort.Instance.settings.GetSettingInt(ms_defaultSettings[10]), + MetaPort.Instance.settings.GetSettingInt(ms_defaultSettings[11]) + ) * 0.01f; } public static bool Enabled @@ -96,22 +199,39 @@ get => ms_enabled; } - public static float DesktopOffsetX + public static Vector3 DesktopOffset { - get => ms_desktopOffsetX; - } - public static float DesktopOffsetY - { - get => ms_desktopOffsetY; - } - public static float DesktopOffsetZ - { - get => ms_desktopOffsetZ; + get => ms_desktopOffset; } public static bool FingersOnly { get => ms_fingersOnly; } + + public static bool ModelVisibility + { + get => ms_modelVisibility; + } + + public static bool HmdMode + { + get => ms_hmdMode; + } + + public static float RootAngle + { + get => ms_rootAngle; + } + + public static bool HeadAttach + { + get => ms_headAttach; + } + + public static Vector3 HeadOffset + { + get => ms_headOffset; + } } } diff --git a/ml_lme_cvr/ml_lme_cvr.csproj b/ml_lme_cvr/ml_lme_cvr.csproj index fdb5a61..eb42178 100644 --- a/ml_lme_cvr/ml_lme_cvr.csproj +++ b/ml_lme_cvr/ml_lme_cvr.csproj @@ -32,6 +32,11 @@ MinimumRecommendedRules.ruleset + + False + C:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\0Harmony.dll + False + C:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll False @@ -50,7 +55,6 @@ - C:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.dll @@ -60,12 +64,18 @@ C:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll False + + False + C:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AssetBundleModule.dll + False + C:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll False + @@ -112,6 +122,9 @@ LeapC.dll + + + copy /y "$(TargetPath)" "C:\Games\Steam\steamapps\common\ChilloutVR\Mods\ diff --git a/ml_lme_cvr/resources/leapmotion_controller.asset b/ml_lme_cvr/resources/leapmotion_controller.asset new file mode 100644 index 0000000..b4b06eb Binary files /dev/null and b/ml_lme_cvr/resources/leapmotion_controller.asset differ