mirror of
https://github.com/hanetzer/sdraw_mods_cvr.git
synced 2025-09-04 02:49:23 +00:00
Merge remote-tracking branch 'origin/master' into experimental
# Conflicts: # README.md # ml_amt/Main.cs # ml_amt/MotionTweaker.cs # ml_amt/Properties/AssemblyInfo.cs # ml_amt/README.md # ml_amt/Utils.cs # ml_lme/GestureMatcher.cs # ml_lme/LeapTracked.cs # ml_lme/Main.cs # ml_lme/Properties/AssemblyInfo.cs # ml_lme/Utils.cs
This commit is contained in:
commit
7d3b76e092
43 changed files with 2786 additions and 834 deletions
14
README.md
Normal file
14
README.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
Merged set of MelonLoader mods for ChilloutVR.
|
||||
|
||||
**State table for game build 2022r170:**
|
||||
| Full name | Short name | Latest version | Available in [CVRMA](https://github.com/knah/CVRMelonAssistant) | Current Status | Notes |
|
||||
|-----------|------------|----------------|-----------------------------------------------------------------|----------------|-------|
|
||||
| Avatar Change Info | ml_aci | 1.0.3 | Retired | Retired | Superseded by `Extended Game Notifications`
|
||||
| Avatar Motion Tweaker | ml_amt | 1.2.3 | Yes, update review | Working |
|
||||
| Desktop Head Tracking | ml_dht | 1.1.1 | Yes | Working |
|
||||
| Desktop Reticle Switch | ml_drs | 1.0.0 | Yes | Working |
|
||||
| Extended Game Notifications | ml_egn | 1.0.1 | Yes | Working
|
||||
| Four Point Tracking | ml_fpt | 1.0.9 | Retired | Deprecated | In-game feature since 2022r170 update
|
||||
| Leap Motion Extension | ml_lme | 1.3.1 | Yes, update review | Working |
|
||||
| Pickup Arm Movement | ml_pam | 1.0.1 | Retired, update review | Working |
|
||||
| Server Connection Info | ml_sci | 1.0.2 | Retired | Retired | Superseded by `Extended Game Notifications`
|
78
ml_amt/AvatarParameter.cs
Normal file
78
ml_amt/AvatarParameter.cs
Normal file
|
@ -0,0 +1,78 @@
|
|||
using ABI_RC.Core.Player;
|
||||
|
||||
namespace ml_amt
|
||||
{
|
||||
class AvatarParameter
|
||||
{
|
||||
public enum ParameterType
|
||||
{
|
||||
Upright,
|
||||
GroundedRaw,
|
||||
Moving
|
||||
}
|
||||
|
||||
public enum ParameterSyncType
|
||||
{
|
||||
Synced,
|
||||
Local
|
||||
}
|
||||
|
||||
public readonly ParameterType m_type;
|
||||
public readonly ParameterSyncType m_sync;
|
||||
public readonly string m_name;
|
||||
public readonly int m_hash; // For local only
|
||||
|
||||
|
||||
public AvatarParameter(ParameterType p_type, string p_name, ParameterSyncType p_sync = ParameterSyncType.Synced, int p_hash = 0)
|
||||
{
|
||||
m_type = p_type;
|
||||
m_sync = p_sync;
|
||||
m_name = p_name;
|
||||
m_hash = p_hash;
|
||||
}
|
||||
|
||||
public void Update(MotionTweaker p_tweaker)
|
||||
{
|
||||
switch(m_type)
|
||||
{
|
||||
case ParameterType.Upright:
|
||||
SetFloat(p_tweaker.GetUpright());
|
||||
break;
|
||||
|
||||
case ParameterType.GroundedRaw:
|
||||
SetBoolean(p_tweaker.GetGroundedRaw());
|
||||
break;
|
||||
|
||||
case ParameterType.Moving:
|
||||
SetBoolean(p_tweaker.GetMoving());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetFloat(float p_value)
|
||||
{
|
||||
switch(m_sync)
|
||||
{
|
||||
case ParameterSyncType.Local:
|
||||
PlayerSetup.Instance._animator.SetFloat(m_hash, p_value);
|
||||
break;
|
||||
case ParameterSyncType.Synced:
|
||||
PlayerSetup.Instance.animatorManager.SetAnimatorParameterFloat(m_name, p_value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetBoolean(bool p_value)
|
||||
{
|
||||
switch(m_sync)
|
||||
{
|
||||
case ParameterSyncType.Local:
|
||||
PlayerSetup.Instance._animator.SetBool(m_hash, p_value);
|
||||
break;
|
||||
case ParameterSyncType.Synced:
|
||||
PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool(m_name, p_value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
142
ml_amt/Main.cs
142
ml_amt/Main.cs
|
@ -1,15 +1,29 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK.SubSystems;
|
||||
using ABI_RC.Systems.MovementSystem;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_amt
|
||||
{
|
||||
public class AvatarMotionTweaker : MelonLoader.MelonMod
|
||||
{
|
||||
static readonly MethodInfo[] ms_fbtDetouredMethods =
|
||||
{
|
||||
typeof(PlayerSetup).GetMethod("Update", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
typeof(PlayerSetup).GetMethod("FixedUpdate", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
typeof(PlayerSetup).GetMethod("UpdatePlayerAvatarMovementData", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
typeof(CVRParameterStreamEntry).GetMethod(nameof(CVRParameterStreamEntry.CheckUpdate))
|
||||
};
|
||||
|
||||
static AvatarMotionTweaker ms_instance = null;
|
||||
|
||||
MotionTweaker m_localTweaker = null;
|
||||
|
||||
static int ms_calibrationCounts = 0;
|
||||
static bool ms_fbtDetour = false;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
|
@ -29,25 +43,49 @@ namespace ml_amt
|
|||
new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(ABI_RC.Systems.IK.SubSystems.BodySystem).GetMethod(nameof(ABI_RC.Systems.IK.SubSystems.BodySystem.Calibrate)),
|
||||
typeof(BodySystem).GetMethod(nameof(BodySystem.Calibrate)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnCalibrate_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
// FBT detour
|
||||
HarmonyInstance.Patch(
|
||||
typeof(ABI_RC.Systems.IK.SubSystems.BodySystem).GetMethod(nameof(ABI_RC.Systems.IK.SubSystems.BodySystem.FBTAvailable)),
|
||||
typeof(BodySystem).GetMethod(nameof(BodySystem.FBTAvailable)),
|
||||
new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnFBTAvailable_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
|
||||
null
|
||||
);
|
||||
foreach(MethodInfo l_detoured in ms_fbtDetouredMethods)
|
||||
{
|
||||
HarmonyInstance.Patch(
|
||||
l_detoured,
|
||||
new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(FBTDetour_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
|
||||
new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(FBTDetour_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
}
|
||||
|
||||
// Alternative collider height
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ReCalibrateAvatar)),
|
||||
new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnReCalibrateAvatar_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
|
||||
typeof(MovementSystem).GetMethod("UpdateCollider", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnUpdateCollider_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
|
||||
null
|
||||
);
|
||||
|
||||
// AAS overriding "fix"
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRAnimatorManager).GetMethod(nameof(CVRAnimatorManager.SetOverrideAnimation), BindingFlags.Instance),
|
||||
new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnAnimationOverride_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
|
||||
null
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRAnimatorManager).GetMethod(nameof(CVRAnimatorManager.RestoreOverrideAnimation)),
|
||||
new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnAnimationOverrideRestore_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
|
||||
null
|
||||
);
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator WaitForLocalPlayer()
|
||||
IEnumerator WaitForLocalPlayer()
|
||||
{
|
||||
while(PlayerSetup.Instance == null)
|
||||
yield return null;
|
||||
|
@ -92,8 +130,6 @@ namespace ml_amt
|
|||
{
|
||||
try
|
||||
{
|
||||
ms_calibrationCounts = 0;
|
||||
|
||||
if(m_localTweaker != null)
|
||||
m_localTweaker.OnSetupAvatar();
|
||||
}
|
||||
|
@ -117,20 +153,98 @@ namespace ml_amt
|
|||
}
|
||||
}
|
||||
|
||||
static void OnReCalibrateAvatar_Prefix()
|
||||
// FBT detection override
|
||||
static void FBTDetour_Prefix()
|
||||
{
|
||||
MotionTweaker.ms_fptActive = false;
|
||||
ms_calibrationCounts++;
|
||||
ms_fbtDetour = true;
|
||||
}
|
||||
static void FBTDetour_Postfix()
|
||||
{
|
||||
ms_fbtDetour = false;
|
||||
}
|
||||
|
||||
static bool OnFBTAvailable_Prefix(ref bool __result)
|
||||
{
|
||||
if(MotionTweaker.ms_fptActive || (ms_calibrationCounts == 0))
|
||||
if(ms_fbtDetour && !BodySystem.isCalibratedAsFullBody)
|
||||
{
|
||||
__result = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Alternative collider size
|
||||
static bool OnUpdateCollider_Prefix(
|
||||
ref MovementSystem __instance,
|
||||
bool __0, // updateRadius
|
||||
CharacterController ___controller,
|
||||
float ____avatarHeight,
|
||||
float ____avatarHeightFactor,
|
||||
float ____minimumColliderRadius,
|
||||
Vector3 ____colliderCenter
|
||||
)
|
||||
{
|
||||
if(!Settings.CollisionScale)
|
||||
return true;
|
||||
|
||||
try
|
||||
{
|
||||
if(___controller != null)
|
||||
{
|
||||
float l_scaledHeight = ____avatarHeight * ____avatarHeightFactor;
|
||||
float l_newRadius = (__0 ? Mathf.Max(____minimumColliderRadius, l_scaledHeight / 6f) : ___controller.radius);
|
||||
|
||||
float l_newHeight = Mathf.Max(l_scaledHeight, l_newRadius * 2f);
|
||||
float l_currentHeight = ___controller.height;
|
||||
|
||||
Vector3 l_newCenter = ____colliderCenter;
|
||||
l_newCenter.y = (l_newHeight + 0.075f) * 0.5f; // Idk where 0.075f has come from
|
||||
Vector3 l_currentCenter = ___controller.center;
|
||||
|
||||
if(__0 || (Mathf.Abs(l_currentHeight - l_newHeight) > (l_currentHeight * 0.05f)) || (Vector3.Distance(l_currentCenter, l_newCenter) > (l_currentHeight * 0.05f)))
|
||||
{
|
||||
bool l_active = ___controller.enabled;
|
||||
|
||||
if(__0)
|
||||
___controller.radius = l_newRadius;
|
||||
___controller.height = l_newHeight;
|
||||
___controller.center = l_newCenter;
|
||||
|
||||
__instance.groundDistance = l_newRadius;
|
||||
|
||||
if(__instance.proxyCollider != null)
|
||||
{
|
||||
if(__0)
|
||||
__instance.proxyCollider.radius = l_newRadius;
|
||||
__instance.proxyCollider.height = l_newHeight;
|
||||
__instance.proxyCollider.center = new Vector3(0f, l_newCenter.y, 0f);
|
||||
}
|
||||
|
||||
if(__instance.forceObject != null)
|
||||
__instance.forceObject.transform.localScale = new Vector3(l_newRadius + 0.1f, l_newHeight, l_newRadius + 0.1f);
|
||||
if(__instance.groundCheck != null)
|
||||
__instance.groundCheck.localPosition = ____colliderCenter;
|
||||
|
||||
___controller.enabled = l_active;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(System.Exception l_exception)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(l_exception);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool OnAnimationOverride_Prefix()
|
||||
{
|
||||
return !Settings.OverrideFix;
|
||||
}
|
||||
|
||||
static bool OnAnimationOverrideRestore_Prefix()
|
||||
{
|
||||
return !Settings.OverrideFix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,32 +11,12 @@ namespace ml_amt
|
|||
[DisallowMultipleComponent]
|
||||
class MotionTweaker : MonoBehaviour
|
||||
{
|
||||
static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f);
|
||||
static readonly FieldInfo ms_grounded = typeof(MovementSystem).GetField("_isGrounded", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
static readonly FieldInfo ms_groundedRaw = typeof(MovementSystem).GetField("_isGroundedRaw", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
static readonly FieldInfo ms_rootVelocity = typeof(IKSolverVR).GetField("rootVelocity", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
static readonly FieldInfo ms_hasToes = typeof(IKSolverVR).GetField("hasToes", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
static readonly int ms_emoteHash = Animator.StringToHash("Emote");
|
||||
|
||||
enum ParameterType
|
||||
{
|
||||
Upright,
|
||||
GroundedRaw,
|
||||
Moving
|
||||
}
|
||||
|
||||
enum ParameterSyncType
|
||||
{
|
||||
Local,
|
||||
Synced
|
||||
}
|
||||
|
||||
struct AdditionalParameterInfo
|
||||
{
|
||||
public ParameterType m_type;
|
||||
public ParameterSyncType m_sync;
|
||||
public string m_name;
|
||||
public int m_hash; // For local only
|
||||
}
|
||||
|
||||
enum PoseState
|
||||
{
|
||||
Standing = 0,
|
||||
|
@ -44,17 +24,18 @@ namespace ml_amt
|
|||
Proning
|
||||
}
|
||||
|
||||
static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f);
|
||||
|
||||
VRIK m_vrIk = null;
|
||||
int m_locomotionLayer = 0;
|
||||
float m_ikWeight = 1f; // Original weight
|
||||
float m_locomotionWeight = 1f; // Original weight
|
||||
bool m_plantFeet = false; // Original plant feet
|
||||
float m_avatarScale = 1f; // Instantiated scale
|
||||
Vector3 m_locomotionOffset = Vector3.zero; // Original locomotion offset
|
||||
bool m_bendNormalLeft = false;
|
||||
bool m_bendNormalRight = false;
|
||||
Transform m_avatarHips = null;
|
||||
float m_viewPointHeight = 1f;
|
||||
bool m_isInVR = false;
|
||||
public static bool ms_fptActive = false;
|
||||
bool m_inVR = false;
|
||||
|
||||
bool m_avatarReady = false;
|
||||
bool m_compatibleAvatar = false;
|
||||
|
@ -77,25 +58,24 @@ namespace ml_amt
|
|||
bool m_ikOverrideFly = true;
|
||||
bool m_ikOverrideJump = true;
|
||||
|
||||
bool m_customLocomotionOffset = false;
|
||||
Vector3 m_locomotionOffset = Vector3.zero;
|
||||
|
||||
bool m_detectEmotes = true;
|
||||
bool m_emoteActive = false;
|
||||
|
||||
bool m_followHips = true;
|
||||
Vector3 m_hipsToPlayer = Vector3.zero;
|
||||
|
||||
readonly List<AdditionalParameterInfo> m_parameters = null;
|
||||
Vector3 m_massCenter = Vector3.zero;
|
||||
|
||||
public MotionTweaker()
|
||||
readonly List<AvatarParameter> m_parameters = null;
|
||||
|
||||
internal MotionTweaker()
|
||||
{
|
||||
m_parameters = new List<AdditionalParameterInfo>();
|
||||
m_parameters = new List<AvatarParameter>();
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
m_isInVR = Utils.IsInVR();
|
||||
m_inVR = Utils.IsInVR();
|
||||
|
||||
Settings.IKOverrideCrouchChange += this.SetIKOverrideCrouch;
|
||||
Settings.CrouchLimitChange += this.SetCrouchLimit;
|
||||
|
@ -107,6 +87,7 @@ namespace ml_amt
|
|||
Settings.IKOverrideJumpChange += this.SetIKOverrideJump;
|
||||
Settings.DetectEmotesChange += this.SetDetectEmotes;
|
||||
Settings.FollowHipsChange += this.SetFollowHips;
|
||||
Settings.MassCenterChange += this.SetMassCenter;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
|
@ -121,6 +102,7 @@ namespace ml_amt
|
|||
Settings.IKOverrideJumpChange -= this.SetIKOverrideJump;
|
||||
Settings.DetectEmotesChange -= this.SetDetectEmotes;
|
||||
Settings.FollowHipsChange -= this.SetFollowHips;
|
||||
Settings.MassCenterChange -= this.SetMassCenter;
|
||||
}
|
||||
|
||||
void Update()
|
||||
|
@ -132,12 +114,12 @@ namespace ml_amt
|
|||
m_moving = !Mathf.Approximately(MovementSystem.Instance.movementVector.magnitude, 0f);
|
||||
|
||||
// Update upright
|
||||
Matrix4x4 l_hmdMatrix = PlayerSetup.Instance.transform.GetMatrix().inverse * (m_isInVR ? PlayerSetup.Instance.vrHeadTracker.transform.GetMatrix() : PlayerSetup.Instance.desktopCameraRig.transform.GetMatrix());
|
||||
Matrix4x4 l_hmdMatrix = PlayerSetup.Instance.transform.GetMatrix().inverse * (m_inVR ? PlayerSetup.Instance.vrHeadTracker.transform.GetMatrix() : PlayerSetup.Instance.desktopCameraRig.transform.GetMatrix());
|
||||
float l_currentHeight = Mathf.Clamp((l_hmdMatrix * ms_pointVector).y, 0f, float.MaxValue);
|
||||
float l_avatarScale = (m_avatarScale > 0f) ? (PlayerSetup.Instance._avatar.transform.localScale.y / m_avatarScale) : 0f;
|
||||
float l_avatarViewHeight = Mathf.Clamp(m_viewPointHeight * l_avatarScale, 0f, float.MaxValue);
|
||||
m_upright = Mathf.Clamp(((l_avatarViewHeight > 0f) ? (l_currentHeight / l_avatarViewHeight) : 0f), 0f, 1f);
|
||||
PoseState l_poseState = (m_upright <= m_proneLimit) ? PoseState.Proning : ((m_upright <= m_crouchLimit) ? PoseState.Crouching : PoseState.Standing);
|
||||
m_upright = Mathf.Clamp01((l_avatarViewHeight > 0f) ? (l_currentHeight / l_avatarViewHeight) : 0f);
|
||||
m_poseState = (m_upright <= Mathf.Min(m_proneLimit, m_crouchLimit)) ? PoseState.Proning : ((m_upright <= Mathf.Max(m_proneLimit, m_crouchLimit)) ? PoseState.Crouching : PoseState.Standing);
|
||||
|
||||
if(m_avatarHips != null)
|
||||
{
|
||||
|
@ -145,21 +127,12 @@ namespace ml_amt
|
|||
m_hipsToPlayer.Set(l_hipsToPoint.x, 0f, l_hipsToPoint.z);
|
||||
}
|
||||
|
||||
if(m_isInVR && (m_vrIk != null) && m_vrIk.enabled)
|
||||
if(m_inVR && (m_vrIk != null) && m_vrIk.enabled)
|
||||
{
|
||||
if(m_poseState != l_poseState)
|
||||
{
|
||||
// Weird fix of torso shaking
|
||||
if(m_ikOverrideCrouch && (l_poseState == PoseState.Standing))
|
||||
ms_rootVelocity.SetValue(m_vrIk.solver, Vector3.zero);
|
||||
if(m_ikOverrideProne && !m_ikOverrideCrouch && (l_poseState == PoseState.Crouching))
|
||||
ms_rootVelocity.SetValue(m_vrIk.solver, Vector3.zero);
|
||||
}
|
||||
|
||||
if(m_adjustedMovement)
|
||||
{
|
||||
MovementSystem.Instance.ChangeCrouch(l_poseState == PoseState.Crouching);
|
||||
MovementSystem.Instance.ChangeProne(l_poseState == PoseState.Proning);
|
||||
MovementSystem.Instance.ChangeCrouch(m_poseState == PoseState.Crouching);
|
||||
MovementSystem.Instance.ChangeProne(m_poseState == PoseState.Proning);
|
||||
|
||||
if(!m_poseTransitions)
|
||||
{
|
||||
|
@ -170,13 +143,11 @@ namespace ml_amt
|
|||
|
||||
if(m_poseTransitions)
|
||||
{
|
||||
PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Crouching", (l_poseState == PoseState.Crouching) && !m_compatibleAvatar && !Utils.IsInFullbody());
|
||||
PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Prone", (l_poseState == PoseState.Proning) && !m_compatibleAvatar && !Utils.IsInFullbody());
|
||||
PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Crouching", (m_poseState == PoseState.Crouching) && !m_compatibleAvatar && !BodySystem.isCalibratedAsFullBody);
|
||||
PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Prone", (m_poseState == PoseState.Proning) && !m_compatibleAvatar && !BodySystem.isCalibratedAsFullBody);
|
||||
}
|
||||
}
|
||||
|
||||
m_poseState = l_poseState;
|
||||
|
||||
m_emoteActive = false;
|
||||
if(m_detectEmotes && (m_locomotionLayer >= 0))
|
||||
{
|
||||
|
@ -186,58 +157,13 @@ namespace ml_amt
|
|||
|
||||
if(m_parameters.Count > 0)
|
||||
{
|
||||
foreach(AdditionalParameterInfo l_param in m_parameters)
|
||||
{
|
||||
switch(l_param.m_type)
|
||||
{
|
||||
case ParameterType.Upright:
|
||||
{
|
||||
switch(l_param.m_sync)
|
||||
{
|
||||
case ParameterSyncType.Local:
|
||||
PlayerSetup.Instance._animator.SetFloat(l_param.m_hash, m_upright);
|
||||
break;
|
||||
case ParameterSyncType.Synced:
|
||||
PlayerSetup.Instance.animatorManager.SetAnimatorParameterFloat(l_param.m_name, m_upright);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ParameterType.GroundedRaw:
|
||||
{
|
||||
switch(l_param.m_sync)
|
||||
{
|
||||
case ParameterSyncType.Local:
|
||||
PlayerSetup.Instance._animator.SetBool(l_param.m_hash, m_groundedRaw);
|
||||
break;
|
||||
case ParameterSyncType.Synced:
|
||||
PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool(l_param.m_name, m_groundedRaw);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ParameterType.Moving:
|
||||
{
|
||||
switch(l_param.m_sync)
|
||||
{
|
||||
case ParameterSyncType.Local:
|
||||
PlayerSetup.Instance._animator.SetBool(l_param.m_hash, m_moving);
|
||||
break;
|
||||
case ParameterSyncType.Synced:
|
||||
PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool(l_param.m_name, m_moving);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
foreach(AvatarParameter l_param in m_parameters)
|
||||
l_param.Update(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnAvatarClear()
|
||||
internal void OnAvatarClear()
|
||||
{
|
||||
m_vrIk = null;
|
||||
m_locomotionLayer = -1;
|
||||
|
@ -248,20 +174,20 @@ namespace ml_amt
|
|||
m_poseState = PoseState.Standing;
|
||||
m_customCrouchLimit = false;
|
||||
m_customProneLimit = false;
|
||||
m_customLocomotionOffset = false;
|
||||
m_locomotionOffset = Vector3.zero;
|
||||
m_avatarScale = 1f;
|
||||
m_locomotionOffset = Vector3.zero;
|
||||
m_emoteActive = false;
|
||||
m_moving = false;
|
||||
m_hipsToPlayer = Vector3.zero;
|
||||
m_avatarHips = null;
|
||||
m_viewPointHeight = 1f;
|
||||
m_massCenter = Vector3.zero;
|
||||
m_parameters.Clear();
|
||||
ms_fptActive = false;
|
||||
}
|
||||
|
||||
public void OnSetupAvatar()
|
||||
internal void OnSetupAvatar()
|
||||
{
|
||||
m_inVR = Utils.IsInVR();
|
||||
m_vrIk = PlayerSetup.Instance._avatar.GetComponent<VRIK>();
|
||||
m_locomotionLayer = PlayerSetup.Instance._animator.GetLayerIndex("Locomotion/Emotes");
|
||||
m_avatarHips = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Hips);
|
||||
|
@ -269,51 +195,63 @@ namespace ml_amt
|
|||
|
||||
// Parse animator parameters
|
||||
AnimatorControllerParameter[] l_params = PlayerSetup.Instance._animator.parameters;
|
||||
ParameterType[] l_enumParams = (ParameterType[])System.Enum.GetValues(typeof(ParameterType));
|
||||
|
||||
foreach(var l_param in l_params)
|
||||
{
|
||||
foreach(var l_enumParam in l_enumParams)
|
||||
foreach(AvatarParameter.ParameterType l_enumParam in System.Enum.GetValues(typeof(AvatarParameter.ParameterType)))
|
||||
{
|
||||
if(l_param.name.Contains(l_enumParam.ToString()) && (m_parameters.FindIndex(p => p.m_type == l_enumParam) == -1))
|
||||
{
|
||||
bool l_local = (l_param.name[0] == '#');
|
||||
|
||||
m_parameters.Add(new AdditionalParameterInfo
|
||||
{
|
||||
m_type = l_enumParam,
|
||||
m_sync = (l_local ? ParameterSyncType.Local : ParameterSyncType.Synced),
|
||||
m_name = l_param.name,
|
||||
m_hash = (l_local ? l_param.nameHash : 0)
|
||||
});
|
||||
m_parameters.Add(new AvatarParameter(
|
||||
l_enumParam,
|
||||
l_param.name,
|
||||
(l_local ? AvatarParameter.ParameterSyncType.Local : AvatarParameter.ParameterSyncType.Synced),
|
||||
(l_local ? l_param.nameHash : 0)
|
||||
));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_compatibleAvatar = m_parameters.Exists(p => p.m_name.Contains("Upright"));
|
||||
m_compatibleAvatar = m_parameters.Exists(p => p.m_type == AvatarParameter.ParameterType.Upright);
|
||||
m_avatarScale = Mathf.Abs(PlayerSetup.Instance._avatar.transform.localScale.y);
|
||||
|
||||
Transform l_customTransform = PlayerSetup.Instance._avatar.transform.Find("CrouchLimit");
|
||||
m_customCrouchLimit = (l_customTransform != null);
|
||||
m_crouchLimit = m_customCrouchLimit ? Mathf.Clamp(l_customTransform.localPosition.y, 0f, 1f) : Settings.CrouchLimit;
|
||||
m_crouchLimit = m_customCrouchLimit ? Mathf.Clamp01(l_customTransform.localPosition.y) : Settings.CrouchLimit;
|
||||
|
||||
l_customTransform = PlayerSetup.Instance._avatar.transform.Find("ProneLimit");
|
||||
m_customProneLimit = (l_customTransform != null);
|
||||
m_proneLimit = m_customProneLimit ? Mathf.Clamp(l_customTransform.localPosition.y, 0f, 1f) : Settings.ProneLimit;
|
||||
|
||||
l_customTransform = PlayerSetup.Instance._avatar.transform.Find("LocomotionOffset");
|
||||
m_customLocomotionOffset = (l_customTransform != null);
|
||||
m_locomotionOffset = m_customLocomotionOffset ? l_customTransform.localPosition : Vector3.zero;
|
||||
m_proneLimit = m_customProneLimit ? Mathf.Clamp01(l_customTransform.localPosition.y) : Settings.ProneLimit;
|
||||
|
||||
// Apply VRIK tweaks
|
||||
if(m_vrIk != null)
|
||||
{
|
||||
if(m_customLocomotionOffset)
|
||||
m_vrIk.solver.locomotion.offset = m_locomotionOffset;
|
||||
m_locomotionOffset = m_vrIk.solver.locomotion.offset;
|
||||
m_massCenter = m_locomotionOffset;
|
||||
|
||||
if((bool)ms_hasToes.GetValue(m_vrIk.solver))
|
||||
{
|
||||
Transform l_foot = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftFoot);
|
||||
if(l_foot == null)
|
||||
l_foot = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightFoot);
|
||||
|
||||
Transform l_toe = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftToes);
|
||||
if(l_toe == null)
|
||||
l_toe = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightToes);
|
||||
|
||||
if((l_foot != null) && (l_toe != null))
|
||||
{
|
||||
Vector3 l_footPos = (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_foot.GetMatrix()) * ms_pointVector;
|
||||
Vector3 l_toePos = (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_toe.GetMatrix()) * ms_pointVector;
|
||||
m_massCenter = new Vector3(0f, 0f, l_toePos.z - l_footPos.z);
|
||||
}
|
||||
}
|
||||
|
||||
m_vrIk.solver.locomotion.offset = (Settings.MassCenter ? m_massCenter : m_locomotionOffset);
|
||||
|
||||
// Place our pre-solver listener first
|
||||
m_vrIk.onPreSolverUpdate.AddListener(this.OnIKPreUpdate);
|
||||
m_vrIk.onPostSolverUpdate.AddListener(this.OnIKPostUpdate);
|
||||
}
|
||||
|
@ -321,9 +259,9 @@ namespace ml_amt
|
|||
m_avatarReady = true;
|
||||
}
|
||||
|
||||
public void OnCalibrate()
|
||||
internal void OnCalibrate()
|
||||
{
|
||||
if(m_avatarReady && BodySystem.enableHipTracking && !BodySystem.enableRightFootTracking && !BodySystem.enableLeftFootTracking && !BodySystem.enableLeftKneeTracking && !BodySystem.enableRightKneeTracking)
|
||||
if(m_avatarReady && BodySystem.isCalibratedAsFullBody && BodySystem.enableHipTracking && !BodySystem.enableRightFootTracking && !BodySystem.enableLeftFootTracking && !BodySystem.enableLeftKneeTracking && !BodySystem.enableRightKneeTracking)
|
||||
{
|
||||
BodySystem.isCalibratedAsFullBody = false;
|
||||
BodySystem.TrackingLeftLegEnabled = false;
|
||||
|
@ -332,8 +270,6 @@ namespace ml_amt
|
|||
|
||||
if(m_vrIk != null)
|
||||
m_vrIk.solver.spine.maxRootAngle = 25f; // I need to rotate my legs, ffs!
|
||||
|
||||
ms_fptActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -343,6 +279,9 @@ namespace ml_amt
|
|||
|
||||
m_ikWeight = m_vrIk.solver.IKPositionWeight;
|
||||
m_locomotionWeight = m_vrIk.solver.locomotion.weight;
|
||||
m_plantFeet = m_vrIk.solver.plantFeet;
|
||||
m_bendNormalLeft = m_vrIk.solver.leftLeg.useAnimatedBendNormal;
|
||||
m_bendNormalRight = m_vrIk.solver.rightLeg.useAnimatedBendNormal;
|
||||
|
||||
if(m_detectEmotes && m_emoteActive)
|
||||
m_vrIk.solver.IKPositionWeight = 0f;
|
||||
|
@ -355,19 +294,24 @@ namespace ml_amt
|
|||
if(m_ikOverrideFly && MovementSystem.Instance.flying)
|
||||
{
|
||||
m_vrIk.solver.locomotion.weight = 0f;
|
||||
m_vrIk.solver.leftLeg.useAnimatedBendNormal = true;
|
||||
m_vrIk.solver.rightLeg.useAnimatedBendNormal = true;
|
||||
l_legsOverride = true;
|
||||
}
|
||||
|
||||
if(m_ikOverrideJump && !m_grounded && !MovementSystem.Instance.flying)
|
||||
{
|
||||
m_vrIk.solver.locomotion.weight = 0f;
|
||||
m_vrIk.solver.leftLeg.useAnimatedBendNormal = true;
|
||||
m_vrIk.solver.rightLeg.useAnimatedBendNormal = true;
|
||||
l_legsOverride = true;
|
||||
}
|
||||
|
||||
bool l_solverActive = !Mathf.Approximately(m_vrIk.solver.IKPositionWeight, 0f);
|
||||
|
||||
if(l_legsOverride && l_solverActive && m_followHips && (!m_moving || (m_poseState == PoseState.Proning)) && m_isInVR && !BodySystem.isCalibratedAsFullBody)
|
||||
if(l_legsOverride && l_solverActive && m_followHips && (!m_moving || (m_poseState == PoseState.Proning)) && m_inVR && !BodySystem.isCalibratedAsFullBody)
|
||||
{
|
||||
m_vrIk.solver.plantFeet = false;
|
||||
ABI_RC.Systems.IK.IKSystem.VrikRootController.enabled = false;
|
||||
PlayerSetup.Instance._avatar.transform.localPosition = m_hipsToPlayer;
|
||||
}
|
||||
|
@ -377,6 +321,9 @@ namespace ml_amt
|
|||
{
|
||||
m_vrIk.solver.IKPositionWeight = m_ikWeight;
|
||||
m_vrIk.solver.locomotion.weight = m_locomotionWeight;
|
||||
m_vrIk.solver.plantFeet = m_plantFeet;
|
||||
m_vrIk.solver.leftLeg.useAnimatedBendNormal = m_bendNormalLeft;
|
||||
m_vrIk.solver.rightLeg.useAnimatedBendNormal = m_bendNormalRight;
|
||||
}
|
||||
|
||||
public void SetIKOverrideCrouch(bool p_state)
|
||||
|
@ -386,7 +333,7 @@ namespace ml_amt
|
|||
public void SetCrouchLimit(float p_value)
|
||||
{
|
||||
if(!m_customCrouchLimit)
|
||||
m_crouchLimit = Mathf.Clamp(p_value, 0f, 1f);
|
||||
m_crouchLimit = Mathf.Clamp01(p_value);
|
||||
}
|
||||
public void SetIKOverrideProne(bool p_state)
|
||||
{
|
||||
|
@ -395,13 +342,13 @@ namespace ml_amt
|
|||
public void SetProneLimit(float p_value)
|
||||
{
|
||||
if(!m_customProneLimit)
|
||||
m_proneLimit = Mathf.Clamp(p_value, 0f, 1f);
|
||||
m_proneLimit = Mathf.Clamp01(p_value);
|
||||
}
|
||||
public void SetPoseTransitions(bool p_state)
|
||||
{
|
||||
m_poseTransitions = p_state;
|
||||
|
||||
if(!m_poseTransitions && m_avatarReady && m_isInVR)
|
||||
if(!m_poseTransitions && m_avatarReady && m_inVR)
|
||||
{
|
||||
PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Crouching", false);
|
||||
PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Prone", false);
|
||||
|
@ -411,7 +358,7 @@ namespace ml_amt
|
|||
{
|
||||
m_adjustedMovement = p_state;
|
||||
|
||||
if(!m_adjustedMovement && m_avatarReady && m_isInVR)
|
||||
if(!m_adjustedMovement && m_avatarReady && m_inVR)
|
||||
{
|
||||
MovementSystem.Instance.ChangeCrouch(false);
|
||||
MovementSystem.Instance.ChangeProne(false);
|
||||
|
@ -433,5 +380,14 @@ namespace ml_amt
|
|||
{
|
||||
m_followHips = p_state;
|
||||
}
|
||||
public void SetMassCenter(bool p_state)
|
||||
{
|
||||
if(m_vrIk != null)
|
||||
m_vrIk.solver.locomotion.offset = (Settings.MassCenter ? m_massCenter : m_locomotionOffset);
|
||||
}
|
||||
|
||||
public float GetUpright() => m_upright;
|
||||
public bool GetGroundedRaw() => m_groundedRaw;
|
||||
public bool GetMoving() => m_moving;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyTitle("AvatarMotionTweaker")]
|
||||
[assembly: AssemblyVersion("1.1.9")]
|
||||
[assembly: AssemblyFileVersion("1.1.9")]
|
||||
[assembly: AssemblyVersion("1.2.3")]
|
||||
[assembly: AssemblyFileVersion("1.2.3")]
|
||||
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.1.9-ex2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.2.3", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
|
@ -18,12 +18,19 @@ Available mod's settings in `Settings - IK - Avatar Motion Tweaker`:
|
|||
* Note: Can be overrided by avatar. For this avatar has to have child gameobject with name `ProneLimit`, its Y-axis location will be used as limit, should be in range [0.0, 1.0].
|
||||
* **IK override while flying:** disables legs locomotion/autostep in fly mode; default value - `true`.
|
||||
* **IK override while jumping:** disables legs locomotion/autostep in jump; default value - `true`.
|
||||
* **Follow hips on IK override:** adjust avatar position to overcome animation snapping on IK override; default value - `true`.
|
||||
* **Follow hips on IK override:** adjusts avatar position to overcome animation snapping on IK override; default value - `true`.
|
||||
* Note: Works best with animations that have root transform position (XZ) based on center of mass.
|
||||
* Note: Made for four point tracking (head, hands, hips) in mind.
|
||||
* **Pose transitions:** allows regular avatars animator to transit in crouch/prone states; default value - `true`.
|
||||
* Note: Avatar is considered as regular if its AAS animator doesn't have `Upright` parameter.
|
||||
* **Adjusted pose movement speed:** scales movement speed upon crouching/proning; default value - `true`.
|
||||
* **Detect animations emote tag:** disables avatar's IK entirely if current animator state has `Emote` tag; default value - `true`;
|
||||
* **Detect animations emote tag:** disables avatar's IK entirely if current animator state has `Emote` tag; default value - `true`.
|
||||
* Note: Created as example for [propoused game feature](https://feedback.abinteractive.net/p/disabling-vr-ik-for-emotes-via-animator-state-tag-7b80d963-053a-41c0-86ac-e3d53c61c1e2).
|
||||
* **Adjusted locomotion mass center:** automatically changes IK locomotion center if avatar has toe bones; default value - `true`.
|
||||
* Note: Compatible with [DesktopVRIK](https://github.com/NotAKidOnSteam/DesktopVRIK) and [FuckToes](https://github.com/NotAKidOnSteam/FuckToes).
|
||||
* **Alternative avatar collider scale:** applies slightly different approach to avatar collider size change; default value - `true`
|
||||
* **Prevent Unity animation override:** disables overriding of animations at runtime for avatars with AAS; default value - `false`.
|
||||
* Note: This options is made for "fix" of [broken animator issues with chairs and combat worlds](https://feedback.abinteractive.net/p/gestures-getting-stuck-locally-upon-entering-vehicles-chairs).
|
||||
|
||||
Available additional parameters for AAS animator:
|
||||
* **`Upright`:** defines linear coefficient between current viewpoint height and avatar's viewpoint height; float, range - [0.0, 1.0].
|
||||
|
@ -35,8 +42,5 @@ Available additional parameters for AAS animator:
|
|||
* **`Moving`:** defines movement state of player
|
||||
* Note: Can be set as local-only (not synced) if starts with `#` character.
|
||||
|
||||
Additional avatars tweaks:
|
||||
* If avatar has child object with name `LocomotionOffset` its local position will be used for offsetting VRIK locomotion mass center.
|
||||
|
||||
Additional mod's behaviour:
|
||||
* Disables FBT state in 4PT mode (head, hands, hips). Be sure to enable only hips tracking in `Settings - IK` tab.
|
||||
* Overrides FBT behaviour in 4PT mode (head, hands, hips). Be sure to disable legs and knees tracking in `Settings - IK tab`.
|
||||
|
|
|
@ -18,7 +18,10 @@ namespace ml_amt
|
|||
IKOverrideFly,
|
||||
IKOverrideJump,
|
||||
DetectEmotes,
|
||||
FollowHips
|
||||
FollowHips,
|
||||
CollisionScale,
|
||||
MassCenter,
|
||||
OverrideFix
|
||||
};
|
||||
|
||||
static bool ms_ikOverrideCrouch = true;
|
||||
|
@ -31,6 +34,9 @@ namespace ml_amt
|
|||
static bool ms_ikOverrideJump = true;
|
||||
static bool ms_detectEmotes = true;
|
||||
static bool ms_followHips = true;
|
||||
static bool ms_collisionScale = true;
|
||||
static bool ms_massCenter = true;
|
||||
static bool ms_overrideFix = false;
|
||||
|
||||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
@ -45,22 +51,30 @@ namespace ml_amt
|
|||
static public event Action<bool> IKOverrideJumpChange;
|
||||
static public event Action<bool> DetectEmotesChange;
|
||||
static public event Action<bool> FollowHipsChange;
|
||||
static public event Action<bool> CollisionScaleChange;
|
||||
static public event Action<bool> MassCenterChange;
|
||||
static public event Action<bool> OverrideFixChange;
|
||||
|
||||
public static void Init()
|
||||
internal static void Init()
|
||||
{
|
||||
ms_category = MelonLoader.MelonPreferences.CreateCategory("AMT");
|
||||
|
||||
ms_entries = new List<MelonLoader.MelonPreferences_Entry>();
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.IKOverrideCrouch.ToString(), true));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.CrouchLimit.ToString(), 65));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.IKOverrideProne.ToString(), true));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.ProneLimit.ToString(), 30));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.PoseTransitions.ToString(), true));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.AdjustedMovement.ToString(), true));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.IKOverrideFly.ToString(), true));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.IKOverrideJump.ToString(), true));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.DetectEmotes.ToString(), true));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.FollowHips.ToString(), true));
|
||||
ms_entries = new List<MelonLoader.MelonPreferences_Entry>()
|
||||
{
|
||||
ms_category.CreateEntry(ModSetting.IKOverrideCrouch.ToString(), true),
|
||||
ms_category.CreateEntry(ModSetting.CrouchLimit.ToString(), 65),
|
||||
ms_category.CreateEntry(ModSetting.IKOverrideProne.ToString(), true),
|
||||
ms_category.CreateEntry(ModSetting.ProneLimit.ToString(), 30),
|
||||
ms_category.CreateEntry(ModSetting.PoseTransitions.ToString(), true),
|
||||
ms_category.CreateEntry(ModSetting.AdjustedMovement.ToString(), true),
|
||||
ms_category.CreateEntry(ModSetting.IKOverrideFly.ToString(), true),
|
||||
ms_category.CreateEntry(ModSetting.IKOverrideJump.ToString(), true),
|
||||
ms_category.CreateEntry(ModSetting.DetectEmotes.ToString(), true),
|
||||
ms_category.CreateEntry(ModSetting.FollowHips.ToString(), true),
|
||||
ms_category.CreateEntry(ModSetting.CollisionScale.ToString(), true),
|
||||
ms_category.CreateEntry(ModSetting.MassCenter.ToString(), true),
|
||||
ms_category.CreateEntry(ModSetting.OverrideFix.ToString(), false)
|
||||
};
|
||||
|
||||
Load();
|
||||
|
||||
|
@ -101,6 +115,9 @@ namespace ml_amt
|
|||
ms_ikOverrideJump = (bool)ms_entries[(int)ModSetting.IKOverrideJump].BoxedValue;
|
||||
ms_detectEmotes = (bool)ms_entries[(int)ModSetting.DetectEmotes].BoxedValue;
|
||||
ms_followHips = (bool)ms_entries[(int)ModSetting.FollowHips].BoxedValue;
|
||||
ms_collisionScale = (bool)ms_entries[(int)ModSetting.CollisionScale].BoxedValue;
|
||||
ms_massCenter = (bool)ms_entries[(int)ModSetting.MassCenter].BoxedValue;
|
||||
ms_overrideFix = (bool)ms_entries[(int)ModSetting.OverrideFix].BoxedValue;
|
||||
}
|
||||
|
||||
static void OnSliderUpdate(string p_name, string p_value)
|
||||
|
@ -189,6 +206,27 @@ namespace ml_amt
|
|||
FollowHipsChange?.Invoke(ms_followHips);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.CollisionScale:
|
||||
{
|
||||
ms_collisionScale = bool.Parse(p_value);
|
||||
CollisionScaleChange?.Invoke(ms_collisionScale);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.MassCenter:
|
||||
{
|
||||
ms_massCenter = bool.Parse(p_value);
|
||||
MassCenterChange?.Invoke(ms_massCenter);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.OverrideFix:
|
||||
{
|
||||
ms_overrideFix = bool.Parse(p_value);
|
||||
OverrideFixChange?.Invoke(ms_overrideFix);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
|
||||
|
@ -235,5 +273,17 @@ namespace ml_amt
|
|||
{
|
||||
get => ms_followHips;
|
||||
}
|
||||
public static bool CollisionScale
|
||||
{
|
||||
get => ms_collisionScale;
|
||||
}
|
||||
public static bool MassCenter
|
||||
{
|
||||
get => ms_massCenter;
|
||||
}
|
||||
public static bool OverrideFix
|
||||
{
|
||||
get => ms_overrideFix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ namespace ml_amt
|
|||
static class Utils
|
||||
{
|
||||
public static bool IsInVR() => ((ABI_RC.Core.Savior.CheckVR.Instance != null) && ABI_RC.Core.Savior.CheckVR.Instance.hasVrDeviceLoaded);
|
||||
public static bool IsInFullbody() => ((IKSystem.Instance != null) && IKSystem.Instance.BodySystem.FBTAvailable());
|
||||
|
||||
// Extensions
|
||||
public static Matrix4x4 GetMatrix(this Transform p_transform, bool p_pos = true, bool p_rot = true, bool p_scl = false)
|
||||
|
|
|
@ -68,8 +68,14 @@
|
|||
<Reference Include="UnityEngine.CoreModule">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.PhysicsModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AvatarParameter.cs" />
|
||||
<Compile Include="MotionTweaker.cs" />
|
||||
<Compile Include="Main.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
|
|
|
@ -249,6 +249,27 @@ function inp_toggle_mod_amt(_obj, _callbackName) {
|
|||
<div id="DetectEmotes" class ="inp_toggle no-scroll" data-current="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class ="row-wrapper">
|
||||
<div class ="option-caption">Adjusted locomotion mass center: </div>
|
||||
<div class ="option-input">
|
||||
<div id="MassCenter" class ="inp_toggle no-scroll" data-current="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class ="row-wrapper">
|
||||
<div class ="option-caption">Alternative avatar collider scale: </div>
|
||||
<div class ="option-input">
|
||||
<div id="CollisionScale" class ="inp_toggle no-scroll" data-current="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class ="row-wrapper">
|
||||
<div class ="option-caption">Prevent Unity animation override (chairs, etc.): </div>
|
||||
<div class ="option-input">
|
||||
<div id="OverrideFix" class ="inp_toggle no-scroll" data-current="false"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
document.getElementById('settings-ik').appendChild(l_block);
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ namespace ml_dht
|
|||
}
|
||||
}
|
||||
|
||||
public void OnEyeControllerUpdate(CVREyeController p_component)
|
||||
internal void OnEyeControllerUpdate(CVREyeController p_component)
|
||||
{
|
||||
if(m_enabled)
|
||||
{
|
||||
|
@ -99,14 +99,14 @@ namespace ml_dht
|
|||
}
|
||||
}
|
||||
|
||||
public void OnFaceTrackingUpdate(CVRFaceTracking p_component)
|
||||
internal void OnFaceTrackingUpdate(CVRFaceTracking p_component)
|
||||
{
|
||||
if(m_enabled && m_faceOverride)
|
||||
{
|
||||
if(m_avatarDescriptor != null)
|
||||
m_avatarDescriptor.useVisemeLipsync = false;
|
||||
|
||||
float l_weight = Mathf.Clamp(Mathf.InverseLerp(0.25f, 1f, Mathf.Abs(m_mouthShapes.y)), 0f, 1f) * 100f;
|
||||
float l_weight = Mathf.Clamp01(Mathf.InverseLerp(0.25f, 1f, Mathf.Abs(m_mouthShapes.y))) * 100f;
|
||||
|
||||
p_component.BlendShapeValues[(int)LipShape_v2.Jaw_Open] = m_mouthShapes.x * 100f;
|
||||
p_component.BlendShapeValues[(int)LipShape_v2.Mouth_Pout] = ((m_mouthShapes.y > 0f) ? l_weight : 0f);
|
||||
|
@ -117,7 +117,7 @@ namespace ml_dht
|
|||
}
|
||||
}
|
||||
|
||||
public void OnSetupAvatar()
|
||||
internal void OnSetupAvatar()
|
||||
{
|
||||
m_avatarDescriptor = PlayerSetup.Instance._avatar.GetComponent<CVRAvatar>();
|
||||
m_headBone = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Head);
|
||||
|
@ -130,7 +130,7 @@ namespace ml_dht
|
|||
m_lookIK.solver.OnPostUpdate += this.OnLookIKPostUpdate;
|
||||
|
||||
}
|
||||
public void OnAvatarClear()
|
||||
internal void OnAvatarClear()
|
||||
{
|
||||
m_avatarDescriptor = null;
|
||||
m_lookIK = null;
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace ml_dht
|
|||
Smoothing,
|
||||
FaceOverride
|
||||
}
|
||||
|
||||
|
||||
static bool ms_enabled = false;
|
||||
static bool ms_headTracking = true;
|
||||
static bool ms_eyeTracking = true;
|
||||
|
@ -25,10 +25,10 @@ namespace ml_dht
|
|||
static bool ms_mirrored = false;
|
||||
static float ms_smoothing = 0.5f;
|
||||
static bool ms_faceOverride = true;
|
||||
|
||||
|
||||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
||||
|
||||
static public event Action<bool> EnabledChange;
|
||||
static public event Action<bool> HeadTrackingChange;
|
||||
static public event Action<bool> EyeTrackingChange;
|
||||
|
@ -36,25 +36,27 @@ namespace ml_dht
|
|||
static public event Action<bool> MirroredChange;
|
||||
static public event Action<float> SmoothingChange;
|
||||
static public event Action<bool> FaceOverrideChange;
|
||||
|
||||
public static void Init()
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
ms_category = MelonLoader.MelonPreferences.CreateCategory("DHT");
|
||||
|
||||
ms_entries = new List<MelonLoader.MelonPreferences_Entry>();
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.Enabled.ToString(), false));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.HeadTracking.ToString(), false));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.EyeTracking.ToString(), true));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.Blinking.ToString(), true));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.Mirrored.ToString(), false));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.Smoothing.ToString(), 50));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.FaceOverride.ToString(), true));
|
||||
|
||||
|
||||
ms_entries = new List<MelonLoader.MelonPreferences_Entry>()
|
||||
{
|
||||
ms_category.CreateEntry(ModSetting.Enabled.ToString(), false),
|
||||
ms_category.CreateEntry(ModSetting.HeadTracking.ToString(), false),
|
||||
ms_category.CreateEntry(ModSetting.EyeTracking.ToString(), true),
|
||||
ms_category.CreateEntry(ModSetting.Blinking.ToString(), true),
|
||||
ms_category.CreateEntry(ModSetting.Mirrored.ToString(), false),
|
||||
ms_category.CreateEntry(ModSetting.Smoothing.ToString(), 50),
|
||||
ms_category.CreateEntry(ModSetting.FaceOverride.ToString(), true)
|
||||
};
|
||||
|
||||
Load();
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitMainMenuUi());
|
||||
}
|
||||
|
||||
|
||||
static System.Collections.IEnumerator WaitMainMenuUi()
|
||||
{
|
||||
while(ViewManager.Instance == null)
|
||||
|
@ -76,18 +78,18 @@ namespace ml_dht
|
|||
ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSettingDHT", l_entry.DisplayName, l_entry.GetValueAsString());
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
static void Load()
|
||||
{
|
||||
ms_enabled = (bool)ms_entries[(int)ModSetting.Enabled].BoxedValue;
|
||||
ms_headTracking = (bool)ms_entries[(int)ModSetting.HeadTracking].BoxedValue;
|
||||
ms_eyeTracking = (bool)ms_entries[(int)ModSetting.EyeTracking].BoxedValue;
|
||||
ms_blinking = (bool)ms_entries[(int)ModSetting.Blinking].BoxedValue;
|
||||
ms_headTracking = (bool)ms_entries[(int)ModSetting.HeadTracking].BoxedValue;
|
||||
ms_eyeTracking = (bool)ms_entries[(int)ModSetting.EyeTracking].BoxedValue;
|
||||
ms_blinking = (bool)ms_entries[(int)ModSetting.Blinking].BoxedValue;
|
||||
ms_mirrored = (bool)ms_entries[(int)ModSetting.Mirrored].BoxedValue;
|
||||
ms_smoothing = ((int)ms_entries[(int)ModSetting.Smoothing].BoxedValue) * 0.01f;
|
||||
ms_faceOverride = (bool)ms_entries[(int)ModSetting.FaceOverride].BoxedValue;
|
||||
}
|
||||
|
||||
|
||||
static void OnSliderUpdate(string p_name, string p_value)
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
|
@ -105,7 +107,7 @@ namespace ml_dht
|
|||
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void OnToggleUpdate(string p_name, string p_value)
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
|
@ -130,13 +132,15 @@ namespace ml_dht
|
|||
{
|
||||
ms_eyeTracking = bool.Parse(p_value);
|
||||
EyeTrackingChange?.Invoke(ms_eyeTracking);
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.Blinking:
|
||||
{
|
||||
ms_blinking = bool.Parse(p_value);
|
||||
BlinkingChange?.Invoke(ms_blinking);
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.Mirrored:
|
||||
{
|
||||
|
@ -149,13 +153,14 @@ namespace ml_dht
|
|||
{
|
||||
ms_faceOverride = bool.Parse(p_value);
|
||||
FaceOverrideChange?.Invoke(ms_faceOverride);
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static bool Enabled
|
||||
{
|
||||
get => ms_enabled;
|
||||
|
|
|
@ -88,6 +88,6 @@
|
|||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>copy /y "$(TargetPath)" "C:\Games\Steam\common\ChilloutVR\Mods\"</PostBuildEvent>
|
||||
<PostBuildEvent>copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\"</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
</Project>
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ReferencePath>C:\Games\Steam\common\ChilloutVR\MelonLoader\;C:\Games\Steam\common\ChilloutVR\ChilloutVR_Data\Managed\</ReferencePath>
|
||||
<ReferencePath>D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\;D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\</ReferencePath>
|
||||
</PropertyGroup>
|
||||
</Project>
|
143
ml_egn/Main.cs
Normal file
143
ml_egn/Main.cs
Normal file
|
@ -0,0 +1,143 @@
|
|||
using ABI_RC.Core.EventSystem;
|
||||
using ABI_RC.Core.InteractionSystem;
|
||||
using ABI_RC.Core.IO;
|
||||
using ABI_RC.Core.Networking;
|
||||
using ABI_RC.Core.Util;
|
||||
using DarkRift.Client;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ml_egn
|
||||
{
|
||||
public class ExtendedGameNotifications : MelonLoader.MelonMod
|
||||
{
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
HarmonyInstance.Patch(
|
||||
typeof(AssetManagement).GetMethod(nameof(AssetManagement.LoadLocalAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(ExtendedGameNotifications).GetMethod(nameof(OnLocalAvatarLoad), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRSyncHelper).GetMethod(nameof(CVRSyncHelper.SpawnProp)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(ExtendedGameNotifications).GetMethod(nameof(OnPropSpawned), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
|
||||
HarmonyInstance.Patch(
|
||||
typeof(NetworkManager).GetMethod("OnGameNetworkConnectionClosed", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(ExtendedGameNotifications).GetMethod(nameof(OnGameNetworkConnectionClosed), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRCamImageSaver).GetMethod(nameof(CVRCamImageSaver.SavePicture), BindingFlags.Public | BindingFlags.Static),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(ExtendedGameNotifications).GetMethod(nameof(OnPictureSave), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRSyncHelper).GetMethod(nameof(CVRSyncHelper.DeleteAllProps), BindingFlags.Public | BindingFlags.Static),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(ExtendedGameNotifications).GetMethod(nameof(OnAllPropsDelete), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRSyncHelper).GetMethod(nameof(CVRSyncHelper.DeleteMyProps), BindingFlags.Public | BindingFlags.Static),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(ExtendedGameNotifications).GetMethod(nameof(OnOwnPropsDelete), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
}
|
||||
|
||||
static void OnLocalAvatarLoad()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Utils.IsMenuOpened())
|
||||
Utils.ShowMenuNotification("Avatar changed", 1f);
|
||||
else
|
||||
Utils.ShowHUDNotification("(Synced) Client", "Avatar changed");
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnPropSpawned()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Utils.IsConnected())
|
||||
{
|
||||
if(Utils.IsMenuOpened())
|
||||
Utils.ShowMenuNotification("Prop spawned", 1f);
|
||||
else
|
||||
Utils.ShowHUDNotification("(Synced) Client", "Prop spawned");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Utils.IsMenuOpened())
|
||||
Utils.ShowMenuAlert("Prop Error", "Not connected to live instance");
|
||||
else
|
||||
Utils.ShowHUDNotification("(Local) Client", "Unable to spawn prop", "Not connected to live instance");
|
||||
}
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnGameNetworkConnectionClosed(DisconnectedEventArgs __1)
|
||||
{
|
||||
try
|
||||
{
|
||||
if((__1 != null) && (!__1.LocalDisconnect))
|
||||
Utils.ShowHUDNotification("(Local) Client", "Connection lost", (__1.Error != System.Net.Sockets.SocketError.Success) ? ("Reason: " + __1.Error.ToString()) : "", true);
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnPictureSave()
|
||||
{
|
||||
try
|
||||
{
|
||||
Utils.ShowHUDNotification("(Local) Client", "Screenshot saved");
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAllPropsDelete()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Utils.IsMenuOpened())
|
||||
Utils.ShowMenuNotification("Props are removed");
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnOwnPropsDelete()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Utils.IsMenuOpened())
|
||||
Utils.ShowMenuNotification("Own props are removed");
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
10
ml_egn/Properties/AssemblyInfo.cs
Normal file
10
ml_egn/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyTitle("ExtendedGameNotifications")]
|
||||
[assembly: AssemblyVersion("1.0.1")]
|
||||
[assembly: AssemblyFileVersion("1.0.1")]
|
||||
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_egn.ExtendedGameNotifications), "ExtendedGameNotifications", "1.0.1", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
12
ml_egn/README.md
Normal file
12
ml_egn/README.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Extended Game Notifications
|
||||
This mod shows main menu notifications and HUD popups upon:
|
||||
* Avatar changing
|
||||
* Prop spawning/deletion
|
||||
* Server connection loss
|
||||
* Screenshot saving
|
||||
Basically, merged previous `Avatar Change Info` and `Server Connection Info` mods in one.
|
||||
|
||||
# Installation
|
||||
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
|
||||
* Get [latest release DLL](../../../releases/latest):
|
||||
* Put `ml_egn.dll` in `Mods` folder of game
|
46
ml_egn/Utils.cs
Normal file
46
ml_egn/Utils.cs
Normal file
|
@ -0,0 +1,46 @@
|
|||
using ABI_RC.Core.InteractionSystem;
|
||||
using ABI_RC.Core.Networking;
|
||||
using ABI_RC.Core.UI;
|
||||
using DarkRift;
|
||||
|
||||
namespace ml_egn
|
||||
{
|
||||
static class Utils
|
||||
{
|
||||
public static bool IsMenuOpened()
|
||||
{
|
||||
return ((ViewManager.Instance != null) ? ViewManager.Instance.isGameMenuOpen() : false);
|
||||
}
|
||||
|
||||
public static void ShowMenuNotification(string p_message, float p_time = 1f)
|
||||
{
|
||||
if(ViewManager.Instance != null)
|
||||
ViewManager.Instance.TriggerPushNotification(p_message, p_time);
|
||||
}
|
||||
|
||||
public static void ShowMenuAlert(string p_title, string p_message)
|
||||
{
|
||||
if(ViewManager.Instance != null)
|
||||
ViewManager.Instance.TriggerAlert(p_title, p_message, -1, true);
|
||||
}
|
||||
|
||||
public static void ShowHUDNotification(string p_title, string p_message, string p_small = "", bool p_immediate = false)
|
||||
{
|
||||
if(CohtmlHud.Instance != null)
|
||||
{
|
||||
if(p_immediate)
|
||||
CohtmlHud.Instance.ViewDropTextImmediate(p_title, p_message, p_small);
|
||||
else
|
||||
CohtmlHud.Instance.ViewDropText(p_title, p_message, p_small);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsConnected()
|
||||
{
|
||||
bool l_result = false;
|
||||
if((NetworkManager.Instance != null) && (NetworkManager.Instance.GameNetwork != null))
|
||||
l_result = (NetworkManager.Instance.GameNetwork.ConnectionState == ConnectionState.Connected);
|
||||
return l_result;
|
||||
}
|
||||
}
|
||||
}
|
82
ml_egn/ml_egn.csproj
Normal file
82
ml_egn/ml_egn.csproj
Normal file
|
@ -0,0 +1,82 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{1B5ACA07-6266-4C9A-BA30-D4BBE6634846}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>ml_egn</RootNamespace>
|
||||
<AssemblyName>ml_egn</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="0Harmony, Version=2.9.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>F:\games\Steam\common\ChilloutVR\MelonLoader\0Harmony.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>F:\games\Steam\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="DarkRift">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="DarkRift.Client, Version=2.4.5.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="MelonLoader, Version=0.5.4.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>F:\games\Steam\common\ChilloutVR\MelonLoader\MelonLoader.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Main.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Utils.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PreBuildEvent>
|
||||
</PreBuildEvent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\"</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
</Project>
|
6
ml_egn/ml_egn.csproj.user
Normal file
6
ml_egn/ml_egn.csproj.user
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ReferencePath>D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\;D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\</ReferencePath>
|
||||
</PropertyGroup>
|
||||
</Project>
|
|
@ -4,7 +4,6 @@ namespace ml_lme
|
|||
{
|
||||
static class GestureMatcher
|
||||
{
|
||||
|
||||
readonly static Vector2[] ms_fingerLimits =
|
||||
{
|
||||
new Vector2(-50f, 0f),
|
||||
|
@ -14,100 +13,75 @@ namespace ml_lme
|
|||
new Vector2(-10f, 25f)
|
||||
};
|
||||
|
||||
public class GesturesData
|
||||
public class HandData
|
||||
{
|
||||
readonly public static int ms_handsCount = 2;
|
||||
readonly public static int ms_fingersCount = 5;
|
||||
public bool m_present = false;
|
||||
public Vector3 m_position = Vector3.zero;
|
||||
public Quaternion m_rotation = Quaternion.identity;
|
||||
public Vector3 m_elbowPosition = Vector3.zero;
|
||||
public readonly float[] m_spreads = null;
|
||||
public readonly float[] m_bends = null;
|
||||
public float m_grabStrength = 0f;
|
||||
|
||||
public bool[] m_handsPresenses = null;
|
||||
public Vector3[] m_handsPositons = null;
|
||||
public Quaternion[] m_handsRotations = null;
|
||||
public Vector3[] m_elbowsPositions = null;
|
||||
public float[] m_leftFingersBends = null;
|
||||
public float[] m_leftFingersSpreads = null;
|
||||
public float[] m_rightFingersBends = null;
|
||||
public float[] m_rightFingersSpreads = null;
|
||||
|
||||
public GesturesData()
|
||||
public HandData()
|
||||
{
|
||||
m_handsPresenses = new bool[ms_handsCount];
|
||||
m_handsPositons = new Vector3[ms_handsCount];
|
||||
m_handsRotations = new Quaternion[ms_handsCount];
|
||||
m_elbowsPositions = new Vector3[ms_handsCount];
|
||||
m_leftFingersBends = new float[ms_fingersCount];
|
||||
m_leftFingersSpreads = new float[ms_fingersCount];
|
||||
m_rightFingersBends = new float[ms_fingersCount];
|
||||
m_rightFingersSpreads = new float[ms_fingersCount];
|
||||
m_spreads = new float[5];
|
||||
m_bends = new float[5];
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
m_present = false;
|
||||
for(int i = 0; i < 5; i++)
|
||||
{
|
||||
m_bends[i] = 0f;
|
||||
m_spreads[i] = 0f;
|
||||
}
|
||||
m_grabStrength = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
public static void GetGestures(Leap.Frame p_frame, ref GesturesData p_data)
|
||||
public class LeapData
|
||||
{
|
||||
// Fill as default
|
||||
for(int i = 0; i < GesturesData.ms_handsCount; i++)
|
||||
p_data.m_handsPresenses[i] = false;
|
||||
for(int i = 0; i < GesturesData.ms_fingersCount; i++)
|
||||
public readonly HandData m_leftHand = null;
|
||||
public readonly HandData m_rightHand = null;
|
||||
|
||||
public LeapData()
|
||||
{
|
||||
p_data.m_leftFingersBends[i] = 0f;
|
||||
p_data.m_leftFingersSpreads[i] = 0f;
|
||||
p_data.m_rightFingersBends[i] = 0f;
|
||||
p_data.m_leftFingersSpreads[i] = 0f;
|
||||
m_leftHand = new HandData();
|
||||
m_rightHand = new HandData();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
m_leftHand.Reset();
|
||||
m_rightHand.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
public static void GetFrameData(Leap.Frame p_frame, LeapData p_data)
|
||||
{
|
||||
p_data.Reset();
|
||||
|
||||
// Fill hands data
|
||||
foreach(Leap.Hand l_hand in p_frame.Hands)
|
||||
{
|
||||
int l_sideID = (l_hand.IsLeft ? 0 : 1);
|
||||
if(!p_data.m_handsPresenses[l_sideID])
|
||||
{
|
||||
p_data.m_handsPresenses[l_sideID] = true;
|
||||
FillHandPosition(l_hand, ref p_data.m_handsPositons[l_sideID]);
|
||||
FillHandRotation(l_hand, ref p_data.m_handsRotations[l_sideID]);
|
||||
FillElbowPosition(l_hand, ref p_data.m_elbowsPositions[l_sideID]);
|
||||
switch(l_sideID)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
FillFingerBends(l_hand, ref p_data.m_leftFingersBends);
|
||||
FilFingerSpreads(l_hand, ref p_data.m_leftFingersSpreads);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
FillFingerBends(l_hand, ref p_data.m_rightFingersBends);
|
||||
FilFingerSpreads(l_hand, ref p_data.m_rightFingersSpreads);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(l_hand.IsLeft && !p_data.m_leftHand.m_present)
|
||||
FillHandData(l_hand, p_data.m_leftHand);
|
||||
if(l_hand.IsRight && !p_data.m_rightHand.m_present)
|
||||
FillHandData(l_hand, p_data.m_rightHand);
|
||||
}
|
||||
}
|
||||
|
||||
static void FillHandPosition(Leap.Hand p_hand, ref Vector3 p_pos)
|
||||
static void FillHandData(Leap.Hand p_hand, HandData p_data)
|
||||
{
|
||||
// Unity's IK and FinalIK move hand bones to target, therefore - wrist
|
||||
p_pos.x = p_hand.WristPosition.x;
|
||||
p_pos.y = p_hand.WristPosition.y;
|
||||
p_pos.z = p_hand.WristPosition.z;
|
||||
}
|
||||
p_data.m_present = true;
|
||||
p_data.m_position.Set(p_hand.WristPosition.x, p_hand.WristPosition.y, p_hand.WristPosition.z);
|
||||
p_data.m_rotation.Set(p_hand.Rotation.x, p_hand.Rotation.y, p_hand.Rotation.z, p_hand.Rotation.w);
|
||||
p_data.m_elbowPosition.Set(p_hand.Arm.ElbowPosition.x, p_hand.Arm.ElbowPosition.y, p_hand.Arm.ElbowPosition.z);
|
||||
|
||||
static void FillHandRotation(Leap.Hand p_hand, ref Quaternion p_rot)
|
||||
{
|
||||
p_rot.x = p_hand.Rotation.x;
|
||||
p_rot.y = p_hand.Rotation.y;
|
||||
p_rot.z = p_hand.Rotation.z;
|
||||
p_rot.w = p_hand.Rotation.w;
|
||||
}
|
||||
|
||||
static void FillElbowPosition(Leap.Hand p_hand, ref Vector3 p_pos)
|
||||
{
|
||||
p_pos.x = p_hand.Arm.ElbowPosition.x;
|
||||
p_pos.y = p_hand.Arm.ElbowPosition.y;
|
||||
p_pos.z = p_hand.Arm.ElbowPosition.z;
|
||||
}
|
||||
|
||||
static void FillFingerBends(Leap.Hand p_hand, ref float[] p_bends)
|
||||
{
|
||||
// Bends
|
||||
foreach(Leap.Finger l_finger in p_hand.Fingers)
|
||||
{
|
||||
Quaternion l_prevSegment = Quaternion.identity;
|
||||
|
@ -132,12 +106,10 @@ namespace ml_lme
|
|||
l_angle += l_curAngle;
|
||||
}
|
||||
|
||||
p_bends[(int)l_finger.Type] = Mathf.InverseLerp(0f, (l_finger.Type == Leap.Finger.FingerType.TYPE_THUMB) ? 90f : 180f, l_angle);
|
||||
p_data.m_bends[(int)l_finger.Type] = Mathf.InverseLerp(0f, (l_finger.Type == Leap.Finger.FingerType.TYPE_THUMB) ? 90f : 180f, l_angle);
|
||||
}
|
||||
}
|
||||
|
||||
static void FilFingerSpreads(Leap.Hand p_hand, ref float[] p_spreads)
|
||||
{
|
||||
// Spreads
|
||||
foreach(Leap.Finger l_finger in p_hand.Fingers)
|
||||
{
|
||||
float l_angle = 0f;
|
||||
|
@ -162,13 +134,15 @@ namespace ml_lme
|
|||
if(l_finger.Type != Leap.Finger.FingerType.TYPE_THUMB)
|
||||
{
|
||||
if(l_angle < 0f)
|
||||
p_spreads[(int)l_finger.Type] = 0.5f * Mathf.InverseLerp(ms_fingerLimits[(int)l_finger.Type].x, 0f, l_angle);
|
||||
p_data.m_spreads[(int)l_finger.Type] = 0.5f * Mathf.InverseLerp(ms_fingerLimits[(int)l_finger.Type].x, 0f, l_angle);
|
||||
else
|
||||
p_spreads[(int)l_finger.Type] = 0.5f + 0.5f * Mathf.InverseLerp(0f, ms_fingerLimits[(int)l_finger.Type].y, l_angle);
|
||||
p_data.m_spreads[(int)l_finger.Type] = 0.5f + 0.5f * Mathf.InverseLerp(0f, ms_fingerLimits[(int)l_finger.Type].y, l_angle);
|
||||
}
|
||||
else
|
||||
p_spreads[(int)l_finger.Type] = Mathf.InverseLerp(ms_fingerLimits[(int)l_finger.Type].x, ms_fingerLimits[(int)l_finger.Type].y, l_angle);
|
||||
p_data.m_spreads[(int)l_finger.Type] = Mathf.InverseLerp(ms_fingerLimits[(int)l_finger.Type].x, ms_fingerLimits[(int)l_finger.Type].y, l_angle);
|
||||
}
|
||||
|
||||
p_data.m_grabStrength = (p_data.m_bends[1] + p_data.m_bends[2] + p_data.m_bends[3] + p_data.m_bends[4]) * 0.25f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
286
ml_lme/LeapInput.cs
Normal file
286
ml_lme/LeapInput.cs
Normal file
|
@ -0,0 +1,286 @@
|
|||
using ABI_RC.Core.InteractionSystem;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Savior;
|
||||
using ABI_RC.Systems.IK;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_lme
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
class LeapInput : CVRInputModule
|
||||
{
|
||||
static readonly FieldInfo ms_indexGestureToggle = typeof(InputModuleSteamVR).GetField("_steamVrIndexGestureToggleValue", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
CVRInputManager m_inputManager = null;
|
||||
InputModuleSteamVR m_steamVrModule = null;
|
||||
bool m_inVR = false;
|
||||
bool m_gripToGrab = true;
|
||||
|
||||
ControllerRay m_handRayLeft = null;
|
||||
ControllerRay m_handRayRight = null;
|
||||
LineRenderer m_lineLeft = null;
|
||||
LineRenderer m_lineRight = null;
|
||||
bool m_interactLeft = false;
|
||||
bool m_interactRight = false;
|
||||
bool m_gripLeft = false;
|
||||
bool m_gripRight = false;
|
||||
|
||||
public new void Start()
|
||||
{
|
||||
base.Start();
|
||||
|
||||
m_inputManager = CVRInputManager.Instance; // _inputManager is stripped out, cool beans
|
||||
m_steamVrModule = m_inputManager.GetComponent<InputModuleSteamVR>();
|
||||
m_inVR = Utils.IsInVR();
|
||||
|
||||
m_handRayLeft = LeapTracking.GetInstance().GetLeftHand().gameObject.AddComponent<ControllerRay>();
|
||||
m_handRayLeft.hand = true;
|
||||
m_handRayLeft.generalMask = -1485;
|
||||
m_handRayLeft.isInteractionRay = true;
|
||||
m_handRayLeft.triggerGazeEvents = false;
|
||||
m_handRayLeft.holderRoot = m_handRayLeft.gameObject;
|
||||
|
||||
m_handRayRight = LeapTracking.GetInstance().GetRightHand().gameObject.AddComponent<ControllerRay>();
|
||||
m_handRayRight.hand = false;
|
||||
m_handRayRight.generalMask = -1485;
|
||||
m_handRayRight.isInteractionRay = true;
|
||||
m_handRayRight.triggerGazeEvents = false;
|
||||
m_handRayRight.holderRoot = m_handRayRight.gameObject;
|
||||
|
||||
m_lineLeft = m_handRayLeft.gameObject.AddComponent<LineRenderer>();
|
||||
m_lineLeft.endWidth = 1f;
|
||||
m_lineLeft.startWidth = 1f;
|
||||
m_lineLeft.textureMode = LineTextureMode.Tile;
|
||||
m_lineLeft.useWorldSpace = false;
|
||||
m_lineLeft.widthMultiplier = 1f;
|
||||
m_lineLeft.allowOcclusionWhenDynamic = false;
|
||||
m_lineLeft.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
|
||||
m_lineLeft.enabled = false;
|
||||
m_lineLeft.receiveShadows = false;
|
||||
m_handRayLeft.lineRenderer = m_lineLeft;
|
||||
|
||||
m_lineRight = m_handRayRight.gameObject.AddComponent<LineRenderer>();
|
||||
m_lineRight.endWidth = 1f;
|
||||
m_lineRight.startWidth = 1f;
|
||||
m_lineRight.textureMode = LineTextureMode.Tile;
|
||||
m_lineRight.useWorldSpace = false;
|
||||
m_lineRight.widthMultiplier = 1f;
|
||||
m_lineRight.allowOcclusionWhenDynamic = false;
|
||||
m_lineRight.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
|
||||
m_lineRight.enabled = false;
|
||||
m_lineRight.receiveShadows = false;
|
||||
m_handRayRight.lineRenderer = m_lineRight;
|
||||
|
||||
Settings.EnabledChange += this.OnEnableChange;
|
||||
Settings.InputChange += this.OnInputChange;
|
||||
|
||||
OnEnableChange(Settings.Enabled);
|
||||
OnInputChange(Settings.Input);
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForSettings());
|
||||
MelonLoader.MelonCoroutines.Start(WaitForMaterial());
|
||||
}
|
||||
|
||||
IEnumerator WaitForSettings()
|
||||
{
|
||||
while(MetaPort.Instance == null)
|
||||
yield return null;
|
||||
while(MetaPort.Instance.settings == null)
|
||||
yield return null;
|
||||
|
||||
m_gripToGrab = MetaPort.Instance.settings.GetSettingsBool("ControlUseGripToGrab", true);
|
||||
MetaPort.Instance.settings.settingBoolChanged.AddListener(this.OnGameSettingBoolChange);
|
||||
}
|
||||
|
||||
IEnumerator WaitForMaterial()
|
||||
{
|
||||
while(PlayerSetup.Instance == null)
|
||||
yield return null;
|
||||
while(PlayerSetup.Instance.leftRay == null)
|
||||
yield return null;
|
||||
while(PlayerSetup.Instance.leftRay.lineRenderer == null)
|
||||
yield return null;
|
||||
|
||||
m_lineLeft.material = PlayerSetup.Instance.leftRay.lineRenderer.material;
|
||||
m_lineLeft.gameObject.layer = PlayerSetup.Instance.leftRay.gameObject.layer;
|
||||
m_lineRight.material = PlayerSetup.Instance.leftRay.lineRenderer.material;
|
||||
m_lineRight.gameObject.layer = PlayerSetup.Instance.leftRay.gameObject.layer;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
Settings.EnabledChange -= this.OnEnableChange;
|
||||
Settings.InputChange -= this.OnInputChange;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
GestureMatcher.LeapData l_data = LeapManager.GetInstance().GetLatestData();
|
||||
|
||||
if(Settings.Enabled)
|
||||
{
|
||||
if(l_data.m_leftHand.m_present)
|
||||
SetFingersInput(l_data.m_leftHand, true);
|
||||
if(l_data.m_rightHand.m_present)
|
||||
SetFingersInput(l_data.m_rightHand, false);
|
||||
}
|
||||
|
||||
m_handRayLeft.enabled = (l_data.m_leftHand.m_present && (!m_inVR || !Utils.IsLeftHandTracked() || !Settings.FingersOnly));
|
||||
m_handRayRight.enabled = (l_data.m_rightHand.m_present && (!m_inVR || !Utils.IsRightHandTracked() || !Settings.FingersOnly));
|
||||
}
|
||||
|
||||
public override void UpdateInput()
|
||||
{
|
||||
if(Settings.Enabled && Settings.Input)
|
||||
{
|
||||
GestureMatcher.LeapData l_data = LeapManager.GetInstance().GetLatestData();
|
||||
|
||||
if(l_data.m_leftHand.m_present && (!m_inVR || !Utils.IsLeftHandTracked() || !Settings.FingersOnly))
|
||||
{
|
||||
float l_strength = l_data.m_leftHand.m_grabStrength;
|
||||
|
||||
float l_interactValue = 0f;
|
||||
if(m_gripToGrab)
|
||||
l_interactValue = Mathf.Clamp01(Mathf.InverseLerp(Mathf.Min(Settings.GripThreadhold, Settings.InteractThreadhold), Mathf.Max(Settings.GripThreadhold, Settings.InteractThreadhold), l_strength));
|
||||
else
|
||||
l_interactValue = Mathf.Clamp01(Mathf.InverseLerp(0f, Settings.InteractThreadhold, l_strength));
|
||||
m_inputManager.interactLeftValue = Mathf.Max(l_interactValue, m_inputManager.interactLeftValue);
|
||||
|
||||
if(m_interactLeft != (l_strength > Settings.InteractThreadhold))
|
||||
{
|
||||
m_interactLeft = (l_strength > Settings.InteractThreadhold);
|
||||
m_inputManager.interactLeftDown |= m_interactLeft;
|
||||
m_inputManager.interactLeftUp |= !m_interactLeft;
|
||||
}
|
||||
|
||||
float l_gripValue = Mathf.Clamp01(Mathf.InverseLerp(0f, Settings.GripThreadhold, l_strength));
|
||||
m_inputManager.gripLeftValue = Mathf.Max(l_gripValue, m_inputManager.gripLeftValue);
|
||||
if(m_gripLeft != (l_strength > Settings.GripThreadhold))
|
||||
{
|
||||
m_gripLeft = (l_strength > Settings.GripThreadhold);
|
||||
m_inputManager.gripLeftDown |= m_gripLeft;
|
||||
m_inputManager.gripLeftUp |= !m_gripLeft;
|
||||
}
|
||||
}
|
||||
|
||||
if(l_data.m_rightHand.m_present && (!m_inVR || !Utils.IsRightHandTracked() || !Settings.FingersOnly))
|
||||
{
|
||||
float l_strength = l_data.m_rightHand.m_grabStrength;
|
||||
|
||||
float l_interactValue = 0f;
|
||||
if(m_gripToGrab)
|
||||
l_interactValue = Mathf.Clamp01(Mathf.InverseLerp(Mathf.Min(Settings.GripThreadhold, Settings.InteractThreadhold), Mathf.Max(Settings.GripThreadhold, Settings.InteractThreadhold), l_strength));
|
||||
else
|
||||
l_interactValue = Mathf.Clamp01(Mathf.InverseLerp(0f, Settings.InteractThreadhold, l_strength));
|
||||
m_inputManager.interactRightValue = Mathf.Max(l_interactValue, m_inputManager.interactRightValue);
|
||||
|
||||
if(m_interactRight != (l_strength > Settings.InteractThreadhold))
|
||||
{
|
||||
m_interactRight = (l_strength > Settings.InteractThreadhold);
|
||||
m_inputManager.interactRightDown |= m_interactRight;
|
||||
m_inputManager.interactRightUp |= !m_interactRight;
|
||||
}
|
||||
|
||||
float l_gripValue = Mathf.Clamp01(Mathf.InverseLerp(0f, Settings.GripThreadhold, l_strength));
|
||||
m_inputManager.gripRightValue = Mathf.Max(l_gripValue, m_inputManager.gripRightValue);
|
||||
if(m_gripRight != (l_strength > Settings.GripThreadhold))
|
||||
{
|
||||
m_gripRight = (l_strength > Settings.GripThreadhold);
|
||||
m_inputManager.gripRightDown |= m_gripRight;
|
||||
m_inputManager.gripRightUp |= !m_gripRight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Settings changes
|
||||
void OnEnableChange(bool p_state)
|
||||
{
|
||||
OnInputChange(p_state && Settings.Input);
|
||||
UpdateFingerTracking();
|
||||
}
|
||||
|
||||
void OnInputChange(bool p_state)
|
||||
{
|
||||
((MonoBehaviour)m_handRayLeft).enabled = (p_state && Settings.Enabled);
|
||||
((MonoBehaviour)m_handRayRight).enabled = (p_state && Settings.Enabled);
|
||||
m_lineLeft.enabled = (p_state && Settings.Enabled);
|
||||
m_lineRight.enabled = (p_state && Settings.Enabled);
|
||||
|
||||
if(!p_state)
|
||||
{
|
||||
m_handRayLeft.DropObject(true);
|
||||
m_handRayLeft.ClearGrabbedObject();
|
||||
|
||||
m_handRayRight.DropObject(true);
|
||||
m_handRayRight.ClearGrabbedObject();
|
||||
|
||||
m_interactLeft = false;
|
||||
m_interactRight = false;
|
||||
m_gripLeft = false;
|
||||
m_gripRight = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Game events
|
||||
internal void OnAvatarSetup()
|
||||
{
|
||||
m_inVR = Utils.IsInVR();
|
||||
UpdateFingerTracking();
|
||||
}
|
||||
|
||||
internal void OnRayScale(float p_scale)
|
||||
{
|
||||
m_handRayLeft.SetRayScale(p_scale);
|
||||
m_handRayRight.SetRayScale(p_scale);
|
||||
}
|
||||
|
||||
// Arbitrary
|
||||
void UpdateFingerTracking()
|
||||
{
|
||||
m_inputManager.individualFingerTracking = (Settings.Enabled || (m_inVR && Utils.AreKnucklesInUse() && !(bool)ms_indexGestureToggle.GetValue(m_steamVrModule)));
|
||||
IKSystem.Instance.FingerSystem.controlActive = m_inputManager.individualFingerTracking;
|
||||
}
|
||||
|
||||
void SetFingersInput(GestureMatcher.HandData p_hand, bool p_left)
|
||||
{
|
||||
m_inputManager.individualFingerTracking = true;
|
||||
IKSystem.Instance.FingerSystem.controlActive = true;
|
||||
|
||||
if(p_left)
|
||||
{
|
||||
m_inputManager.fingerCurlLeftThumb = p_hand.m_bends[0];
|
||||
m_inputManager.fingerCurlLeftIndex = p_hand.m_bends[1];
|
||||
m_inputManager.fingerCurlLeftMiddle = p_hand.m_bends[2];
|
||||
m_inputManager.fingerCurlLeftRing = p_hand.m_bends[3];
|
||||
m_inputManager.fingerCurlLeftPinky = p_hand.m_bends[4];
|
||||
IKSystem.Instance.FingerSystem.leftThumbCurl = p_hand.m_bends[0];
|
||||
IKSystem.Instance.FingerSystem.leftIndexCurl = p_hand.m_bends[1];
|
||||
IKSystem.Instance.FingerSystem.leftMiddleCurl = p_hand.m_bends[2];
|
||||
IKSystem.Instance.FingerSystem.leftRingCurl = p_hand.m_bends[3];
|
||||
IKSystem.Instance.FingerSystem.leftPinkyCurl = p_hand.m_bends[4];
|
||||
}
|
||||
else
|
||||
{
|
||||
m_inputManager.fingerCurlRightThumb = p_hand.m_bends[0];
|
||||
m_inputManager.fingerCurlRightIndex = p_hand.m_bends[1];
|
||||
m_inputManager.fingerCurlRightMiddle = p_hand.m_bends[2];
|
||||
m_inputManager.fingerCurlRightRing = p_hand.m_bends[3];
|
||||
m_inputManager.fingerCurlRightPinky = p_hand.m_bends[4];
|
||||
IKSystem.Instance.FingerSystem.rightThumbCurl = p_hand.m_bends[0];
|
||||
IKSystem.Instance.FingerSystem.rightIndexCurl = p_hand.m_bends[1];
|
||||
IKSystem.Instance.FingerSystem.rightMiddleCurl = p_hand.m_bends[2];
|
||||
IKSystem.Instance.FingerSystem.rightRingCurl = p_hand.m_bends[3];
|
||||
IKSystem.Instance.FingerSystem.rightPinkyCurl = p_hand.m_bends[4];
|
||||
}
|
||||
}
|
||||
|
||||
void OnGameSettingBoolChange(string p_name, bool p_state)
|
||||
{
|
||||
if(p_name == "ControlUseGripToGrab")
|
||||
m_gripToGrab = p_state;
|
||||
}
|
||||
}
|
||||
}
|
212
ml_lme/LeapManager.cs
Normal file
212
ml_lme/LeapManager.cs
Normal file
|
@ -0,0 +1,212 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Savior;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_lme
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
class LeapManager : MonoBehaviour
|
||||
{
|
||||
static LeapManager ms_instance = null;
|
||||
|
||||
readonly Leap.Controller m_leapController = null;
|
||||
readonly GestureMatcher.LeapData m_leapData = null;
|
||||
|
||||
LeapTracking m_leapTracking = null;
|
||||
LeapTracked m_leapTracked = null;
|
||||
LeapInput m_leapInput = null;
|
||||
|
||||
public static LeapManager GetInstance() => ms_instance;
|
||||
|
||||
internal LeapManager()
|
||||
{
|
||||
m_leapController = new Leap.Controller();
|
||||
m_leapData = new GestureMatcher.LeapData();
|
||||
}
|
||||
~LeapManager()
|
||||
{
|
||||
m_leapController.StopConnection();
|
||||
m_leapController.Dispose();
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
if(ms_instance == null)
|
||||
ms_instance = this;
|
||||
|
||||
DontDestroyOnLoad(this);
|
||||
|
||||
m_leapController.Device += this.OnLeapDeviceInitialized;
|
||||
m_leapController.DeviceFailure += this.OnLeapDeviceFailure;
|
||||
m_leapController.DeviceLost += this.OnLeapDeviceLost;
|
||||
m_leapController.Connect += this.OnLeapServiceConnect;
|
||||
m_leapController.Disconnect += this.OnLeapServiceDisconnect;
|
||||
|
||||
Settings.EnabledChange += this.OnEnableChange;
|
||||
Settings.TrackingModeChange += this.OnTrackingModeChange;
|
||||
|
||||
m_leapTracking = new GameObject("[LeapTrackingRoot]").AddComponent<LeapTracking>();
|
||||
m_leapTracking.transform.parent = this.transform;
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForInputManager());
|
||||
MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
|
||||
|
||||
OnEnableChange(Settings.Enabled);
|
||||
OnTrackingModeChange(Settings.TrackingMode);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
m_leapController.Device -= this.OnLeapDeviceInitialized;
|
||||
m_leapController.DeviceFailure -= this.OnLeapDeviceFailure;
|
||||
m_leapController.DeviceLost -= this.OnLeapDeviceLost;
|
||||
m_leapController.Connect -= this.OnLeapServiceConnect;
|
||||
m_leapController.Disconnect -= this.OnLeapServiceDisconnect;
|
||||
|
||||
Settings.EnabledChange -= this.OnEnableChange;
|
||||
Settings.TrackingModeChange -= this.OnTrackingModeChange;
|
||||
}
|
||||
|
||||
IEnumerator WaitForInputManager()
|
||||
{
|
||||
while(CVRInputManager.Instance == null)
|
||||
yield return null;
|
||||
|
||||
m_leapInput = CVRInputManager.Instance.gameObject.AddComponent<LeapInput>();
|
||||
}
|
||||
|
||||
IEnumerator WaitForLocalPlayer()
|
||||
{
|
||||
while(PlayerSetup.Instance == null)
|
||||
yield return null;
|
||||
|
||||
m_leapTracked = PlayerSetup.Instance.gameObject.AddComponent<LeapTracked>();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if(Settings.Enabled)
|
||||
{
|
||||
m_leapData.Reset();
|
||||
|
||||
if(m_leapController.IsConnected)
|
||||
{
|
||||
Leap.Frame l_frame = m_leapController.Frame();
|
||||
GestureMatcher.GetFrameData(l_frame, m_leapData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public GestureMatcher.LeapData GetLatestData() => m_leapData;
|
||||
|
||||
// Device events
|
||||
void OnLeapDeviceInitialized(object p_sender, Leap.DeviceEventArgs p_args)
|
||||
{
|
||||
if(Settings.Enabled)
|
||||
{
|
||||
m_leapController.SubscribeToDeviceEvents(p_args.Device);
|
||||
UpdateDeviceTrackingMode();
|
||||
}
|
||||
|
||||
Utils.ShowHUDNotification("Leap Motion Extension", "Device initialized");
|
||||
}
|
||||
|
||||
void OnLeapDeviceFailure(object p_sender, Leap.DeviceFailureEventArgs p_args)
|
||||
{
|
||||
Utils.ShowHUDNotification("Leap Motion Extension", "Device failure", "Code " + p_args.ErrorCode + ": " + p_args.ErrorMessage);
|
||||
}
|
||||
|
||||
void OnLeapDeviceLost(object p_sender, Leap.DeviceEventArgs p_args)
|
||||
{
|
||||
m_leapController.UnsubscribeFromDeviceEvents(p_args.Device);
|
||||
|
||||
Utils.ShowHUDNotification("Leap Motion Extension", "Device lost");
|
||||
}
|
||||
|
||||
void OnLeapServiceConnect(object p_sender, Leap.ConnectionEventArgs p_args)
|
||||
{
|
||||
Utils.ShowHUDNotification("Leap Motion Extension", "Service connected");
|
||||
}
|
||||
|
||||
void OnLeapServiceDisconnect(object p_sender, Leap.ConnectionLostEventArgs p_args)
|
||||
{
|
||||
Utils.ShowHUDNotification("Leap Motion Extension", "Service disconnected");
|
||||
}
|
||||
|
||||
// Settings
|
||||
void OnEnableChange(bool p_state)
|
||||
{
|
||||
if(p_state)
|
||||
{
|
||||
m_leapController.StartConnection();
|
||||
UpdateDeviceTrackingMode();
|
||||
}
|
||||
else
|
||||
m_leapController.StopConnection();
|
||||
}
|
||||
|
||||
void OnTrackingModeChange(Settings.LeapTrackingMode p_mode)
|
||||
{
|
||||
if(Settings.Enabled)
|
||||
UpdateDeviceTrackingMode();
|
||||
}
|
||||
|
||||
// Game events
|
||||
internal void OnAvatarClear()
|
||||
{
|
||||
if(m_leapTracking != null)
|
||||
m_leapTracking.OnAvatarClear();
|
||||
if(m_leapTracked != null)
|
||||
m_leapTracked.OnAvatarClear();
|
||||
}
|
||||
|
||||
internal void OnAvatarSetup()
|
||||
{
|
||||
if(m_leapTracking != null)
|
||||
m_leapTracking.OnAvatarSetup();
|
||||
if(m_leapInput != null)
|
||||
m_leapInput.OnAvatarSetup();
|
||||
if(m_leapTracked != null)
|
||||
m_leapTracked.OnAvatarSetup();
|
||||
}
|
||||
|
||||
internal void OnCalibrate()
|
||||
{
|
||||
if(m_leapTracked != null)
|
||||
m_leapTracked.OnCalibrate();
|
||||
}
|
||||
|
||||
internal void OnRayScale(float p_scale)
|
||||
{
|
||||
if(m_leapInput != null)
|
||||
m_leapInput.OnRayScale(p_scale);
|
||||
}
|
||||
|
||||
internal void OnPlayspaceScale(float p_relation)
|
||||
{
|
||||
if(m_leapTracking != null)
|
||||
m_leapTracking.OnPlayspaceScale(p_relation);
|
||||
}
|
||||
|
||||
// Arbitrary
|
||||
void UpdateDeviceTrackingMode()
|
||||
{
|
||||
m_leapController.ClearPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_SCREENTOP, null);
|
||||
m_leapController.ClearPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_HMD, null);
|
||||
|
||||
switch(Settings.TrackingMode)
|
||||
{
|
||||
case Settings.LeapTrackingMode.Screentop:
|
||||
m_leapController.SetPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_SCREENTOP, null);
|
||||
break;
|
||||
case Settings.LeapTrackingMode.HMD:
|
||||
m_leapController.SetPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_HMD, null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Savior;
|
||||
using ABI_RC.Systems.IK;
|
||||
using RootMotion.FinalIK;
|
||||
using System.Reflection;
|
||||
|
@ -11,57 +10,54 @@ namespace ml_lme
|
|||
class LeapTracked : MonoBehaviour
|
||||
{
|
||||
static readonly float[] ms_tposeMuscles = typeof(ABI_RC.Systems.IK.SubSystems.BodySystem).GetField("TPoseMuscles", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null) as float[];
|
||||
static readonly FieldInfo ms_indexGestureToggle = typeof(InputModuleSteamVR).GetField("_steamVrIndexGestureToggleValue", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
static readonly Quaternion ms_offsetLeft = Quaternion.Euler(0f, 0f, 270f);
|
||||
static readonly Quaternion ms_offsetRight = Quaternion.Euler(0f, 0f, 90f);
|
||||
static readonly Quaternion ms_offsetLeftDesktop = Quaternion.Euler(0f, 90f, 0f);
|
||||
static readonly Quaternion ms_offsetRightDesktop = Quaternion.Euler(0f, 270f, 0f);
|
||||
|
||||
InputModuleSteamVR m_steamVrModule = null;
|
||||
VRIK m_vrIK = null;
|
||||
Vector2 m_armsWeights = Vector2.zero;
|
||||
bool m_isInVR = false;
|
||||
Vector4 m_armsWeights = Vector2.zero;
|
||||
bool m_inVR = false;
|
||||
Transform m_hips = null;
|
||||
Transform m_origLeftHand = null;
|
||||
Transform m_origRightHand = null;
|
||||
Transform m_origLeftElbow = null;
|
||||
Transform m_origRightElbow = null;
|
||||
|
||||
bool m_enabled = true;
|
||||
bool m_fingersOnly = false;
|
||||
bool m_trackElbows = true;
|
||||
|
||||
ArmIK m_leftIK = null;
|
||||
ArmIK m_rightIK = null;
|
||||
ArmIK m_leftArmIK = null;
|
||||
ArmIK m_rightArmIK = null;
|
||||
HumanPoseHandler m_poseHandler = null;
|
||||
HumanPose m_pose;
|
||||
Transform m_leftHand = null;
|
||||
Transform m_rightHand = null;
|
||||
Transform m_leftHandTarget = null;
|
||||
Transform m_rightHandTarget = null;
|
||||
Transform m_leftElbow = null;
|
||||
Transform m_rightElbow = null;
|
||||
bool m_leftTargetActive = false;
|
||||
bool m_rightTargetActive = false;
|
||||
|
||||
void Start()
|
||||
{
|
||||
m_steamVrModule = CVRInputManager.Instance.GetComponent<InputModuleSteamVR>();
|
||||
m_isInVR = Utils.IsInVR();
|
||||
m_inVR = Utils.IsInVR();
|
||||
|
||||
if(m_leftHand != null)
|
||||
{
|
||||
m_leftHandTarget = new GameObject("RotationTarget").transform;
|
||||
m_leftHandTarget.parent = m_leftHand;
|
||||
m_leftHandTarget.localPosition = Vector3.zero;
|
||||
m_leftHandTarget.localRotation = Quaternion.identity;
|
||||
}
|
||||
if(m_rightHand != null)
|
||||
{
|
||||
m_rightHandTarget = new GameObject("RotationTarget").transform;
|
||||
m_rightHandTarget.parent = m_rightHand;
|
||||
m_rightHandTarget.localPosition = Vector3.zero;
|
||||
m_rightHandTarget.localRotation = Quaternion.identity;
|
||||
}
|
||||
m_leftHandTarget = new GameObject("RotationTarget").transform;
|
||||
m_leftHandTarget.parent = LeapTracking.GetInstance().GetLeftHand();
|
||||
m_leftHandTarget.localPosition = Vector3.zero;
|
||||
m_leftHandTarget.localRotation = Quaternion.identity;
|
||||
|
||||
m_rightHandTarget = new GameObject("RotationTarget").transform;
|
||||
m_rightHandTarget.parent = LeapTracking.GetInstance().GetRightHand();
|
||||
m_rightHandTarget.localPosition = Vector3.zero;
|
||||
m_rightHandTarget.localRotation = Quaternion.identity;
|
||||
|
||||
Settings.EnabledChange += this.SetEnabled;
|
||||
Settings.FingersOnlyChange += this.SetFingersOnly;
|
||||
Settings.TrackElbowsChange += this.SetTrackElbows;
|
||||
|
||||
SetEnabled(Settings.Enabled);
|
||||
SetFingersOnly(Settings.FingersOnly);
|
||||
SetTrackElbows(Settings.TrackElbows);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
|
@ -71,17 +67,16 @@ namespace ml_lme
|
|||
Settings.TrackElbowsChange -= this.SetTrackElbows;
|
||||
}
|
||||
|
||||
public void SetEnabled(bool p_state)
|
||||
void SetEnabled(bool p_state)
|
||||
{
|
||||
m_enabled = p_state;
|
||||
|
||||
RefreshFingersTracking();
|
||||
RefreshArmIK();
|
||||
if(!m_enabled || m_fingersOnly)
|
||||
RestoreVRIK();
|
||||
}
|
||||
|
||||
public void SetFingersOnly(bool p_state)
|
||||
void SetFingersOnly(bool p_state)
|
||||
{
|
||||
m_fingersOnly = p_state;
|
||||
|
||||
|
@ -90,199 +85,163 @@ namespace ml_lme
|
|||
RestoreVRIK();
|
||||
}
|
||||
|
||||
public void SetTrackElbows(bool p_state)
|
||||
void SetTrackElbows(bool p_state)
|
||||
{
|
||||
m_trackElbows = p_state;
|
||||
|
||||
if((m_leftIK != null) && (m_rightIK != null))
|
||||
if((m_leftArmIK != null) && (m_rightArmIK != null))
|
||||
{
|
||||
m_leftIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
|
||||
m_rightIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
|
||||
m_leftArmIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
|
||||
m_rightArmIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
|
||||
}
|
||||
|
||||
if(m_vrIK != null)
|
||||
{
|
||||
if(m_leftTargetActive)
|
||||
m_vrIK.solver.leftArm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
|
||||
if(m_rightTargetActive)
|
||||
m_vrIK.solver.rightArm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
|
||||
}
|
||||
RestoreVRIK();
|
||||
}
|
||||
|
||||
public void SetTransforms(Transform p_left, Transform p_right, Transform p_leftElbow, Transform p_rightElbow)
|
||||
{
|
||||
m_leftHand = p_left;
|
||||
m_rightHand = p_right;
|
||||
|
||||
m_leftElbow = p_leftElbow;
|
||||
m_rightElbow = p_rightElbow;
|
||||
}
|
||||
|
||||
public void UpdateTracking(GestureMatcher.GesturesData p_data)
|
||||
void Update()
|
||||
{
|
||||
if(m_enabled)
|
||||
{
|
||||
if((m_leftIK != null) && (m_rightIK != null))
|
||||
{
|
||||
m_leftIK.solver.IKPositionWeight = Mathf.Lerp(m_leftIK.solver.IKPositionWeight, (p_data.m_handsPresenses[0] && !m_fingersOnly) ? 1f : 0f, 0.25f);
|
||||
m_leftIK.solver.IKRotationWeight = Mathf.Lerp(m_leftIK.solver.IKRotationWeight, (p_data.m_handsPresenses[0] && !m_fingersOnly) ? 1f : 0f, 0.25f);
|
||||
if(m_trackElbows)
|
||||
m_leftIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_leftIK.solver.arm.bendGoalWeight, (p_data.m_handsPresenses[0] && !m_fingersOnly) ? 1f : 0f, 0.25f);
|
||||
GestureMatcher.LeapData l_data = LeapManager.GetInstance().GetLatestData();
|
||||
|
||||
m_rightIK.solver.IKPositionWeight = Mathf.Lerp(m_rightIK.solver.IKPositionWeight, (p_data.m_handsPresenses[1] && !m_fingersOnly) ? 1f : 0f, 0.25f);
|
||||
m_rightIK.solver.IKRotationWeight = Mathf.Lerp(m_rightIK.solver.IKRotationWeight, (p_data.m_handsPresenses[1] && !m_fingersOnly) ? 1f : 0f, 0.25f);
|
||||
if((m_leftArmIK != null) && (m_rightArmIK != null))
|
||||
{
|
||||
m_leftArmIK.solver.IKPositionWeight = Mathf.Lerp(m_leftArmIK.solver.IKPositionWeight, (l_data.m_leftHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f);
|
||||
m_leftArmIK.solver.IKRotationWeight = Mathf.Lerp(m_leftArmIK.solver.IKRotationWeight, (l_data.m_leftHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f);
|
||||
if(m_trackElbows)
|
||||
m_rightIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_rightIK.solver.arm.bendGoalWeight, (p_data.m_handsPresenses[1] && !m_fingersOnly) ? 1f : 0f, 0.25f);
|
||||
m_leftArmIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_leftArmIK.solver.arm.bendGoalWeight, (l_data.m_leftHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f);
|
||||
|
||||
m_rightArmIK.solver.IKPositionWeight = Mathf.Lerp(m_rightArmIK.solver.IKPositionWeight, (l_data.m_rightHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f);
|
||||
m_rightArmIK.solver.IKRotationWeight = Mathf.Lerp(m_rightArmIK.solver.IKRotationWeight, (l_data.m_rightHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f);
|
||||
if(m_trackElbows)
|
||||
m_rightArmIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_rightArmIK.solver.arm.bendGoalWeight, (l_data.m_rightHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f);
|
||||
}
|
||||
|
||||
if((m_vrIK != null) && !m_fingersOnly)
|
||||
{
|
||||
if(p_data.m_handsPresenses[0] && !m_leftTargetActive)
|
||||
if(l_data.m_leftHand.m_present && !m_leftTargetActive)
|
||||
{
|
||||
m_vrIK.solver.leftArm.target = m_leftHandTarget;
|
||||
m_vrIK.solver.leftArm.bendGoal = m_leftElbow;
|
||||
m_vrIK.solver.leftArm.bendGoal = LeapTracking.GetInstance().GetLeftElbow();
|
||||
m_vrIK.solver.leftArm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
|
||||
m_leftTargetActive = true;
|
||||
}
|
||||
if(!p_data.m_handsPresenses[0] && m_leftTargetActive)
|
||||
if(!l_data.m_leftHand.m_present && m_leftTargetActive)
|
||||
{
|
||||
m_vrIK.solver.leftArm.target = IKSystem.Instance.leftHandAnchor;
|
||||
m_vrIK.solver.leftArm.bendGoal = null;
|
||||
m_vrIK.solver.leftArm.bendGoalWeight = 0f;
|
||||
m_vrIK.solver.leftArm.target = m_origLeftHand;
|
||||
m_vrIK.solver.leftArm.bendGoal = m_origLeftElbow;
|
||||
m_vrIK.solver.leftArm.bendGoalWeight = ((m_origLeftElbow != null) ? 1f : 0f);
|
||||
m_leftTargetActive = false;
|
||||
}
|
||||
|
||||
if(p_data.m_handsPresenses[1] && !m_rightTargetActive)
|
||||
if(l_data.m_rightHand.m_present && !m_rightTargetActive)
|
||||
{
|
||||
m_vrIK.solver.rightArm.target = m_rightHandTarget;
|
||||
m_vrIK.solver.rightArm.bendGoal = m_rightElbow;
|
||||
m_vrIK.solver.rightArm.bendGoal = LeapTracking.GetInstance().GetRightElbow();
|
||||
m_vrIK.solver.rightArm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
|
||||
m_rightTargetActive = true;
|
||||
}
|
||||
if(!p_data.m_handsPresenses[1] && m_rightTargetActive)
|
||||
if(!l_data.m_rightHand.m_present && m_rightTargetActive)
|
||||
{
|
||||
m_vrIK.solver.rightArm.target = IKSystem.Instance.rightHandAnchor;
|
||||
m_vrIK.solver.rightArm.bendGoal = null;
|
||||
m_vrIK.solver.rightArm.bendGoalWeight = 0f;
|
||||
m_vrIK.solver.rightArm.target = m_origRightHand;
|
||||
m_vrIK.solver.rightArm.bendGoal = m_origRightElbow;
|
||||
m_vrIK.solver.rightArm.bendGoalWeight = ((m_origRightElbow != null) ? 1f : 0f);
|
||||
m_rightTargetActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(p_data.m_handsPresenses[0])
|
||||
{
|
||||
CVRInputManager.Instance.individualFingerTracking = true;
|
||||
CVRInputManager.Instance.fingerCurlLeftThumb = p_data.m_leftFingersBends[0];
|
||||
CVRInputManager.Instance.fingerCurlLeftIndex = p_data.m_leftFingersBends[1];
|
||||
CVRInputManager.Instance.fingerCurlLeftMiddle = p_data.m_leftFingersBends[2];
|
||||
CVRInputManager.Instance.fingerCurlLeftRing = p_data.m_leftFingersBends[3];
|
||||
CVRInputManager.Instance.fingerCurlLeftPinky = p_data.m_leftFingersBends[4];
|
||||
|
||||
IKSystem.Instance.FingerSystem.controlActive = true;
|
||||
IKSystem.Instance.FingerSystem.leftThumbCurl = p_data.m_leftFingersBends[0];
|
||||
IKSystem.Instance.FingerSystem.leftIndexCurl = p_data.m_leftFingersBends[1];
|
||||
IKSystem.Instance.FingerSystem.leftMiddleCurl = p_data.m_leftFingersBends[2];
|
||||
IKSystem.Instance.FingerSystem.leftRingCurl = p_data.m_leftFingersBends[3];
|
||||
IKSystem.Instance.FingerSystem.leftPinkyCurl = p_data.m_leftFingersBends[4];
|
||||
}
|
||||
|
||||
if(p_data.m_handsPresenses[1])
|
||||
{
|
||||
CVRInputManager.Instance.individualFingerTracking = true;
|
||||
CVRInputManager.Instance.fingerCurlRightThumb = p_data.m_rightFingersBends[0];
|
||||
CVRInputManager.Instance.fingerCurlRightIndex = p_data.m_rightFingersBends[1];
|
||||
CVRInputManager.Instance.fingerCurlRightMiddle = p_data.m_rightFingersBends[2];
|
||||
CVRInputManager.Instance.fingerCurlRightRing = p_data.m_rightFingersBends[3];
|
||||
CVRInputManager.Instance.fingerCurlRightPinky = p_data.m_rightFingersBends[4];
|
||||
|
||||
IKSystem.Instance.FingerSystem.controlActive = true;
|
||||
IKSystem.Instance.FingerSystem.rightThumbCurl = p_data.m_rightFingersBends[0];
|
||||
IKSystem.Instance.FingerSystem.rightIndexCurl = p_data.m_rightFingersBends[1];
|
||||
IKSystem.Instance.FingerSystem.rightMiddleCurl = p_data.m_rightFingersBends[2];
|
||||
IKSystem.Instance.FingerSystem.rightRingCurl = p_data.m_rightFingersBends[3];
|
||||
IKSystem.Instance.FingerSystem.rightPinkyCurl = p_data.m_rightFingersBends[4];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateTrackingLate(GestureMatcher.GesturesData p_data)
|
||||
void LateUpdate()
|
||||
{
|
||||
if(m_enabled && !m_isInVR && (m_poseHandler != null))
|
||||
if(m_enabled && !m_inVR && (m_poseHandler != null))
|
||||
{
|
||||
GestureMatcher.LeapData l_data = LeapManager.GetInstance().GetLatestData();
|
||||
|
||||
Vector3 l_hipsLocalPos = m_hips.localPosition;
|
||||
|
||||
m_poseHandler.GetHumanPose(ref m_pose);
|
||||
UpdateFingers(p_data);
|
||||
UpdateFingers(l_data);
|
||||
m_poseHandler.SetHumanPose(ref m_pose);
|
||||
|
||||
m_hips.localPosition = l_hipsLocalPos;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateFingers(GestureMatcher.GesturesData p_data)
|
||||
void UpdateFingers(GestureMatcher.LeapData p_data)
|
||||
{
|
||||
if(p_data.m_handsPresenses[0])
|
||||
if(p_data.m_leftHand.m_present)
|
||||
{
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb1Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_leftFingersBends[0]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb2Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_leftFingersBends[0]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb3Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_leftFingersBends[0]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumbSpread, Mathf.Lerp(-1.5f, 1.0f, p_data.m_leftFingersSpreads[0])); // Ok
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb1Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_leftHand.m_bends[0]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb2Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_leftHand.m_bends[0]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumb3Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_leftHand.m_bends[0]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftThumbSpread, Mathf.Lerp(-1.5f, 1.0f, p_data.m_leftHand.m_spreads[0])); // Ok
|
||||
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[1]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[1]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[1]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndexSpread, Mathf.Lerp(1f, -1f, p_data.m_leftFingersSpreads[1])); // Ok
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[1]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[1]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndex3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[1]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftIndexSpread, Mathf.Lerp(1f, -1f, p_data.m_leftHand.m_spreads[1])); // Ok
|
||||
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[2]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[2]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[2]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddleSpread, Mathf.Lerp(2f, -2f, p_data.m_leftFingersSpreads[2]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[2]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[2]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[2]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftMiddleSpread, Mathf.Lerp(2f, -2f, p_data.m_leftHand.m_spreads[2]));
|
||||
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[3]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[3]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[3]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRingSpread, Mathf.Lerp(-2f, 2f, p_data.m_leftFingersSpreads[3]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[3]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[3]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRing3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[3]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftRingSpread, Mathf.Lerp(-2f, 2f, p_data.m_leftHand.m_spreads[3]));
|
||||
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[4]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[4]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftFingersBends[4]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittleSpread, Mathf.Lerp(-0.5f, 1f, p_data.m_leftFingersSpreads[4]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[4]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[4]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_leftHand.m_bends[4]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.LeftLittleSpread, Mathf.Lerp(-0.5f, 1f, p_data.m_leftHand.m_spreads[4]));
|
||||
}
|
||||
|
||||
if(p_data.m_handsPresenses[1])
|
||||
if(p_data.m_rightHand.m_present)
|
||||
{
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb1Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_rightFingersBends[0]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb2Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_rightFingersBends[0]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb3Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_rightFingersBends[0]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumbSpread, Mathf.Lerp(-1.5f, 1.0f, p_data.m_rightFingersSpreads[0])); // Ok
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb1Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_rightHand.m_bends[0]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb2Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_rightHand.m_bends[0]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumb3Stretched, Mathf.Lerp(0.85f, -0.85f, p_data.m_rightHand.m_bends[0]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightThumbSpread, Mathf.Lerp(-1.5f, 1.0f, p_data.m_rightHand.m_spreads[0])); // Ok
|
||||
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[1]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[1]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[1]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndexSpread, Mathf.Lerp(1f, -1f, p_data.m_rightFingersSpreads[1])); // Ok
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[1]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[1]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndex3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[1]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightIndexSpread, Mathf.Lerp(1f, -1f, p_data.m_rightHand.m_spreads[1])); // Ok
|
||||
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[2]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[2]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[2]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddleSpread, Mathf.Lerp(2f, -2f, p_data.m_rightFingersSpreads[2]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[2]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[2]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[2]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightMiddleSpread, Mathf.Lerp(2f, -2f, p_data.m_rightHand.m_spreads[2]));
|
||||
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[3]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[3]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[3]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRingSpread, Mathf.Lerp(-2f, 2f, p_data.m_rightFingersSpreads[3]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[3]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[3]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRing3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[3]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightRingSpread, Mathf.Lerp(-2f, 2f, p_data.m_rightHand.m_spreads[3]));
|
||||
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[4]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[4]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightFingersBends[4]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittleSpread, Mathf.Lerp(-0.5f, 1f, p_data.m_rightFingersSpreads[4]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle1Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[4]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle2Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[4]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittle3Stretched, Mathf.Lerp(0.7f, -1f, p_data.m_rightHand.m_bends[4]));
|
||||
UpdatePoseMuscle(ref m_pose, (int)MuscleIndex.RightLittleSpread, Mathf.Lerp(-0.5f, 1f, p_data.m_rightHand.m_spreads[4]));
|
||||
}
|
||||
}
|
||||
|
||||
public void OnAvatarClear()
|
||||
internal void OnAvatarClear()
|
||||
{
|
||||
m_vrIK = null;
|
||||
m_origLeftHand = null;
|
||||
m_origRightHand = null;
|
||||
m_origLeftElbow = null;
|
||||
m_origRightElbow = null;
|
||||
m_hips = null;
|
||||
m_armsWeights = Vector2.zero;
|
||||
m_leftIK = null;
|
||||
m_rightIK = null;
|
||||
m_leftArmIK = null;
|
||||
m_rightArmIK = null;
|
||||
m_leftTargetActive = false;
|
||||
m_rightTargetActive = false;
|
||||
|
||||
if(!m_isInVR)
|
||||
if(!m_inVR)
|
||||
m_poseHandler?.Dispose();
|
||||
m_poseHandler = null;
|
||||
|
||||
|
@ -292,24 +251,27 @@ namespace ml_lme
|
|||
m_rightHandTarget.localRotation = Quaternion.identity;
|
||||
}
|
||||
|
||||
public void OnSetupAvatar()
|
||||
internal void OnAvatarSetup()
|
||||
{
|
||||
m_inVR = Utils.IsInVR();
|
||||
m_vrIK = PlayerSetup.Instance._animator.GetComponent<VRIK>();
|
||||
|
||||
RefreshFingersTracking();
|
||||
|
||||
if(PlayerSetup.Instance._animator.isHuman)
|
||||
{
|
||||
if(!m_isInVR)
|
||||
m_hips = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Hips);
|
||||
|
||||
if(!m_inVR)
|
||||
{
|
||||
// Force desktop avatar into T-Pose
|
||||
m_poseHandler = new HumanPoseHandler(PlayerSetup.Instance._animator.avatar, PlayerSetup.Instance._avatar.transform);
|
||||
m_poseHandler.GetHumanPose(ref m_pose);
|
||||
|
||||
HumanPose l_tPose = new HumanPose();
|
||||
l_tPose.bodyPosition = m_pose.bodyPosition;
|
||||
l_tPose.bodyRotation = m_pose.bodyRotation;
|
||||
l_tPose.muscles = new float[m_pose.muscles.Length];
|
||||
HumanPose l_tPose = new HumanPose
|
||||
{
|
||||
bodyPosition = m_pose.bodyPosition,
|
||||
bodyRotation = m_pose.bodyRotation,
|
||||
muscles = new float[m_pose.muscles.Length]
|
||||
};
|
||||
for(int i = 0; i < l_tPose.muscles.Length; i++)
|
||||
l_tPose.muscles[i] = ms_tposeMuscles[i];
|
||||
m_poseHandler.SetHumanPose(ref l_tPose);
|
||||
|
@ -317,11 +279,11 @@ namespace ml_lme
|
|||
|
||||
Transform l_hand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand);
|
||||
if(l_hand != null)
|
||||
m_leftHandTarget.localRotation = ((m_vrIK != null) ? ms_offsetLeft : ms_offsetLeftDesktop) * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_hand.GetMatrix()).rotation;
|
||||
m_leftHandTarget.localRotation = (m_inVR ? ms_offsetLeft : ms_offsetLeftDesktop) * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_hand.GetMatrix()).rotation;
|
||||
|
||||
l_hand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand);
|
||||
if(l_hand != null)
|
||||
m_rightHandTarget.localRotation = ((m_vrIK != null) ? ms_offsetRight : ms_offsetRightDesktop) * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_hand.GetMatrix()).rotation;
|
||||
m_rightHandTarget.localRotation = (m_inVR ? ms_offsetRight : ms_offsetRightDesktop) * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_hand.GetMatrix()).rotation;
|
||||
|
||||
if(m_vrIK == null)
|
||||
{
|
||||
|
@ -331,9 +293,9 @@ namespace ml_lme
|
|||
if(l_chest == null)
|
||||
l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Spine);
|
||||
|
||||
m_leftIK = PlayerSetup.Instance._avatar.AddComponent<ArmIK>();
|
||||
m_leftIK.solver.isLeft = true;
|
||||
m_leftIK.solver.SetChain(
|
||||
m_leftArmIK = PlayerSetup.Instance._avatar.AddComponent<ArmIK>();
|
||||
m_leftArmIK.solver.isLeft = true;
|
||||
m_leftArmIK.solver.SetChain(
|
||||
l_chest,
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftShoulder),
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftUpperArm),
|
||||
|
@ -341,14 +303,14 @@ namespace ml_lme
|
|||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand),
|
||||
PlayerSetup.Instance._animator.transform
|
||||
);
|
||||
m_leftIK.solver.arm.target = m_leftHandTarget;
|
||||
m_leftIK.solver.arm.bendGoal = m_leftElbow;
|
||||
m_leftIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
|
||||
m_leftIK.enabled = (m_enabled && !m_fingersOnly);
|
||||
m_leftArmIK.solver.arm.target = m_leftHandTarget;
|
||||
m_leftArmIK.solver.arm.bendGoal = LeapTracking.GetInstance().GetLeftElbow();
|
||||
m_leftArmIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
|
||||
m_leftArmIK.enabled = (m_enabled && !m_fingersOnly);
|
||||
|
||||
m_rightIK = PlayerSetup.Instance._avatar.AddComponent<ArmIK>();
|
||||
m_rightIK.solver.isLeft = false;
|
||||
m_rightIK.solver.SetChain(
|
||||
m_rightArmIK = PlayerSetup.Instance._avatar.AddComponent<ArmIK>();
|
||||
m_rightArmIK.solver.isLeft = false;
|
||||
m_rightArmIK.solver.SetChain(
|
||||
l_chest,
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightShoulder),
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightUpperArm),
|
||||
|
@ -356,31 +318,51 @@ namespace ml_lme
|
|||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand),
|
||||
PlayerSetup.Instance._animator.transform
|
||||
);
|
||||
m_rightIK.solver.arm.target = m_rightHandTarget;
|
||||
m_rightIK.solver.arm.bendGoal = m_rightElbow;
|
||||
m_rightIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
|
||||
m_rightIK.enabled = (m_enabled && !m_fingersOnly);
|
||||
m_rightArmIK.solver.arm.target = m_rightHandTarget;
|
||||
m_rightArmIK.solver.arm.bendGoal = LeapTracking.GetInstance().GetRightElbow();
|
||||
m_rightArmIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
|
||||
m_rightArmIK.enabled = (m_enabled && !m_fingersOnly);
|
||||
|
||||
m_poseHandler?.SetHumanPose(ref m_pose);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_origLeftHand = m_vrIK.solver.leftArm.target;
|
||||
m_origRightHand = m_vrIK.solver.rightArm.target;
|
||||
m_origLeftElbow = m_vrIK.solver.leftArm.bendGoal;
|
||||
m_origRightElbow = m_vrIK.solver.rightArm.bendGoal;
|
||||
m_vrIK.solver.OnPreUpdate += this.OnIKPreUpdate;
|
||||
m_vrIK.solver.OnPostUpdate += this.OnIKPostUpdate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnCalibrate()
|
||||
{
|
||||
if(m_vrIK != null)
|
||||
{
|
||||
m_origLeftHand = m_vrIK.solver.leftArm.target;
|
||||
m_origRightHand = m_vrIK.solver.rightArm.target;
|
||||
m_origLeftElbow = m_vrIK.solver.leftArm.bendGoal;
|
||||
m_origRightElbow = m_vrIK.solver.rightArm.bendGoal;
|
||||
}
|
||||
}
|
||||
|
||||
void OnIKPreUpdate()
|
||||
{
|
||||
m_armsWeights.Set(m_vrIK.solver.leftArm.positionWeight, m_vrIK.solver.rightArm.positionWeight);
|
||||
m_armsWeights.Set(
|
||||
m_vrIK.solver.leftArm.positionWeight,
|
||||
m_vrIK.solver.leftArm.rotationWeight,
|
||||
m_vrIK.solver.rightArm.positionWeight,
|
||||
m_vrIK.solver.rightArm.rotationWeight
|
||||
);
|
||||
|
||||
if(m_leftTargetActive && Mathf.Approximately(m_armsWeights.x, 0f))
|
||||
if(m_leftTargetActive && (Mathf.Approximately(m_armsWeights.x, 0f) || Mathf.Approximately(m_armsWeights.y, 0f)))
|
||||
{
|
||||
m_vrIK.solver.leftArm.positionWeight = 1f;
|
||||
m_vrIK.solver.leftArm.rotationWeight = 1f;
|
||||
}
|
||||
if(m_rightTargetActive && Mathf.Approximately(m_armsWeights.y, 0f))
|
||||
if(m_rightTargetActive && (Mathf.Approximately(m_armsWeights.z, 0f) || Mathf.Approximately(m_armsWeights.w, 0f)))
|
||||
{
|
||||
m_vrIK.solver.rightArm.positionWeight = 1f;
|
||||
m_vrIK.solver.rightArm.rotationWeight = 1f;
|
||||
|
@ -389,10 +371,9 @@ namespace ml_lme
|
|||
void OnIKPostUpdate()
|
||||
{
|
||||
m_vrIK.solver.leftArm.positionWeight = m_armsWeights.x;
|
||||
m_vrIK.solver.leftArm.rotationWeight = m_armsWeights.x;
|
||||
|
||||
m_vrIK.solver.rightArm.positionWeight = m_armsWeights.y;
|
||||
m_vrIK.solver.rightArm.rotationWeight = m_armsWeights.y;
|
||||
m_vrIK.solver.leftArm.rotationWeight = m_armsWeights.y;
|
||||
m_vrIK.solver.rightArm.positionWeight = m_armsWeights.z;
|
||||
m_vrIK.solver.rightArm.rotationWeight = m_armsWeights.w;
|
||||
}
|
||||
|
||||
void RestoreVRIK()
|
||||
|
@ -401,16 +382,16 @@ namespace ml_lme
|
|||
{
|
||||
if(m_leftTargetActive)
|
||||
{
|
||||
m_vrIK.solver.leftArm.target = IKSystem.Instance.leftHandAnchor;
|
||||
m_vrIK.solver.leftArm.bendGoal = null;
|
||||
m_vrIK.solver.leftArm.bendGoalWeight = 0f;
|
||||
m_vrIK.solver.leftArm.target = m_origLeftHand;
|
||||
m_vrIK.solver.leftArm.bendGoal = m_origLeftElbow;
|
||||
m_vrIK.solver.leftArm.bendGoalWeight = ((m_origLeftElbow != null) ? 1f : 0f);
|
||||
m_leftTargetActive = false;
|
||||
}
|
||||
if(m_rightTargetActive)
|
||||
{
|
||||
m_vrIK.solver.rightArm.target = IKSystem.Instance.rightHandAnchor;
|
||||
m_vrIK.solver.rightArm.bendGoal = null;
|
||||
m_vrIK.solver.rightArm.bendGoalWeight = 0f;
|
||||
m_vrIK.solver.rightArm.target = m_origRightHand;
|
||||
m_vrIK.solver.rightArm.bendGoal = m_origRightElbow;
|
||||
m_vrIK.solver.rightArm.bendGoalWeight = ((m_origRightElbow != null) ? 1f : 0f);
|
||||
m_rightTargetActive = false;
|
||||
}
|
||||
}
|
||||
|
@ -418,19 +399,13 @@ namespace ml_lme
|
|||
|
||||
void RefreshArmIK()
|
||||
{
|
||||
if((m_leftIK != null) && (m_rightIK != null))
|
||||
if((m_leftArmIK != null) && (m_rightArmIK != null))
|
||||
{
|
||||
m_leftIK.enabled = (m_enabled && !m_fingersOnly);
|
||||
m_rightIK.enabled = (m_enabled && !m_fingersOnly);
|
||||
m_leftArmIK.enabled = (m_enabled && !m_fingersOnly);
|
||||
m_rightArmIK.enabled = (m_enabled && !m_fingersOnly);
|
||||
}
|
||||
}
|
||||
|
||||
void RefreshFingersTracking()
|
||||
{
|
||||
CVRInputManager.Instance.individualFingerTracking = (m_enabled || (m_isInVR && Utils.AreKnucklesInUse() && !(bool)ms_indexGestureToggle.GetValue(m_steamVrModule)));
|
||||
IKSystem.Instance.FingerSystem.controlActive = CVRInputManager.Instance.individualFingerTracking;
|
||||
}
|
||||
|
||||
static void UpdatePoseMuscle(ref HumanPose p_pose, int p_index, float p_value)
|
||||
{
|
||||
if(p_pose.muscles.Length > p_index)
|
||||
|
|
204
ml_lme/LeapTracking.cs
Normal file
204
ml_lme/LeapTracking.cs
Normal file
|
@ -0,0 +1,204 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_lme
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
class LeapTracking : MonoBehaviour
|
||||
{
|
||||
static LeapTracking ms_instance = null;
|
||||
static Quaternion ms_identityRotation = Quaternion.identity;
|
||||
|
||||
bool m_inVR = false;
|
||||
|
||||
GameObject m_leapHandLeft = null;
|
||||
GameObject m_leapHandRight = null;
|
||||
GameObject m_leapElbowLeft = null;
|
||||
GameObject m_leapElbowRight = null;
|
||||
GameObject m_leapControllerModel = null;
|
||||
|
||||
float m_scaleRelation = 1f;
|
||||
|
||||
public static LeapTracking GetInstance() => ms_instance;
|
||||
|
||||
void Start()
|
||||
{
|
||||
if(ms_instance == null)
|
||||
ms_instance = this;
|
||||
|
||||
m_inVR = Utils.IsInVR();
|
||||
|
||||
m_leapHandLeft = new GameObject("LeapHandLeft");
|
||||
m_leapHandLeft.transform.parent = this.transform;
|
||||
m_leapHandLeft.transform.localPosition = Vector3.zero;
|
||||
m_leapHandLeft.transform.localRotation = Quaternion.identity;
|
||||
|
||||
m_leapHandRight = new GameObject("LeapHandRight");
|
||||
m_leapHandRight.transform.parent = this.transform;
|
||||
m_leapHandRight.transform.localPosition = Vector3.zero;
|
||||
m_leapHandRight.transform.localRotation = Quaternion.identity;
|
||||
|
||||
m_leapElbowLeft = new GameObject("LeapElbowLeft");
|
||||
m_leapElbowLeft.transform.parent = this.transform;
|
||||
m_leapElbowLeft.transform.localPosition = Vector3.zero;
|
||||
m_leapElbowLeft.transform.localRotation = Quaternion.identity;
|
||||
|
||||
m_leapElbowRight = new GameObject("LeapElbowRight");
|
||||
m_leapElbowRight.transform.parent = this.transform;
|
||||
m_leapElbowRight.transform.localPosition = Vector3.zero;
|
||||
m_leapElbowRight.transform.localRotation = Quaternion.identity;
|
||||
|
||||
m_leapControllerModel = AssetsHandler.GetAsset("assets/models/leapmotion/leap_motion_1_0.obj");
|
||||
if(m_leapControllerModel != null)
|
||||
{
|
||||
m_leapControllerModel.name = "LeapModel";
|
||||
m_leapControllerModel.transform.parent = this.transform;
|
||||
m_leapControllerModel.transform.localPosition = Vector3.zero;
|
||||
m_leapControllerModel.transform.localRotation = Quaternion.identity;
|
||||
}
|
||||
|
||||
Settings.DesktopOffsetChange += this.OnDesktopOffsetChange;
|
||||
Settings.ModelVisibilityChange += this.OnModelVisibilityChange;
|
||||
Settings.TrackingModeChange += this.OnTrackingModeChange;
|
||||
Settings.RootAngleChange += this.OnRootAngleChange;
|
||||
Settings.HeadAttachChange += this.OnHeadAttachChange;
|
||||
Settings.HeadOffsetChange += this.OnHeadOffsetChange;
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
|
||||
|
||||
OnModelVisibilityChange(Settings.ModelVisibility);
|
||||
OnTrackingModeChange(Settings.TrackingMode);
|
||||
OnRootAngleChange(Settings.RootAngle);
|
||||
}
|
||||
|
||||
IEnumerator WaitForLocalPlayer()
|
||||
{
|
||||
while(PlayerSetup.Instance == null)
|
||||
yield return null;
|
||||
|
||||
OnHeadAttachChange(Settings.HeadAttach);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
Settings.DesktopOffsetChange -= this.OnDesktopOffsetChange;
|
||||
Settings.ModelVisibilityChange -= this.OnModelVisibilityChange;
|
||||
Settings.TrackingModeChange -= this.OnTrackingModeChange;
|
||||
Settings.RootAngleChange -= this.OnRootAngleChange;
|
||||
Settings.HeadAttachChange -= this.OnHeadAttachChange;
|
||||
Settings.HeadOffsetChange -= this.OnHeadOffsetChange;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if(Settings.Enabled)
|
||||
{
|
||||
GestureMatcher.LeapData l_data = LeapManager.GetInstance().GetLatestData();
|
||||
|
||||
if(l_data.m_leftHand.m_present)
|
||||
{
|
||||
Utils.LeapToUnity(ref l_data.m_leftHand.m_position, ref l_data.m_leftHand.m_rotation, Settings.TrackingMode);
|
||||
m_leapHandLeft.transform.localPosition = l_data.m_leftHand.m_position;
|
||||
m_leapHandLeft.transform.localRotation = l_data.m_leftHand.m_rotation;
|
||||
|
||||
Utils.LeapToUnity(ref l_data.m_leftHand.m_elbowPosition, ref ms_identityRotation, Settings.TrackingMode);
|
||||
m_leapElbowLeft.transform.localPosition = l_data.m_leftHand.m_elbowPosition;
|
||||
}
|
||||
|
||||
if(l_data.m_rightHand.m_present)
|
||||
{
|
||||
Utils.LeapToUnity(ref l_data.m_rightHand.m_position, ref l_data.m_rightHand.m_rotation, Settings.TrackingMode);
|
||||
m_leapHandRight.transform.localPosition = l_data.m_rightHand.m_position;
|
||||
m_leapHandRight.transform.localRotation = l_data.m_rightHand.m_rotation;
|
||||
|
||||
Utils.LeapToUnity(ref l_data.m_rightHand.m_elbowPosition, ref ms_identityRotation, Settings.TrackingMode);
|
||||
m_leapElbowRight.transform.localPosition = l_data.m_rightHand.m_elbowPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Transform GetLeftHand() => m_leapHandLeft.transform;
|
||||
public Transform GetRightHand() => m_leapHandRight.transform;
|
||||
public Transform GetLeftElbow() => m_leapElbowLeft.transform;
|
||||
public Transform GetRightElbow() => m_leapElbowRight.transform;
|
||||
|
||||
// Settings
|
||||
void OnDesktopOffsetChange(Vector3 p_offset)
|
||||
{
|
||||
if(!Settings.HeadAttach)
|
||||
this.transform.localPosition = p_offset * (!m_inVR ? m_scaleRelation : 1f);
|
||||
}
|
||||
|
||||
void OnModelVisibilityChange(bool p_state)
|
||||
{
|
||||
m_leapControllerModel.SetActive(p_state);
|
||||
}
|
||||
|
||||
void OnTrackingModeChange(Settings.LeapTrackingMode p_mode)
|
||||
{
|
||||
switch(p_mode)
|
||||
{
|
||||
case Settings.LeapTrackingMode.Screentop:
|
||||
m_leapControllerModel.transform.localRotation = Quaternion.Euler(0f, 0f, 180f);
|
||||
break;
|
||||
case Settings.LeapTrackingMode.Desktop:
|
||||
m_leapControllerModel.transform.localRotation = Quaternion.identity;
|
||||
break;
|
||||
case Settings.LeapTrackingMode.HMD:
|
||||
m_leapControllerModel.transform.localRotation = Quaternion.Euler(270f, 180f, 0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnRootAngleChange(Vector3 p_angle)
|
||||
{
|
||||
this.transform.localRotation = Quaternion.Euler(p_angle);
|
||||
}
|
||||
|
||||
void OnHeadAttachChange(bool p_state)
|
||||
{
|
||||
if(!m_inVR)
|
||||
{
|
||||
this.transform.parent = (p_state ? PlayerSetup.Instance.desktopCamera.transform : PlayerSetup.Instance.desktopCameraRig.transform);
|
||||
this.transform.localPosition = (p_state ? Settings.HeadOffset : Settings.DesktopOffset) * m_scaleRelation;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.transform.parent = (p_state ? PlayerSetup.Instance.vrCamera.transform : PlayerSetup.Instance.vrCameraRig.transform);
|
||||
this.transform.localPosition = (p_state ? Settings.HeadOffset : Settings.DesktopOffset);
|
||||
}
|
||||
|
||||
this.transform.localScale = Vector3.one * (!m_inVR ? m_scaleRelation : 1f);
|
||||
this.transform.localRotation = Quaternion.Euler(Settings.RootAngle);
|
||||
}
|
||||
|
||||
void OnHeadOffsetChange(Vector3 p_offset)
|
||||
{
|
||||
if(Settings.HeadAttach)
|
||||
this.transform.localPosition = p_offset * (!m_inVR ? m_scaleRelation : 1f);
|
||||
}
|
||||
|
||||
// Game events
|
||||
internal void OnAvatarClear()
|
||||
{
|
||||
m_scaleRelation = 1f;
|
||||
OnHeadAttachChange(Settings.HeadAttach);
|
||||
}
|
||||
|
||||
internal void OnAvatarSetup()
|
||||
{
|
||||
m_inVR = Utils.IsInVR();
|
||||
OnHeadAttachChange(Settings.HeadAttach);
|
||||
}
|
||||
|
||||
internal void OnPlayspaceScale(float p_relation)
|
||||
{
|
||||
m_scaleRelation = p_relation;
|
||||
OnHeadAttachChange(Settings.HeadAttach);
|
||||
}
|
||||
}
|
||||
}
|
367
ml_lme/Main.cs
367
ml_lme/Main.cs
|
@ -1,5 +1,6 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.UI;
|
||||
using ABI_RC.Systems.IK.SubSystems;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
|
@ -10,16 +11,7 @@ namespace ml_lme
|
|||
{
|
||||
static LeapMotionExtension ms_instance = null;
|
||||
|
||||
Leap.Controller m_leapController = null;
|
||||
GestureMatcher.GesturesData m_gesturesData = null;
|
||||
|
||||
GameObject m_leapTrackingRoot = null;
|
||||
GameObject[] m_leapHands = null;
|
||||
GameObject[] m_leapElbows = null;
|
||||
GameObject m_leapControllerModel = null;
|
||||
LeapTracked m_leapTracked = null;
|
||||
|
||||
bool m_isInVR = false;
|
||||
LeapManager m_leapManager = null;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
|
@ -27,26 +19,8 @@ namespace ml_lme
|
|||
ms_instance = this;
|
||||
|
||||
DependenciesHandler.ExtractDependencies();
|
||||
|
||||
Settings.Init();
|
||||
Settings.EnabledChange += this.OnEnableChange;
|
||||
Settings.DesktopOffsetChange += this.OnDesktopOffsetChange;
|
||||
Settings.ModelVisibilityChange += this.OnModelVisibilityChange;
|
||||
Settings.TrackingModeChange += this.OnTrackingModeChange;
|
||||
Settings.RootAngleChange += this.OnRootAngleChange;
|
||||
Settings.HeadAttachChange += this.OnHeadAttachChange;
|
||||
Settings.HeadOffsetChange += this.OnHeadOffsetChange;
|
||||
|
||||
m_leapController = new Leap.Controller();
|
||||
m_leapController.Device += this.OnLeapDeviceInitialized;
|
||||
m_leapController.DeviceFailure += this.OnLeapDeviceFailure;
|
||||
m_leapController.DeviceLost += this.OnLeapDeviceLost;
|
||||
m_leapController.Connect += this.OnLeapServiceConnect;
|
||||
m_leapController.Disconnect += this.OnLeapServiceDisconnect;
|
||||
|
||||
m_gesturesData = new GestureMatcher.GesturesData();
|
||||
m_leapHands = new GameObject[GestureMatcher.GesturesData.ms_handsCount];
|
||||
m_leapElbows = new GameObject[GestureMatcher.GesturesData.ms_handsCount];
|
||||
AssetsHandler.Load();
|
||||
|
||||
// Patches
|
||||
HarmonyInstance.Patch(
|
||||
|
@ -59,280 +33,37 @@ namespace ml_lme
|
|||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(BodySystem).GetMethod(nameof(BodySystem.Calibrate)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnCalibrate_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetControllerRayScale)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnRayScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod("SetPlaySpaceScale", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnPlayspaceScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(CreateTrackingObjects());
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator CreateTrackingObjects()
|
||||
{
|
||||
AssetsHandler.Load();
|
||||
|
||||
while(PlayerSetup.Instance == null)
|
||||
yield return null;
|
||||
while(PlayerSetup.Instance.desktopCameraRig == null)
|
||||
yield return null;
|
||||
while(PlayerSetup.Instance.desktopCamera == null)
|
||||
yield return null;
|
||||
while(PlayerSetup.Instance.vrCameraRig == null)
|
||||
yield return null;
|
||||
while(PlayerSetup.Instance.vrCamera == null)
|
||||
yield return null;
|
||||
|
||||
m_isInVR = Utils.IsInVR();
|
||||
|
||||
m_leapTrackingRoot = new GameObject("[LeapRoot]");
|
||||
|
||||
for(int i = 0; i < GestureMatcher.GesturesData.ms_handsCount; i++)
|
||||
{
|
||||
m_leapHands[i] = new GameObject("LeapHand" + i);
|
||||
m_leapHands[i].transform.parent = m_leapTrackingRoot.transform;
|
||||
m_leapHands[i].transform.localPosition = Vector3.zero;
|
||||
m_leapHands[i].transform.localRotation = Quaternion.identity;
|
||||
|
||||
m_leapElbows[i] = new GameObject("LeapElbow" + i);
|
||||
m_leapElbows[i].transform.parent = m_leapTrackingRoot.transform;
|
||||
m_leapElbows[i].transform.localPosition = Vector3.zero;
|
||||
m_leapElbows[i].transform.localRotation = Quaternion.identity;
|
||||
}
|
||||
|
||||
m_leapControllerModel = AssetsHandler.GetAsset("assets/models/leapmotion/leap_motion_1_0.obj");
|
||||
if(m_leapControllerModel != null)
|
||||
{
|
||||
m_leapControllerModel.name = "LeapModel";
|
||||
m_leapControllerModel.transform.parent = m_leapTrackingRoot.transform;
|
||||
m_leapControllerModel.transform.localPosition = Vector3.zero;
|
||||
m_leapControllerModel.transform.localRotation = Quaternion.identity;
|
||||
}
|
||||
|
||||
// Player setup
|
||||
m_leapTracked = PlayerSetup.Instance.gameObject.AddComponent<LeapTracked>();
|
||||
m_leapTracked.SetTransforms(m_leapHands[0].transform, m_leapHands[1].transform, m_leapElbows[0].transform, m_leapElbows[1].transform);
|
||||
m_leapTracked.SetEnabled(Settings.Enabled);
|
||||
m_leapTracked.SetTrackElbows(Settings.TrackElbows);
|
||||
m_leapTracked.SetFingersOnly(Settings.FingersOnly);
|
||||
|
||||
OnEnableChange(Settings.Enabled);
|
||||
OnModelVisibilityChange(Settings.ModelVisibility);
|
||||
OnTrackingModeChange(Settings.TrackingMode);
|
||||
OnHeadAttachChange(Settings.HeadAttach); // Includes offsets and parenting
|
||||
MelonLoader.MelonCoroutines.Start(WaitForRootLogic());
|
||||
}
|
||||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
m_leapController?.StopConnection();
|
||||
m_leapController?.Dispose();
|
||||
m_leapController = null;
|
||||
|
||||
m_gesturesData = null;
|
||||
}
|
||||
|
||||
public override void OnUpdate()
|
||||
IEnumerator WaitForRootLogic()
|
||||
{
|
||||
if(Settings.Enabled)
|
||||
{
|
||||
for(int i = 0; i < GestureMatcher.GesturesData.ms_handsCount; i++)
|
||||
m_gesturesData.m_handsPresenses[i] = false;
|
||||
while(ABI_RC.Core.RootLogic.Instance == null)
|
||||
yield return null;
|
||||
|
||||
if((m_leapController != null) && m_leapController.IsConnected)
|
||||
{
|
||||
Leap.Frame l_frame = m_leapController.Frame();
|
||||
if(l_frame != null)
|
||||
{
|
||||
GestureMatcher.GetGestures(l_frame, ref m_gesturesData);
|
||||
|
||||
for(int i = 0; i < GestureMatcher.GesturesData.ms_handsCount; i++)
|
||||
{
|
||||
if((m_leapHands[i] != null) && m_gesturesData.m_handsPresenses[i])
|
||||
{
|
||||
Vector3 l_pos = m_gesturesData.m_handsPositons[i];
|
||||
Quaternion l_rot = m_gesturesData.m_handsRotations[i];
|
||||
Utils.LeapToUnity(ref l_pos, ref l_rot, Settings.TrackingMode);
|
||||
m_leapHands[i].transform.localPosition = l_pos;
|
||||
m_leapHands[i].transform.localRotation = l_rot;
|
||||
|
||||
l_pos = m_gesturesData.m_elbowsPositions[i];
|
||||
Utils.LeapToUnity(ref l_pos, ref l_rot, Settings.TrackingMode);
|
||||
m_leapElbows[i].transform.localPosition = l_pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(m_leapTracked != null)
|
||||
m_leapTracked.UpdateTracking(m_gesturesData);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnLateUpdate()
|
||||
{
|
||||
if(Settings.Enabled && !m_isInVR && (m_leapTracked != null))
|
||||
m_leapTracked.UpdateTrackingLate(m_gesturesData);
|
||||
}
|
||||
|
||||
// Settings changes
|
||||
void OnEnableChange(bool p_state)
|
||||
{
|
||||
if(p_state)
|
||||
{
|
||||
m_leapController?.StartConnection();
|
||||
UpdateDeviceTrackingMode();
|
||||
}
|
||||
else
|
||||
m_leapController?.StopConnection();
|
||||
}
|
||||
|
||||
void OnDesktopOffsetChange(Vector3 p_offset)
|
||||
{
|
||||
if((m_leapTrackingRoot != null) && !Settings.HeadAttach)
|
||||
{
|
||||
if(!m_isInVR)
|
||||
m_leapTrackingRoot.transform.localPosition = p_offset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x;
|
||||
else
|
||||
m_leapTrackingRoot.transform.localPosition = p_offset;
|
||||
}
|
||||
}
|
||||
|
||||
void OnModelVisibilityChange(bool p_state)
|
||||
{
|
||||
if(m_leapControllerModel != null)
|
||||
m_leapControllerModel.SetActive(p_state);
|
||||
}
|
||||
|
||||
void OnTrackingModeChange(Settings.LeapTrackingMode p_mode)
|
||||
{
|
||||
if(Settings.Enabled)
|
||||
UpdateDeviceTrackingMode();
|
||||
|
||||
if(m_leapControllerModel != null)
|
||||
{
|
||||
switch(p_mode)
|
||||
{
|
||||
case Settings.LeapTrackingMode.Screentop:
|
||||
m_leapControllerModel.transform.localRotation = Quaternion.Euler(0f, 0f, 180f);
|
||||
break;
|
||||
case Settings.LeapTrackingMode.Desktop:
|
||||
m_leapControllerModel.transform.localRotation = Quaternion.identity;
|
||||
break;
|
||||
case Settings.LeapTrackingMode.HMD:
|
||||
m_leapControllerModel.transform.localRotation = Quaternion.Euler(270f, 180f, 0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnRootAngleChange(Vector3 p_angle)
|
||||
{
|
||||
if(m_leapTrackingRoot != null)
|
||||
m_leapTrackingRoot.transform.localRotation = Quaternion.Euler(p_angle);
|
||||
}
|
||||
|
||||
void OnHeadAttachChange(bool p_state)
|
||||
{
|
||||
if(m_leapTrackingRoot != null)
|
||||
{
|
||||
if(p_state)
|
||||
{
|
||||
if(!m_isInVR)
|
||||
{
|
||||
m_leapTrackingRoot.transform.parent = PlayerSetup.Instance.desktopCamera.transform;
|
||||
m_leapTrackingRoot.transform.localPosition = Settings.HeadOffset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x;
|
||||
m_leapTrackingRoot.transform.localScale = PlayerSetup.Instance.vrCameraRig.transform.localScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_leapTrackingRoot.transform.parent = PlayerSetup.Instance.vrCamera.transform;
|
||||
m_leapTrackingRoot.transform.localPosition = Settings.HeadOffset;
|
||||
m_leapTrackingRoot.transform.localScale = Vector3.one;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!m_isInVR)
|
||||
{
|
||||
m_leapTrackingRoot.transform.parent = PlayerSetup.Instance.desktopCameraRig.transform;
|
||||
m_leapTrackingRoot.transform.localPosition = Settings.DesktopOffset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x;
|
||||
m_leapTrackingRoot.transform.localScale = PlayerSetup.Instance.vrCameraRig.transform.localScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_leapTrackingRoot.transform.parent = PlayerSetup.Instance.vrCameraRig.transform;
|
||||
m_leapTrackingRoot.transform.localPosition = Settings.DesktopOffset;
|
||||
m_leapTrackingRoot.transform.localScale = Vector3.one;
|
||||
}
|
||||
}
|
||||
|
||||
m_leapTrackingRoot.transform.localRotation = Quaternion.Euler(Settings.RootAngle);
|
||||
}
|
||||
}
|
||||
|
||||
void OnHeadOffsetChange(Vector3 p_offset)
|
||||
{
|
||||
if((m_leapTrackingRoot != null) && Settings.HeadAttach)
|
||||
{
|
||||
if(!m_isInVR)
|
||||
m_leapTrackingRoot.transform.localPosition = p_offset * PlayerSetup.Instance.vrCameraRig.transform.localScale.x;
|
||||
else
|
||||
m_leapTrackingRoot.transform.localPosition = p_offset;
|
||||
}
|
||||
}
|
||||
|
||||
// Internal utility
|
||||
void UpdateDeviceTrackingMode()
|
||||
{
|
||||
m_leapController?.ClearPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_SCREENTOP, null);
|
||||
m_leapController?.ClearPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_HMD, null);
|
||||
|
||||
switch(Settings.TrackingMode)
|
||||
{
|
||||
case Settings.LeapTrackingMode.Screentop:
|
||||
m_leapController?.SetPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_SCREENTOP, null);
|
||||
break;
|
||||
case Settings.LeapTrackingMode.HMD:
|
||||
m_leapController?.SetPolicy(Leap.Controller.PolicyFlag.POLICY_OPTIMIZE_HMD, null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Leap events
|
||||
void OnLeapDeviceInitialized(object p_sender, Leap.DeviceEventArgs p_args)
|
||||
{
|
||||
if(Settings.Enabled)
|
||||
{
|
||||
m_leapController?.SubscribeToDeviceEvents(p_args.Device);
|
||||
UpdateDeviceTrackingMode();
|
||||
}
|
||||
|
||||
if(CohtmlHud.Instance != null)
|
||||
CohtmlHud.Instance.ViewDropText("Leap Motion Extension", "Device initialized");
|
||||
}
|
||||
|
||||
void OnLeapDeviceFailure(object p_sender, Leap.DeviceFailureEventArgs p_args)
|
||||
{
|
||||
if(CohtmlHud.Instance != null)
|
||||
CohtmlHud.Instance.ViewDropText("Leap Motion Extension", "Device failure, code " + p_args.ErrorCode + ": " + p_args.ErrorMessage);
|
||||
}
|
||||
|
||||
void OnLeapDeviceLost(object p_sender, Leap.DeviceEventArgs p_args)
|
||||
{
|
||||
m_leapController?.UnsubscribeFromDeviceEvents(p_args.Device);
|
||||
|
||||
if(CohtmlHud.Instance != null)
|
||||
CohtmlHud.Instance.ViewDropText("Leap Motion Extension", "Device lost");
|
||||
}
|
||||
|
||||
void OnLeapServiceConnect(object p_sender, Leap.ConnectionEventArgs p_args)
|
||||
{
|
||||
if(CohtmlHud.Instance != null)
|
||||
CohtmlHud.Instance.ViewDropText("Leap Motion Extension", "Service connected");
|
||||
}
|
||||
|
||||
void OnLeapServiceDisconnect(object p_sender, Leap.ConnectionLostEventArgs p_args)
|
||||
{
|
||||
if(CohtmlHud.Instance != null)
|
||||
CohtmlHud.Instance.ViewDropText("Leap Motion Extension", "Service disconnected");
|
||||
m_leapManager = new GameObject("LeapMotionManager").AddComponent<LeapManager>();
|
||||
}
|
||||
|
||||
// Patches
|
||||
|
@ -341,8 +72,8 @@ namespace ml_lme
|
|||
{
|
||||
try
|
||||
{
|
||||
if(m_leapTracked != null)
|
||||
m_leapTracked.OnAvatarClear();
|
||||
if(m_leapManager != null)
|
||||
m_leapManager.OnAvatarClear();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
|
@ -355,10 +86,50 @@ namespace ml_lme
|
|||
{
|
||||
try
|
||||
{
|
||||
if(m_leapTracked != null)
|
||||
m_leapTracked.OnSetupAvatar();
|
||||
if(m_leapManager != null)
|
||||
m_leapManager.OnAvatarSetup();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
OnHeadAttachChange(Settings.HeadAttach);
|
||||
static void OnCalibrate_Postfix() => ms_instance?.OnCalibrate();
|
||||
void OnCalibrate()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_leapManager != null)
|
||||
m_leapManager.OnCalibrate();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnRayScale_Postfix(float __0) => ms_instance?.OnRayScale(__0);
|
||||
void OnRayScale(float p_scale)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_leapManager != null)
|
||||
m_leapManager.OnRayScale(p_scale);
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyTitle("LeapMotionExtension")]
|
||||
[assembly: AssemblyVersion("1.2.8")]
|
||||
[assembly: AssemblyFileVersion("1.2.8")]
|
||||
[assembly: AssemblyVersion("1.3.1")]
|
||||
[assembly: AssemblyFileVersion("1.3.1")]
|
||||
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.2.8-ex2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.3.1", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Leap Motion Extension
|
||||
This mod allows you to use your Leap Motion controller for hands and fingers visual tracking.
|
||||
This mod allows you to use your Leap Motion controller for hands and fingers tracking.
|
||||
|
||||
[](https://youtu.be/nak1C8uibgc)
|
||||
|
||||
|
@ -12,12 +12,15 @@ This mod allows you to use your Leap Motion controller for hands and fingers vis
|
|||
# Usage
|
||||
## Settings
|
||||
Available mod's settings in `Settings - Implementation - Leap Motion Tracking`:
|
||||
* **Enable tracking:** enable hands tracking from Leap Motion data, disabled by default.
|
||||
* **Tracking mode:** set Leap Motion tracking mode, available values: `Screentop`, `Desktop` (by default), `HMD`.
|
||||
* **Enable tracking:** enables/disables hands tracking from Leap Motion data, disabled by default.
|
||||
* **Tracking mode:** sets Leap Motion tracking mode, available values: `Screentop`, `Desktop` (by default), `HMD`.
|
||||
* **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.
|
||||
* **Attach to head:** attaches 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 X/Y/X:** rotation around specific axis, useful for neck mounts, 0 by default.
|
||||
* **Track elbows:** elbows tracking, works best in `Screentop` and `HMD` tracking modes, `true` by default.
|
||||
* **Fingers tracking only:** apply only fingers tracking, disabled by default.
|
||||
* **Model visibility:** show Leap Motion controller model, useful for tracking visualizing, disabled by default.
|
||||
* **Fingers tracking only:** applies only fingers tracking, disabled by default.
|
||||
* **Model visibility:** shows Leap Motion controller model, useful for tracking visualizing, disabled by default.
|
||||
* **Interaction input:** enables in-game interactions (props, menu and etc.); `true` by default.
|
||||
* **Interact gesture threadhold:** activation limit for interaction based on hand gesture; 80 by default.
|
||||
* **Grip gesture threadhold:** activation limit for grip based on hand gesture; 40 by default.
|
||||
|
|
|
@ -31,7 +31,10 @@ namespace ml_lme
|
|||
HeadX,
|
||||
HeadY,
|
||||
HeadZ,
|
||||
TrackElbows
|
||||
TrackElbows,
|
||||
Input,
|
||||
InteractThreadhold,
|
||||
GripThreadhold
|
||||
};
|
||||
|
||||
static bool ms_enabled = false;
|
||||
|
@ -43,6 +46,9 @@ namespace ml_lme
|
|||
static bool ms_headAttach = false;
|
||||
static Vector3 ms_headOffset = new Vector3(0f, -0.3f, 0.15f);
|
||||
static bool ms_trackElbows = true;
|
||||
static bool ms_input = true;
|
||||
static float ms_interactThreadhold = 0.8f;
|
||||
static float ms_gripThreadhold = 0.4f;
|
||||
|
||||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
@ -56,27 +62,35 @@ namespace ml_lme
|
|||
static public event Action<bool> HeadAttachChange;
|
||||
static public event Action<Vector3> HeadOffsetChange;
|
||||
static public event Action<bool> TrackElbowsChange;
|
||||
static public event Action<bool> InputChange;
|
||||
static public event Action<float> InteractThreadholdChange;
|
||||
static public event Action<float> GripThreadholdChange;
|
||||
|
||||
public static void Init()
|
||||
internal static void Init()
|
||||
{
|
||||
ms_category = MelonLoader.MelonPreferences.CreateCategory("LME");
|
||||
|
||||
ms_entries = new List<MelonLoader.MelonPreferences_Entry>();
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.Enabled.ToString(), ms_enabled));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.DesktopX.ToString(), 0));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.DesktopY.ToString(), -45));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.DesktopZ.ToString(), 30));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.FingersOnly.ToString(), ms_modelVisibility));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.Model.ToString(), ms_modelVisibility));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.Mode.ToString(), (int)ms_trackingMode));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.AngleX.ToString(), 0));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.AngleY.ToString(), 0));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.AngleZ.ToString(), 0));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.Head.ToString(), ms_headAttach));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.HeadX.ToString(), 0));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.HeadY.ToString(), -30));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.HeadZ.ToString(), 15));
|
||||
ms_entries.Add(ms_category.CreateEntry(ModSetting.TrackElbows.ToString(), true));
|
||||
ms_entries = new List<MelonLoader.MelonPreferences_Entry>()
|
||||
{
|
||||
ms_category.CreateEntry(ModSetting.Enabled.ToString(), ms_enabled),
|
||||
ms_category.CreateEntry(ModSetting.DesktopX.ToString(), 0),
|
||||
ms_category.CreateEntry(ModSetting.DesktopY.ToString(), -45),
|
||||
ms_category.CreateEntry(ModSetting.DesktopZ.ToString(), 30),
|
||||
ms_category.CreateEntry(ModSetting.FingersOnly.ToString(), ms_modelVisibility),
|
||||
ms_category.CreateEntry(ModSetting.Model.ToString(), ms_modelVisibility),
|
||||
ms_category.CreateEntry(ModSetting.Mode.ToString(), (int)ms_trackingMode),
|
||||
ms_category.CreateEntry(ModSetting.AngleX.ToString(), 0),
|
||||
ms_category.CreateEntry(ModSetting.AngleY.ToString(), 0),
|
||||
ms_category.CreateEntry(ModSetting.AngleZ.ToString(), 0),
|
||||
ms_category.CreateEntry(ModSetting.Head.ToString(), ms_headAttach),
|
||||
ms_category.CreateEntry(ModSetting.HeadX.ToString(), 0),
|
||||
ms_category.CreateEntry(ModSetting.HeadY.ToString(), -30),
|
||||
ms_category.CreateEntry(ModSetting.HeadZ.ToString(), 15),
|
||||
ms_category.CreateEntry(ModSetting.TrackElbows.ToString(), true),
|
||||
ms_category.CreateEntry(ModSetting.Input.ToString(), true),
|
||||
ms_category.CreateEntry(ModSetting.InteractThreadhold.ToString(), 80),
|
||||
ms_category.CreateEntry(ModSetting.GripThreadhold.ToString(), 40),
|
||||
};
|
||||
|
||||
Load();
|
||||
|
||||
|
@ -129,6 +143,9 @@ namespace ml_lme
|
|||
(int)ms_entries[(int)ModSetting.HeadZ].BoxedValue
|
||||
) * 0.01f;
|
||||
ms_trackElbows = (bool)ms_entries[(int)ModSetting.TrackElbows].BoxedValue;
|
||||
ms_input = (bool)ms_entries[(int)ModSetting.Input].BoxedValue;
|
||||
ms_interactThreadhold = (int)ms_entries[(int)ModSetting.InteractThreadhold].BoxedValue * 0.01f;
|
||||
ms_gripThreadhold = (int)ms_entries[(int)ModSetting.GripThreadhold].BoxedValue * 0.01f;
|
||||
}
|
||||
|
||||
static void OnToggleUpdate(string p_name, string p_value)
|
||||
|
@ -171,6 +188,13 @@ namespace ml_lme
|
|||
TrackElbowsChange?.Invoke(ms_trackElbows);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.Input:
|
||||
{
|
||||
ms_input = bool.Parse(p_value);
|
||||
InputChange?.Invoke(ms_input);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
|
||||
|
@ -241,6 +265,18 @@ namespace ml_lme
|
|||
HeadOffsetChange?.Invoke(ms_headOffset);
|
||||
}
|
||||
break;
|
||||
case ModSetting.InteractThreadhold:
|
||||
{
|
||||
ms_interactThreadhold = int.Parse(p_value) * 0.01f;
|
||||
InteractThreadholdChange?.Invoke(ms_interactThreadhold);
|
||||
}
|
||||
break;
|
||||
case ModSetting.GripThreadhold:
|
||||
{
|
||||
ms_gripThreadhold = int.Parse(p_value) * 0.01f;
|
||||
GripThreadholdChange?.Invoke(ms_gripThreadhold);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
|
||||
|
@ -301,5 +337,17 @@ namespace ml_lme
|
|||
{
|
||||
get => ms_trackElbows;
|
||||
}
|
||||
public static bool Input
|
||||
{
|
||||
get => ms_input;
|
||||
}
|
||||
public static float InteractThreadhold
|
||||
{
|
||||
get => ms_interactThreadhold;
|
||||
}
|
||||
public static float GripThreadhold
|
||||
{
|
||||
get => ms_gripThreadhold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.UI;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
|
@ -8,16 +9,28 @@ namespace ml_lme
|
|||
{
|
||||
static readonly Quaternion ms_hmdRotationFix = new Quaternion(0f, 0.7071068f, 0.7071068f, 0f);
|
||||
static readonly Quaternion ms_screentopRotationFix = new Quaternion(0f, 0f, -1f, 0f);
|
||||
|
||||
public static bool AreKnucklesInUse() => PlayerSetup.Instance._trackerManager.trackerNames.Contains("knuckles");
|
||||
|
||||
public static bool IsInVR() => ((ABI_RC.Core.Savior.CheckVR.Instance != null) && ABI_RC.Core.Savior.CheckVR.Instance.hasVrDeviceLoaded);
|
||||
public static bool AreKnucklesInUse() => PlayerSetup.Instance._trackerManager.trackerNames.Contains("knuckles");
|
||||
public static bool IsLeftHandTracked() => ((VRTrackerManager.Instance.leftHand != null) && VRTrackerManager.Instance.leftHand.active);
|
||||
public static bool IsRightHandTracked() => ((VRTrackerManager.Instance.rightHand != null) && VRTrackerManager.Instance.rightHand.active);
|
||||
|
||||
public static Matrix4x4 GetMatrix(this Transform p_transform, bool p_pos = true, bool p_rot = true, bool p_scl = false)
|
||||
{
|
||||
return Matrix4x4.TRS(p_pos ? p_transform.position : Vector3.zero, p_rot ? p_transform.rotation : Quaternion.identity, p_scl ? p_transform.lossyScale : Vector3.one);
|
||||
}
|
||||
|
||||
|
||||
public static void ShowHUDNotification(string p_title, string p_message, string p_small = "", bool p_immediate = false)
|
||||
{
|
||||
if(CohtmlHud.Instance != null)
|
||||
{
|
||||
if(p_immediate)
|
||||
CohtmlHud.Instance.ViewDropTextImmediate(p_title, p_message, p_small);
|
||||
else
|
||||
CohtmlHud.Instance.ViewDropText(p_title, p_message, p_small);
|
||||
}
|
||||
}
|
||||
|
||||
public static void LeapToUnity(ref Vector3 p_pos, ref Quaternion p_rot, Settings.LeapTrackingMode p_mode)
|
||||
{
|
||||
p_pos *= 0.001f;
|
||||
|
|
|
@ -84,7 +84,10 @@
|
|||
<Compile Include="AssetsHandler.cs" />
|
||||
<Compile Include="DependenciesHandler.cs" />
|
||||
<Compile Include="GestureMatcher.cs" />
|
||||
<Compile Include="LeapInput.cs" />
|
||||
<Compile Include="LeapManager.cs" />
|
||||
<Compile Include="LeapTracked.cs" />
|
||||
<Compile Include="LeapTracking.cs" />
|
||||
<Compile Include="Main.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Scripts.cs" />
|
||||
|
|
|
@ -384,6 +384,27 @@ function inp_dropdown_mod_lme(_obj, _callbackName) {
|
|||
<div id="Model" class ="inp_toggle no-scroll" data-current="false"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class ="row-wrapper">
|
||||
<div class ="option-caption">Interaction input: </div>
|
||||
<div class ="option-input">
|
||||
<div id="Input" class ="inp_toggle no-scroll" data-current="false"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class ="row-wrapper">
|
||||
<div class ="option-caption">Interact gesture threadhold: </div>
|
||||
<div class ="option-input">
|
||||
<div id="InteractThreadhold" class ="inp_slider no-scroll" data-min="0" data-max="100" data-current="80"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class ="row-wrapper">
|
||||
<div class ="option-caption">Grip gesture threadhold: </div>
|
||||
<div class ="option-input">
|
||||
<div id="GripThreadhold" class ="inp_slider no-scroll" data-min="0" data-max="100" data-current="40"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
document.getElementById('settings-implementation').appendChild(l_block);
|
||||
|
||||
|
|
|
@ -3,38 +3,28 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
|||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.28307.1738
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_fpt", "ml_fpt\ml_fpt.csproj", "{EC0A8C41-A429-42CD-B8FA-401A802D4BA6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_lme", "ml_lme\ml_lme.csproj", "{83CC74B7-F444-40E1-BD06-67CEC995A919}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_aci", "ml_aci\ml_aci.csproj", "{1B5ACA07-6266-4C9A-BA30-D4BBE6634846}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_drs", "ml_drs\ml_drs.csproj", "{06CD5155-4459-48C3-8A53-E0B91136351B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_amt", "ml_amt\ml_amt.csproj", "{74E13D02-A506-41A2-A2CF-C8B3D5B1E452}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_sci", "ml_sci\ml_sci.csproj", "{E5481D41-196C-4241-AF26-6595EF1863C1}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_dht", "ml_dht\ml_dht.csproj", "{6DD89FC3-A974-4C39-A3EE-F60C24B17B5B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_egn", "ml_egn\ml_egn.csproj", "{1B5ACA07-6266-4C9A-BA30-D4BBE6634846}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_pam", "ml_pam\ml_pam.csproj", "{3B5028DE-8C79-40DF-A1EF-BDB29D366125}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{EC0A8C41-A429-42CD-B8FA-401A802D4BA6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{EC0A8C41-A429-42CD-B8FA-401A802D4BA6}.Debug|x64.Build.0 = Debug|x64
|
||||
{EC0A8C41-A429-42CD-B8FA-401A802D4BA6}.Release|x64.ActiveCfg = Release|x64
|
||||
{EC0A8C41-A429-42CD-B8FA-401A802D4BA6}.Release|x64.Build.0 = Release|x64
|
||||
{83CC74B7-F444-40E1-BD06-67CEC995A919}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{83CC74B7-F444-40E1-BD06-67CEC995A919}.Debug|x64.Build.0 = Debug|x64
|
||||
{83CC74B7-F444-40E1-BD06-67CEC995A919}.Release|x64.ActiveCfg = Release|x64
|
||||
{83CC74B7-F444-40E1-BD06-67CEC995A919}.Release|x64.Build.0 = Release|x64
|
||||
{1B5ACA07-6266-4C9A-BA30-D4BBE6634846}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1B5ACA07-6266-4C9A-BA30-D4BBE6634846}.Debug|x64.Build.0 = Debug|x64
|
||||
{1B5ACA07-6266-4C9A-BA30-D4BBE6634846}.Release|x64.ActiveCfg = Release|x64
|
||||
{1B5ACA07-6266-4C9A-BA30-D4BBE6634846}.Release|x64.Build.0 = Release|x64
|
||||
{06CD5155-4459-48C3-8A53-E0B91136351B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{06CD5155-4459-48C3-8A53-E0B91136351B}.Debug|x64.Build.0 = Debug|x64
|
||||
{06CD5155-4459-48C3-8A53-E0B91136351B}.Release|x64.ActiveCfg = Release|x64
|
||||
|
@ -43,14 +33,18 @@ Global
|
|||
{74E13D02-A506-41A2-A2CF-C8B3D5B1E452}.Debug|x64.Build.0 = Debug|x64
|
||||
{74E13D02-A506-41A2-A2CF-C8B3D5B1E452}.Release|x64.ActiveCfg = Release|x64
|
||||
{74E13D02-A506-41A2-A2CF-C8B3D5B1E452}.Release|x64.Build.0 = Release|x64
|
||||
{E5481D41-196C-4241-AF26-6595EF1863C1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E5481D41-196C-4241-AF26-6595EF1863C1}.Debug|x64.Build.0 = Debug|x64
|
||||
{E5481D41-196C-4241-AF26-6595EF1863C1}.Release|x64.ActiveCfg = Release|x64
|
||||
{E5481D41-196C-4241-AF26-6595EF1863C1}.Release|x64.Build.0 = Release|x64
|
||||
{6DD89FC3-A974-4C39-A3EE-F60C24B17B5B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6DD89FC3-A974-4C39-A3EE-F60C24B17B5B}.Debug|x64.Build.0 = Debug|x64
|
||||
{6DD89FC3-A974-4C39-A3EE-F60C24B17B5B}.Release|x64.ActiveCfg = Release|x64
|
||||
{6DD89FC3-A974-4C39-A3EE-F60C24B17B5B}.Release|x64.Build.0 = Release|x64
|
||||
{1B5ACA07-6266-4C9A-BA30-D4BBE6634846}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1B5ACA07-6266-4C9A-BA30-D4BBE6634846}.Debug|x64.Build.0 = Debug|x64
|
||||
{1B5ACA07-6266-4C9A-BA30-D4BBE6634846}.Release|x64.ActiveCfg = Release|x64
|
||||
{1B5ACA07-6266-4C9A-BA30-D4BBE6634846}.Release|x64.Build.0 = Release|x64
|
||||
{3B5028DE-8C79-40DF-A1EF-BDB29D366125}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3B5028DE-8C79-40DF-A1EF-BDB29D366125}.Debug|x64.Build.0 = Debug|x64
|
||||
{3B5028DE-8C79-40DF-A1EF-BDB29D366125}.Release|x64.ActiveCfg = Release|x64
|
||||
{3B5028DE-8C79-40DF-A1EF-BDB29D366125}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
284
ml_pam/ArmMover.cs
Normal file
284
ml_pam/ArmMover.cs
Normal file
|
@ -0,0 +1,284 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.InteractionSystem;
|
||||
using ABI_RC.Core.Player;
|
||||
using RootMotion.FinalIK;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_pam
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
class ArmMover : MonoBehaviour
|
||||
{
|
||||
const float c_offsetLimit = 0.5f;
|
||||
|
||||
static readonly float[] ms_tposeMuscles = typeof(ABI_RC.Systems.IK.SubSystems.BodySystem).GetField("TPoseMuscles", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null) as float[];
|
||||
static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f);
|
||||
static readonly Quaternion ms_offsetRight = Quaternion.Euler(0f, 0f, 90f);
|
||||
static readonly Quaternion ms_offsetRightDesktop = Quaternion.Euler(0f, 270f, 0f);
|
||||
static readonly Quaternion ms_palmToLeft = Quaternion.Euler(0f, 0f, -90f);
|
||||
|
||||
bool m_inVR = false;
|
||||
VRIK m_vrIK = null;
|
||||
Vector2 m_armWeight = Vector2.zero;
|
||||
Transform m_origRightHand = null;
|
||||
float m_playspaceScale = 1f;
|
||||
|
||||
bool m_enabled = true;
|
||||
ArmIK m_armIK = null;
|
||||
Transform m_target = null;
|
||||
Transform m_rotationTarget = null;
|
||||
CVRPickupObject m_pickup = null;
|
||||
Matrix4x4 m_offset = Matrix4x4.identity;
|
||||
bool m_targetActive = false;
|
||||
|
||||
void Start()
|
||||
{
|
||||
m_inVR = Utils.IsInVR();
|
||||
|
||||
m_target = new GameObject("ArmPickupTarget").transform;
|
||||
m_target.parent = PlayerSetup.Instance.GetActiveCamera().transform;
|
||||
m_target.localPosition = Vector3.zero;
|
||||
m_target.localRotation = Quaternion.identity;
|
||||
|
||||
m_rotationTarget = new GameObject("RotationTarget").transform;
|
||||
m_rotationTarget.parent = m_target;
|
||||
m_rotationTarget.localPosition = new Vector3(c_offsetLimit * Settings.GrabOffset, 0f, 0f);
|
||||
m_rotationTarget.localRotation = Quaternion.identity;
|
||||
|
||||
m_enabled = Settings.Enabled;
|
||||
|
||||
Settings.EnabledChange += this.SetEnabled;
|
||||
Settings.GrabOffsetChange += this.SetGrabOffset;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
Settings.EnabledChange -= this.SetEnabled;
|
||||
Settings.GrabOffsetChange -= this.SetGrabOffset;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if(m_enabled && (m_pickup != null))
|
||||
{
|
||||
Matrix4x4 l_result = m_pickup.transform.GetMatrix() * m_offset;
|
||||
m_target.position = l_result * ms_pointVector;
|
||||
}
|
||||
}
|
||||
|
||||
void OnIKPreUpdate()
|
||||
{
|
||||
m_armWeight.Set(m_vrIK.solver.rightArm.positionWeight, m_vrIK.solver.rightArm.rotationWeight);
|
||||
|
||||
if(m_targetActive && (Mathf.Approximately(m_armWeight.x, 0f) || Mathf.Approximately(m_armWeight.y, 0f)))
|
||||
{
|
||||
m_vrIK.solver.rightArm.positionWeight = 1f;
|
||||
m_vrIK.solver.rightArm.rotationWeight = 1f;
|
||||
}
|
||||
}
|
||||
void OnIKPostUpdate()
|
||||
{
|
||||
m_vrIK.solver.rightArm.positionWeight = m_armWeight.x;
|
||||
m_vrIK.solver.rightArm.rotationWeight = m_armWeight.y;
|
||||
}
|
||||
|
||||
// Settings
|
||||
void SetEnabled(bool p_state)
|
||||
{
|
||||
m_enabled = p_state;
|
||||
|
||||
RefreshArmIK();
|
||||
if(m_enabled)
|
||||
RestorePickup();
|
||||
else
|
||||
RestoreVRIK();
|
||||
}
|
||||
|
||||
void SetGrabOffset(float p_value)
|
||||
{
|
||||
if(m_rotationTarget != null)
|
||||
m_rotationTarget.localPosition = new Vector3(c_offsetLimit * m_playspaceScale * p_value, 0f, 0f);
|
||||
}
|
||||
|
||||
// Game events
|
||||
internal void OnAvatarClear()
|
||||
{
|
||||
m_vrIK = null;
|
||||
m_origRightHand = null;
|
||||
m_armIK = null;
|
||||
m_targetActive = false;
|
||||
}
|
||||
|
||||
internal void OnAvatarSetup()
|
||||
{
|
||||
// Recheck if user could switch to VR
|
||||
if(m_inVR != Utils.IsInVR())
|
||||
{
|
||||
m_target.parent = PlayerSetup.Instance.GetActiveCamera().transform;
|
||||
m_target.localPosition = Vector3.zero;
|
||||
m_target.localRotation = Quaternion.identity;
|
||||
}
|
||||
|
||||
m_inVR = Utils.IsInVR();
|
||||
m_vrIK = PlayerSetup.Instance._animator.GetComponent<VRIK>();
|
||||
|
||||
if(PlayerSetup.Instance._animator.isHuman)
|
||||
{
|
||||
HumanPose l_currentPose = new HumanPose();
|
||||
HumanPoseHandler l_poseHandler = null;
|
||||
|
||||
if(!m_inVR)
|
||||
{
|
||||
l_poseHandler = new HumanPoseHandler(PlayerSetup.Instance._animator.avatar, PlayerSetup.Instance._avatar.transform);
|
||||
l_poseHandler.GetHumanPose(ref l_currentPose);
|
||||
|
||||
HumanPose l_tPose = new HumanPose
|
||||
{
|
||||
bodyPosition = l_currentPose.bodyPosition,
|
||||
bodyRotation = l_currentPose.bodyRotation,
|
||||
muscles = new float[l_currentPose.muscles.Length]
|
||||
};
|
||||
for(int i = 0; i < l_tPose.muscles.Length; i++)
|
||||
l_tPose.muscles[i] = ms_tposeMuscles[i];
|
||||
|
||||
l_poseHandler.SetHumanPose(ref l_tPose);
|
||||
}
|
||||
|
||||
Transform l_hand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand);
|
||||
if(l_hand != null)
|
||||
m_rotationTarget.localRotation = (ms_palmToLeft * (m_inVR ? ms_offsetRight : ms_offsetRightDesktop)) * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_hand.GetMatrix()).rotation;
|
||||
|
||||
if(m_vrIK == null)
|
||||
{
|
||||
Transform l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.UpperChest);
|
||||
if(l_chest == null)
|
||||
l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Chest);
|
||||
if(l_chest == null)
|
||||
l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Spine);
|
||||
|
||||
m_armIK = PlayerSetup.Instance._avatar.AddComponent<ArmIK>();
|
||||
m_armIK.solver.isLeft = false;
|
||||
m_armIK.solver.SetChain(
|
||||
l_chest,
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightShoulder),
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightUpperArm),
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightLowerArm),
|
||||
l_hand,
|
||||
PlayerSetup.Instance._animator.transform
|
||||
);
|
||||
m_armIK.solver.arm.target = m_rotationTarget;
|
||||
m_armIK.solver.arm.positionWeight = 1f;
|
||||
m_armIK.solver.arm.rotationWeight = 1f;
|
||||
m_armIK.solver.IKPositionWeight = 0f;
|
||||
m_armIK.solver.IKRotationWeight = 0f;
|
||||
m_armIK.enabled = m_enabled;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_origRightHand = m_vrIK.solver.rightArm.target;
|
||||
m_vrIK.solver.OnPreUpdate += this.OnIKPreUpdate;
|
||||
m_vrIK.solver.OnPostUpdate += this.OnIKPostUpdate;
|
||||
}
|
||||
|
||||
l_poseHandler?.SetHumanPose(ref l_currentPose);
|
||||
l_poseHandler?.Dispose();
|
||||
}
|
||||
|
||||
if(m_enabled)
|
||||
RestorePickup();
|
||||
}
|
||||
|
||||
internal void OnPickupGrab(CVRPickupObject p_pickup, ControllerRay p_ray, Vector3 p_hit)
|
||||
{
|
||||
if(p_ray == ViewManager.Instance.desktopControllerRay)
|
||||
{
|
||||
m_pickup = p_pickup;
|
||||
|
||||
// Set offsets
|
||||
if(m_pickup.gripType == CVRPickupObject.GripType.Origin)
|
||||
{
|
||||
if(m_pickup.ikReference != null)
|
||||
m_offset = (m_pickup.transform.GetMatrix().inverse * m_pickup.ikReference.GetMatrix());
|
||||
else
|
||||
{
|
||||
if(m_pickup.gripOrigin != null)
|
||||
m_offset = m_pickup.transform.GetMatrix().inverse * m_pickup.gripOrigin.GetMatrix();
|
||||
}
|
||||
}
|
||||
else
|
||||
m_offset = m_pickup.transform.GetMatrix().inverse * Matrix4x4.Translate(p_hit);
|
||||
|
||||
if(m_enabled)
|
||||
{
|
||||
if((m_vrIK != null) && !m_targetActive)
|
||||
{
|
||||
m_vrIK.solver.rightArm.target = m_rotationTarget;
|
||||
m_targetActive = true;
|
||||
}
|
||||
|
||||
if(m_armIK != null)
|
||||
{
|
||||
m_armIK.solver.IKPositionWeight = 1f;
|
||||
m_armIK.solver.IKRotationWeight = 1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnPickupDrop(CVRPickupObject p_pickup)
|
||||
{
|
||||
if(m_pickup == p_pickup)
|
||||
{
|
||||
m_pickup = null;
|
||||
|
||||
if(m_enabled)
|
||||
{
|
||||
RestoreVRIK();
|
||||
|
||||
if(m_armIK != null)
|
||||
{
|
||||
m_armIK.solver.IKPositionWeight = 0f;
|
||||
m_armIK.solver.IKRotationWeight = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnPlayspaceScale(float p_relation)
|
||||
{
|
||||
m_playspaceScale = p_relation;
|
||||
SetGrabOffset(Settings.GrabOffset);
|
||||
}
|
||||
|
||||
// Arbitrary
|
||||
void RestorePickup()
|
||||
{
|
||||
if((m_vrIK != null) && (m_pickup != null))
|
||||
{
|
||||
m_vrIK.solver.rightArm.target = m_rotationTarget;
|
||||
m_targetActive = true;
|
||||
}
|
||||
if((m_armIK != null) && (m_pickup != null))
|
||||
{
|
||||
m_armIK.solver.IKPositionWeight = 1f;
|
||||
m_armIK.solver.IKRotationWeight = 1f;
|
||||
}
|
||||
}
|
||||
|
||||
void RestoreVRIK()
|
||||
{
|
||||
if((m_vrIK != null) && m_targetActive)
|
||||
{
|
||||
m_vrIK.solver.rightArm.target = m_origRightHand;
|
||||
m_targetActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
void RefreshArmIK()
|
||||
{
|
||||
if(m_armIK != null)
|
||||
m_armIK.enabled = m_enabled;
|
||||
}
|
||||
}
|
||||
}
|
136
ml_pam/Main.cs
Normal file
136
ml_pam/Main.cs
Normal file
|
@ -0,0 +1,136 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.InteractionSystem;
|
||||
using ABI_RC.Core.Player;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_pam
|
||||
{
|
||||
public class PickupArmMovement : MelonLoader.MelonMod
|
||||
{
|
||||
static PickupArmMovement ms_instance = null;
|
||||
|
||||
ArmMover m_localMover = null;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
if(ms_instance == null)
|
||||
ms_instance = this;
|
||||
|
||||
Settings.Init();
|
||||
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRPickupObject).GetMethod(nameof(CVRPickupObject.Grab)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnCVRPickupObjectGrab_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRPickupObject).GetMethod(nameof(CVRPickupObject.Drop)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnCVRPickupObjectDrop_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod("SetPlaySpaceScale", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnPlayspaceScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator WaitForLocalPlayer()
|
||||
{
|
||||
while(PlayerSetup.Instance == null)
|
||||
yield return null;
|
||||
|
||||
m_localMover = PlayerSetup.Instance.gameObject.AddComponent<ArmMover>();
|
||||
}
|
||||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
}
|
||||
|
||||
static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear();
|
||||
void OnAvatarClear()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localMover != null)
|
||||
m_localMover.OnAvatarClear();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar();
|
||||
void OnSetupAvatar()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localMover != null)
|
||||
m_localMover.OnAvatarSetup();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCVRPickupObjectGrab_Postfix(ref CVRPickupObject __instance, ControllerRay __1, Vector3 __2) => ms_instance?.OnCVRPickupObjectGrab(__instance, __1, __2);
|
||||
void OnCVRPickupObjectGrab(CVRPickupObject p_pickup, ControllerRay p_ray, Vector3 p_hit)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(p_pickup.IsGrabbedByMe() && (m_localMover != null))
|
||||
m_localMover.OnPickupGrab(p_pickup, p_ray, p_hit);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCVRPickupObjectDrop_Postfix(ref CVRPickupObject __instance) => ms_instance?.OnCVRPickupObjectDrop(__instance);
|
||||
void OnCVRPickupObjectDrop(CVRPickupObject p_pickup)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localMover != null)
|
||||
m_localMover.OnPickupDrop(p_pickup);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnPlayspaceScale_Postfix(float ____avatarScaleRelation) => ms_instance?.OnPlayspaceScale(____avatarScaleRelation);
|
||||
void OnPlayspaceScale(float p_relation)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localMover != null)
|
||||
m_localMover.OnPlayspaceScale(p_relation);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
ml_pam/Properties/AssemblyInfo.cs
Normal file
11
ml_pam/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyTitle("PickupArmMovement")]
|
||||
[assembly: AssemblyVersion("1.0.1")]
|
||||
[assembly: AssemblyFileVersion("1.0.1")]
|
||||
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_pam.PickupArmMovement), "PickupArmMovement", "1.0.1", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||
[assembly: MelonLoader.MelonPriority(1)]
|
||||
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
12
ml_pam/README.md
Normal file
12
ml_pam/README.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Pickup Arm Movement
|
||||
This mod adds arm tracking upon holding pickup in desktop mode.
|
||||
|
||||
# Installation
|
||||
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
|
||||
* Get [latest release DLL](../../../releases/latest):
|
||||
* Put `ml_pam.dll` in `Mods` folder of game
|
||||
|
||||
# Usage
|
||||
Available mod's settings in `Settings - Interactions`:
|
||||
* **Enable hand movement:** enables/disables arm tracking; default value - `true`.
|
||||
* **Grab offset:** offset from pickup grab point; defalut value - `25`.
|
26
ml_pam/Scripts.cs
Normal file
26
ml_pam/Scripts.cs
Normal file
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ml_pam
|
||||
{
|
||||
static class Scripts
|
||||
{
|
||||
public static string GetEmbeddedScript(string p_name)
|
||||
{
|
||||
string l_result = "";
|
||||
Assembly l_assembly = Assembly.GetExecutingAssembly();
|
||||
string l_assemblyName = l_assembly.GetName().Name;
|
||||
|
||||
try
|
||||
{
|
||||
Stream l_libraryStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name);
|
||||
StreamReader l_streadReader = new StreamReader(l_libraryStream);
|
||||
l_result = l_streadReader.ReadToEnd();
|
||||
}
|
||||
catch(Exception) { }
|
||||
|
||||
return l_result;
|
||||
}
|
||||
}
|
||||
}
|
113
ml_pam/Settings.cs
Normal file
113
ml_pam/Settings.cs
Normal file
|
@ -0,0 +1,113 @@
|
|||
using ABI_RC.Core.InteractionSystem;
|
||||
using cohtml;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ml_pam
|
||||
{
|
||||
static class Settings
|
||||
{
|
||||
public enum ModSetting
|
||||
{
|
||||
Enabled = 0,
|
||||
GrabOffset
|
||||
}
|
||||
|
||||
static bool ms_enabled = true;
|
||||
static float ms_grabOffset = 0.25f;
|
||||
|
||||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
||||
static public event Action<bool> EnabledChange;
|
||||
static public event Action<float> GrabOffsetChange;
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
ms_category = MelonLoader.MelonPreferences.CreateCategory("PAM");
|
||||
|
||||
ms_entries = new List<MelonLoader.MelonPreferences_Entry>()
|
||||
{
|
||||
ms_category.CreateEntry(ModSetting.Enabled.ToString(), ms_enabled),
|
||||
ms_category.CreateEntry(ModSetting.GrabOffset.ToString(), 25),
|
||||
};
|
||||
|
||||
Load();
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitMainMenuUi());
|
||||
}
|
||||
|
||||
static System.Collections.IEnumerator WaitMainMenuUi()
|
||||
{
|
||||
while(ViewManager.Instance == null)
|
||||
yield return null;
|
||||
while(ViewManager.Instance.gameMenuView == null)
|
||||
yield return null;
|
||||
while(ViewManager.Instance.gameMenuView.Listener == null)
|
||||
yield return null;
|
||||
|
||||
ViewManager.Instance.gameMenuView.Listener.ReadyForBindings += () =>
|
||||
{
|
||||
ViewManager.Instance.gameMenuView.View.BindCall("MelonMod_PAM_Call_InpToggle", new Action<string, string>(OnToggleUpdate));
|
||||
ViewManager.Instance.gameMenuView.View.BindCall("MelonMod_PAM_Call_InpSlider", new Action<string, string>(OnSliderUpdate));
|
||||
};
|
||||
ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) =>
|
||||
{
|
||||
ViewManager.Instance.gameMenuView.View.ExecuteScript(Scripts.GetEmbeddedScript("menu.js"));
|
||||
foreach(var l_entry in ms_entries)
|
||||
ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSettingPAM", l_entry.DisplayName, l_entry.GetValueAsString());
|
||||
};
|
||||
}
|
||||
|
||||
static void Load()
|
||||
{
|
||||
ms_enabled = (bool)ms_entries[(int)ModSetting.Enabled].BoxedValue;
|
||||
ms_grabOffset = (int)ms_entries[(int)ModSetting.GrabOffset].BoxedValue * 0.01f;
|
||||
}
|
||||
|
||||
static void OnToggleUpdate(string p_name, string p_value)
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
switch(l_setting)
|
||||
{
|
||||
case ModSetting.Enabled:
|
||||
{
|
||||
ms_enabled = bool.Parse(p_value);
|
||||
EnabledChange?.Invoke(ms_enabled);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSliderUpdate(string p_name, string p_value)
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
switch(l_setting)
|
||||
{
|
||||
case ModSetting.GrabOffset:
|
||||
{
|
||||
ms_grabOffset = int.Parse(p_value) * 0.01f;
|
||||
GrabOffsetChange?.Invoke(ms_grabOffset);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Enabled
|
||||
{
|
||||
get => ms_enabled;
|
||||
}
|
||||
public static float GrabOffset
|
||||
{
|
||||
get => ms_grabOffset;
|
||||
}
|
||||
}
|
||||
}
|
15
ml_pam/Utils.cs
Normal file
15
ml_pam/Utils.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using UnityEngine;
|
||||
|
||||
namespace ml_pam
|
||||
{
|
||||
static class Utils
|
||||
{
|
||||
public static bool IsInVR() => ((ABI_RC.Core.Savior.CheckVR.Instance != null) && ABI_RC.Core.Savior.CheckVR.Instance.hasVrDeviceLoaded);
|
||||
|
||||
// Extensions
|
||||
public static Matrix4x4 GetMatrix(this Transform p_transform, bool p_pos = true, bool p_rot = true, bool p_scl = false)
|
||||
{
|
||||
return Matrix4x4.TRS(p_pos ? p_transform.position : Vector3.zero, p_rot ? p_transform.rotation : Quaternion.identity, p_scl ? p_transform.localScale : Vector3.one);
|
||||
}
|
||||
}
|
||||
}
|
90
ml_pam/ml_pam.csproj
Normal file
90
ml_pam/ml_pam.csproj
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{3B5028DE-8C79-40DF-A1EF-BDB29D366125}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>ml_pam</RootNamespace>
|
||||
<AssemblyName>ml_pam</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="0Harmony, Version=2.9.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\0Harmony.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp-firstpass, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="cohtml.Net">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Cohtml.Runtime">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="MelonLoader, Version=0.5.7.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\MelonLoader.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="UnityEngine.AnimationModule">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ArmMover.cs" />
|
||||
<Compile Include="Main.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Scripts.cs" />
|
||||
<Compile Include="Settings.cs" />
|
||||
<Compile Include="Utils.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="resources\menu.js" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\"</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
</Project>
|
6
ml_pam/ml_pam.csproj.user
Normal file
6
ml_pam/ml_pam.csproj.user
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ReferencePath>D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\;D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\</ReferencePath>
|
||||
</PropertyGroup>
|
||||
</Project>
|
209
ml_pam/resources/menu.js
Normal file
209
ml_pam/resources/menu.js
Normal file
|
@ -0,0 +1,209 @@
|
|||
// Add settings
|
||||
var g_modSettingsPAM = [];
|
||||
|
||||
engine.on('updateModSettingPAM', function (_name, _value) {
|
||||
for (var i = 0; i < g_modSettingsPAM.length; i++) {
|
||||
if (g_modSettingsPAM[i].name == _name) {
|
||||
g_modSettingsPAM[i].updateValue(_value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Modified from original `inp` types, because I have no js knowledge to hook stuff
|
||||
function inp_toggle_mod_pam(_obj, _callbackName) {
|
||||
this.obj = _obj;
|
||||
this.callbackName = _callbackName;
|
||||
this.value = _obj.getAttribute('data-current');
|
||||
this.name = _obj.id;
|
||||
this.type = _obj.getAttribute('data-type');
|
||||
|
||||
var self = this;
|
||||
|
||||
this.mouseDown = function (_e) {
|
||||
self.value = self.value == "True" ? "False" : "True";
|
||||
self.updateState();
|
||||
}
|
||||
|
||||
this.updateState = function () {
|
||||
self.obj.classList.remove("checked");
|
||||
if (self.value == "True") {
|
||||
self.obj.classList.add("checked");
|
||||
}
|
||||
|
||||
engine.call(self.callbackName, self.name, self.value);
|
||||
}
|
||||
|
||||
_obj.addEventListener('mousedown', this.mouseDown);
|
||||
|
||||
this.getValue = function () {
|
||||
return self.value;
|
||||
}
|
||||
|
||||
this.updateValue = function (value) {
|
||||
self.value = value;
|
||||
|
||||
self.obj.classList.remove("checked");
|
||||
if (self.value == "True") {
|
||||
self.obj.classList.add("checked");
|
||||
}
|
||||
}
|
||||
|
||||
this.updateValue(this.value);
|
||||
|
||||
return {
|
||||
name: this.name,
|
||||
value: this.getValue,
|
||||
updateValue: this.updateValue
|
||||
}
|
||||
}
|
||||
|
||||
function inp_slider_mod_pam(_obj, _callbackName) {
|
||||
this.obj = _obj;
|
||||
this.callbackName = _callbackName;
|
||||
this.minValue = parseFloat(_obj.getAttribute('data-min'));
|
||||
this.maxValue = parseFloat(_obj.getAttribute('data-max'));
|
||||
this.percent = 0;
|
||||
this.value = parseFloat(_obj.getAttribute('data-current'));
|
||||
this.dragActive = false;
|
||||
this.name = _obj.id;
|
||||
this.type = _obj.getAttribute('data-type');
|
||||
this.stepSize = _obj.getAttribute('data-stepSize') || 0;
|
||||
this.format = _obj.getAttribute('data-format') || '{value}';
|
||||
|
||||
var self = this;
|
||||
|
||||
if (this.stepSize != 0)
|
||||
this.value = Math.round(this.value / this.stepSize) * this.stepSize;
|
||||
else
|
||||
this.value = Math.round(this.value);
|
||||
|
||||
this.valueLabelBackground = document.createElement('div');
|
||||
this.valueLabelBackground.className = 'valueLabel background';
|
||||
this.valueLabelBackground.innerHTML = this.format.replace('{value}', this.value);
|
||||
this.obj.appendChild(this.valueLabelBackground);
|
||||
|
||||
this.valueBar = document.createElement('div');
|
||||
this.valueBar.className = 'valueBar';
|
||||
this.valueBar.setAttribute('style', 'width: ' + (((this.value - this.minValue) / (this.maxValue - this.minValue)) * 100) + '%;');
|
||||
this.obj.appendChild(this.valueBar);
|
||||
|
||||
this.valueLabelForeground = document.createElement('div');
|
||||
this.valueLabelForeground.className = 'valueLabel foreground';
|
||||
this.valueLabelForeground.innerHTML = this.format.replace('{value}', this.value);
|
||||
this.valueLabelForeground.setAttribute('style', 'width: ' + (1.0 / ((this.value - this.minValue) / (this.maxValue - this.minValue)) * 100) + '%;');
|
||||
this.valueBar.appendChild(this.valueLabelForeground);
|
||||
|
||||
this.mouseDown = function (_e) {
|
||||
self.dragActive = true;
|
||||
self.mouseMove(_e, false);
|
||||
}
|
||||
|
||||
this.mouseMove = function (_e, _write) {
|
||||
if (self.dragActive) {
|
||||
var rect = _obj.getBoundingClientRect();
|
||||
var start = rect.left;
|
||||
var end = rect.right;
|
||||
self.percent = Math.min(Math.max((_e.clientX - start) / rect.width, 0), 1);
|
||||
var value = self.percent;
|
||||
value *= (self.maxValue - self.minValue);
|
||||
value += self.minValue;
|
||||
if (self.stepSize != 0) {
|
||||
value = Math.round(value / self.stepSize);
|
||||
self.value = value * self.stepSize;
|
||||
self.percent = (self.value - self.minValue) / (self.maxValue - self.minValue);
|
||||
}
|
||||
else
|
||||
self.value = Math.round(value);
|
||||
|
||||
self.valueBar.setAttribute('style', 'width: ' + (self.percent * 100) + '%;');
|
||||
self.valueLabelForeground.setAttribute('style', 'width: ' + (1.0 / self.percent * 100) + '%;');
|
||||
self.valueLabelBackground.innerHTML = self.valueLabelForeground.innerHTML = self.format.replace('{value}', self.value);
|
||||
|
||||
engine.call(self.callbackName, self.name, "" + self.value);
|
||||
self.displayImperial();
|
||||
}
|
||||
}
|
||||
|
||||
this.mouseUp = function (_e) {
|
||||
self.mouseMove(_e, true);
|
||||
self.dragActive = false;
|
||||
}
|
||||
|
||||
_obj.addEventListener('mousedown', this.mouseDown);
|
||||
document.addEventListener('mousemove', this.mouseMove);
|
||||
document.addEventListener('mouseup', this.mouseUp);
|
||||
|
||||
this.getValue = function () {
|
||||
return self.value;
|
||||
}
|
||||
|
||||
this.updateValue = function (value) {
|
||||
if (self.stepSize != 0)
|
||||
self.value = Math.round(value * self.stepSize) / self.stepSize;
|
||||
else
|
||||
self.value = Math.round(value);
|
||||
self.percent = (self.value - self.minValue) / (self.maxValue - self.minValue);
|
||||
self.valueBar.setAttribute('style', 'width: ' + (self.percent * 100) + '%;');
|
||||
self.valueLabelForeground.setAttribute('style', 'width: ' + (1.0 / self.percent * 100) + '%;');
|
||||
self.valueLabelBackground.innerHTML = self.valueLabelForeground.innerHTML = self.format.replace('{value}', self.value);
|
||||
self.displayImperial();
|
||||
}
|
||||
|
||||
this.displayImperial = function () {
|
||||
var displays = document.querySelectorAll('.imperialDisplay');
|
||||
for (var i = 0; i < displays.length; i++) {
|
||||
var binding = displays[i].getAttribute('data-binding');
|
||||
if (binding == self.name) {
|
||||
var realFeet = ((self.value * 0.393700) / 12);
|
||||
var feet = Math.floor(realFeet);
|
||||
var inches = Math.floor((realFeet - feet) * 12);
|
||||
displays[i].innerHTML = feet + "'" + inches + '''';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name: this.name,
|
||||
value: this.getValue,
|
||||
updateValue: this.updateValue
|
||||
}
|
||||
}
|
||||
|
||||
// Add own menu
|
||||
{
|
||||
let l_block = document.createElement('div');
|
||||
l_block.innerHTML = `
|
||||
<div class ="settings-subcategory">
|
||||
<div class ="subcategory-name">Pickup Arm Mover</div>
|
||||
<div class ="subcategory-description"></div>
|
||||
</div>
|
||||
|
||||
<div class ="row-wrapper">
|
||||
<div class ="option-caption">Enable hand movement: </div>
|
||||
<div class ="option-input">
|
||||
<div id="Enabled" class ="inp_toggle no-scroll" data-current="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class ="row-wrapper">
|
||||
<div class ="option-caption">Grab offset: </div>
|
||||
<div class ="option-input">
|
||||
<div id="GrabOffset" class ="inp_slider no-scroll" data-min="0" data-max="100" data-current="25"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
document.getElementById('settings-interaction').appendChild(l_block);
|
||||
|
||||
// Update toggles in new menu block
|
||||
let l_toggles = l_block.querySelectorAll('.inp_toggle');
|
||||
for (var i = 0; i < l_toggles.length; i++) {
|
||||
g_modSettingsPAM[g_modSettingsPAM.length] = new inp_toggle_mod_pam(l_toggles[i], 'MelonMod_PAM_Call_InpToggle');
|
||||
}
|
||||
|
||||
// Update sliders in new menu block
|
||||
let l_sliders = l_block.querySelectorAll('.inp_slider');
|
||||
for (var i = 0; i < l_sliders.length; i++) {
|
||||
g_modSettingsPAM[g_modSettingsPAM.length] = new inp_slider_mod_pam(l_sliders[i], 'MelonMod_PAM_Call_InpSlider');
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue