Custom event classes for patched methods

Update to LeapCSharp 6.15.0
This commit is contained in:
SDraw 2024-04-26 23:52:25 +03:00
parent 4b879d53d5
commit 85925a7072
No known key found for this signature in database
GPG key ID: BB95B4DAB2BB8BB5
76 changed files with 3443 additions and 2187 deletions

151
ml_lme/GameEvents.cs Normal file
View file

@ -0,0 +1,151 @@
using ABI.CCK.Components;
using ABI_RC.Core.Player;
using ABI_RC.Systems.IK;
using System;
using System.Reflection;
namespace ml_lme
{
static class GameEvents
{
internal class GameEvent
{
event Action m_action;
public void AddHandler(Action p_listener) => m_action += p_listener;
public void RemoveHandler(Action p_listener) => m_action -= p_listener;
public void Invoke() => m_action?.Invoke();
}
internal class GameEvent<T1>
{
event Action<T1> m_action;
public void AddHandler(Action<T1> p_listener) => m_action += p_listener;
public void RemoveHandler(Action<T1> p_listener) => m_action -= p_listener;
public void Invoke(T1 p_obj) => m_action?.Invoke(p_obj);
}
public static readonly GameEvent OnAvatarSetup = new GameEvent();
public static readonly GameEvent OnAvatarClear = new GameEvent();
public static readonly GameEvent OnAvatarReuse = new GameEvent();
public static readonly GameEvent<float> OnRayScale = new GameEvent<float>();
public static readonly GameEvent<float> OnPlayspaceScale = new GameEvent<float>();
public static readonly GameEvent<CVRPickupObject> OnPickupGrab = new GameEvent<CVRPickupObject>();
internal static void Init(HarmonyLib.Harmony p_instance)
{
try
{
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch(
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetControllerRayScale)),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnRayScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch(
typeof(PlayerSetup).GetMethod("SetPlaySpaceScale", BindingFlags.NonPublic | BindingFlags.Instance),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnPlayspaceScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
p_instance.Patch(
typeof(CVRPickupObject).GetMethod(nameof(CVRPickupObject.Grab), BindingFlags.Public | BindingFlags.Instance),
null,
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnPickupGrab_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnAvatarClear_Postfix()
{
try
{
OnAvatarClear.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnSetupAvatar_Postfix()
{
try
{
OnAvatarSetup.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnAvatarReinitialize_Postfix()
{
try
{
OnAvatarReuse.Invoke();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnRayScale_Postfix(float __0)
{
try
{
OnRayScale.Invoke(__0);
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnPlayspaceScale_Postfix(float ____avatarScaleRelation)
{
try
{
OnPlayspaceScale.Invoke(____avatarScaleRelation);
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnPickupGrab_Postfix(ref CVRPickupObject __instance)
{
try
{
OnPickupGrab.Invoke(__instance);
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
}
}

View file

@ -81,21 +81,24 @@ namespace ml_lme
m_handRayLeft.otherRay = m_handRayRight;
m_handRayRight.otherRay = m_handRayLeft;
Settings.EnabledChange += this.OnEnableChange;
Settings.InteractionChange += this.OnInteractionChange;
Settings.GesturesChange += this.OnGesturesChange;
Settings.FingersOnlyChange += this.OnFingersOnlyChange;
OnEnableChange(Settings.Enabled);
OnInteractionChange(Settings.Interaction);
OnGesturesChange(Settings.Gestures);
OnFingersOnlyChange(Settings.FingersOnly);
OnEnableChanged(Settings.Enabled);
OnInteractionChanged(Settings.Interaction);
OnGesturesChanged(Settings.Gestures);
OnFingersOnlyChanged(Settings.FingersOnly);
MelonLoader.MelonCoroutines.Start(WaitForSettings());
MelonLoader.MelonCoroutines.Start(WaitForMaterial());
VRModeSwitchEvents.OnInitializeXR.AddListener(OnModeSwitch);
VRModeSwitchEvents.OnDeinitializeXR.AddListener(OnModeSwitch);
Settings.OnEnabledChanged.AddHandler(this.OnEnableChanged);
Settings.OnInteractionChanged.AddHandler(this.OnInteractionChanged);
Settings.OnGesturesChanged.AddHandler(this.OnGesturesChanged);
Settings.OnFingersOnlyChanged.AddHandler(this.OnFingersOnlyChanged);
GameEvents.OnRayScale.AddHandler(this.OnRayScale);
GameEvents.OnPickupGrab.AddHandler(this.OnPickupGrab);
}
IEnumerator WaitForSettings()
@ -149,14 +152,17 @@ namespace ml_lme
Object.Destroy(m_lineRight);
m_lineRight = null;
Settings.EnabledChange -= this.OnEnableChange;
Settings.InteractionChange -= this.OnInteractionChange;
Settings.GesturesChange -= this.OnGesturesChange;
Settings.FingersOnlyChange -= this.OnFingersOnlyChange;
MetaPort.Instance.settings.settingBoolChanged.RemoveListener(this.OnGameSettingBoolChange);
VRModeSwitchEvents.OnInitializeXR.RemoveListener(OnModeSwitch);
VRModeSwitchEvents.OnDeinitializeXR.RemoveListener(OnModeSwitch);
Settings.OnEnabledChanged.RemoveHandler(this.OnEnableChanged);
Settings.OnInteractionChanged.RemoveHandler(this.OnInteractionChanged);
Settings.OnGesturesChanged.RemoveHandler(this.OnGesturesChanged);
Settings.OnFingersOnlyChanged.RemoveHandler(this.OnFingersOnlyChanged);
GameEvents.OnRayScale.RemoveHandler(this.OnRayScale);
GameEvents.OnPickupGrab.RemoveHandler(this.OnPickupGrab);
}
public override void UpdateInput()
@ -360,7 +366,7 @@ namespace ml_lme
}
// Settings changes
void OnEnableChange(bool p_state)
void OnEnableChanged(bool p_state)
{
base.InputEnabled = p_state;
@ -382,10 +388,10 @@ namespace ml_lme
SetGameFingersTracking(m_inVR && Utils.AreKnucklesInUse() && !CVRInputManager._moduleXR.GestureToggleValue);
}
OnInteractionChange(Settings.Interaction);
OnInteractionChanged(Settings.Interaction);
}
void OnInteractionChange(bool p_state)
void OnInteractionChanged(bool p_state)
{
bool l_state = (p_state && Settings.Enabled && !Settings.FingersOnly);
@ -407,7 +413,7 @@ namespace ml_lme
}
}
void OnGesturesChange(bool p_state)
void OnGesturesChanged(bool p_state)
{
base._inputManager.gestureLeft = 0f;
base._inputManager.gestureLeftRaw = 0f;
@ -415,19 +421,19 @@ namespace ml_lme
base._inputManager.gestureRightRaw = 0f;
}
void OnFingersOnlyChange(bool p_state)
void OnFingersOnlyChanged(bool p_state)
{
OnInteractionChange(Settings.Interaction);
OnInteractionChanged(Settings.Interaction);
}
// Game events
internal void OnRayScale(float p_scale)
void OnRayScale(float p_scale)
{
m_handRayLeft.SetRayScale(p_scale);
m_handRayRight.SetRayScale(p_scale);
}
internal void OnPickupGrab(CVRPickupObject p_pickup)
void OnPickupGrab(CVRPickupObject p_pickup)
{
if(p_pickup.gripType == CVRPickupObject.GripType.Origin)
{
@ -460,7 +466,7 @@ namespace ml_lme
m_handRayRight.SetVRActive(m_inVR);
}
OnEnableChange(Settings.Enabled);
OnEnableChanged(Settings.Enabled);
}
// Arbitrary
@ -493,11 +499,11 @@ namespace ml_lme
base._inputManager.finger3StretchedLeftPinky = LeapTracked.ms_lastLeftFingerBones[18];
base._inputManager.fingerSpreadLeftPinky = LeapTracked.ms_lastLeftFingerBones[19];
base._inputManager.fingerFullCurlNormalizedLeftThumb = p_hand.m_bends[0];
base._inputManager.fingerFullCurlNormalizedLeftIndex = p_hand.m_bends[1];
base._inputManager.fingerFullCurlNormalizedLeftMiddle = p_hand.m_bends[2];
base._inputManager.fingerFullCurlNormalizedLeftRing = p_hand.m_bends[3];
base._inputManager.fingerFullCurlNormalizedLeftPinky = p_hand.m_bends[4];
base._inputManager.fingerFullCurlNormalizedLeftThumb = p_hand.m_normalizedCurls[0];
base._inputManager.fingerFullCurlNormalizedLeftIndex = p_hand.m_normalizedCurls[1];
base._inputManager.fingerFullCurlNormalizedLeftMiddle = p_hand.m_normalizedCurls[2];
base._inputManager.fingerFullCurlNormalizedLeftRing = p_hand.m_normalizedCurls[3];
base._inputManager.fingerFullCurlNormalizedLeftPinky = p_hand.m_normalizedCurls[4];
}
else
{
@ -526,11 +532,11 @@ namespace ml_lme
base._inputManager.finger3StretchedRightPinky = LeapTracked.ms_lastRightFingerBones[18];
base._inputManager.fingerSpreadRightPinky = LeapTracked.ms_lastRightFingerBones[19];
base._inputManager.fingerFullCurlNormalizedRightThumb = p_hand.m_bends[0];
base._inputManager.fingerFullCurlNormalizedRightIndex = p_hand.m_bends[1];
base._inputManager.fingerFullCurlNormalizedRightMiddle = p_hand.m_bends[2];
base._inputManager.fingerFullCurlNormalizedRightRing = p_hand.m_bends[3];
base._inputManager.fingerFullCurlNormalizedRightPinky = p_hand.m_bends[4];
base._inputManager.fingerFullCurlNormalizedRightThumb = p_hand.m_normalizedCurls[0];
base._inputManager.fingerFullCurlNormalizedRightIndex = p_hand.m_normalizedCurls[1];
base._inputManager.fingerFullCurlNormalizedRightMiddle = p_hand.m_normalizedCurls[2];
base._inputManager.fingerFullCurlNormalizedRightRing = p_hand.m_normalizedCurls[3];
base._inputManager.fingerFullCurlNormalizedRightPinky = p_hand.m_normalizedCurls[4];
}
}

View file

@ -1,5 +1,4 @@
using ABI.CCK.Components;
using ABI_RC.Core.Player;
using ABI_RC.Core.Player;
using ABI_RC.Systems.InputManagement;
using System.Collections;
using UnityEngine;
@ -23,6 +22,8 @@ namespace ml_lme
if(Instance == null)
Instance = this;
ScriptableObject.CreateInstance<Leap.Unity.UltraleapSettings>().ResetToDefaults();
m_leapController = new Leap.Controller();
m_leapData = new LeapParser.LeapData();
@ -34,14 +35,14 @@ namespace ml_lme
m_leapController.Connect += this.OnLeapServiceConnect;
m_leapController.Disconnect += this.OnLeapServiceDisconnect;
Settings.EnabledChange += this.OnEnableChange;
Settings.TrackingModeChange += this.OnTrackingModeChange;
Settings.OnEnabledChanged.AddHandler(this.OnEnableChanged);
Settings.OnTrackingModeChanged.AddHandler(this.OnTrackingModeChanged);
m_leapTracking = new GameObject("[LeapTrackingRoot]").AddComponent<LeapTracking>();
m_leapTracking.transform.parent = this.transform;
OnEnableChange(Settings.Enabled);
OnTrackingModeChange(Settings.TrackingMode);
OnEnableChanged(Settings.Enabled);
OnTrackingModeChanged(Settings.TrackingMode);
MelonLoader.MelonCoroutines.Start(WaitForObjects());
}
@ -77,8 +78,8 @@ namespace ml_lme
}
m_leapInput = null;
Settings.EnabledChange -= this.OnEnableChange;
Settings.TrackingModeChange -= this.OnTrackingModeChange;
Settings.OnEnabledChanged.RemoveHandler(this.OnEnableChanged);
Settings.OnTrackingModeChanged.RemoveHandler(this.OnTrackingModeChanged);
}
IEnumerator WaitForObjects()
@ -149,7 +150,7 @@ namespace ml_lme
}
// Settings
void OnEnableChange(bool p_state)
void OnEnableChanged(bool p_state)
{
if(p_state)
{
@ -160,52 +161,12 @@ namespace ml_lme
m_leapController.StopConnection();
}
void OnTrackingModeChange(Settings.LeapTrackingMode p_mode)
void OnTrackingModeChanged(Settings.LeapTrackingMode p_mode)
{
if(Settings.Enabled)
UpdateDeviceTrackingMode();
}
// Game events
internal void OnAvatarClear()
{
if(m_leapTracking != null)
m_leapTracking.OnAvatarClear();
if(m_leapTracked != null)
m_leapTracked.OnAvatarClear();
}
internal void OnAvatarSetup()
{
if(m_leapTracking != null)
m_leapTracking.OnAvatarSetup();
if(m_leapTracked != null)
m_leapTracked.OnAvatarSetup();
}
internal void OnAvatarReinitialize()
{
if(m_leapTracked != null)
m_leapTracked.OnAvatarReinitialize();
}
internal void OnRayScale(float p_scale)
{
m_leapInput?.OnRayScale(p_scale);
}
internal void OnPlayspaceScale(float p_relation)
{
if(m_leapTracking != null)
m_leapTracking.OnPlayspaceScale(p_relation);
}
internal void OnPickupGrab(CVRPickupObject p_pickup)
{
m_leapInput?.OnPickupGrab(p_pickup);
}
// Arbitrary
void UpdateDeviceTrackingMode()
{

View file

@ -13,31 +13,20 @@ namespace ml_lme
new Vector2(0f, 180f)
};
readonly static Vector2[] ms_spreadLimits =
{
new Vector2(-25f, 25f), // Unity's default limits
new Vector2(-20f, 20f),
new Vector2(-7.5f, 7.5f),
new Vector2(-7.5f, 7.5f),
new Vector2(-20f, 20f)
};
public class HandData
{
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 readonly float[] m_normalizedCurls = null;
public float m_grabStrength = 0f;
public Vector3[] m_fingerPosition;
public Quaternion[] m_fingerRotation;
public HandData()
{
m_spreads = new float[5];
m_bends = new float[5];
m_normalizedCurls = new float[5];
m_fingerPosition = new Vector3[20];
m_fingerRotation = new Quaternion[20];
}
@ -45,17 +34,16 @@ namespace ml_lme
public void Reset()
{
m_present = false;
m_grabStrength = 0f;
for(int i = 0; i < 5; i++)
{
m_bends[i] = 0f;
m_spreads[i] = 0f;
}
m_normalizedCurls[i] = 0f;
for(int i = 0; i < 20; i++)
{
m_fingerPosition[i].Set(0f, 0f, 0f);
m_fingerRotation[i].Set(0f, 0f, 0f, 1f);
}
m_grabStrength = 0f;
}
}
@ -99,7 +87,7 @@ namespace ml_lme
p_data.m_rotation = p_hand.Rotation;
p_data.m_elbowPosition = p_hand.Arm.ElbowPosition;
// Bends
// Curls
foreach(Leap.Finger l_finger in p_hand.Fingers)
{
Quaternion l_parentRot = Quaternion.identity;
@ -126,30 +114,10 @@ namespace ml_lme
l_parentRot = l_bone.Rotation;
}
p_data.m_bends[(int)l_finger.Type] = Utils.InverseLerpUnclamped(ms_bendLimits[(int)l_finger.Type].x, ms_bendLimits[(int)l_finger.Type].y, l_angle);
p_data.m_normalizedCurls[(int)l_finger.Type] = Utils.InverseLerpUnclamped(ms_bendLimits[(int)l_finger.Type].x, ms_bendLimits[(int)l_finger.Type].y, l_angle);
}
// Spreads
foreach(Leap.Finger l_finger in p_hand.Fingers)
{
Leap.Bone l_parent = l_finger.Bone(Leap.Bone.BoneType.TYPE_METACARPAL);
Leap.Bone l_child = l_finger.Bone(Leap.Bone.BoneType.TYPE_PROXIMAL);
Quaternion l_diff = Quaternion.Inverse(l_parent.Rotation) * l_child.Rotation;
// Spread - local Y rotation
float l_angle = l_diff.eulerAngles.y;
if(l_angle > 180f)
l_angle -= 360f;
if(p_hand.IsRight)
l_angle *= -1f;
p_data.m_spreads[(int)l_finger.Type] = Utils.InverseLerpUnclamped(ms_spreadLimits[(int)l_finger.Type].x, ms_spreadLimits[(int)l_finger.Type].y, l_angle) * 2f - 1f;
if((l_finger.Type != Leap.Finger.FingerType.TYPE_THUMB) && (p_data.m_bends[(int)l_finger.Type] >= 0.8f))
p_data.m_spreads[(int)l_finger.Type] = Mathf.Lerp(p_data.m_spreads[(int)l_finger.Type], 0f, (p_data.m_bends[(int)l_finger.Type] - 0.8f) * 5f);
}
p_data.m_grabStrength = Mathf.Clamp01((p_data.m_bends[1] + p_data.m_bends[2] + p_data.m_bends[3] + p_data.m_bends[4]) * 0.25f);
p_data.m_grabStrength = Mathf.Clamp01((p_data.m_normalizedCurls[1] + p_data.m_normalizedCurls[2] + p_data.m_normalizedCurls[3] + p_data.m_normalizedCurls[4]) * 0.25f);
}
}
}

View file

@ -94,7 +94,6 @@ namespace ml_lme
public static readonly float[] ms_lastLeftFingerBones = new float[20];
public static readonly float[] ms_lastRightFingerBones = new float[20];
bool m_inVR = false;
VRIK m_vrIK = null;
Transform m_hips = null;
@ -126,8 +125,6 @@ namespace ml_lme
// Unity events
void Start()
{
m_inVR = Utils.IsInVR();
m_leftHandTarget = new GameObject("RotationTarget").transform;
m_leftHandTarget.parent = LeapTracking.Instance.GetLeftHand().GetRoot();
m_leftHandTarget.localPosition = Vector3.zero;
@ -138,13 +135,17 @@ namespace ml_lme
m_rightHandTarget.localPosition = Vector3.zero;
m_rightHandTarget.localRotation = Quaternion.identity;
Settings.EnabledChange += this.OnEnabledChange;
Settings.FingersOnlyChange += this.OnFingersOnlyChange;
Settings.TrackElbowsChange += this.OnTrackElbowsChange;
OnEnabledChanged(Settings.Enabled);
OnFingersOnlyChanged(Settings.FingersOnly);
OnTrackElbowsChanged(Settings.TrackElbows);
OnEnabledChange(Settings.Enabled);
OnFingersOnlyChange(Settings.FingersOnly);
OnTrackElbowsChange(Settings.TrackElbows);
Settings.OnEnabledChanged.AddHandler(this.OnEnabledChanged);
Settings.OnFingersOnlyChanged.AddHandler(this.OnFingersOnlyChanged);
Settings.OnTrackElbowsChanged.AddHandler(this.OnTrackElbowsChanged);
GameEvents.OnAvatarClear.AddHandler(this.OnAvatarClear);
GameEvents.OnAvatarSetup.AddHandler(this.OnAvatarSetup);
GameEvents.OnAvatarReuse.AddHandler(this.OnAvatarReuse);
}
void OnDestroy()
@ -164,9 +165,13 @@ namespace ml_lme
m_vrIK = null;
Settings.EnabledChange -= this.OnEnabledChange;
Settings.FingersOnlyChange -= this.OnFingersOnlyChange;
Settings.TrackElbowsChange -= this.OnTrackElbowsChange;
Settings.OnEnabledChanged.RemoveHandler(this.OnEnabledChanged);
Settings.OnFingersOnlyChanged.RemoveHandler(this.OnFingersOnlyChanged);
Settings.OnTrackElbowsChanged.RemoveHandler(this.OnTrackElbowsChanged);
GameEvents.OnAvatarClear.RemoveHandler(this.OnAvatarClear);
GameEvents.OnAvatarSetup.RemoveHandler(this.OnAvatarSetup);
GameEvents.OnAvatarReuse.RemoveHandler(this.OnAvatarReuse);
}
void Update()
@ -245,7 +250,7 @@ namespace ml_lme
}
// Game events
internal void OnAvatarClear()
void OnAvatarClear()
{
m_vrIK = null;
m_hips = null;
@ -269,10 +274,8 @@ namespace ml_lme
m_rightFingerOffsets.Clear();
}
internal void OnAvatarSetup()
void OnAvatarSetup()
{
m_inVR = Utils.IsInVR();
if(PlayerSetup.Instance._animator.isHuman)
{
Utils.SetAvatarTPose();
@ -293,27 +296,26 @@ namespace ml_lme
m_vrIK = PlayerSetup.Instance._animator.GetComponent<VRIK>();
if(m_vrIK != null)
{
m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreUpdate);
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate);
m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreSolverUpdate);
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostSolverUpdate);
}
else
SetupArmIK();
}
}
internal void OnAvatarReinitialize()
void OnAvatarReuse()
{
// Old VRIK is destroyed by game
m_inVR = Utils.IsInVR();
m_vrIK = PlayerSetup.Instance._animator.GetComponent<VRIK>();
if(m_inVR)
if(Utils.IsInVR())
RemoveArmIK();
if(m_vrIK != null)
{
m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreUpdate);
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate);
m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreSolverUpdate);
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostSolverUpdate);
}
else
{
@ -323,7 +325,7 @@ namespace ml_lme
}
// VRIK updates
void OnIKPreUpdate()
void OnIKPreSolverUpdate()
{
if(m_leftTargetActive)
{
@ -354,7 +356,7 @@ namespace ml_lme
m_vrIK.solver.rightArm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
}
}
void OnIKPostUpdate()
void OnIKPostSolverUpdate()
{
if(m_leftTargetActive)
{
@ -375,7 +377,7 @@ namespace ml_lme
}
// Settings
void OnEnabledChange(bool p_state)
void OnEnabledChanged(bool p_state)
{
m_enabled = p_state;
@ -383,7 +385,7 @@ namespace ml_lme
ResetTargetsStates();
}
void OnFingersOnlyChange(bool p_state)
void OnFingersOnlyChanged(bool p_state)
{
m_fingersOnly = p_state;
@ -391,7 +393,7 @@ namespace ml_lme
ResetTargetsStates();
}
void OnTrackElbowsChange(bool p_state)
void OnTrackElbowsChanged(bool p_state)
{
m_trackElbows = p_state;

View file

@ -62,23 +62,27 @@ namespace ml_lme
m_leapHandRight = new LeapHand(m_leapHands.transform.Find("HandR"), false);
}
Settings.DesktopOffsetChange += this.OnDesktopOffsetChange;
Settings.ModelVisibilityChange += this.OnModelVisibilityChange;
Settings.VisualHandsChange += this.OnVisualHandsChange;
Settings.TrackingModeChange += this.OnTrackingModeChange;
Settings.RootAngleChange += this.OnRootAngleChange;
Settings.HeadAttachChange += this.OnHeadAttachChange;
Settings.HeadOffsetChange += this.OnHeadOffsetChange;
OnModelVisibilityChanged(Settings.ModelVisibility);
OnVisualHandsChanged(Settings.VisualHands);
OnTrackingModeChanged(Settings.TrackingMode);
OnRootAngleChanged(Settings.RootAngle);
MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
OnModelVisibilityChange(Settings.ModelVisibility);
OnVisualHandsChange(Settings.VisualHands);
OnTrackingModeChange(Settings.TrackingMode);
OnRootAngleChange(Settings.RootAngle);
VRModeSwitchEvents.OnInitializeXR.AddListener(this.OnAvatarSetup);
VRModeSwitchEvents.OnDeinitializeXR.AddListener(this.OnAvatarSetup);
VRModeSwitchEvents.OnInitializeXR.AddListener(this.OnModeSwitch);
VRModeSwitchEvents.OnDeinitializeXR.AddListener(this.OnModeSwitch);
Settings.OnDesktopOffsetChanged.AddHandler(this.OnDesktopOffsetChanged);
Settings.OnModelVisibilityChanged.AddHandler(this.OnModelVisibilityChanged);
Settings.OnVisualHandsChanged.AddHandler(this.OnVisualHandsChanged);
Settings.OnTrackingModeChanged.AddHandler(this.OnTrackingModeChanged);
Settings.OnRootAngleChanged.AddHandler(this.OnRootAngleChanged);
Settings.OnHeadAttachChanged.AddHandler(this.OnHeadAttachChanged);
Settings.OnHeadOffsetChanged.AddHandler(this.OnHeadOffsetChanged);
GameEvents.OnAvatarClear.AddHandler(this.OnAvatarClear);
GameEvents.OnAvatarSetup.AddHandler(this.OnAvatarSetup);
GameEvents.OnPlayspaceScale.AddHandler(this.OnPlayspaceScale);
}
IEnumerator WaitForLocalPlayer()
@ -86,7 +90,7 @@ namespace ml_lme
while(PlayerSetup.Instance == null)
yield return null;
OnHeadAttachChange(Settings.HeadAttach);
OnHeadAttachChanged(Settings.HeadAttach);
}
void OnDestroy()
@ -112,16 +116,20 @@ namespace ml_lme
Object.Destroy(m_leapControllerModel);
m_leapControllerModel = null;
Settings.DesktopOffsetChange -= this.OnDesktopOffsetChange;
Settings.ModelVisibilityChange -= this.OnModelVisibilityChange;
Settings.VisualHandsChange -= this.OnVisualHandsChange;
Settings.TrackingModeChange -= this.OnTrackingModeChange;
Settings.RootAngleChange -= this.OnRootAngleChange;
Settings.HeadAttachChange -= this.OnHeadAttachChange;
Settings.HeadOffsetChange -= this.OnHeadOffsetChange;
VRModeSwitchEvents.OnInitializeXR.RemoveListener(this.OnAvatarSetup);
VRModeSwitchEvents.OnDeinitializeXR.RemoveListener(this.OnAvatarSetup);
VRModeSwitchEvents.OnInitializeXR.RemoveListener(this.OnModeSwitch);
VRModeSwitchEvents.OnDeinitializeXR.RemoveListener(this.OnModeSwitch);
Settings.OnDesktopOffsetChanged.RemoveHandler(this.OnDesktopOffsetChanged);
Settings.OnModelVisibilityChanged.RemoveHandler(this.OnModelVisibilityChanged);
Settings.OnVisualHandsChanged.RemoveHandler(this.OnVisualHandsChanged);
Settings.OnTrackingModeChanged.RemoveHandler(this.OnTrackingModeChanged);
Settings.OnRootAngleChanged.RemoveHandler(this.OnRootAngleChanged);
Settings.OnHeadAttachChanged.RemoveHandler(this.OnHeadAttachChanged);
Settings.OnHeadOffsetChanged.RemoveHandler(this.OnHeadOffsetChanged);
GameEvents.OnAvatarClear.RemoveHandler(this.OnAvatarClear);
GameEvents.OnAvatarSetup.RemoveHandler(this.OnAvatarSetup);
GameEvents.OnPlayspaceScale.RemoveHandler(this.OnPlayspaceScale);
}
void Update()
@ -142,7 +150,7 @@ namespace ml_lme
OrientationAdjustment(ref l_data.m_leftHand.m_elbowPosition, ref ms_dummyRotation, Settings.TrackingMode);
m_leapElbowLeft.localPosition = l_data.m_leftHand.m_elbowPosition;
m_leapHandLeft?.Update(l_data.m_leftHand);
m_leapHandLeft.Update(l_data.m_leftHand);
}
if(l_data.m_rightHand.m_present)
@ -157,7 +165,7 @@ namespace ml_lme
OrientationAdjustment(ref l_data.m_rightHand.m_elbowPosition, ref ms_dummyRotation, Settings.TrackingMode);
m_leapElbowRight.localPosition = l_data.m_rightHand.m_elbowPosition;
m_leapHandRight?.Update(l_data.m_rightHand);
m_leapHandRight.Update(l_data.m_rightHand);
}
}
}
@ -173,24 +181,24 @@ namespace ml_lme
}
// Settings
void OnDesktopOffsetChange(Vector3 p_offset)
void OnDesktopOffsetChanged(Vector3 p_offset)
{
if(!Settings.HeadAttach)
this.transform.localPosition = p_offset * (!m_inVR ? m_scaleRelation : 1f);
}
void OnModelVisibilityChange(bool p_state)
void OnModelVisibilityChanged(bool p_state)
{
m_leapControllerModel.SetActive(p_state);
}
void OnVisualHandsChange(bool p_state)
void OnVisualHandsChanged(bool p_state)
{
m_leapHandLeft?.SetMeshActive(p_state);
m_leapHandRight?.SetMeshActive(p_state);
}
void OnTrackingModeChange(Settings.LeapTrackingMode p_mode)
void OnTrackingModeChanged(Settings.LeapTrackingMode p_mode)
{
switch(p_mode)
{
@ -206,12 +214,12 @@ namespace ml_lme
}
}
void OnRootAngleChange(Vector3 p_angle)
void OnRootAngleChanged(Vector3 p_angle)
{
this.transform.localRotation = Quaternion.Euler(p_angle);
}
void OnHeadAttachChange(bool p_state)
void OnHeadAttachChanged(bool p_state)
{
if(!m_inVR)
{
@ -228,35 +236,29 @@ namespace ml_lme
this.transform.localRotation = Quaternion.Euler(Settings.RootAngle);
}
void OnHeadOffsetChange(Vector3 p_offset)
void OnHeadOffsetChanged(Vector3 p_offset)
{
if(Settings.HeadAttach)
this.transform.localPosition = p_offset * (!m_inVR ? m_scaleRelation : 1f);
}
// Game events
internal void OnAvatarClear()
void OnAvatarClear()
{
m_scaleRelation = 1f;
OnHeadAttachChange(Settings.HeadAttach);
OnHeadAttachChanged(Settings.HeadAttach);
}
internal void OnAvatarSetup()
void OnAvatarSetup()
{
m_inVR = Utils.IsInVR();
OnHeadAttachChange(Settings.HeadAttach);
OnHeadAttachChanged(Settings.HeadAttach);
}
internal void OnPlayspaceScale(float p_relation)
void OnPlayspaceScale(float p_relation)
{
m_scaleRelation = p_relation;
OnHeadAttachChange(Settings.HeadAttach);
}
void OnModeSwitch()
{
m_inVR = Utils.IsInVR();
OnHeadAttachChange(Settings.HeadAttach);
OnHeadAttachChanged(Settings.HeadAttach);
}
// Utils

View file

@ -1,8 +1,4 @@
using ABI.CCK.Components;
using ABI_RC.Core.Player;
using ABI_RC.Systems.IK;
using System.Collections;
using System.Reflection;
using System.Collections;
using UnityEngine;
namespace ml_lme
@ -10,61 +6,21 @@ namespace ml_lme
public class LeapMotionExtension : MelonLoader.MelonMod
{
static LeapMotionExtension ms_instance = null;
LeapManager m_leapManager = null;
public override void OnInitializeMelon()
{
if(ms_instance == null)
ms_instance = this;
DependenciesHandler.ExtractDependencies();
Settings.Init();
AssetsHandler.Load();
// Patches
HarmonyInstance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
null,
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
HarmonyInstance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
null,
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
HarmonyInstance.Patch(
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
null,
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
HarmonyInstance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetControllerRayScale)),
null,
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnRayScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
HarmonyInstance.Patch(
typeof(PlayerSetup).GetMethod("SetPlaySpaceScale", BindingFlags.NonPublic | BindingFlags.Instance),
null,
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnPlayspaceScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
HarmonyInstance.Patch(
typeof(CVRPickupObject).GetMethod(nameof(CVRPickupObject.Grab), BindingFlags.Public | BindingFlags.Instance),
null,
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnPickupGrab_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
GameEvents.Init(HarmonyInstance);
ModSupporter.Init();
MelonLoader.MelonCoroutines.Start(WaitForRootLogic());
}
public override void OnDeinitializeMelon()
{
if(ms_instance == this)
ms_instance = null;
if(m_leapManager != null)
Object.Destroy(m_leapManager);
m_leapManager = null;
@ -77,90 +33,5 @@ namespace ml_lme
m_leapManager = new GameObject("LeapMotionManager").AddComponent<LeapManager>();
}
// Patches
static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear();
void OnAvatarClear()
{
try
{
if(m_leapManager != null)
m_leapManager.OnAvatarClear();
}
catch(System.Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar();
void OnSetupAvatar()
{
try
{
if(m_leapManager != null)
m_leapManager.OnAvatarSetup();
}
catch(System.Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnAvatarReinitialize_Postfix() => ms_instance?.OnAvatarReinitialize();
void OnAvatarReinitialize()
{
try
{
if(m_leapManager != null)
m_leapManager.OnAvatarReinitialize();
}
catch(System.Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnRayScale_Postfix(float __0) => ms_instance?.OnRayScale(__0);
void OnRayScale(float p_scale)
{
try
{
if(m_leapManager != null)
m_leapManager.OnRayScale(p_scale);
}
catch(System.Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnPlayspaceScale_Postfix(float ____avatarScaleRelation) => ms_instance?.OnPlayspaceScale(____avatarScaleRelation);
void OnPlayspaceScale(float p_relation)
{
try
{
if(m_leapManager != null)
m_leapManager.OnPlayspaceScale(p_relation);
}
catch(System.Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnPickupGrab_Postfix(ref CVRPickupObject __instance) => ms_instance?.OnPickupGrab(__instance);
void OnPickupGrab(CVRPickupObject p_pickup)
{
try
{
if(m_leapManager != null)
m_leapManager.OnPickupGrab(p_pickup);
}
catch(System.Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
}
}

View file

@ -1,4 +1,4 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.4.9", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.5.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
[assembly: MelonLoader.MelonOptionalDependencies("ml_pmc")]
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]

View file

@ -7,6 +7,14 @@ namespace ml_lme
{
static class Settings
{
internal class SettingEvent<T>
{
event Action<T> m_action;
public void AddHandler(Action<T> p_listener) => m_action += p_listener;
public void RemoveHandler(Action<T> p_listener) => m_action -= p_listener;
public void Invoke(T p_value) => m_action?.Invoke(p_value);
}
public enum LeapTrackingMode
{
Screentop = 0,
@ -58,21 +66,21 @@ namespace ml_lme
static MelonLoader.MelonPreferences_Category ms_category = null;
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
public static event Action<bool> EnabledChange;
public static event Action<Vector3> DesktopOffsetChange;
public static event Action<bool> FingersOnlyChange;
public static event Action<bool> ModelVisibilityChange;
public static event Action<LeapTrackingMode> TrackingModeChange;
public static event Action<Vector3> RootAngleChange;
public static event Action<bool> HeadAttachChange;
public static event Action<Vector3> HeadOffsetChange;
public static event Action<bool> TrackElbowsChange;
public static event Action<bool> InteractionChange;
public static event Action<bool> GesturesChange;
public static event Action<float> InteractThreadholdChange;
public static event Action<float> GripThreadholdChange;
public static event Action<bool> VisualHandsChange;
public static event Action<bool> MechanimFilterChange;
public static readonly SettingEvent<bool> OnEnabledChanged = new SettingEvent<bool>();
public static readonly SettingEvent<Vector3> OnDesktopOffsetChanged = new SettingEvent<Vector3>();
public static readonly SettingEvent<bool> OnFingersOnlyChanged = new SettingEvent<bool>();
public static readonly SettingEvent<bool> OnModelVisibilityChanged = new SettingEvent<bool>();
public static readonly SettingEvent<LeapTrackingMode> OnTrackingModeChanged = new SettingEvent<LeapTrackingMode>();
public static readonly SettingEvent<Vector3> OnRootAngleChanged = new SettingEvent<Vector3>();
public static readonly SettingEvent<bool> OnHeadAttachChanged = new SettingEvent<bool>();
public static readonly SettingEvent<Vector3> OnHeadOffsetChanged = new SettingEvent<Vector3>();
public static readonly SettingEvent<bool> OnTrackElbowsChanged = new SettingEvent<bool>();
public static readonly SettingEvent<bool> OnInteractionChanged = new SettingEvent<bool>();
public static readonly SettingEvent<bool> OnGesturesChanged = new SettingEvent<bool>();
public static readonly SettingEvent<float> OnInteractThreadholdChanged = new SettingEvent<float>();
public static readonly SettingEvent<float> OnGripThreadholdChanged = new SettingEvent<float>();
public static readonly SettingEvent<bool> OnVisualHandsChanged = new SettingEvent<bool>();
public static readonly SettingEvent<bool> OnMechanimFilterChanged = new SettingEvent<bool>();
internal static void Init()
{
@ -103,7 +111,33 @@ namespace ml_lme
ms_category.CreateEntry(ModSetting.MechanimFilter.ToString(), MechanimFilter)
};
Load();
Enabled = (bool)ms_entries[(int)ModSetting.Enabled].BoxedValue;
DesktopOffset = new Vector3(
(int)ms_entries[(int)ModSetting.DesktopX].BoxedValue,
(int)ms_entries[(int)ModSetting.DesktopY].BoxedValue,
(int)ms_entries[(int)ModSetting.DesktopZ].BoxedValue
) * 0.01f;
FingersOnly = (bool)ms_entries[(int)ModSetting.FingersOnly].BoxedValue;
ModelVisibility = (bool)ms_entries[(int)ModSetting.Model].BoxedValue;
TrackingMode = (LeapTrackingMode)(int)ms_entries[(int)ModSetting.Mode].BoxedValue;
RootAngle = new Vector3(
(int)ms_entries[(int)ModSetting.AngleX].BoxedValue,
(int)ms_entries[(int)ModSetting.AngleY].BoxedValue,
(int)ms_entries[(int)ModSetting.AngleZ].BoxedValue
);
HeadAttach = (bool)ms_entries[(int)ModSetting.Head].BoxedValue;
HeadOffset = new Vector3(
(int)ms_entries[(int)ModSetting.HeadX].BoxedValue,
(int)ms_entries[(int)ModSetting.HeadY].BoxedValue,
(int)ms_entries[(int)ModSetting.HeadZ].BoxedValue
) * 0.01f;
TrackElbows = (bool)ms_entries[(int)ModSetting.TrackElbows].BoxedValue;
Interaction = (bool)ms_entries[(int)ModSetting.Interaction].BoxedValue;
Gestures = (bool)ms_entries[(int)ModSetting.Gestures].BoxedValue;
InteractThreadhold = (int)ms_entries[(int)ModSetting.InteractThreadhold].BoxedValue * 0.01f;
GripThreadhold = (int)ms_entries[(int)ModSetting.GripThreadhold].BoxedValue * 0.01f;
VisualHands = (bool)ms_entries[(int)ModSetting.VisualHands].BoxedValue;
MechanimFilter = (bool)ms_entries[(int)ModSetting.MechanimFilter].BoxedValue;
MelonLoader.MelonCoroutines.Start(WaitMainMenuUi());
}
@ -132,226 +166,216 @@ namespace ml_lme
};
}
static void Load()
{
Enabled = (bool)ms_entries[(int)ModSetting.Enabled].BoxedValue;
DesktopOffset = new Vector3(
(int)ms_entries[(int)ModSetting.DesktopX].BoxedValue,
(int)ms_entries[(int)ModSetting.DesktopY].BoxedValue,
(int)ms_entries[(int)ModSetting.DesktopZ].BoxedValue
) * 0.01f;
FingersOnly = (bool)ms_entries[(int)ModSetting.FingersOnly].BoxedValue;
ModelVisibility = (bool)ms_entries[(int)ModSetting.Model].BoxedValue;
TrackingMode = (LeapTrackingMode)(int)ms_entries[(int)ModSetting.Mode].BoxedValue;
RootAngle = new Vector3(
(int)ms_entries[(int)ModSetting.AngleX].BoxedValue,
(int)ms_entries[(int)ModSetting.AngleY].BoxedValue,
(int)ms_entries[(int)ModSetting.AngleZ].BoxedValue
);
HeadAttach = (bool)ms_entries[(int)ModSetting.Head].BoxedValue;
HeadOffset = new Vector3(
(int)ms_entries[(int)ModSetting.HeadX].BoxedValue,
(int)ms_entries[(int)ModSetting.HeadY].BoxedValue,
(int)ms_entries[(int)ModSetting.HeadZ].BoxedValue
) * 0.01f;
TrackElbows = (bool)ms_entries[(int)ModSetting.TrackElbows].BoxedValue;
Interaction = (bool)ms_entries[(int)ModSetting.Interaction].BoxedValue;
Gestures = (bool)ms_entries[(int)ModSetting.Gestures].BoxedValue;
InteractThreadhold = (int)ms_entries[(int)ModSetting.InteractThreadhold].BoxedValue * 0.01f;
GripThreadhold = (int)ms_entries[(int)ModSetting.GripThreadhold].BoxedValue * 0.01f;
VisualHands = (bool)ms_entries[(int)ModSetting.VisualHands].BoxedValue;
MechanimFilter = (bool)ms_entries[(int)ModSetting.MechanimFilter].BoxedValue;
}
static void OnToggleUpdate(string p_name, string p_value)
{
if(Enum.TryParse(p_name, out ModSetting l_setting))
try
{
switch(l_setting)
if(Enum.TryParse(p_name, out ModSetting l_setting))
{
case ModSetting.Enabled:
switch(l_setting)
{
Enabled = bool.Parse(p_value);
EnabledChange?.Invoke(Enabled);
}
break;
case ModSetting.Enabled:
{
Enabled = bool.Parse(p_value);
OnEnabledChanged.Invoke(Enabled);
}
break;
case ModSetting.FingersOnly:
{
FingersOnly = bool.Parse(p_value);
FingersOnlyChange?.Invoke(FingersOnly);
}
break;
case ModSetting.FingersOnly:
{
FingersOnly = bool.Parse(p_value);
OnFingersOnlyChanged.Invoke(FingersOnly);
}
break;
case ModSetting.Model:
{
ModelVisibility = bool.Parse(p_value);
ModelVisibilityChange?.Invoke(ModelVisibility);
}
break;
case ModSetting.Model:
{
ModelVisibility = bool.Parse(p_value);
OnModelVisibilityChanged.Invoke(ModelVisibility);
}
break;
case ModSetting.Head:
{
HeadAttach = bool.Parse(p_value);
HeadAttachChange?.Invoke(HeadAttach);
}
break;
case ModSetting.Head:
{
HeadAttach = bool.Parse(p_value);
OnHeadAttachChanged.Invoke(HeadAttach);
}
break;
case ModSetting.TrackElbows:
{
TrackElbows = bool.Parse(p_value);
TrackElbowsChange?.Invoke(TrackElbows);
}
break;
case ModSetting.TrackElbows:
{
TrackElbows = bool.Parse(p_value);
OnTrackElbowsChanged.Invoke(TrackElbows);
}
break;
case ModSetting.Interaction:
{
Interaction = bool.Parse(p_value);
InteractionChange?.Invoke(Interaction);
}
break;
case ModSetting.Interaction:
{
Interaction = bool.Parse(p_value);
OnInteractionChanged.Invoke(Interaction);
}
break;
case ModSetting.Gestures:
{
Gestures = bool.Parse(p_value);
GesturesChange?.Invoke(Gestures);
}
break;
case ModSetting.Gestures:
{
Gestures = bool.Parse(p_value);
OnGesturesChanged.Invoke(Gestures);
}
break;
case ModSetting.VisualHands:
{
VisualHands = bool.Parse(p_value);
VisualHandsChange?.Invoke(VisualHands);
case ModSetting.VisualHands:
{
VisualHands = bool.Parse(p_value);
OnVisualHandsChanged.Invoke(VisualHands);
}
break;
case ModSetting.MechanimFilter:
{
MechanimFilter = bool.Parse(p_value);
OnMechanimFilterChanged.Invoke(MechanimFilter);
}
break;
}
break;
case ModSetting.MechanimFilter:
{
MechanimFilter = bool.Parse(p_value);
MechanimFilterChange?.Invoke(MechanimFilter);
}
break;
ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
}
ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnSliderUpdate(string p_name, string p_value)
{
if(Enum.TryParse(p_name, out ModSetting l_setting))
try
{
switch(l_setting)
if(Enum.TryParse(p_name, out ModSetting l_setting))
{
case ModSetting.DesktopX:
switch(l_setting)
{
Vector3 l_current = DesktopOffset;
l_current.x = int.Parse(p_value) * 0.01f;
DesktopOffset = l_current;
DesktopOffsetChange?.Invoke(l_current);
}
break;
case ModSetting.DesktopY:
{
Vector3 l_current = DesktopOffset;
l_current.y = int.Parse(p_value) * 0.01f;
DesktopOffset = l_current;
DesktopOffsetChange?.Invoke(l_current);
}
break;
case ModSetting.DesktopZ:
{
Vector3 l_current = DesktopOffset;
l_current.z = int.Parse(p_value) * 0.01f;
DesktopOffset = l_current;
DesktopOffsetChange?.Invoke(l_current);
}
break;
case ModSetting.DesktopX:
{
Vector3 l_current = DesktopOffset;
l_current.x = int.Parse(p_value) * 0.01f;
DesktopOffset = l_current;
OnDesktopOffsetChanged.Invoke(l_current);
}
break;
case ModSetting.DesktopY:
{
Vector3 l_current = DesktopOffset;
l_current.y = int.Parse(p_value) * 0.01f;
DesktopOffset = l_current;
OnDesktopOffsetChanged.Invoke(l_current);
}
break;
case ModSetting.DesktopZ:
{
Vector3 l_current = DesktopOffset;
l_current.z = int.Parse(p_value) * 0.01f;
DesktopOffset = l_current;
OnDesktopOffsetChanged.Invoke(l_current);
}
break;
case ModSetting.AngleX:
{
Vector3 l_current = RootAngle;
l_current.x = int.Parse(p_value);
RootAngle = l_current;
RootAngleChange?.Invoke(l_current);
}
break;
case ModSetting.AngleX:
{
Vector3 l_current = RootAngle;
l_current.x = int.Parse(p_value);
RootAngle = l_current;
OnRootAngleChanged.Invoke(l_current);
}
break;
case ModSetting.AngleY:
{
Vector3 l_current = RootAngle;
l_current.y = int.Parse(p_value);
RootAngle = l_current;
RootAngleChange?.Invoke(l_current);
}
break;
case ModSetting.AngleY:
{
Vector3 l_current = RootAngle;
l_current.y = int.Parse(p_value);
RootAngle = l_current;
OnRootAngleChanged.Invoke(l_current);
}
break;
case ModSetting.AngleZ:
{
Vector3 l_current = RootAngle;
l_current.z = int.Parse(p_value);
RootAngle = l_current;
RootAngleChange?.Invoke(l_current);
}
break;
case ModSetting.AngleZ:
{
Vector3 l_current = RootAngle;
l_current.z = int.Parse(p_value);
RootAngle = l_current;
OnRootAngleChanged.Invoke(l_current);
}
break;
case ModSetting.HeadX:
{
Vector3 l_current = HeadOffset;
l_current.x = int.Parse(p_value) * 0.01f;
HeadOffset = l_current;
HeadOffsetChange?.Invoke(l_current);
case ModSetting.HeadX:
{
Vector3 l_current = HeadOffset;
l_current.x = int.Parse(p_value) * 0.01f;
HeadOffset = l_current;
OnHeadOffsetChanged.Invoke(l_current);
}
break;
case ModSetting.HeadY:
{
Vector3 l_current = HeadOffset;
l_current.y = int.Parse(p_value) * 0.01f;
HeadOffset = l_current;
OnHeadOffsetChanged.Invoke(l_current);
}
break;
case ModSetting.HeadZ:
{
Vector3 l_current = HeadOffset;
l_current.z = int.Parse(p_value) * 0.01f;
HeadOffset = l_current;
OnHeadOffsetChanged.Invoke(l_current);
}
break;
case ModSetting.InteractThreadhold:
{
InteractThreadhold = int.Parse(p_value) * 0.01f;
OnInteractThreadholdChanged.Invoke(InteractThreadhold);
}
break;
case ModSetting.GripThreadhold:
{
GripThreadhold = int.Parse(p_value) * 0.01f;
OnGripThreadholdChanged.Invoke(GripThreadhold);
}
break;
}
break;
case ModSetting.HeadY:
{
Vector3 l_current = HeadOffset;
l_current.y = int.Parse(p_value) * 0.01f;
HeadOffset = l_current;
HeadOffsetChange?.Invoke(l_current);
}
break;
case ModSetting.HeadZ:
{
Vector3 l_current = HeadOffset;
l_current.z = int.Parse(p_value) * 0.01f;
HeadOffset = l_current;
HeadOffsetChange?.Invoke(l_current);
}
break;
case ModSetting.InteractThreadhold:
{
InteractThreadhold = int.Parse(p_value) * 0.01f;
InteractThreadholdChange?.Invoke(InteractThreadhold);
}
break;
case ModSetting.GripThreadhold:
{
GripThreadhold = int.Parse(p_value) * 0.01f;
GripThreadholdChange?.Invoke(GripThreadhold);
}
break;
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
}
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnDropdownUpdate(string p_name, string p_value)
{
if(Enum.TryParse(p_name, out ModSetting l_setting))
try
{
switch(l_setting)
if(Enum.TryParse(p_name, out ModSetting l_setting))
{
case ModSetting.Mode:
switch(l_setting)
{
TrackingMode = (LeapTrackingMode)int.Parse(p_value);
TrackingModeChange?.Invoke(TrackingMode);
case ModSetting.Mode:
{
TrackingMode = (LeapTrackingMode)int.Parse(p_value);
OnTrackingModeChanged.Invoke(TrackingMode);
}
break;
}
break;
}
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
}
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
}

View file

@ -4,7 +4,7 @@
<TargetFramework>netstandard2.1</TargetFramework>
<Platforms>x64</Platforms>
<PackageId>LeapMotionExtension</PackageId>
<Version>1.4.9</Version>
<Version>1.5.0</Version>
<Authors>SDraw</Authors>
<Company>None</Company>
<Product>LeapMotionExtension</Product>
@ -93,6 +93,11 @@
<Private>false</Private>
<SpecificVersion>false</SpecificVersion>
</Reference>
<Reference Include="UnityEngine.JSONSerializeModule">
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.JSONSerializeModule.dll</HintPath>
<SpecificVersion>false</SpecificVersion>
<Private>false</Private>
</Reference>
<Reference Include="UnityEngine.XRModule">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.XRModule.dll</HintPath>
<Private>false</Private>

View file

@ -30,7 +30,7 @@ namespace Leap
/// Note that the Controller.Config provides a properly initialized Config object already.
/// @since 3.0
/// </summary>
[Obsolete("Config.cs is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
public Config(Connection.Key connectionKey)
{
_connection = Connection.GetConnection(connectionKey);
@ -38,9 +38,10 @@ namespace Leap
_connection.LeapConfigResponse += handleConfigResponse;
}
[Obsolete("Config.cs is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
public Config(int connectionId) : this(new Connection.Key(connectionId)) { }
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
private void handleConfigChange(object sender, ConfigChangeEventArgs eventArgs)
{
object actionDelegate;
@ -52,6 +53,7 @@ namespace Leap
}
}
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
private void handleConfigResponse(object sender, SetConfigResponseEventArgs eventArgs)
{
object actionDelegate = new object();

View file

@ -72,13 +72,9 @@ namespace LeapInternal
private IntPtr _leapConnection;
private volatile bool _isRunning = false;
public bool IsRunning { get { return _isRunning; } }
private Thread _polster;
/// <summary>
/// Has the connection been set up in multi device aware mode
/// </summary>
private bool _multiDeviceAwareConnection = false;
/// <summary>
/// Minimum service version that support setting the tracking mode on a per dervice basis
/// </summary>
@ -88,6 +84,7 @@ namespace LeapInternal
private Dictionary<uint, UInt64> _activePolicies = new Dictionary<uint, ulong>();
//Config change status
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
private Dictionary<uint, string> _configRequests = new Dictionary<uint, string>();
//Connection events
@ -124,13 +121,16 @@ namespace LeapInternal
public EventHandler<FrameEventArgs> LeapFrame;
public EventHandler<InternalFrameEventArgs> LeapInternalFrame;
public EventHandler<LogEventArgs> LeapLogEvent;
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
public EventHandler<SetConfigResponseEventArgs> LeapConfigResponse;
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
public EventHandler<ConfigChangeEventArgs> LeapConfigChange;
public EventHandler<DistortionEventArgs> LeapDistortionChange;
public EventHandler<DroppedFrameEventArgs> LeapDroppedFrame;
public EventHandler<ImageEventArgs> LeapImage;
public EventHandler<PointMappingChangeEventArgs> LeapPointMappingChange;
public EventHandler<HeadPoseEventArgs> LeapHeadPoseChange;
public EventHandler<FiducialPoseEventArgs> LeapFiducialPose;
public Action<BeginProfilingForThreadArgs> LeapBeginProfilingForThread;
public Action<EndProfilingForThreadArgs> LeapEndProfilingForThread;
@ -151,10 +151,6 @@ namespace LeapInternal
if (_disposed)
return;
if (disposing)
{
}
Stop();
LeapC.DestroyConnection(_leapConnection);
_leapConnection = IntPtr.Zero;
@ -181,9 +177,8 @@ namespace LeapInternal
{
LEAP_CONNECTION_CONFIG config = new LEAP_CONNECTION_CONFIG();
config.server_namespace = Marshal.StringToHGlobalAnsi(serverNamespace);
config.flags = multiDeviceAware ? (uint)eLeapConnectionFlag.eLeapConnectionFlag_MultipleDevicesAware : 0;
config.flags = (uint)eLeapConnectionFlag.eLeapConnectionFlag_MultipleDevicesAware;
config.size = (uint)Marshal.SizeOf(config);
_multiDeviceAwareConnection = multiDeviceAware;
Start(config);
}
@ -210,7 +205,18 @@ namespace LeapInternal
return;
}
}
// Produce metadata to send before connection is opened
string metadata = MetadataUtil.GetMetaData();
UIntPtr uIntPtr = new UIntPtr((uint)metadata.Length);
if (metadata != null && metadata != "")
{
LeapC.SetConnectionMetadata(_leapConnection, metadata, uIntPtr);
}
result = LeapC.OpenConnection(_leapConnection);
if (result != eLeapRS.eLeapRS_Success)
{
reportAbnormalResults("LeapC OpenConnection call was ", result);
@ -308,7 +314,6 @@ namespace LeapInternal
{
case eLeapEventType.eLeapEventType_None:
break;
case eLeapEventType.eLeapEventType_Connection:
LEAP_CONNECTION_EVENT connection_evt;
StructMarshal<LEAP_CONNECTION_EVENT>.PtrToStruct(_msg.eventStructPtr, out connection_evt);
@ -319,13 +324,11 @@ namespace LeapInternal
StructMarshal<LEAP_CONNECTION_LOST_EVENT>.PtrToStruct(_msg.eventStructPtr, out connection_lost_evt);
handleConnectionLost(ref connection_lost_evt);
break;
case eLeapEventType.eLeapEventType_Device:
LEAP_DEVICE_EVENT device_evt;
StructMarshal<LEAP_DEVICE_EVENT>.PtrToStruct(_msg.eventStructPtr, out device_evt);
handleDevice(ref device_evt);
break;
// Note that unplugging a device generates an eLeapEventType_DeviceLost event
// message, not a failure message. DeviceLost is further down.
case eLeapEventType.eLeapEventType_DeviceFailure:
@ -333,7 +336,6 @@ namespace LeapInternal
StructMarshal<LEAP_DEVICE_FAILURE_EVENT>.PtrToStruct(_msg.eventStructPtr, out device_failure_evt);
handleFailedDevice(ref device_failure_evt);
break;
case eLeapEventType.eLeapEventType_Policy:
LEAP_POLICY_EVENT policy_evt;
StructMarshal<LEAP_POLICY_EVENT>.PtrToStruct(_msg.eventStructPtr, out policy_evt);
@ -354,11 +356,6 @@ namespace LeapInternal
StructMarshal<LEAP_DEVICE_EVENT>.PtrToStruct(_msg.eventStructPtr, out device_lost_evt);
handleLostDevice(ref device_lost_evt);
break;
case eLeapEventType.eLeapEventType_ConfigChange:
LEAP_CONFIG_CHANGE_EVENT config_change_evt;
StructMarshal<LEAP_CONFIG_CHANGE_EVENT>.PtrToStruct(_msg.eventStructPtr, out config_change_evt);
handleConfigChange(ref config_change_evt);
break;
case eLeapEventType.eLeapEventType_DroppedFrame:
LEAP_DROPPED_FRAME_EVENT dropped_frame_evt;
StructMarshal<LEAP_DROPPED_FRAME_EVENT>.PtrToStruct(_msg.eventStructPtr, out dropped_frame_evt);
@ -374,16 +371,21 @@ namespace LeapInternal
StructMarshal<LEAP_POINT_MAPPING_CHANGE_EVENT>.PtrToStruct(_msg.eventStructPtr, out point_mapping_change_evt);
handlePointMappingChange(ref point_mapping_change_evt);
break;
case eLeapEventType.eLeapEventType_HeadPose:
LEAP_HEAD_POSE_EVENT head_pose_event;
StructMarshal<LEAP_HEAD_POSE_EVENT>.PtrToStruct(_msg.eventStructPtr, out head_pose_event);
handleHeadPoseChange(ref head_pose_event);
break;
case eLeapEventType.eLeapEventType_DeviceStatusChange:
LEAP_DEVICE_STATUS_CHANGE_EVENT status_evt;
StructMarshal<LEAP_DEVICE_STATUS_CHANGE_EVENT>.PtrToStruct(_msg.eventStructPtr, out status_evt);
handleDeviceStatusEvent(ref status_evt);
break;
case eLeapEventType.eLeapEventType_NewDeviceTransform:
LEAP_NEW_DEVICE_TRANSFORM new_transform_evt;
StructMarshal<LEAP_NEW_DEVICE_TRANSFORM>.PtrToStruct(_msg.eventStructPtr, out new_transform_evt);
handleNewDeviceTransform(ref new_transform_evt, _msg.deviceID);
break;
case eLeapEventType.eLeapEventType_Fiducial:
LEAP_FIDUCIAL_POSE_EVENT fiducial_event;
StructMarshal<LEAP_FIDUCIAL_POSE_EVENT>.PtrToStruct(_msg.eventStructPtr, out fiducial_event);
handleFiducialPoseEvent(ref fiducial_event);
break;
} //switch on _msg.type
if (LeapEndProfilingBlock != null && hasBegunProfilingForThread)
@ -582,7 +584,6 @@ namespace LeapInternal
}
Marshal.FreeHGlobal(trackingBuffer);
}
public void GetInterpolatedLeftRightTransform(Int64 time,
@ -622,6 +623,15 @@ namespace LeapInternal
device.UpdateStatus(statusEvent.status);
}
private void handleFiducialPoseEvent(ref LEAP_FIDUCIAL_POSE_EVENT fiducialPoseEvent)
{
if (LeapFiducialPose != null)
{
LeapFiducialPose.DispatchOnContext(this, EventContext,
new FiducialPoseEventArgs(fiducialPoseEvent));
}
}
private void handleDevice(ref LEAP_DEVICE_EVENT deviceMsg)
{
IntPtr deviceHandle = deviceMsg.device.handle;
@ -733,19 +743,6 @@ namespace LeapInternal
}
}
private void handleConfigChange(ref LEAP_CONFIG_CHANGE_EVENT configEvent)
{
string config_key = "";
_configRequests.TryGetValue(configEvent.requestId, out config_key);
if (config_key != null)
_configRequests.Remove(configEvent.requestId);
if (LeapConfigChange != null)
{
LeapConfigChange.DispatchOnContext(this, EventContext,
new ConfigChangeEventArgs(config_key, configEvent.status != false, configEvent.requestId));
}
}
private void reportLogMessage(ref LEAP_LOG_EVENT logMsg)
{
if (LeapLogEvent != null)
@ -866,29 +863,30 @@ namespace LeapInternal
_activePolicies[deviceID] = policyMsg.current_policy;
}
private void handleNewDeviceTransform(ref LEAP_NEW_DEVICE_TRANSFORM deviceTransformMsg, UInt32 deviceID)
{
Device device = _devices.FindDeviceByID(deviceID);
if (device != null)
{
device.FindDeviceTransform();
}
}
public void SetAndClearPolicy(Controller.PolicyFlag set, Controller.PolicyFlag clear, Device device = null)
{
UInt64 setFlags = (ulong)FlagForPolicy(set);
UInt64 clearFlags = (ulong)FlagForPolicy(clear);
eLeapRS result;
if (device == null || !_multiDeviceAwareConnection)
if (device != null && Controller.CheckRequiredServiceVersion(MinServiceVersionForMultiModeSupport, this))
{
result = LeapC.SetPolicyFlags(_leapConnection, setFlags, clearFlags);
result = LeapC.SetPolicyFlagsEx(_leapConnection, device.Handle, setFlags, clearFlags);
}
else
{
if (!Controller.CheckRequiredServiceVersion(MinServiceVersionForMultiModeSupport, this))
{
UnityEngine.Debug.LogWarning(String.Format("Your current tracking service does not support setting policy flags on a per device basis (min version is {0}.{1}.{2}). Please update your service: https://developer.leapmotion.com/tracking-software-download",
MinServiceVersionForMultiModeSupport.major,
MinServiceVersionForMultiModeSupport.minor,
MinServiceVersionForMultiModeSupport.patch));
return;
}
result = LeapC.SetPolicyFlagsEx(_leapConnection, device.Handle, setFlags, clearFlags);
result = LeapC.SetPolicyFlags(_leapConnection, setFlags, clearFlags);
}
reportAbnormalResults("LeapC SetAndClearPolicy call was ", result);
@ -900,23 +898,13 @@ namespace LeapInternal
eLeapRS result;
if (device == null || !_multiDeviceAwareConnection)
if (device != null && Controller.CheckRequiredServiceVersion(MinServiceVersionForMultiModeSupport, this))
{
result = LeapC.SetPolicyFlags(_leapConnection, setFlags, 0);
result = LeapC.SetPolicyFlagsEx(_leapConnection, device.Handle, setFlags, 0);
}
else
{
if (!Controller.CheckRequiredServiceVersion(MinServiceVersionForMultiModeSupport, this))
{
UnityEngine.Debug.LogWarning(String.Format("Your current tracking service does not support setting policy flags on a per device basis (min version is {0}.{1}.{2}). Please update your service: https://developer.leapmotion.com/tracking-software-download",
MinServiceVersionForMultiModeSupport.major,
MinServiceVersionForMultiModeSupport.minor,
MinServiceVersionForMultiModeSupport.patch));
return;
}
result = LeapC.SetPolicyFlagsEx(_leapConnection, device.Handle, setFlags, 0);
result = LeapC.SetPolicyFlags(_leapConnection, setFlags, 0);
}
reportAbnormalResults("LeapC SetPolicyFlags call was ", result);
@ -928,23 +916,13 @@ namespace LeapInternal
eLeapRS result;
if (device == null || !_multiDeviceAwareConnection)
if (device != null && Controller.CheckRequiredServiceVersion(MinServiceVersionForMultiModeSupport, this))
{
result = LeapC.SetPolicyFlags(_leapConnection, 0, clearFlags);
result = LeapC.SetPolicyFlagsEx(_leapConnection, device.Handle, 0, clearFlags);
}
else
{
if (!Controller.CheckRequiredServiceVersion(MinServiceVersionForMultiModeSupport, this))
{
UnityEngine.Debug.LogWarning(String.Format("Your current tracking service does not support clearing policy flags on a per device basis (min version is {0}.{1}.{2}). Please update your service: https://developer.leapmotion.com/tracking-software-download",
MinServiceVersionForMultiModeSupport.major,
MinServiceVersionForMultiModeSupport.minor,
MinServiceVersionForMultiModeSupport.patch));
return;
}
result = LeapC.SetPolicyFlagsEx(_leapConnection, device.Handle, 0, clearFlags);
result = LeapC.SetPolicyFlags(_leapConnection, 0, clearFlags);
}
reportAbnormalResults("LeapC SetPolicyFlags call was ", result);
@ -1071,6 +1049,7 @@ namespace LeapInternal
return _activePolicies.ContainsKey(deviceID);
}
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
public uint GetConfigValue(string config_key)
{
uint requestId = 0;
@ -1080,6 +1059,7 @@ namespace LeapInternal
return requestId;
}
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
public uint SetConfigValue<T>(string config_key, T value) where T : IConvertible
{
uint requestId = 0;
@ -1322,6 +1302,19 @@ namespace LeapInternal
Marshal.FreeHGlobal(buffer);
}
/// <summary>
/// Send a specific set of hints to hDevice, if this does not include previously set ones, they will be cleared.
/// </summary>
/// <param name="hDevice">The Device pointer for the trcking device to set the hints for</param>
/// <param name="hints">The array of hints</param>
public void RequestHandTrackingHintsOnDevice(IntPtr hDevice, string[] hints)
{
eLeapRS result;
result = LeapC.SetDeviceHints(_leapConnection, hDevice, hints);
reportAbnormalResults("LeapC SetDeviceHints call was ", result);
}
private eLeapRS _lastResult; //Used to avoid repeating the same log message, ie. for events like time out
private void reportAbnormalResults(string context, eLeapRS result)
{

View file

@ -10,6 +10,7 @@ namespace Leap
{
using LeapInternal;
using System;
using System.Linq;
using System.Threading;
using UnityEngine;
@ -41,7 +42,6 @@ namespace Leap
{
Connection _connection;
bool _disposed = false;
bool _supportsMultipleDevices = true;
string _serverNamespace = "Leap Service";
/// <summary>
@ -232,6 +232,7 @@ namespace Leap
/// Dispatched when a configuration setting changes.
/// @since 3.0
/// </summary>
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
public event EventHandler<ConfigChangeEventArgs> ConfigChange
{
add
@ -403,6 +404,21 @@ namespace Leap
}
}
/// <summary>
/// Dispatched when a Fiducial Marker has been tracked.
/// </summary>
public event EventHandler<FiducialPoseEventArgs> FiducialPose
{
add
{
_connection.LeapFiducialPose += value;
}
remove
{
_connection.LeapFiducialPose -= value;
}
}
public void Dispose()
{
Dispose(true);
@ -446,14 +462,16 @@ namespace Leap
_connection = Connection.GetConnection(new Connection.Key(connectionKey, serverNamespace));
_connection.EventContext = SynchronizationContext.Current;
if (_connection.IsRunning)
_hasInitialized = true;
_connection.LeapInit += OnInit;
_connection.LeapConnection += OnConnect;
_connection.LeapConnectionLost += OnDisconnect;
_supportsMultipleDevices = supportsMultipleDevices;
_serverNamespace = serverNamespace;
_connection.Start(serverNamespace, supportsMultipleDevices);
StartConnection();
}
@ -467,7 +485,7 @@ namespace Leap
/// </summary>
public void StartConnection()
{
_connection.Start(_serverNamespace, _supportsMultipleDevices);
_connection.Start(_serverNamespace);
}
/// <summary>
@ -621,6 +639,21 @@ namespace Leap
return _connection.IsDeviceAvailable(device);
}
/// <summary>
/// Send a specific set of hints, if this does not include previously set ones, they will be cleared.
/// </summary>
/// <param name="hints">The hints you wish to send</param>
/// <param name="device">An optional specific Device, otherwise the first found will be used</param>
public void RequestHandTrackingHints(string[] hints, Device device = null)
{
if (device == null)
{
device = Devices.ActiveDevices.FirstOrDefault();
}
_connection.RequestHandTrackingHintsOnDevice(device.Handle, hints);
}
/// <summary>
/// In most cases you should get Frame objects using the LeapProvider.CurrentFrame
/// property. The data in Frame objects taken directly from a Leap.Controller instance
@ -870,7 +903,7 @@ namespace Leap
///
/// @since 1.0
/// </summary>
[Obsolete("Config.cs is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
public Config Config
{
get

View file

@ -14,12 +14,30 @@ namespace LeapInternal
{
public static readonly float MM_TO_M = 1e-3f;
public static bool leapToUnityTransformSet = false;
private static LeapTransform leapToUnityTransform;
/**
* Provides a static LeapTransform that converts from Leap units and coordinates to Unity
*/
public static LeapTransform LeapToUnityTransform
{
get
{
if (!leapToUnityTransformSet)
{
leapToUnityTransform = new LeapTransform(Vector3.zero, Quaternion.identity, new Vector3(MM_TO_M, MM_TO_M, MM_TO_M));
leapToUnityTransform.MirrorZ();
leapToUnityTransformSet = true;
}
return leapToUnityTransform;
}
}
public static void TransformToUnityUnits(this Hand hand)
{
LeapTransform leapTransform = new LeapTransform(Vector3.zero, Quaternion.identity, new Vector3(MM_TO_M, MM_TO_M, MM_TO_M));
leapTransform.MirrorZ();
hand.Transform(leapTransform);
hand.Transform(LeapToUnityTransform);
}

View file

@ -255,67 +255,78 @@ namespace Leap
return devicePose;
}
bool deviceTransformAvailable = LeapC.GetDeviceTransformAvailable(Handle);
if (!deviceTransformAvailable)
{
devicePose = Pose.identity;
poseSet = true;
return Pose.identity;
}
float[] data = new float[16];
eLeapRS result = LeapC.GetDeviceTransform(Handle, data);
if (result != eLeapRS.eLeapRS_Success || data == null)
{
devicePose = Pose.identity;
poseSet = true;
return Pose.identity;
}
// Using the LEAP->OPENXR device transform matrix
// Unitys matrices are generated as 4 columns:
Matrix4x4 deviceTransform = new Matrix4x4(
new Vector4(data[0], data[1], data[2], data[3]),
new Vector4(data[4], data[5], data[6], data[7]),
new Vector4(data[8], data[9], data[10], data[11]),
new Vector4(data[12], data[13], data[14], data[15]));
// An example of the expected matrix if it were 8cm forward from the head origin
// Unitys matrices are generated as 4 columns:
//Matrix4x4 deviceTransform = new Matrix4x4(
// new Vector4(-0.001f, 0, 0, 0),
// new Vector4(0, 0, -0.001f, 0),
// new Vector4(0, -0.001f, 0, 0),
// new Vector4(0, 0, -0.08f, 1));
if (deviceTransform == Matrix4x4.identity)
{
devicePose = Pose.identity;
poseSet = true;
return Pose.identity;
}
Matrix4x4 openXRToUnity = new Matrix4x4(
new Vector4(1f, 0, 0, 0),
new Vector4(0, 1f, 0, 0),
new Vector4(0, 0, -1f, 0),
new Vector4(0, 0, 0, 1));
deviceTransform = openXRToUnity * deviceTransform;
Vector3 outputPos = deviceTransform.GetPosition();
//Quaternion outputRot = deviceTransform.rotation; // Note: the matrices we receive are not rotatrion matrices. This produces unexpected results
devicePose = new Pose(outputPos, Quaternion.identity);
poseSet = true;
return devicePose;
return FindDeviceTransform();
}
}
internal Pose FindDeviceTransform()
{
// Check the service has valid support for device transforms
LEAP_VERSION minimumServiceVersion = new LEAP_VERSION { major = 5, minor = 19, patch = 0 };
if (!ServerStatus.IsServiceVersionValid(minimumServiceVersion))
{
devicePose = Pose.identity;
poseSet = true;
return Pose.identity;
}
// Check the device transform is available before asking for one
bool deviceTransformAvailable = LeapC.GetDeviceTransformAvailable(Handle);
if (!deviceTransformAvailable)
{
devicePose = Pose.identity;
return Pose.identity;
}
// Get the device transform data and check it is valid as data
float[] data = new float[16];
eLeapRS result = LeapC.GetDeviceTransform(Handle, data);
if (result != eLeapRS.eLeapRS_Success || data == null)
{
devicePose = Pose.identity;
return Pose.identity;
}
// Using the LEAP->OPENXR device transform matrix
// Unitys matrices are generated as 4 columns:
Matrix4x4 deviceTransform = new Matrix4x4(
new Vector4(data[0], data[1], data[2], data[3]),
new Vector4(data[4], data[5], data[6], data[7]),
new Vector4(data[8], data[9], data[10], data[11]),
new Vector4(data[12], data[13], data[14], data[15]));
////An example of the expected matrix if it were 8cm forward from the head origin
//// Unitys matrices are generated as 4 columns:
//Matrix4x4 deviceTransform = new Matrix4x4(
// new Vector4(-0.001f, 0, 0, 0),
// new Vector4(0, 0, -0.001f, 0),
// new Vector4(0, -0.001f, 0, 0),
// new Vector4(0, 0, -0.08f, 1));
//// An example of applying a rotation to the existing device transform
//Matrix4x4 rotationMatrix = Matrix4x4.Rotate(Quaternion.Euler(0, 90, 0));
//deviceTransform = deviceTransform * rotationMatrix;
Matrix4x4 openXRToUnitySwizzle = new Matrix4x4(
new Vector4(1.0f, 0, 0, 0),
new Vector4(0, 1.0f, 0, 0),
new Vector4(0, 0, -1f, 0),
new Vector4(0, 0, 0, 1f));
// Converts device transform from openxr space to unity space
deviceTransform = openXRToUnitySwizzle.inverse * deviceTransform * openXRToUnitySwizzle;
Vector3 outputPos = deviceTransform.GetPosition();
Quaternion outputRot = deviceTransform.rotation;
devicePose = new Pose(outputPos, outputRot);
poseSet = true;
return devicePose;
}
/// <summary>
/// Returns the internal status field of the current device
/// </summary>

View file

@ -10,6 +10,7 @@ namespace Leap
{
using LeapInternal;
using System;
using System.Runtime.InteropServices;
/// <summary>
/// An enumeration defining the types of Leap Motion events.
@ -35,7 +36,8 @@ namespace Leap
EVENT_DROPPED_FRAME,
EVENT_IMAGE, //!< An unrequested image is available
EVENT_POINT_MAPPING_CHANGE,
EVENT_HEAD_POSE
EVENT_HEAD_POSE,
EVENT_FIDUCIAL_POSE
};
/// <summary>
/// A generic object with no arguments beyond the event type.
@ -159,6 +161,7 @@ namespace Leap
/// Provides the configuration key, whether the change was successful, and the id of the original change request.
/// @since 3.0
/// </summary>
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
public class ConfigChangeEventArgs : LeapEventArgs
{
public ConfigChangeEventArgs(string config_key, bool succeeded, uint requestId) : base(LeapEvent.EVENT_CONFIG_CHANGE)
@ -308,6 +311,33 @@ namespace Leap
public LEAP_QUATERNION headOrientation { get; set; }
}
/// <summary>
/// Dispatched when a Fiducial Marker is tracked
///
/// Note: Family and Size are not currently implemented
/// </summary>
public class FiducialPoseEventArgs : LeapEventArgs
{
public FiducialPoseEventArgs(LEAP_FIDUCIAL_POSE_EVENT poseEvent) : base(LeapEvent.EVENT_FIDUCIAL_POSE)
{
this.id = poseEvent.id;
this.family = ""; // TODO: Marshal.PtrToStringAnsi(poseEvent.family); - when ptr is implemented in LeapC
this.size = poseEvent.size;
this.timestamp = poseEvent.timestamp;
this.estimated_error = poseEvent.estimated_error;
this.translation = poseEvent.translation;
this.rotation = poseEvent.rotation;
}
public int id { get; set; }
public string family { get; set; }
public float size { get; set; }
public float timestamp { get; set; }
public float estimated_error { get; set; }
public LEAP_VECTOR translation { get; set; }
public LEAP_QUATERNION rotation { get; set; }
}
public struct BeginProfilingForThreadArgs
{
public string threadName;

View file

@ -37,6 +37,7 @@ namespace Leap
//new
event EventHandler<PolicyEventArgs> PolicyChange;
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
event EventHandler<ConfigChangeEventArgs> ConfigChange;
event EventHandler<DistortionEventArgs> DistortionChange;
event EventHandler<ImageEventArgs> ImageReady;

View file

@ -532,15 +532,26 @@ namespace LeapInternal
/// <summary>
/// A new head pose is available.
/// </summary>
[Obsolete("Head pose events are not supported and will never be raised")]
eLeapEventType_HeadPose,
/// <summary>
/// A new head pose is available.
/// </summary>
[Obsolete("Eye pose events are not supported and will never be raised")]
eLeapEventType_Eyes,
/// <summary>
/// A new head pose is available.
/// A new IMU information frame is available.
/// </summary>
eLeapEventType_IMU
eLeapEventType_IMU,
/// <summary>
/// Notification that the service received a new device transformation matrix
/// Use LeapGetDeviceTransform to update your cached information.
/// </summary>
eLeapEventType_NewDeviceTransform,
/// <summary>
/// An event provided when a fiducial marker has been tracked
/// </summary>
eLeapEventType_Fiducial
};
public enum eLeapDeviceFlag : uint
@ -718,6 +729,12 @@ namespace LeapInternal
public LEAP_VECTOR head_angular_velocity;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct LEAP_NEW_DEVICE_TRANSFORM
{
public UInt32 reserved;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct LEAP_CONNECTION_MESSAGE
{
@ -974,6 +991,18 @@ namespace LeapInternal
public string zoneName;
}
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct LEAP_FIDUCIAL_POSE_EVENT
{
public int id;
public IntPtr family; // char*
public float size;
public Int64 timestamp;
public float estimated_error;
public LEAP_VECTOR translation;
public LEAP_QUATERNION rotation;
}
public class LeapC
{
private LeapC() { }
@ -1023,6 +1052,9 @@ namespace LeapInternal
[DllImport("LeapC", EntryPoint = "LeapOpenConnection")]
public static extern eLeapRS OpenConnection(IntPtr hConnection);
[DllImport("LeapC", EntryPoint = "LeapSetConnectionMetadata")]
public static extern eLeapRS SetConnectionMetadata(IntPtr hConnection, string metadata, UIntPtr len);
[DllImport("LeapC", EntryPoint = "LeapSetAllocator")]
public static extern eLeapRS SetAllocator(IntPtr hConnection, ref LEAP_ALLOCATOR pAllocator);
@ -1122,12 +1154,15 @@ namespace LeapInternal
[DllImport("LeapC", EntryPoint = "LeapDestroyConnection")]
public static extern void DestroyConnection(IntPtr connection);
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
[DllImport("LeapC", EntryPoint = "LeapSaveConfigValue")]
private static extern eLeapRS SaveConfigValue(IntPtr hConnection, string key, IntPtr value, out UInt32 requestId);
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
[DllImport("LeapC", EntryPoint = "LeapRequestConfigValue")]
public static extern eLeapRS RequestConfigValue(IntPtr hConnection, string name, out UInt32 request_id);
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
public static eLeapRS SaveConfigValue(IntPtr hConnection, string key, bool value, out UInt32 requestId)
{
LEAP_VARIANT_VALUE_TYPE valueStruct = new LEAP_VARIANT_VALUE_TYPE(); //This is a C# approximation of a C union
@ -1135,6 +1170,7 @@ namespace LeapInternal
valueStruct.boolValue = value ? 1 : 0;
return SaveConfigWithValueType(hConnection, key, valueStruct, out requestId);
}
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
public static eLeapRS SaveConfigValue(IntPtr hConnection, string key, Int32 value, out UInt32 requestId)
{
LEAP_VARIANT_VALUE_TYPE valueStruct = new LEAP_VARIANT_VALUE_TYPE();
@ -1142,6 +1178,7 @@ namespace LeapInternal
valueStruct.intValue = value;
return SaveConfigWithValueType(hConnection, key, valueStruct, out requestId);
}
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
public static eLeapRS SaveConfigValue(IntPtr hConnection, string key, float value, out UInt32 requestId)
{
LEAP_VARIANT_VALUE_TYPE valueStruct = new LEAP_VARIANT_VALUE_TYPE();
@ -1149,6 +1186,7 @@ namespace LeapInternal
valueStruct.floatValue = value;
return SaveConfigWithValueType(hConnection, key, valueStruct, out requestId);
}
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
public static eLeapRS SaveConfigValue(IntPtr hConnection, string key, string value, out UInt32 requestId)
{
LEAP_VARIANT_REF_TYPE valueStruct;
@ -1156,6 +1194,8 @@ namespace LeapInternal
valueStruct.stringValue = value;
return SaveConfigWithRefType(hConnection, key, valueStruct, out requestId);
}
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
private static eLeapRS SaveConfigWithValueType(IntPtr hConnection, string key, LEAP_VARIANT_VALUE_TYPE valueStruct, out UInt32 requestId)
{
IntPtr configValue = Marshal.AllocHGlobal(Marshal.SizeOf(valueStruct));
@ -1171,6 +1211,8 @@ namespace LeapInternal
}
return callResult;
}
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
private static eLeapRS SaveConfigWithRefType(IntPtr hConnection, string key, LEAP_VARIANT_REF_TYPE valueStruct, out UInt32 requestId)
{
IntPtr configValue = Marshal.AllocHGlobal(Marshal.SizeOf(valueStruct));
@ -1230,5 +1272,43 @@ namespace LeapInternal
[DllImport("LeapC", EntryPoint = "LeapGetVersion")]
public static extern eLeapRS GetVersion(IntPtr hConnection, eLeapVersionPart versionPart, ref LEAP_VERSION pVersion);
[DllImport("LeapC", EntryPoint = "LeapGetServerStatus")]
public static extern eLeapRS GetServerStatus(UInt32 timeout, ref IntPtr status);
[DllImport("LeapC", EntryPoint = "LeapReleaseServerStatus")]
public static extern eLeapRS ReleaseServerStatus(ref LEAP_SERVER_STATUS status);
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct LEAP_SERVER_STATUS
{
public string version;
public UInt32 device_count;
public IntPtr devices;
}
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct LEAP_SERVER_STATUS_DEVICE
{
public string serial;
public string type;
}
public static eLeapRS SetDeviceHints(IntPtr hConnection, IntPtr hDevice, string[] hints)
{
// Ensure the final element of the array is null terminated.
if (hints.Length == 0 || hints[^1] != null)
{
Array.Resize(ref hints, hints.Length + 1);
hints[^1] = null;
}
return SetDeviceHintsInternal(hConnection, hDevice, hints);
}
[DllImport("LeapC", EntryPoint = "LeapSetDeviceHints")]
private static extern eLeapRS SetDeviceHintsInternal(IntPtr hConnection, IntPtr hDevice, string[] hints);
}
}

138
ml_lme/vendor/LeapCSharp/MetadataUtil.cs vendored Normal file
View file

@ -0,0 +1,138 @@
/******************************************************************************
* Copyright (C) Ultraleap, Inc. 2011-2024. *
* *
* Use subject to the terms of the Apache License 2.0 available at *
* http://www.apache.org/licenses/LICENSE-2.0, or another agreement *
* between Ultraleap and you, your company or other organization. *
******************************************************************************/
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Rendering;
namespace Leap
{
/// <summary>
/// This class captures information regarding use of the Ultraleap Unity Plugin
/// This data is anonymized and only sent to Ultraleap when you choose to allow it.
/// You can change your analytics preferences in the Ultraleap Tracking Control Panel.
/// "Settings > Help Improve Tracking"
/// </summary>
#if UNITY_EDITOR
[UnityEditor.InitializeOnLoad]
#endif
public class MetadataUtil
{
[System.Serializable]
private struct Analytics
{
public Telemetry telemetry;
}
[System.Serializable]
private struct Telemetry
{
public string app_name;
public string app_type;
public string engine_name;
public string engine_version;
public string plugin_version;
public string installation_source;
public string interaction_system;
public string render_pipeline;
}
#if UNITY_EDITOR
// Fire a one-off call to capture metadata at edit time on the first editor update
static MetadataUtil()
{
UnityEditor.EditorApplication.update -= FirstEditorUpdate;
UnityEditor.EditorApplication.update += FirstEditorUpdate;
}
static void FirstEditorUpdate()
{
UnityEditor.EditorApplication.update -= FirstEditorUpdate;
// This will capture some values within the editor that may not be accessible in builds
// e.g. Plugin Source and Plugin Versions
GetMetaData();
}
#endif
public static string GetMetaData()
{
Analytics analytics = new Analytics();
analytics.telemetry = new Telemetry();
analytics.telemetry.app_name = Application.productName;
analytics.telemetry.app_type = GetAppType();
analytics.telemetry.engine_name = "Unity";
analytics.telemetry.engine_version = Application.unityVersion;
analytics.telemetry.plugin_version = Leap.Unity.UltraleapSettings.Instance.PluginVersion;
analytics.telemetry.installation_source = Leap.Unity.UltraleapSettings.Instance.PluginSource;
analytics.telemetry.interaction_system = GetInteractionSystem();
analytics.telemetry.render_pipeline = GetRenderPipeline();
string json = JsonUtility.ToJson(analytics, true);
return json;
}
static string GetAppType()
{
string appType = "Build";
#if UNITY_EDITOR
appType = "Editor";
#endif
return appType;
}
static string GetRenderPipeline()
{
string renderPipeline = "Built In";
if (QualitySettings.renderPipeline != null)
{
renderPipeline = QualitySettings.renderPipeline.GetType().ToString().Split(".").Last();
}
else if (GraphicsSettings.currentRenderPipeline != null)
{
renderPipeline = GraphicsSettings.currentRenderPipeline.GetType().ToString().Split(".").Last();
}
return renderPipeline;
}
static string GetInteractionSystem()
{
// Physical Hands
if (GameObject.Find("Physical Hands Manager") ||
GameObject.Find("Left HardContactHand") ||
GameObject.Find("Left SoftContactHand") ||
GameObject.Find("Left NoContactHand"))
{
return "Physical Hands";
}
// Interaction Engine
if (GameObject.Find("Interaction Hand (Left)"))
{
return "Interaction Engine";
}
// XR Hands
if (Leap.Unity.UltraleapSettings.Instance.leapSubsystemEnabled ||
Leap.Unity.UltraleapSettings.Instance.updateLeapInputSystem ||
Leap.Unity.UltraleapSettings.Instance.updateMetaInputSystem)
{
return "UL XR Hands";
}
return "Unknown";
}
}
}

112
ml_lme/vendor/LeapCSharp/ServerStatus.cs vendored Normal file
View file

@ -0,0 +1,112 @@
/******************************************************************************
* Copyright (C) Ultraleap, Inc. 2011-2024. *
* *
* Use subject to the terms of the Apache License 2.0 available at *
* http://www.apache.org/licenses/LICENSE-2.0, or another agreement *
* between Ultraleap and you, your company or other organization. *
******************************************************************************/
namespace LeapInternal
{
using System;
using System.Runtime.InteropServices;
using UnityEngine;
public static class ServerStatus
{
const double requestInterval = 1.0f;
static double lastRequestTimestamp;
static LeapC.LEAP_SERVER_STATUS lastStatus;
static LeapC.LEAP_SERVER_STATUS_DEVICE[] lastDevices;
public static void GetStatus()
{
if (lastRequestTimestamp + requestInterval < Time.realtimeSinceStartup)
{
IntPtr statusPtr = new IntPtr();
LeapC.GetServerStatus(1000, ref statusPtr);
lastStatus = Marshal.PtrToStructure<LeapC.LEAP_SERVER_STATUS>(statusPtr);
MarshalUnmananagedArray2Struct(lastStatus.devices, (int)lastStatus.device_count, out lastDevices);
LeapC.ReleaseServerStatus(ref lastStatus);
lastRequestTimestamp = Time.realtimeSinceStartup;
}
}
public static bool IsServiceVersionValid(LEAP_VERSION _requiredVersion)
{
GetStatus();
if (lastStatus.version != null)
{
string[] versions = lastStatus.version.Split('v')[1].Split('-')[0].Split('.');
LEAP_VERSION curVersion = new LEAP_VERSION { major = int.Parse(versions[0]), minor = int.Parse(versions[1]), patch = int.Parse(versions[2]) };
if (_requiredVersion.major < curVersion.major)
{
return true;
}
else if (_requiredVersion.major == curVersion.major)
{
if (_requiredVersion.minor < curVersion.minor)
{
return true;
}
else if (_requiredVersion.minor == curVersion.minor && _requiredVersion.patch <= curVersion.patch)
{
return true;
}
}
return false;
}
return false;
}
public static string[] GetSerialNumbers()
{
GetStatus();
string[] serials = new string[lastDevices.Length];
for (int i = 0; i < lastDevices.Length; i++)
{
serials[i] = lastDevices[i].serial;
}
return serials;
}
public static string GetDeviceType(string _serial)
{
GetStatus();
if (lastDevices != null)
{
for (int i = 0; i < lastDevices.Length; i++)
{
if (_serial == "" || _serial == lastDevices[i].serial)
{
return lastDevices[i].type;
}
}
}
return "";
}
public static void MarshalUnmananagedArray2Struct<T>(IntPtr unmanagedArray, int length, out T[] mangagedArray)
{
var size = Marshal.SizeOf(typeof(T));
mangagedArray = new T[length];
for (int i = 0; i < length; i++)
{
IntPtr ins = new IntPtr(unmanagedArray.ToInt64() + i * size);
mangagedArray[i] = Marshal.PtrToStructure<T>(ins);
}
}
}
}

View file

@ -0,0 +1,380 @@
/******************************************************************************
* Copyright (C) Ultraleap, Inc. 2011-2024. *
* *
* Use subject to the terms of the Apache License 2.0 available at *
* http://www.apache.org/licenses/LICENSE-2.0, or another agreement *
* between Ultraleap and you, your company or other organization. *
******************************************************************************/
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
using System.IO;
#endif
namespace Leap.Unity
{
#if UNITY_EDITOR
[CustomEditor(typeof(UltraleapSettings))]
public class UltraleapSettingsDrawer : Editor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
EditorGUILayout.Space(20);
if (GUILayout.Button("Open Ultraleap Settings"))
{
SettingsService.OpenProjectSettings("Project/Ultraleap");
}
}
}
#endif
#if UNITY_EDITOR
static class UltraleapProjectSettings
{
static SerializedObject settings = UltraleapSettings.GetSerializedSettings();
[SettingsProvider]
public static SettingsProvider CreateUltraleapSettingsProvider()
{
// First parameter is the path in the Settings window.
// Second parameter is the scope of this setting: it only appears in the Project Settings window.
var provider = new SettingsProvider("Project/Ultraleap", SettingsScope.Project)
{
// By default the last token of the path is used as display name if no label is provided.
label = "Ultraleap",
// Create the SettingsProvider and initialize its drawing (IMGUI) function in place:
guiHandler = (searchContext) =>
{
if (settings == null)
{
settings = UltraleapSettings.GetSerializedSettings();
}
LeapSubSystemSection(settings);
InputActionsSection(settings);
HintingSection(settings);
NotificationSection(settings);
ResetSection(settings);
settings.ApplyModifiedProperties();
settings.UpdateIfRequiredOrScript();
},
// Populate the search keywords to enable smart search filtering and label highlighting:
keywords = new HashSet<string>(new[] { "XRHands", "Leap", "Leap Input System", "Meta Aim System", "Subsystem", "Leap Motion", "Ultraleap", "Ultraleap Settings" })
};
return provider;
}
private static void LeapSubSystemSection(SerializedObject settings)
{
EditorGUILayout.Space(10);
EditorGUILayout.LabelField("Leap XRHands Subsystem", EditorStyles.boldLabel);
EditorGUILayout.Space(5);
EditorGUILayout.HelpBox("If using OpenXR for hand input, use the Hand Tracking Subsystem in XR Plug-in Management/OpenXR. Do not enable both subsystems." +
"\r\n\nThis option can not be toggled at runtime.", MessageType.Info, true);
EditorGUILayout.Space(5);
using (new EditorGUI.IndentLevelScope())
{
SerializedProperty leapSubsystemEnabledProperty = settings.FindProperty("leapSubsystemEnabled");
leapSubsystemEnabledProperty.boolValue = EditorGUILayout.ToggleLeft("Enable Leap XRHands Subsystem", leapSubsystemEnabledProperty.boolValue);
}
EditorGUILayout.Space(30);
settings.ApplyModifiedProperties();
}
private static void InputActionsSection(SerializedObject settings)
{
EditorGUILayout.LabelField("Input Actions", EditorStyles.boldLabel);
EditorGUILayout.Space(5);
using (new EditorGUI.IndentLevelScope())
{
SerializedProperty updateLeapInputSystemProperty = settings.FindProperty("updateLeapInputSystem");
updateLeapInputSystemProperty.boolValue = EditorGUILayout.ToggleLeft("Update Leap Input System with XRHands", updateLeapInputSystemProperty.boolValue);
SerializedProperty updateMetaInputSystemProperty = settings.FindProperty("updateMetaInputSystem");
updateMetaInputSystemProperty.boolValue = EditorGUILayout.ToggleLeft("Update Meta Aim Input System with XRHands", updateMetaInputSystemProperty.boolValue);
}
EditorGUILayout.Space(30);
settings.ApplyModifiedProperties();
}
private static void HintingSection(SerializedObject settings)
{
EditorGUILayout.LabelField("Hand Tracking Hints", EditorStyles.boldLabel);
EditorGUILayout.Space(5);
using (new EditorGUI.IndentLevelScope())
{
SerializedProperty hints = settings.FindProperty("startupHints");
EditorGUILayout.PropertyField(hints, true);
}
EditorGUILayout.Space(10);
settings.ApplyModifiedProperties();
}
private static void NotificationSection(SerializedObject settings)
{
EditorGUILayout.LabelField("Notifications", EditorStyles.boldLabel);
EditorGUILayout.Space(5);
using (new EditorGUI.IndentLevelScope())
{
// Android Build Warnings
SerializedProperty showAndroidBuildArchitectureWarning = settings.FindProperty("showAndroidBuildArchitectureWarning");
showAndroidBuildArchitectureWarning.boolValue = EditorGUILayout.ToggleLeft("Show Android Architecture build warning", showAndroidBuildArchitectureWarning.boolValue);
// Physical Hands Settings Warnings
SerializedProperty showPhysicalHandsPhysicsSettingsWarning = settings.FindProperty("showPhysicalHandsPhysicsSettingsWarning");
showPhysicalHandsPhysicsSettingsWarning.boolValue = EditorGUILayout.ToggleLeft("Show Physical Hands settings warning", showPhysicalHandsPhysicsSettingsWarning.boolValue);
// Attachment Hands delete content warnings
bool curValue = !EditorUtility.GetDialogOptOutDecision(DialogOptOutDecisionType.ForThisMachine, "UL attachment hands popup");
curValue = EditorGUILayout.ToggleLeft("Show clear Attachment Hands deletes content warning", curValue);
EditorUtility.SetDialogOptOutDecision(DialogOptOutDecisionType.ForThisMachine, "UL attachment hands popup", !curValue);
}
EditorGUILayout.Space(30);
settings.ApplyModifiedProperties();
}
private static void ResetSection(SerializedObject settings)
{
EditorGUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button("Reset To Defaults", GUILayout.MaxWidth(EditorGUIUtility.currentViewWidth/2)))
{
if (EditorUtility.DisplayDialog("Reset all settings", "This will reset all settings in this Ultraleap settings file", "Yes", "No"))
{
UltraleapSettings.Instance.ResetToDefaults();
}
}
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
settings.ApplyModifiedProperties();
}
}
#endif
public class UltraleapSettings : ScriptableObject
{
static UltraleapSettings instance;
public static UltraleapSettings Instance
{
get
{
if (instance != null)
return instance;
else
return instance = FindSettingsSO();
}
set { instance = value; }
}
// XRHands and Input System
[HideInInspector, SerializeField]
public bool leapSubsystemEnabled = false;
[HideInInspector, SerializeField]
public bool updateLeapInputSystem = false;
[HideInInspector, SerializeField]
public bool updateMetaInputSystem = false;
[HideInInspector, SerializeField]
public string[] startupHints = new string[] { };
[HideInInspector, SerializeField]
public bool showAndroidBuildArchitectureWarning = true;
[HideInInspector, SerializeField]
public bool showPhysicalHandsPhysicsSettingsWarning = true;
[HideInInspector, SerializeField]
public string pluginVersion = "Unknown";
public string PluginVersion
{
get
{
#if UNITY_EDITOR
pluginVersion = GetPluginVersion();
#endif
return pluginVersion;
}
}
[HideInInspector, SerializeField]
public string pluginSource = "Unknown";
public string PluginSource
{
get
{
#if UNITY_EDITOR
pluginSource = GetPluginSource();
#endif
return pluginSource;
}
}
public void ResetToDefaults()
{
leapSubsystemEnabled = false;
updateLeapInputSystem = false;
updateMetaInputSystem = false;
startupHints = new string[] { };
showAndroidBuildArchitectureWarning = true;
showPhysicalHandsPhysicsSettingsWarning = true;
}
#if UNITY_EDITOR
static string GetPluginVersion()
{
if (Utils.IsPackageAvailable("com.ultraleap.tracking", out var packageInfo)) // Check the package exists so we can use package manage wizardry
{
return packageInfo.version;
}
else // We are not using package manager :( we need to look for version number elsewhere
{
return FindPluginVersionInAssets();
}
}
static string GetPluginSource()
{
if (Utils.IsPackageAvailable("com.ultraleap.tracking", out var packageInfo)) // Check the package exists so we can use package manage wizardry
{
if (packageInfo.source == UnityEditor.PackageManager.PackageSource.Registry &&
packageInfo.registry != null &&
packageInfo.registry.url.Contains("openupm"))
{
return "UPM OpenUPM";
}
else
{
return "UPM " + packageInfo.source;
}
}
else // We are not using package manager :( we need to look for version number elsewhere
{
return "Unity Package";
}
}
[MenuItem("Ultraleap/Open Ultraleap Settings", false, 50)]
private static void SelectULSettingsDropdown()
{
SettingsService.OpenProjectSettings("Project/Ultraleap");
}
[MenuItem("Ultraleap/Help/Documentation", false, 100)]
private static void OpenDocs()
{
Application.OpenURL("https://docs.ultraleap.com/unity-api/");
}
[MenuItem("Ultraleap/Help/Report a Bug", false, 101)]
private static void OpenGithubNewIssueView()
{
Application.OpenURL("https://github.com/ultraleap/UnityPlugin/issues/new");
}
[MenuItem("Ultraleap/Help/Support/Submit a Support Request", false, 102)]
private static void OpenSupportRequest()
{
Application.OpenURL("https://support.leapmotion.com/hc/en-us/requests/new");
}
[MenuItem("Ultraleap/Help/Support/Join Our Discord", false, 103)]
private static void OpenDiscord()
{
Application.OpenURL("https://discord.com/invite/3VCndThqxS");
}
#endif
private static UltraleapSettings FindSettingsSO()
{
// Try to directly load the asset
UltraleapSettings ultraleapSettings = Resources.Load<UltraleapSettings>("Ultraleap Settings");
if (ultraleapSettings != null)
{
instance = ultraleapSettings;
return instance;
}
UltraleapSettings[] settingsSO = Resources.FindObjectsOfTypeAll(typeof(UltraleapSettings)) as UltraleapSettings[];
if (settingsSO != null && settingsSO.Length > 0)
{
instance = settingsSO[0]; // Assume there is only one settings file
}
else
{
instance = CreateSettingsSO();
}
return instance;
}
static UltraleapSettings CreateSettingsSO()
{
UltraleapSettings newSO = null;
#if UNITY_EDITOR
newSO = ScriptableObject.CreateInstance<UltraleapSettings>();
Directory.CreateDirectory(Application.dataPath + "/Resources/");
AssetDatabase.CreateAsset(newSO, "Assets/Resources/Ultraleap Settings.asset");
#endif
return newSO;
}
#if UNITY_EDITOR
public static SerializedObject GetSerializedSettings()
{
return new SerializedObject(Instance);
}
static string FindPluginVersionInAssets()
{
string pluginVersionFromAssets = "";
string[] fileGUIDs = AssetDatabase.FindAssets("Version");
foreach (var guid in fileGUIDs)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
if (path.Contains("/Ultraleap/Tracking/Version.txt"))
{
string content = File.ReadAllText(path);
pluginVersionFromAssets = content;
break;
}
}
return pluginVersionFromAssets;
}
#endif
}
}