mirror of
https://github.com/hanetzer/sdraw_mods_cvr.git
synced 2025-09-03 10:29:22 +00:00
Custom event classes for patched methods
Update to LeapCSharp 6.15.0
This commit is contained in:
parent
4b879d53d5
commit
85925a7072
76 changed files with 3443 additions and 2187 deletions
|
@ -42,7 +42,7 @@ namespace ml_amt
|
|||
switch(m_type)
|
||||
{
|
||||
case ParameterType.Moving:
|
||||
SetBoolean(p_tweaker.GetMoving());
|
||||
SetBoolean(p_tweaker.IsMoving());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
105
ml_amt/GameEvents.cs
Normal file
105
ml_amt/GameEvents.cs
Normal file
|
@ -0,0 +1,105 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ml_amt
|
||||
{
|
||||
static class GameEvents
|
||||
{
|
||||
internal class GameEvent
|
||||
{
|
||||
event Action m_action;
|
||||
public void AddHandler(Action p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action p_listener) => m_action -= p_listener;
|
||||
public void Invoke() => m_action?.Invoke();
|
||||
}
|
||||
|
||||
public static readonly GameEvent OnAvatarSetup = new GameEvent();
|
||||
public static readonly GameEvent OnAvatarClear = new GameEvent();
|
||||
public static readonly GameEvent OnAvatarReuse = new GameEvent();
|
||||
public static readonly GameEvent OnPlayspaceScale = new GameEvent();
|
||||
|
||||
internal static void Init(HarmonyLib.Harmony p_instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
p_instance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(PlayerSetup).GetMethod("SetPlaySpaceScale", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnPlayspaceScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarClear_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarClear.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarSetup.Invoke();
|
||||
}
|
||||
catch(Exception l_exception)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(l_exception);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarReinitialize_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarReuse.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnPlayspaceScale_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnPlayspaceScale.Invoke();
|
||||
}
|
||||
catch(Exception l_exception)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(l_exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,44 +1,16 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ml_amt
|
||||
{
|
||||
public class AvatarMotionTweaker : MelonLoader.MelonMod
|
||||
{
|
||||
static AvatarMotionTweaker ms_instance = null;
|
||||
|
||||
MotionTweaker m_localTweaker = 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(AvatarMotionTweaker).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod("SetPlaySpaceScale", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnPlayspaceScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
GameEvents.Init(HarmonyInstance);
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
|
||||
}
|
||||
|
@ -53,68 +25,9 @@ namespace ml_amt
|
|||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
if(m_localTweaker != null)
|
||||
UnityEngine.Object.Destroy(m_localTweaker);
|
||||
m_localTweaker = null;
|
||||
}
|
||||
|
||||
static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear();
|
||||
void OnAvatarClear()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localTweaker != null)
|
||||
m_localTweaker.OnAvatarClear();
|
||||
}
|
||||
catch(Exception l_exception)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(l_exception);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar();
|
||||
void OnSetupAvatar()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localTweaker != null)
|
||||
m_localTweaker.OnSetupAvatar();
|
||||
}
|
||||
catch(Exception l_exception)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(l_exception);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarReinitialize_Postfix() => ms_instance?.OnAvatarReinitialize();
|
||||
void OnAvatarReinitialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localTweaker != null)
|
||||
m_localTweaker.OnAvatarReinitialize();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnPlayspaceScale_Postfix() => ms_instance?.OnPlayspaceScale();
|
||||
void OnPlayspaceScale()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localTweaker != null)
|
||||
m_localTweaker.OnPlayspaceScale();
|
||||
}
|
||||
catch(Exception l_exception)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(l_exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,12 +31,8 @@ namespace ml_amt
|
|||
bool m_avatarReady = false;
|
||||
bool m_grounded = false;
|
||||
bool m_moving = false;
|
||||
|
||||
bool m_locomotionOverride = false;
|
||||
|
||||
bool m_ikOverrideFly = true;
|
||||
bool m_ikOverrideJump = true;
|
||||
|
||||
bool m_detectEmotes = true;
|
||||
bool m_emoteActive = false;
|
||||
|
||||
Vector3 m_massCenter = Vector3.zero;
|
||||
|
@ -53,18 +49,17 @@ namespace ml_amt
|
|||
// Unity events
|
||||
void Start()
|
||||
{
|
||||
SetCrouchLimit(Settings.CrouchLimit);
|
||||
SetProneLimit(Settings.ProneLimit);
|
||||
SetIKOverrideFly(Settings.IKOverrideFly);
|
||||
SetIKOverrideJump(Settings.IKOverrideJump);
|
||||
SetDetectEmotes(Settings.DetectEmotes);
|
||||
OnCrouchLimitChanged(Settings.CrouchLimit);
|
||||
OnProneLimitChanged(Settings.ProneLimit);
|
||||
|
||||
Settings.CrouchLimitChange += this.SetCrouchLimit;
|
||||
Settings.ProneLimitChange += this.SetProneLimit;
|
||||
Settings.IKOverrideFlyChange += this.SetIKOverrideFly;
|
||||
Settings.IKOverrideJumpChange += this.SetIKOverrideJump;
|
||||
Settings.DetectEmotesChange += this.SetDetectEmotes;
|
||||
Settings.MassCenterChange += this.OnMassCenterChange;
|
||||
Settings.OnCrouchLimitChanged.AddHandler(this.OnCrouchLimitChanged);
|
||||
Settings.OnProneLimitChanged.AddHandler(this.OnProneLimitChanged);
|
||||
Settings.OnMassCenterChanged.AddHandler(this.OnMassCenterChanged);
|
||||
|
||||
GameEvents.OnAvatarSetup.AddHandler(this.OnAvatarSetup);
|
||||
GameEvents.OnAvatarClear.AddHandler(this.OnAvatarClear);
|
||||
GameEvents.OnAvatarReuse.AddHandler(this.OnAvatarReuse);
|
||||
GameEvents.OnPlayspaceScale.AddHandler(this.OnPlayspaceScale);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
|
@ -73,12 +68,14 @@ namespace ml_amt
|
|||
m_ikLimits = null;
|
||||
m_parameters.Clear();
|
||||
|
||||
Settings.CrouchLimitChange -= this.SetCrouchLimit;
|
||||
Settings.ProneLimitChange -= this.SetProneLimit;
|
||||
Settings.IKOverrideFlyChange -= this.SetIKOverrideFly;
|
||||
Settings.IKOverrideJumpChange -= this.SetIKOverrideJump;
|
||||
Settings.DetectEmotesChange -= this.SetDetectEmotes;
|
||||
Settings.MassCenterChange -= this.OnMassCenterChange;
|
||||
Settings.OnCrouchLimitChanged.RemoveHandler(this.OnCrouchLimitChanged);
|
||||
Settings.OnProneLimitChanged.RemoveHandler(this.OnProneLimitChanged);
|
||||
Settings.OnMassCenterChanged.RemoveHandler(this.OnMassCenterChanged);
|
||||
|
||||
GameEvents.OnAvatarSetup.RemoveHandler(this.OnAvatarSetup);
|
||||
GameEvents.OnAvatarClear.RemoveHandler(this.OnAvatarClear);
|
||||
GameEvents.OnAvatarReuse.RemoveHandler(this.OnAvatarReuse);
|
||||
GameEvents.OnPlayspaceScale.RemoveHandler(this.OnPlayspaceScale);
|
||||
}
|
||||
|
||||
void Update()
|
||||
|
@ -91,7 +88,7 @@ namespace ml_amt
|
|||
UpdateIKLimits();
|
||||
|
||||
m_emoteActive = false;
|
||||
if(m_detectEmotes && (m_locomotionLayer >= 0))
|
||||
if(Settings.DetectEmotes && (m_locomotionLayer >= 0))
|
||||
{
|
||||
AnimatorStateInfo l_animState = PlayerSetup.Instance._animator.GetCurrentAnimatorStateInfo(m_locomotionLayer);
|
||||
m_emoteActive = (l_animState.tagHash == ms_emoteHash);
|
||||
|
@ -103,7 +100,7 @@ namespace ml_amt
|
|||
}
|
||||
|
||||
// Game events
|
||||
internal void OnAvatarClear()
|
||||
void OnAvatarClear()
|
||||
{
|
||||
m_vrIk = null;
|
||||
m_locomotionLayer = -1;
|
||||
|
@ -122,7 +119,7 @@ namespace ml_amt
|
|||
BetterBetterCharacterController.Instance.avatarProneLimit = Mathf.Clamp01(Settings.ProneLimit);
|
||||
}
|
||||
|
||||
internal void OnSetupAvatar()
|
||||
void OnAvatarSetup()
|
||||
{
|
||||
Utils.SetAvatarTPose();
|
||||
|
||||
|
@ -164,20 +161,20 @@ namespace ml_amt
|
|||
|
||||
m_vrIk.solver.locomotion.offset = (Settings.MassCenter ? m_massCenter : m_locomotionOffset);
|
||||
|
||||
m_vrIk.onPreSolverUpdate.AddListener(this.OnIKPreUpdate);
|
||||
m_vrIk.onPostSolverUpdate.AddListener(this.OnIKPostUpdate);
|
||||
m_vrIk.onPreSolverUpdate.AddListener(this.OnIKPreSolverUpdate);
|
||||
m_vrIk.onPostSolverUpdate.AddListener(this.OnIKPostSolverUpdate);
|
||||
}
|
||||
|
||||
m_avatarReady = true;
|
||||
}
|
||||
|
||||
internal void OnPlayspaceScale()
|
||||
void OnPlayspaceScale()
|
||||
{
|
||||
if((m_vrIk != null) && Settings.MassCenter)
|
||||
m_vrIk.solver.locomotion.offset = m_massCenter * GetRelativeScale();
|
||||
}
|
||||
|
||||
internal void OnAvatarReinitialize()
|
||||
void OnAvatarReuse()
|
||||
{
|
||||
// Old VRIK is destroyed by game
|
||||
Utils.SetAvatarTPose();
|
||||
|
@ -187,13 +184,13 @@ namespace ml_amt
|
|||
{
|
||||
m_vrIk.solver.locomotion.offset = (Settings.MassCenter ? m_massCenter : m_locomotionOffset);
|
||||
|
||||
m_vrIk.onPreSolverUpdate.AddListener(this.OnIKPreUpdate);
|
||||
m_vrIk.onPostSolverUpdate.AddListener(this.OnIKPostUpdate);
|
||||
m_vrIk.onPreSolverUpdate.AddListener(this.OnIKPreSolverUpdate);
|
||||
m_vrIk.onPostSolverUpdate.AddListener(this.OnIKPostSolverUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
// IK events
|
||||
void OnIKPreUpdate()
|
||||
void OnIKPreSolverUpdate()
|
||||
{
|
||||
bool l_locomotionOverride = false;
|
||||
|
||||
|
@ -203,7 +200,7 @@ namespace ml_amt
|
|||
m_ikState.m_bendNormalLeft = m_vrIk.solver.leftLeg.useAnimatedBendNormal;
|
||||
m_ikState.m_bendNormalRight = m_vrIk.solver.rightLeg.useAnimatedBendNormal;
|
||||
|
||||
if(m_detectEmotes && m_emoteActive)
|
||||
if(Settings.DetectEmotes && m_emoteActive)
|
||||
m_vrIk.solver.IKPositionWeight = 0f;
|
||||
|
||||
if(!BodySystem.isCalibratedAsFullBody)
|
||||
|
@ -214,14 +211,14 @@ namespace ml_amt
|
|||
m_vrIk.solver.rightLeg.useAnimatedBendNormal = true;
|
||||
l_locomotionOverride = true;
|
||||
}
|
||||
if(m_ikOverrideFly && BetterBetterCharacterController.Instance.IsFlying())
|
||||
if(Settings.IKOverrideFly && BetterBetterCharacterController.Instance.IsFlying())
|
||||
{
|
||||
m_vrIk.solver.locomotion.weight = 0f;
|
||||
m_vrIk.solver.leftLeg.useAnimatedBendNormal = true;
|
||||
m_vrIk.solver.rightLeg.useAnimatedBendNormal = true;
|
||||
l_locomotionOverride = true;
|
||||
}
|
||||
if(m_ikOverrideJump && !m_grounded && !BetterBetterCharacterController.Instance.IsFlying())
|
||||
if(Settings.IKOverrideJump && !m_grounded && !BetterBetterCharacterController.Instance.IsFlying())
|
||||
{
|
||||
m_vrIk.solver.locomotion.weight = 0f;
|
||||
m_vrIk.solver.leftLeg.useAnimatedBendNormal = true;
|
||||
|
@ -235,7 +232,7 @@ namespace ml_amt
|
|||
m_locomotionOverride = l_locomotionOverride;
|
||||
}
|
||||
|
||||
void OnIKPostUpdate()
|
||||
void OnIKPostSolverUpdate()
|
||||
{
|
||||
m_vrIk.solver.IKPositionWeight = m_ikState.m_weight;
|
||||
m_vrIk.solver.locomotion.weight = m_ikState.m_locomotionWeight;
|
||||
|
@ -245,29 +242,17 @@ namespace ml_amt
|
|||
}
|
||||
|
||||
// Settings
|
||||
void SetCrouchLimit(float p_value)
|
||||
void OnCrouchLimitChanged(float p_value)
|
||||
{
|
||||
if(m_ikLimits == null)
|
||||
BetterBetterCharacterController.Instance.avatarCrouchLimit = Mathf.Clamp01(p_value);
|
||||
}
|
||||
void SetProneLimit(float p_value)
|
||||
void OnProneLimitChanged(float p_value)
|
||||
{
|
||||
if(m_ikLimits == null)
|
||||
BetterBetterCharacterController.Instance.avatarProneLimit = Mathf.Clamp01(p_value);
|
||||
}
|
||||
void SetIKOverrideFly(bool p_state)
|
||||
{
|
||||
m_ikOverrideFly = p_state;
|
||||
}
|
||||
void SetIKOverrideJump(bool p_state)
|
||||
{
|
||||
m_ikOverrideJump = p_state;
|
||||
}
|
||||
void SetDetectEmotes(bool p_state)
|
||||
{
|
||||
m_detectEmotes = p_state;
|
||||
}
|
||||
void OnMassCenterChange(bool p_state)
|
||||
void OnMassCenterChanged(bool p_state)
|
||||
{
|
||||
if(m_vrIk != null)
|
||||
m_vrIk.solver.locomotion.offset = (Settings.MassCenter ? (m_massCenter * GetRelativeScale()) : m_locomotionOffset);
|
||||
|
@ -290,6 +275,6 @@ namespace ml_amt
|
|||
}
|
||||
|
||||
// Parameters access
|
||||
public bool GetMoving() => m_moving;
|
||||
public bool IsMoving() => m_moving;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.3.8", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.3.9", "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)]
|
||||
|
|
|
@ -6,6 +6,14 @@ namespace ml_amt
|
|||
{
|
||||
static class Settings
|
||||
{
|
||||
internal class SettingEvent<T>
|
||||
{
|
||||
event Action<T> m_action;
|
||||
public void AddHandler(Action<T> p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action<T> p_listener) => m_action -= p_listener;
|
||||
public void Invoke(T p_value) => m_action?.Invoke(p_value);
|
||||
}
|
||||
|
||||
enum ModSetting
|
||||
{
|
||||
CrouchLimit,
|
||||
|
@ -26,12 +34,12 @@ namespace ml_amt
|
|||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
||||
public static event Action<float> CrouchLimitChange;
|
||||
public static event Action<float> ProneLimitChange;
|
||||
public static event Action<bool> IKOverrideFlyChange;
|
||||
public static event Action<bool> IKOverrideJumpChange;
|
||||
public static event Action<bool> DetectEmotesChange;
|
||||
public static event Action<bool> MassCenterChange;
|
||||
public static readonly SettingEvent<float> OnCrouchLimitChanged = new SettingEvent<float>();
|
||||
public static readonly SettingEvent<float> OnProneLimitChanged = new SettingEvent<float>();
|
||||
public static readonly SettingEvent<bool> OnIKOverrideFlyChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnIKOverrideJumpChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnDetectEmotesChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnMassCenterChanged = new SettingEvent<bool>();
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
|
@ -81,6 +89,8 @@ namespace ml_amt
|
|||
}
|
||||
|
||||
static void OnSliderUpdate(string p_name, string p_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
|
@ -89,14 +99,14 @@ namespace ml_amt
|
|||
case ModSetting.CrouchLimit:
|
||||
{
|
||||
CrouchLimit = int.Parse(p_value) * 0.01f;
|
||||
CrouchLimitChange?.Invoke(CrouchLimit);
|
||||
OnCrouchLimitChanged.Invoke(CrouchLimit);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.ProneLimit:
|
||||
{
|
||||
ProneLimit = int.Parse(p_value) * 0.01f;
|
||||
ProneLimitChange?.Invoke(ProneLimit);
|
||||
OnProneLimitChanged.Invoke(ProneLimit);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -104,8 +114,15 @@ namespace ml_amt
|
|||
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnToggleUpdate(string p_name, string p_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
|
@ -114,28 +131,28 @@ namespace ml_amt
|
|||
case ModSetting.IKOverrideFly:
|
||||
{
|
||||
IKOverrideFly = bool.Parse(p_value);
|
||||
IKOverrideFlyChange?.Invoke(IKOverrideFly);
|
||||
OnIKOverrideFlyChanged.Invoke(IKOverrideFly);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.IKOverrideJump:
|
||||
{
|
||||
IKOverrideJump = bool.Parse(p_value);
|
||||
IKOverrideJumpChange?.Invoke(IKOverrideJump);
|
||||
OnIKOverrideJumpChanged.Invoke(IKOverrideJump);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.DetectEmotes:
|
||||
{
|
||||
DetectEmotes = bool.Parse(p_value);
|
||||
DetectEmotesChange?.Invoke(DetectEmotes);
|
||||
OnDetectEmotesChanged.Invoke(DetectEmotes);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.MassCenter:
|
||||
{
|
||||
MassCenter = bool.Parse(p_value);
|
||||
MassCenterChange?.Invoke(MassCenter);
|
||||
OnMassCenterChanged.Invoke(MassCenter);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -143,5 +160,10 @@ namespace ml_amt
|
|||
ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<Company>None</Company>
|
||||
<Product>AvatarMotionTweaker</Product>
|
||||
<PackageId>AvatarMotionTweaker</PackageId>
|
||||
<Version>1.3.8</Version>
|
||||
<Version>1.3.9</Version>
|
||||
<Platforms>x64</Platforms>
|
||||
<AssemblyName>ml_amt</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_asl.AvatarSyncedLook), "AvatarSyncedLook", "1.0.2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_asl.AvatarSyncedLook), "AvatarSyncedLook", "1.0.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)]
|
||||
|
|
|
@ -6,6 +6,14 @@ namespace ml_asl
|
|||
{
|
||||
static class Settings
|
||||
{
|
||||
internal class SettingEvent<T>
|
||||
{
|
||||
event Action<T> m_action;
|
||||
public void AddHandler(Action<T> p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action<T> p_listener) => m_action -= p_listener;
|
||||
public void Invoke(T p_value) => m_action?.Invoke(p_value);
|
||||
}
|
||||
|
||||
public enum ModSetting
|
||||
{
|
||||
Enabled = 0
|
||||
|
@ -16,7 +24,7 @@ namespace ml_asl
|
|||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
||||
public static event Action<bool> EnabledChange;
|
||||
public static readonly SettingEvent<bool> OnEnabledChanged = new SettingEvent<bool>();
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
|
@ -55,6 +63,8 @@ namespace ml_asl
|
|||
}
|
||||
|
||||
static void OnToggleUpdate(string p_name, string p_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
|
@ -63,7 +73,7 @@ namespace ml_asl
|
|||
case ModSetting.Enabled:
|
||||
{
|
||||
Enabled = bool.Parse(p_value);
|
||||
EnabledChange?.Invoke(Enabled);
|
||||
OnEnabledChanged.Invoke(Enabled);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -71,5 +81,10 @@ namespace ml_asl
|
|||
ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>AvatarSyncedLook</Product>
|
||||
<Version>1.0.2</Version>
|
||||
<Version>1.0.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
|
|
@ -81,6 +81,11 @@ namespace ml_bft
|
|||
|
||||
m_pose = new HumanPose();
|
||||
m_lastValues = new float[40];
|
||||
|
||||
GameEvents.OnAvatarSetup.AddHandler(this.OnAvatarSetup);
|
||||
GameEvents.OnAvatarClear.AddHandler(this.OnAvatarClear);
|
||||
GameEvents.OnAvatarReuse.AddHandler(this.OnAvatarReuse);
|
||||
GameEvents.OnIKSystemLateUpdate.AddHandler(this.OnIKSystemLateUpdate);
|
||||
}
|
||||
internal void Cleanup()
|
||||
{
|
||||
|
@ -90,6 +95,11 @@ namespace ml_bft
|
|||
m_leftFingerOffsets.Clear();
|
||||
m_rightFingerOffsets.Clear();
|
||||
m_ready = false;
|
||||
|
||||
GameEvents.OnAvatarSetup.RemoveHandler(this.OnAvatarSetup);
|
||||
GameEvents.OnAvatarClear.RemoveHandler(this.OnAvatarClear);
|
||||
GameEvents.OnAvatarReuse.RemoveHandler(this.OnAvatarReuse);
|
||||
GameEvents.OnIKSystemLateUpdate.RemoveHandler(this.OnIKSystemLateUpdate);
|
||||
}
|
||||
|
||||
internal void OnAvatarSetup()
|
||||
|
@ -173,7 +183,7 @@ namespace ml_bft
|
|||
m_rightFingerOffsets.Clear();
|
||||
}
|
||||
|
||||
internal void OnReinitializeAvatar()
|
||||
internal void OnAvatarReuse()
|
||||
{
|
||||
OnAvatarClear();
|
||||
OnAvatarSetup();
|
||||
|
|
133
ml_bft/GameEvents.cs
Normal file
133
ml_bft/GameEvents.cs
Normal file
|
@ -0,0 +1,133 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK;
|
||||
using ABI_RC.Systems.InputManagement;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_bft
|
||||
{
|
||||
static class GameEvents
|
||||
{
|
||||
internal class GameEvent
|
||||
{
|
||||
event Action m_action;
|
||||
public void AddHandler(Action p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action p_listener) => m_action -= p_listener;
|
||||
public void Invoke() => m_action?.Invoke();
|
||||
}
|
||||
internal class GameEvent<T1, T2>
|
||||
{
|
||||
event Action<T1, T2> m_action;
|
||||
public void AddHandler(Action<T1, T2> p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action<T1, T2> p_listener) => m_action -= p_listener;
|
||||
public void Invoke(T1 p_objA, T2 p_objB) => m_action?.Invoke(p_objA, p_objB);
|
||||
}
|
||||
|
||||
public static readonly GameEvent OnAvatarSetup = new GameEvent();
|
||||
public static readonly GameEvent OnAvatarClear = new GameEvent();
|
||||
public static readonly GameEvent OnAvatarReuse = new GameEvent();
|
||||
public static readonly GameEvent OnInputUpdate = new GameEvent();
|
||||
public static readonly GameEvent<HumanPoseHandler, Transform> OnIKSystemLateUpdate = new GameEvent<HumanPoseHandler, Transform>();
|
||||
|
||||
internal static void Init(HarmonyLib.Harmony p_instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
p_instance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(CVRInputManager).GetMethod("UpdateInput", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnInputUpdate_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(IKSystem).GetMethod("LateUpdate", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnIKSystemLateUpdate_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarClear_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarClear.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarSetup.Invoke();
|
||||
}
|
||||
catch(Exception l_exception)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(l_exception);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarReinitialize_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarReuse.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnInputUpdate_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnInputUpdate.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnIKSystemLateUpdate_Postfix(HumanPoseHandler ____humanPoseHandler, Transform ____hipTransform)
|
||||
{
|
||||
try
|
||||
{
|
||||
OnIKSystemLateUpdate.Invoke(____humanPoseHandler, ____hipTransform);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ namespace ml_bft
|
|||
m_localRotations = new List<Quaternion>();
|
||||
m_renderers = new List<Renderer>();
|
||||
|
||||
Settings.ShowHandsChange += this.OnShowHandsChange;
|
||||
Settings.OnShowHandsChanged.AddHandler(this.OnShowHandsChanged);
|
||||
}
|
||||
|
||||
public virtual void Cleanup()
|
||||
|
@ -31,7 +31,7 @@ namespace ml_bft
|
|||
m_localRotations.Clear();
|
||||
m_renderers.Clear();
|
||||
|
||||
Settings.ShowHandsChange -= this.OnShowHandsChange;
|
||||
Settings.OnShowHandsChanged.RemoveHandler(this.OnShowHandsChanged);
|
||||
}
|
||||
|
||||
public virtual void Update()
|
||||
|
@ -47,7 +47,7 @@ namespace ml_bft
|
|||
{
|
||||
}
|
||||
|
||||
protected void OnShowHandsChange(bool p_state)
|
||||
protected void OnShowHandsChanged(bool p_state)
|
||||
{
|
||||
foreach(var l_render in m_renderers)
|
||||
{
|
||||
|
|
|
@ -75,10 +75,10 @@ namespace ml_bft
|
|||
|
||||
m_skeletonAction = SteamVR_Input.GetAction<SteamVR_Action_Skeleton>(p_left ? "SkeletonLeftHand" : "SkeletonRightHand");
|
||||
|
||||
base.OnShowHandsChange(Settings.ShowHands);
|
||||
OnMotionRangeChange(Settings.MotionRange);
|
||||
base.OnShowHandsChanged(Settings.ShowHands);
|
||||
OnMotionRangeChanged(Settings.MotionRange);
|
||||
|
||||
Settings.MotionRangeChange += this.OnMotionRangeChange;
|
||||
Settings.OnMotionRangeChanged.AddHandler(this.OnMotionRangeChanged);
|
||||
}
|
||||
|
||||
public override void Cleanup()
|
||||
|
@ -87,7 +87,7 @@ namespace ml_bft
|
|||
|
||||
m_skeletonAction = null;
|
||||
|
||||
Settings.MotionRangeChange -= this.OnMotionRangeChange;
|
||||
Settings.OnMotionRangeChanged.RemoveHandler(this.OnMotionRangeChanged);
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
|
@ -233,7 +233,7 @@ namespace ml_bft
|
|||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.root].rotation = p_base * (m_left ? Quaternion.Euler(0f, -90f, -90f) : Quaternion.Euler(0f, 90f, 90f));
|
||||
}
|
||||
|
||||
void OnMotionRangeChange(Settings.MotionRangeType p_mode)
|
||||
void OnMotionRangeChanged(Settings.MotionRangeType p_mode)
|
||||
{
|
||||
switch(p_mode)
|
||||
{
|
||||
|
|
|
@ -65,7 +65,7 @@ namespace ml_bft
|
|||
m_localRotations[i] = m_bones[i].localRotation;
|
||||
}
|
||||
|
||||
base.OnShowHandsChange(Settings.ShowHands);
|
||||
base.OnShowHandsChanged(Settings.ShowHands);
|
||||
}
|
||||
|
||||
public override Transform GetSourceForBone(HumanBodyBones p_bone)
|
||||
|
|
|
@ -28,7 +28,9 @@ namespace ml_bft
|
|||
VRModeSwitchEvents.OnInitializeXR.AddListener(this.OnSwitchToVR);
|
||||
VRModeSwitchEvents.OnDeinitializeXR.AddListener(this.OnSwitchToDesktop);
|
||||
|
||||
Settings.SkeletalInputChange += this.OnSkeletalInputChange;
|
||||
Settings.OnSkeletalInputChanged.AddHandler(this.OnSkeletalInputChanged);
|
||||
|
||||
GameEvents.OnInputUpdate.AddHandler(this.OnInputUpdate);
|
||||
}
|
||||
internal void Cleanup()
|
||||
{
|
||||
|
@ -36,6 +38,10 @@ namespace ml_bft
|
|||
Instance = null;
|
||||
|
||||
RemoveHandlers();
|
||||
|
||||
Settings.OnSkeletalInputChanged.RemoveHandler(this.OnSkeletalInputChanged);
|
||||
|
||||
GameEvents.OnInputUpdate.RemoveHandler(this.OnInputUpdate);
|
||||
}
|
||||
|
||||
void SetupHandlers()
|
||||
|
@ -152,7 +158,7 @@ namespace ml_bft
|
|||
}
|
||||
|
||||
// Settings
|
||||
void OnSkeletalInputChange(bool p_value)
|
||||
void OnSkeletalInputChanged(bool p_value)
|
||||
{
|
||||
if(!p_value)
|
||||
CVRInputManager.Instance.individualFingerTracking = Utils.AreKnucklesInUse();
|
||||
|
|
111
ml_bft/Main.cs
111
ml_bft/Main.cs
|
@ -1,60 +1,23 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK;
|
||||
using ABI_RC.Systems.InputManagement;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace ml_bft
|
||||
{
|
||||
public class BetterFingersTracking : MelonLoader.MelonMod
|
||||
{
|
||||
static BetterFingersTracking ms_instance = null;
|
||||
|
||||
InputHandler m_inputHandler = null;
|
||||
FingerSystem m_fingerSystem = null;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
if(ms_instance == null)
|
||||
ms_instance = this;
|
||||
|
||||
Settings.Init();
|
||||
AssetsHandler.Load();
|
||||
|
||||
// Needed patches: avatar initialization and reinitialization on vr switch, after input update, after late iksystem update
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(BetterFingersTracking).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(BetterFingersTracking).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(BetterFingersTracking).GetMethod(nameof(OnReinitializeAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRInputManager).GetMethod("UpdateInput", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(BetterFingersTracking).GetMethod(nameof(OnInputUpdate_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(IKSystem).GetMethod("LateUpdate", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(BetterFingersTracking).GetMethod(nameof(OnIKSystemLateUpdate_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
GameEvents.Init(HarmonyInstance);
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForInstances());
|
||||
}
|
||||
IEnumerator WaitForInstances()
|
||||
{
|
||||
while(CVRInputManager.Instance == null)
|
||||
while(ABI_RC.Systems.InputManagement.CVRInputManager.Instance == null)
|
||||
yield return null;
|
||||
|
||||
m_inputHandler = new InputHandler();
|
||||
|
@ -63,79 +26,11 @@ namespace ml_bft
|
|||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
m_inputHandler?.Cleanup();
|
||||
m_inputHandler = null;
|
||||
|
||||
m_fingerSystem?.Cleanup();
|
||||
m_fingerSystem = null;
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar();
|
||||
void OnSetupAvatar()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_fingerSystem?.OnAvatarSetup();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear();
|
||||
void OnAvatarClear()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_fingerSystem?.OnAvatarClear();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnReinitializeAvatar_Postfix() => ms_instance?.OnAvatarReinitialize();
|
||||
void OnAvatarReinitialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_fingerSystem?.OnReinitializeAvatar();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnInputUpdate_Postfix() => ms_instance?.OnInputUpdate();
|
||||
void OnInputUpdate()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_inputHandler?.OnInputUpdate();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnIKSystemLateUpdate_Postfix(HumanPoseHandler ____humanPoseHandler, Transform ____hipTransform) => ms_instance?.OnIKSystemLateUpdate(____humanPoseHandler, ____hipTransform);
|
||||
void OnIKSystemLateUpdate(HumanPoseHandler p_handler, Transform p_hips)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_fingerSystem?.OnIKSystemLateUpdate(p_handler, p_hips);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_bft.BetterFingersTracking), "BetterFingersTracking", "1.0.2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_bft.BetterFingersTracking), "BetterFingersTracking", "1.0.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)]
|
||||
|
|
|
@ -6,6 +6,14 @@ namespace ml_bft
|
|||
{
|
||||
static class Settings
|
||||
{
|
||||
internal class SettingEvent<T>
|
||||
{
|
||||
event Action<T> m_action;
|
||||
public void AddHandler(Action<T> p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action<T> p_listener) => m_action -= p_listener;
|
||||
public void Invoke(T p_value) => m_action?.Invoke(p_value);
|
||||
}
|
||||
|
||||
public enum MotionRangeType
|
||||
{
|
||||
WithController = 0,
|
||||
|
@ -27,10 +35,10 @@ namespace ml_bft
|
|||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
||||
public static event Action<bool> SkeletalInputChange;
|
||||
public static event Action<MotionRangeType> MotionRangeChange;
|
||||
public static event Action<bool> ShowHandsChange;
|
||||
public static event Action<bool> MechanimFilterChange;
|
||||
public static readonly SettingEvent<bool> OnSkeletalInputChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<MotionRangeType> OnMotionRangeChanged = new SettingEvent<MotionRangeType>();
|
||||
public static readonly SettingEvent<bool> OnShowHandsChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnMechanimFilterChanged = new SettingEvent<bool>();
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
|
@ -75,6 +83,8 @@ namespace ml_bft
|
|||
}
|
||||
|
||||
static void OnToggleUpdate(string p_name, string p_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
|
@ -83,21 +93,21 @@ namespace ml_bft
|
|||
case ModSetting.SkeletalInput:
|
||||
{
|
||||
SkeletalInput = bool.Parse(p_value);
|
||||
SkeletalInputChange?.Invoke(SkeletalInput);
|
||||
OnSkeletalInputChanged.Invoke(SkeletalInput);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.ShowHands:
|
||||
{
|
||||
ShowHands = bool.Parse(p_value);
|
||||
ShowHandsChange?.Invoke(ShowHands);
|
||||
OnShowHandsChanged.Invoke(ShowHands);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.MechanimFilter:
|
||||
{
|
||||
MechanimFilter = bool.Parse(p_value);
|
||||
MechanimFilterChange?.Invoke(MechanimFilter);
|
||||
OnMechanimFilterChanged.Invoke(MechanimFilter);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -105,8 +115,15 @@ namespace ml_bft
|
|||
ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnDropdownUpdate(string p_name, string p_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
|
@ -115,7 +132,7 @@ namespace ml_bft
|
|||
case ModSetting.MotionRange:
|
||||
{
|
||||
MotionRange = (MotionRangeType)int.Parse(p_value);
|
||||
MotionRangeChange?.Invoke(MotionRange);
|
||||
OnMotionRangeChanged.Invoke(MotionRange);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -123,5 +140,10 @@ namespace ml_bft
|
|||
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>BetterFingersTracking</Product>
|
||||
<Version>1.0.2</Version>
|
||||
<Version>1.0.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
|
157
ml_dht/GameEvents.cs
Normal file
157
ml_dht/GameEvents.cs
Normal file
|
@ -0,0 +1,157 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Player.EyeMovement;
|
||||
using ABI_RC.Systems.IK;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ml_dht
|
||||
{
|
||||
static class GameEvents
|
||||
{
|
||||
internal class EventResult
|
||||
{
|
||||
public bool m_result = false;
|
||||
}
|
||||
internal class GameEvent
|
||||
{
|
||||
event Action m_action;
|
||||
public void AddHandler(Action p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action p_listener) => m_action -= p_listener;
|
||||
public void Invoke() => m_action?.Invoke();
|
||||
}
|
||||
internal class GameEvent<T1>
|
||||
{
|
||||
event Action<T1> m_action;
|
||||
public void AddHandler(Action<T1> p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action<T1> p_listener) => m_action -= p_listener;
|
||||
public void Invoke(T1 p_obj) => m_action?.Invoke(p_obj);
|
||||
}
|
||||
internal class GameEvent<T1, T2>
|
||||
{
|
||||
event Action<T1, T2> m_action;
|
||||
public void AddHandler(Action<T1, T2> p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action<T1, T2> p_listener) => m_action -= p_listener;
|
||||
public void Invoke(T1 p_objA, T2 p_objB) => m_action?.Invoke(p_objA, p_objB);
|
||||
}
|
||||
|
||||
public static readonly GameEvent OnAvatarSetup = new GameEvent();
|
||||
public static readonly GameEvent OnAvatarClear = new GameEvent();
|
||||
public static readonly GameEvent OnAvatarReuse = new GameEvent();
|
||||
public static readonly GameEvent<EyeMovementController> OnEyeControllerUpdate = new GameEvent<EyeMovementController>();
|
||||
public static readonly GameEvent<CVRFaceTracking, EventResult> OnFaceTrackingUpdate = new GameEvent<CVRFaceTracking, EventResult>();
|
||||
|
||||
static readonly EventResult ms_result = new EventResult();
|
||||
|
||||
internal static void InitA(HarmonyLib.Harmony p_instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
p_instance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
internal static void InitB(HarmonyLib.Harmony p_instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
p_instance.Patch(
|
||||
typeof(EyeMovementController).GetMethod("Update", BindingFlags.Instance | BindingFlags.NonPublic),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnEyeControllerUpdate_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(CVRFaceTracking).GetMethod("UpdateLocalData", BindingFlags.Instance | BindingFlags.NonPublic),
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnFaceTrackingLocalUpdate_Prefix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarSetup.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarClear_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarClear.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarReinitialize_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarReuse.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnEyeControllerUpdate_Postfix(ref EyeMovementController __instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
OnEyeControllerUpdate.Invoke(__instance);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static bool OnFaceTrackingLocalUpdate_Prefix(ref CVRFaceTracking __instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
ms_result.m_result = false;
|
||||
OnFaceTrackingUpdate.Invoke(__instance, ms_result);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
return !ms_result.m_result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -47,20 +47,32 @@ namespace ml_dht
|
|||
// Unity events
|
||||
void Start()
|
||||
{
|
||||
SetEnabled(Settings.Enabled);
|
||||
SetHeadTracking(Settings.HeadTracking);
|
||||
SetSmoothing(Settings.Smoothing);
|
||||
OnEnabledChanged(Settings.Enabled);
|
||||
OnHeadTrackingChanged(Settings.HeadTracking);
|
||||
OnSmoothingChanged(Settings.Smoothing);
|
||||
|
||||
Settings.EnabledChange += this.SetEnabled;
|
||||
Settings.HeadTrackingChange += this.SetHeadTracking;
|
||||
Settings.SmoothingChange += this.SetSmoothing;
|
||||
Settings.OnEnabledChanged.AddHandler(this.OnEnabledChanged);
|
||||
Settings.OnHeadTrackingChanged.AddHandler(this.OnHeadTrackingChanged);
|
||||
Settings.OnSmoothingChanged.AddHandler(this.OnSmoothingChanged);
|
||||
|
||||
GameEvents.OnAvatarClear.AddHandler(this.OnAvatarClear);
|
||||
GameEvents.OnAvatarSetup.AddHandler(this.OnAvatarSetup);
|
||||
GameEvents.OnAvatarReuse.AddHandler(this.OnAvatarReuse);
|
||||
GameEvents.OnEyeControllerUpdate.AddHandler(this.OnEyeControllerUpdate);
|
||||
GameEvents.OnFaceTrackingUpdate.AddHandler(this.UpdateFaceTracking);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
Settings.EnabledChange -= this.SetEnabled;
|
||||
Settings.HeadTrackingChange -= this.SetHeadTracking;
|
||||
Settings.SmoothingChange -= this.SetSmoothing;
|
||||
Settings.OnEnabledChanged.RemoveHandler(this.OnEnabledChanged);
|
||||
Settings.OnHeadTrackingChanged.RemoveHandler(this.OnHeadTrackingChanged);
|
||||
Settings.OnSmoothingChanged.RemoveHandler(this.OnSmoothingChanged);
|
||||
|
||||
GameEvents.OnAvatarClear.RemoveHandler(this.OnAvatarClear);
|
||||
GameEvents.OnAvatarSetup.RemoveHandler(this.OnAvatarSetup);
|
||||
GameEvents.OnAvatarReuse.RemoveHandler(this.OnAvatarReuse);
|
||||
GameEvents.OnEyeControllerUpdate.RemoveHandler(this.OnEyeControllerUpdate);
|
||||
GameEvents.OnFaceTrackingUpdate.RemoveHandler(this.UpdateFaceTracking);
|
||||
}
|
||||
|
||||
void Update()
|
||||
|
@ -96,7 +108,7 @@ namespace ml_dht
|
|||
}
|
||||
|
||||
// Game events
|
||||
internal void OnSetupAvatar()
|
||||
internal void OnAvatarSetup()
|
||||
{
|
||||
Utils.SetAvatarTPose();
|
||||
|
||||
|
@ -112,7 +124,7 @@ namespace ml_dht
|
|||
m_lookIK.onPostSolverUpdate.AddListener(this.OnLookIKPostUpdate);
|
||||
|
||||
}
|
||||
internal void OnAvatarClear()
|
||||
void OnAvatarClear()
|
||||
{
|
||||
m_avatarDescriptor = null;
|
||||
m_lookIK = null;
|
||||
|
@ -120,7 +132,7 @@ namespace ml_dht
|
|||
m_lastHeadRotation = Quaternion.identity;
|
||||
m_bindRotation = Quaternion.identity;
|
||||
}
|
||||
internal void OnAvatarReinitialize()
|
||||
void OnAvatarReuse()
|
||||
{
|
||||
m_camera = PlayerSetup.Instance.GetActiveCamera().transform;
|
||||
m_lookIK = PlayerSetup.Instance._avatar.GetComponent<LookAtIK>();
|
||||
|
@ -128,7 +140,7 @@ namespace ml_dht
|
|||
m_lookIK.onPostSolverUpdate.AddListener(this.OnLookIKPostUpdate);
|
||||
}
|
||||
|
||||
internal void OnEyeControllerUpdate(EyeMovementController p_component)
|
||||
void OnEyeControllerUpdate(EyeMovementController p_component)
|
||||
{
|
||||
if(m_enabled)
|
||||
{
|
||||
|
@ -148,10 +160,9 @@ namespace ml_dht
|
|||
}
|
||||
}
|
||||
|
||||
internal bool UpdateFaceTracking(CVRFaceTracking p_component)
|
||||
void UpdateFaceTracking(CVRFaceTracking p_component, GameEvents.EventResult p_result)
|
||||
{
|
||||
bool l_result = false;
|
||||
if(m_enabled && Settings.FaceTracking)
|
||||
if(p_component.isLocal && p_component.UseFacialTracking && m_enabled && Settings.FaceTracking)
|
||||
{
|
||||
if(!m_lipDataSent)
|
||||
{
|
||||
|
@ -161,13 +172,12 @@ namespace ml_dht
|
|||
p_component.LipSyncWasUpdated = true;
|
||||
p_component.UpdateShapesLocal_Private();
|
||||
|
||||
l_result = true;
|
||||
p_result.m_result |= true;
|
||||
}
|
||||
return l_result;
|
||||
}
|
||||
|
||||
// Settings
|
||||
void SetEnabled(bool p_state)
|
||||
void OnEnabledChanged(bool p_state)
|
||||
{
|
||||
if(m_enabled != p_state)
|
||||
{
|
||||
|
@ -175,7 +185,7 @@ namespace ml_dht
|
|||
TryRestoreHeadRotation();
|
||||
}
|
||||
}
|
||||
void SetHeadTracking(bool p_state)
|
||||
void OnHeadTrackingChanged(bool p_state)
|
||||
{
|
||||
if(m_headTracking != p_state)
|
||||
{
|
||||
|
@ -183,7 +193,7 @@ namespace ml_dht
|
|||
TryRestoreHeadRotation();
|
||||
}
|
||||
}
|
||||
void SetSmoothing(float p_value)
|
||||
void OnSmoothingChanged(float p_value)
|
||||
{
|
||||
m_smoothing = 1f - Mathf.Clamp(p_value, 0f, 0.99f);
|
||||
}
|
||||
|
|
112
ml_dht/Main.cs
112
ml_dht/Main.cs
|
@ -1,42 +1,17 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Player.EyeMovement;
|
||||
using ABI_RC.Core.Savior;
|
||||
using ABI_RC.Systems.IK;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ml_dht
|
||||
{
|
||||
public class DesktopHeadTracking : MelonLoader.MelonMod
|
||||
{
|
||||
static DesktopHeadTracking ms_instance = null;
|
||||
|
||||
DataParser m_dataParser = null;
|
||||
HeadTracked m_localTracked = null;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
if(ms_instance == null)
|
||||
ms_instance = this;
|
||||
|
||||
Settings.Init();
|
||||
|
||||
// Patches
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
GameEvents.InitA(HarmonyInstance);
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForInstances());
|
||||
}
|
||||
|
@ -49,26 +24,14 @@ namespace ml_dht
|
|||
while(PlayerSetup.Instance == null)
|
||||
yield return null;
|
||||
|
||||
GameEvents.InitB(HarmonyInstance);
|
||||
|
||||
m_dataParser = new DataParser();
|
||||
m_localTracked = PlayerSetup.Instance.gameObject.AddComponent<HeadTracked>();
|
||||
|
||||
// If you think it's a joke to put patch here, go on, try to put it in OnInitializeMelon, you melon :>
|
||||
HarmonyInstance.Patch(
|
||||
typeof(EyeMovementController).GetMethod("Update", BindingFlags.Instance | BindingFlags.NonPublic),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnEyeControllerUpdate_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRFaceTracking).GetMethod("UpdateLocalData", BindingFlags.Instance | BindingFlags.NonPublic),
|
||||
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnFaceTrackingLocalUpdate_Prefix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
}
|
||||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
m_dataParser = null;
|
||||
m_localTracked = null;
|
||||
}
|
||||
|
@ -82,74 +45,5 @@ namespace ml_dht
|
|||
m_localTracked.UpdateTrackingData(ref m_dataParser.GetLatestTrackingData());
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar();
|
||||
void OnSetupAvatar()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localTracked != null)
|
||||
m_localTracked.OnSetupAvatar();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear();
|
||||
void OnAvatarClear()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localTracked != null)
|
||||
m_localTracked.OnAvatarClear();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarReinitialize_Postfix() => ms_instance?.OnAvatarReinitialize();
|
||||
void OnAvatarReinitialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localTracked != null)
|
||||
m_localTracked.OnAvatarReinitialize();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnEyeControllerUpdate_Postfix(ref EyeMovementController __instance) => ms_instance?.OnEyeControllerUpdate(__instance);
|
||||
void OnEyeControllerUpdate(EyeMovementController p_component)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(p_component.IsLocal && (m_localTracked != null))
|
||||
m_localTracked.OnEyeControllerUpdate(p_component);
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static bool OnFaceTrackingLocalUpdate_Prefix(ref CVRFaceTracking __instance)
|
||||
{
|
||||
bool? l_result = ms_instance?.OnFaceTrackingLocalUpdate(__instance);
|
||||
return l_result.GetValueOrDefault(true);
|
||||
}
|
||||
bool OnFaceTrackingLocalUpdate(CVRFaceTracking p_component)
|
||||
{
|
||||
bool l_result = true;
|
||||
if(p_component.UseFacialTracking && (m_localTracked != null))
|
||||
l_result = !m_localTracked.UpdateFaceTracking(p_component);
|
||||
return l_result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_dht.DesktopHeadTracking), "DesktopHeadTracking", "1.2.2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_dht.DesktopHeadTracking), "DesktopHeadTracking", "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)]
|
|
@ -6,6 +6,14 @@ namespace ml_dht
|
|||
{
|
||||
static class Settings
|
||||
{
|
||||
internal class SettingEvent<T>
|
||||
{
|
||||
event Action<T> m_action;
|
||||
public void AddHandler(Action<T> p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action<T> p_listener) => m_action -= p_listener;
|
||||
public void Invoke(T p_value) => m_action?.Invoke(p_value);
|
||||
}
|
||||
|
||||
enum ModSetting
|
||||
{
|
||||
Enabled = 0,
|
||||
|
@ -28,13 +36,13 @@ namespace ml_dht
|
|||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
||||
public static event Action<bool> EnabledChange;
|
||||
public static event Action<bool> HeadTrackingChange;
|
||||
public static event Action<bool> EyeTrackingChange;
|
||||
public static event Action<bool> FaceTrackingChange;
|
||||
public static event Action<bool> BlinkingChange;
|
||||
public static event Action<bool> MirroredChange;
|
||||
public static event Action<float> SmoothingChange;
|
||||
public static readonly SettingEvent<bool> OnEnabledChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnHeadTrackingChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnEyeTrackingChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnFaceTrackingChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnBlinkingChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnMirroredChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<float> OnSmoothingChanged = new SettingEvent<float>();
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
|
@ -86,6 +94,8 @@ namespace ml_dht
|
|||
}
|
||||
|
||||
static void OnSliderUpdate(string p_name, string p_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
|
@ -94,7 +104,7 @@ namespace ml_dht
|
|||
case ModSetting.Smoothing:
|
||||
{
|
||||
Smoothing = int.Parse(p_value) * 0.01f;
|
||||
SmoothingChange?.Invoke(Smoothing);
|
||||
OnSmoothingChanged.Invoke(Smoothing);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -102,8 +112,15 @@ namespace ml_dht
|
|||
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnToggleUpdate(string p_name, string p_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
|
@ -112,42 +129,42 @@ namespace ml_dht
|
|||
case ModSetting.Enabled:
|
||||
{
|
||||
Enabled = bool.Parse(p_value);
|
||||
EnabledChange?.Invoke(Enabled);
|
||||
OnEnabledChanged.Invoke(Enabled);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.HeadTracking:
|
||||
{
|
||||
HeadTracking = bool.Parse(p_value);
|
||||
HeadTrackingChange?.Invoke(HeadTracking);
|
||||
OnHeadTrackingChanged.Invoke(HeadTracking);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.EyeTracking:
|
||||
{
|
||||
EyeTracking = bool.Parse(p_value);
|
||||
EyeTrackingChange?.Invoke(EyeTracking);
|
||||
OnEyeTrackingChanged.Invoke(EyeTracking);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.FaceTracking:
|
||||
{
|
||||
FaceTracking = bool.Parse(p_value);
|
||||
FaceTrackingChange?.Invoke(FaceTracking);
|
||||
OnFaceTrackingChanged.Invoke(FaceTracking);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.Blinking:
|
||||
{
|
||||
Blinking = bool.Parse(p_value);
|
||||
BlinkingChange?.Invoke(Blinking);
|
||||
OnBlinkingChanged.Invoke(Blinking);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.Mirrored:
|
||||
{
|
||||
Mirrored = bool.Parse(p_value);
|
||||
MirroredChange?.Invoke(Mirrored);
|
||||
OnMirroredChanged.Invoke(Mirrored);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -155,5 +172,10 @@ namespace ml_dht
|
|||
ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>DesktopHeadTracking</Product>
|
||||
<Version>1.2.2</Version>
|
||||
<Version>1.2.3</Version>
|
||||
<Platforms>x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
|
|
151
ml_lme/GameEvents.cs
Normal file
151
ml_lme/GameEvents.cs
Normal file
|
@ -0,0 +1,151 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ml_lme
|
||||
{
|
||||
static class GameEvents
|
||||
{
|
||||
internal class GameEvent
|
||||
{
|
||||
event Action m_action;
|
||||
public void AddHandler(Action p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action p_listener) => m_action -= p_listener;
|
||||
public void Invoke() => m_action?.Invoke();
|
||||
}
|
||||
internal class GameEvent<T1>
|
||||
{
|
||||
event Action<T1> m_action;
|
||||
public void AddHandler(Action<T1> p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action<T1> p_listener) => m_action -= p_listener;
|
||||
public void Invoke(T1 p_obj) => m_action?.Invoke(p_obj);
|
||||
}
|
||||
|
||||
public static readonly GameEvent OnAvatarSetup = new GameEvent();
|
||||
public static readonly GameEvent OnAvatarClear = new GameEvent();
|
||||
public static readonly GameEvent OnAvatarReuse = new GameEvent();
|
||||
public static readonly GameEvent<float> OnRayScale = new GameEvent<float>();
|
||||
public static readonly GameEvent<float> OnPlayspaceScale = new GameEvent<float>();
|
||||
public static readonly GameEvent<CVRPickupObject> OnPickupGrab = new GameEvent<CVRPickupObject>();
|
||||
|
||||
internal static void Init(HarmonyLib.Harmony p_instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
p_instance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetControllerRayScale)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnRayScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(PlayerSetup).GetMethod("SetPlaySpaceScale", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnPlayspaceScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(CVRPickupObject).GetMethod(nameof(CVRPickupObject.Grab), BindingFlags.Public | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnPickupGrab_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarClear_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarClear.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarSetup.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarReinitialize_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarReuse.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnRayScale_Postfix(float __0)
|
||||
{
|
||||
try
|
||||
{
|
||||
OnRayScale.Invoke(__0);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnPlayspaceScale_Postfix(float ____avatarScaleRelation)
|
||||
{
|
||||
try
|
||||
{
|
||||
OnPlayspaceScale.Invoke(____avatarScaleRelation);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnPickupGrab_Postfix(ref CVRPickupObject __instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
OnPickupGrab.Invoke(__instance);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -81,21 +81,24 @@ namespace ml_lme
|
|||
m_handRayLeft.otherRay = m_handRayRight;
|
||||
m_handRayRight.otherRay = m_handRayLeft;
|
||||
|
||||
Settings.EnabledChange += this.OnEnableChange;
|
||||
Settings.InteractionChange += this.OnInteractionChange;
|
||||
Settings.GesturesChange += this.OnGesturesChange;
|
||||
Settings.FingersOnlyChange += this.OnFingersOnlyChange;
|
||||
|
||||
OnEnableChange(Settings.Enabled);
|
||||
OnInteractionChange(Settings.Interaction);
|
||||
OnGesturesChange(Settings.Gestures);
|
||||
OnFingersOnlyChange(Settings.FingersOnly);
|
||||
OnEnableChanged(Settings.Enabled);
|
||||
OnInteractionChanged(Settings.Interaction);
|
||||
OnGesturesChanged(Settings.Gestures);
|
||||
OnFingersOnlyChanged(Settings.FingersOnly);
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForSettings());
|
||||
MelonLoader.MelonCoroutines.Start(WaitForMaterial());
|
||||
|
||||
VRModeSwitchEvents.OnInitializeXR.AddListener(OnModeSwitch);
|
||||
VRModeSwitchEvents.OnDeinitializeXR.AddListener(OnModeSwitch);
|
||||
|
||||
Settings.OnEnabledChanged.AddHandler(this.OnEnableChanged);
|
||||
Settings.OnInteractionChanged.AddHandler(this.OnInteractionChanged);
|
||||
Settings.OnGesturesChanged.AddHandler(this.OnGesturesChanged);
|
||||
Settings.OnFingersOnlyChanged.AddHandler(this.OnFingersOnlyChanged);
|
||||
|
||||
GameEvents.OnRayScale.AddHandler(this.OnRayScale);
|
||||
GameEvents.OnPickupGrab.AddHandler(this.OnPickupGrab);
|
||||
}
|
||||
|
||||
IEnumerator WaitForSettings()
|
||||
|
@ -149,14 +152,17 @@ namespace ml_lme
|
|||
Object.Destroy(m_lineRight);
|
||||
m_lineRight = null;
|
||||
|
||||
Settings.EnabledChange -= this.OnEnableChange;
|
||||
Settings.InteractionChange -= this.OnInteractionChange;
|
||||
Settings.GesturesChange -= this.OnGesturesChange;
|
||||
Settings.FingersOnlyChange -= this.OnFingersOnlyChange;
|
||||
|
||||
MetaPort.Instance.settings.settingBoolChanged.RemoveListener(this.OnGameSettingBoolChange);
|
||||
VRModeSwitchEvents.OnInitializeXR.RemoveListener(OnModeSwitch);
|
||||
VRModeSwitchEvents.OnDeinitializeXR.RemoveListener(OnModeSwitch);
|
||||
|
||||
Settings.OnEnabledChanged.RemoveHandler(this.OnEnableChanged);
|
||||
Settings.OnInteractionChanged.RemoveHandler(this.OnInteractionChanged);
|
||||
Settings.OnGesturesChanged.RemoveHandler(this.OnGesturesChanged);
|
||||
Settings.OnFingersOnlyChanged.RemoveHandler(this.OnFingersOnlyChanged);
|
||||
|
||||
GameEvents.OnRayScale.RemoveHandler(this.OnRayScale);
|
||||
GameEvents.OnPickupGrab.RemoveHandler(this.OnPickupGrab);
|
||||
}
|
||||
|
||||
public override void UpdateInput()
|
||||
|
@ -360,7 +366,7 @@ namespace ml_lme
|
|||
}
|
||||
|
||||
// Settings changes
|
||||
void OnEnableChange(bool p_state)
|
||||
void OnEnableChanged(bool p_state)
|
||||
{
|
||||
base.InputEnabled = p_state;
|
||||
|
||||
|
@ -382,10 +388,10 @@ namespace ml_lme
|
|||
SetGameFingersTracking(m_inVR && Utils.AreKnucklesInUse() && !CVRInputManager._moduleXR.GestureToggleValue);
|
||||
}
|
||||
|
||||
OnInteractionChange(Settings.Interaction);
|
||||
OnInteractionChanged(Settings.Interaction);
|
||||
}
|
||||
|
||||
void OnInteractionChange(bool p_state)
|
||||
void OnInteractionChanged(bool p_state)
|
||||
{
|
||||
bool l_state = (p_state && Settings.Enabled && !Settings.FingersOnly);
|
||||
|
||||
|
@ -407,7 +413,7 @@ namespace ml_lme
|
|||
}
|
||||
}
|
||||
|
||||
void OnGesturesChange(bool p_state)
|
||||
void OnGesturesChanged(bool p_state)
|
||||
{
|
||||
base._inputManager.gestureLeft = 0f;
|
||||
base._inputManager.gestureLeftRaw = 0f;
|
||||
|
@ -415,19 +421,19 @@ namespace ml_lme
|
|||
base._inputManager.gestureRightRaw = 0f;
|
||||
}
|
||||
|
||||
void OnFingersOnlyChange(bool p_state)
|
||||
void OnFingersOnlyChanged(bool p_state)
|
||||
{
|
||||
OnInteractionChange(Settings.Interaction);
|
||||
OnInteractionChanged(Settings.Interaction);
|
||||
}
|
||||
|
||||
// Game events
|
||||
internal void OnRayScale(float p_scale)
|
||||
void OnRayScale(float p_scale)
|
||||
{
|
||||
m_handRayLeft.SetRayScale(p_scale);
|
||||
m_handRayRight.SetRayScale(p_scale);
|
||||
}
|
||||
|
||||
internal void OnPickupGrab(CVRPickupObject p_pickup)
|
||||
void OnPickupGrab(CVRPickupObject p_pickup)
|
||||
{
|
||||
if(p_pickup.gripType == CVRPickupObject.GripType.Origin)
|
||||
{
|
||||
|
@ -460,7 +466,7 @@ namespace ml_lme
|
|||
m_handRayRight.SetVRActive(m_inVR);
|
||||
}
|
||||
|
||||
OnEnableChange(Settings.Enabled);
|
||||
OnEnableChanged(Settings.Enabled);
|
||||
}
|
||||
|
||||
// Arbitrary
|
||||
|
@ -493,11 +499,11 @@ namespace ml_lme
|
|||
base._inputManager.finger3StretchedLeftPinky = LeapTracked.ms_lastLeftFingerBones[18];
|
||||
base._inputManager.fingerSpreadLeftPinky = LeapTracked.ms_lastLeftFingerBones[19];
|
||||
|
||||
base._inputManager.fingerFullCurlNormalizedLeftThumb = p_hand.m_bends[0];
|
||||
base._inputManager.fingerFullCurlNormalizedLeftIndex = p_hand.m_bends[1];
|
||||
base._inputManager.fingerFullCurlNormalizedLeftMiddle = p_hand.m_bends[2];
|
||||
base._inputManager.fingerFullCurlNormalizedLeftRing = p_hand.m_bends[3];
|
||||
base._inputManager.fingerFullCurlNormalizedLeftPinky = p_hand.m_bends[4];
|
||||
base._inputManager.fingerFullCurlNormalizedLeftThumb = p_hand.m_normalizedCurls[0];
|
||||
base._inputManager.fingerFullCurlNormalizedLeftIndex = p_hand.m_normalizedCurls[1];
|
||||
base._inputManager.fingerFullCurlNormalizedLeftMiddle = p_hand.m_normalizedCurls[2];
|
||||
base._inputManager.fingerFullCurlNormalizedLeftRing = p_hand.m_normalizedCurls[3];
|
||||
base._inputManager.fingerFullCurlNormalizedLeftPinky = p_hand.m_normalizedCurls[4];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -526,11 +532,11 @@ namespace ml_lme
|
|||
base._inputManager.finger3StretchedRightPinky = LeapTracked.ms_lastRightFingerBones[18];
|
||||
base._inputManager.fingerSpreadRightPinky = LeapTracked.ms_lastRightFingerBones[19];
|
||||
|
||||
base._inputManager.fingerFullCurlNormalizedRightThumb = p_hand.m_bends[0];
|
||||
base._inputManager.fingerFullCurlNormalizedRightIndex = p_hand.m_bends[1];
|
||||
base._inputManager.fingerFullCurlNormalizedRightMiddle = p_hand.m_bends[2];
|
||||
base._inputManager.fingerFullCurlNormalizedRightRing = p_hand.m_bends[3];
|
||||
base._inputManager.fingerFullCurlNormalizedRightPinky = p_hand.m_bends[4];
|
||||
base._inputManager.fingerFullCurlNormalizedRightThumb = p_hand.m_normalizedCurls[0];
|
||||
base._inputManager.fingerFullCurlNormalizedRightIndex = p_hand.m_normalizedCurls[1];
|
||||
base._inputManager.fingerFullCurlNormalizedRightMiddle = p_hand.m_normalizedCurls[2];
|
||||
base._inputManager.fingerFullCurlNormalizedRightRing = p_hand.m_normalizedCurls[3];
|
||||
base._inputManager.fingerFullCurlNormalizedRightPinky = p_hand.m_normalizedCurls[4];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.InputManagement;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
@ -23,6 +22,8 @@ namespace ml_lme
|
|||
if(Instance == null)
|
||||
Instance = this;
|
||||
|
||||
ScriptableObject.CreateInstance<Leap.Unity.UltraleapSettings>().ResetToDefaults();
|
||||
|
||||
m_leapController = new Leap.Controller();
|
||||
m_leapData = new LeapParser.LeapData();
|
||||
|
||||
|
@ -34,14 +35,14 @@ namespace ml_lme
|
|||
m_leapController.Connect += this.OnLeapServiceConnect;
|
||||
m_leapController.Disconnect += this.OnLeapServiceDisconnect;
|
||||
|
||||
Settings.EnabledChange += this.OnEnableChange;
|
||||
Settings.TrackingModeChange += this.OnTrackingModeChange;
|
||||
Settings.OnEnabledChanged.AddHandler(this.OnEnableChanged);
|
||||
Settings.OnTrackingModeChanged.AddHandler(this.OnTrackingModeChanged);
|
||||
|
||||
m_leapTracking = new GameObject("[LeapTrackingRoot]").AddComponent<LeapTracking>();
|
||||
m_leapTracking.transform.parent = this.transform;
|
||||
|
||||
OnEnableChange(Settings.Enabled);
|
||||
OnTrackingModeChange(Settings.TrackingMode);
|
||||
OnEnableChanged(Settings.Enabled);
|
||||
OnTrackingModeChanged(Settings.TrackingMode);
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForObjects());
|
||||
}
|
||||
|
@ -77,8 +78,8 @@ namespace ml_lme
|
|||
}
|
||||
m_leapInput = null;
|
||||
|
||||
Settings.EnabledChange -= this.OnEnableChange;
|
||||
Settings.TrackingModeChange -= this.OnTrackingModeChange;
|
||||
Settings.OnEnabledChanged.RemoveHandler(this.OnEnableChanged);
|
||||
Settings.OnTrackingModeChanged.RemoveHandler(this.OnTrackingModeChanged);
|
||||
}
|
||||
|
||||
IEnumerator WaitForObjects()
|
||||
|
@ -149,7 +150,7 @@ namespace ml_lme
|
|||
}
|
||||
|
||||
// Settings
|
||||
void OnEnableChange(bool p_state)
|
||||
void OnEnableChanged(bool p_state)
|
||||
{
|
||||
if(p_state)
|
||||
{
|
||||
|
@ -160,52 +161,12 @@ namespace ml_lme
|
|||
m_leapController.StopConnection();
|
||||
}
|
||||
|
||||
void OnTrackingModeChange(Settings.LeapTrackingMode p_mode)
|
||||
void OnTrackingModeChanged(Settings.LeapTrackingMode p_mode)
|
||||
{
|
||||
if(Settings.Enabled)
|
||||
UpdateDeviceTrackingMode();
|
||||
}
|
||||
|
||||
// Game events
|
||||
internal void OnAvatarClear()
|
||||
{
|
||||
if(m_leapTracking != null)
|
||||
m_leapTracking.OnAvatarClear();
|
||||
if(m_leapTracked != null)
|
||||
m_leapTracked.OnAvatarClear();
|
||||
}
|
||||
|
||||
internal void OnAvatarSetup()
|
||||
{
|
||||
if(m_leapTracking != null)
|
||||
m_leapTracking.OnAvatarSetup();
|
||||
|
||||
if(m_leapTracked != null)
|
||||
m_leapTracked.OnAvatarSetup();
|
||||
}
|
||||
|
||||
internal void OnAvatarReinitialize()
|
||||
{
|
||||
if(m_leapTracked != null)
|
||||
m_leapTracked.OnAvatarReinitialize();
|
||||
}
|
||||
|
||||
internal void OnRayScale(float p_scale)
|
||||
{
|
||||
m_leapInput?.OnRayScale(p_scale);
|
||||
}
|
||||
|
||||
internal void OnPlayspaceScale(float p_relation)
|
||||
{
|
||||
if(m_leapTracking != null)
|
||||
m_leapTracking.OnPlayspaceScale(p_relation);
|
||||
}
|
||||
|
||||
internal void OnPickupGrab(CVRPickupObject p_pickup)
|
||||
{
|
||||
m_leapInput?.OnPickupGrab(p_pickup);
|
||||
}
|
||||
|
||||
// Arbitrary
|
||||
void UpdateDeviceTrackingMode()
|
||||
{
|
||||
|
|
|
@ -13,31 +13,20 @@ namespace ml_lme
|
|||
new Vector2(0f, 180f)
|
||||
};
|
||||
|
||||
readonly static Vector2[] ms_spreadLimits =
|
||||
{
|
||||
new Vector2(-25f, 25f), // Unity's default limits
|
||||
new Vector2(-20f, 20f),
|
||||
new Vector2(-7.5f, 7.5f),
|
||||
new Vector2(-7.5f, 7.5f),
|
||||
new Vector2(-20f, 20f)
|
||||
};
|
||||
|
||||
public class HandData
|
||||
{
|
||||
public bool m_present = false;
|
||||
public Vector3 m_position = Vector3.zero;
|
||||
public Quaternion m_rotation = Quaternion.identity;
|
||||
public Vector3 m_elbowPosition = Vector3.zero;
|
||||
public readonly float[] m_spreads = null;
|
||||
public readonly float[] m_bends = null;
|
||||
public readonly float[] m_normalizedCurls = null;
|
||||
public float m_grabStrength = 0f;
|
||||
public Vector3[] m_fingerPosition;
|
||||
public Quaternion[] m_fingerRotation;
|
||||
|
||||
public HandData()
|
||||
{
|
||||
m_spreads = new float[5];
|
||||
m_bends = new float[5];
|
||||
m_normalizedCurls = new float[5];
|
||||
m_fingerPosition = new Vector3[20];
|
||||
m_fingerRotation = new Quaternion[20];
|
||||
}
|
||||
|
@ -45,17 +34,16 @@ namespace ml_lme
|
|||
public void Reset()
|
||||
{
|
||||
m_present = false;
|
||||
m_grabStrength = 0f;
|
||||
|
||||
for(int i = 0; i < 5; i++)
|
||||
{
|
||||
m_bends[i] = 0f;
|
||||
m_spreads[i] = 0f;
|
||||
}
|
||||
m_normalizedCurls[i] = 0f;
|
||||
|
||||
for(int i = 0; i < 20; i++)
|
||||
{
|
||||
m_fingerPosition[i].Set(0f, 0f, 0f);
|
||||
m_fingerRotation[i].Set(0f, 0f, 0f, 1f);
|
||||
}
|
||||
m_grabStrength = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,7 +87,7 @@ namespace ml_lme
|
|||
p_data.m_rotation = p_hand.Rotation;
|
||||
p_data.m_elbowPosition = p_hand.Arm.ElbowPosition;
|
||||
|
||||
// Bends
|
||||
// Curls
|
||||
foreach(Leap.Finger l_finger in p_hand.Fingers)
|
||||
{
|
||||
Quaternion l_parentRot = Quaternion.identity;
|
||||
|
@ -126,30 +114,10 @@ namespace ml_lme
|
|||
l_parentRot = l_bone.Rotation;
|
||||
}
|
||||
|
||||
p_data.m_bends[(int)l_finger.Type] = Utils.InverseLerpUnclamped(ms_bendLimits[(int)l_finger.Type].x, ms_bendLimits[(int)l_finger.Type].y, l_angle);
|
||||
p_data.m_normalizedCurls[(int)l_finger.Type] = Utils.InverseLerpUnclamped(ms_bendLimits[(int)l_finger.Type].x, ms_bendLimits[(int)l_finger.Type].y, l_angle);
|
||||
}
|
||||
|
||||
// Spreads
|
||||
foreach(Leap.Finger l_finger in p_hand.Fingers)
|
||||
{
|
||||
Leap.Bone l_parent = l_finger.Bone(Leap.Bone.BoneType.TYPE_METACARPAL);
|
||||
Leap.Bone l_child = l_finger.Bone(Leap.Bone.BoneType.TYPE_PROXIMAL);
|
||||
Quaternion l_diff = Quaternion.Inverse(l_parent.Rotation) * l_child.Rotation;
|
||||
|
||||
// Spread - local Y rotation
|
||||
float l_angle = l_diff.eulerAngles.y;
|
||||
if(l_angle > 180f)
|
||||
l_angle -= 360f;
|
||||
|
||||
if(p_hand.IsRight)
|
||||
l_angle *= -1f;
|
||||
|
||||
p_data.m_spreads[(int)l_finger.Type] = Utils.InverseLerpUnclamped(ms_spreadLimits[(int)l_finger.Type].x, ms_spreadLimits[(int)l_finger.Type].y, l_angle) * 2f - 1f;
|
||||
if((l_finger.Type != Leap.Finger.FingerType.TYPE_THUMB) && (p_data.m_bends[(int)l_finger.Type] >= 0.8f))
|
||||
p_data.m_spreads[(int)l_finger.Type] = Mathf.Lerp(p_data.m_spreads[(int)l_finger.Type], 0f, (p_data.m_bends[(int)l_finger.Type] - 0.8f) * 5f);
|
||||
}
|
||||
|
||||
p_data.m_grabStrength = Mathf.Clamp01((p_data.m_bends[1] + p_data.m_bends[2] + p_data.m_bends[3] + p_data.m_bends[4]) * 0.25f);
|
||||
p_data.m_grabStrength = Mathf.Clamp01((p_data.m_normalizedCurls[1] + p_data.m_normalizedCurls[2] + p_data.m_normalizedCurls[3] + p_data.m_normalizedCurls[4]) * 0.25f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,7 +94,6 @@ namespace ml_lme
|
|||
public static readonly float[] ms_lastLeftFingerBones = new float[20];
|
||||
public static readonly float[] ms_lastRightFingerBones = new float[20];
|
||||
|
||||
bool m_inVR = false;
|
||||
VRIK m_vrIK = null;
|
||||
Transform m_hips = null;
|
||||
|
||||
|
@ -126,8 +125,6 @@ namespace ml_lme
|
|||
// Unity events
|
||||
void Start()
|
||||
{
|
||||
m_inVR = Utils.IsInVR();
|
||||
|
||||
m_leftHandTarget = new GameObject("RotationTarget").transform;
|
||||
m_leftHandTarget.parent = LeapTracking.Instance.GetLeftHand().GetRoot();
|
||||
m_leftHandTarget.localPosition = Vector3.zero;
|
||||
|
@ -138,13 +135,17 @@ namespace ml_lme
|
|||
m_rightHandTarget.localPosition = Vector3.zero;
|
||||
m_rightHandTarget.localRotation = Quaternion.identity;
|
||||
|
||||
Settings.EnabledChange += this.OnEnabledChange;
|
||||
Settings.FingersOnlyChange += this.OnFingersOnlyChange;
|
||||
Settings.TrackElbowsChange += this.OnTrackElbowsChange;
|
||||
OnEnabledChanged(Settings.Enabled);
|
||||
OnFingersOnlyChanged(Settings.FingersOnly);
|
||||
OnTrackElbowsChanged(Settings.TrackElbows);
|
||||
|
||||
OnEnabledChange(Settings.Enabled);
|
||||
OnFingersOnlyChange(Settings.FingersOnly);
|
||||
OnTrackElbowsChange(Settings.TrackElbows);
|
||||
Settings.OnEnabledChanged.AddHandler(this.OnEnabledChanged);
|
||||
Settings.OnFingersOnlyChanged.AddHandler(this.OnFingersOnlyChanged);
|
||||
Settings.OnTrackElbowsChanged.AddHandler(this.OnTrackElbowsChanged);
|
||||
|
||||
GameEvents.OnAvatarClear.AddHandler(this.OnAvatarClear);
|
||||
GameEvents.OnAvatarSetup.AddHandler(this.OnAvatarSetup);
|
||||
GameEvents.OnAvatarReuse.AddHandler(this.OnAvatarReuse);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
|
@ -164,9 +165,13 @@ namespace ml_lme
|
|||
|
||||
m_vrIK = null;
|
||||
|
||||
Settings.EnabledChange -= this.OnEnabledChange;
|
||||
Settings.FingersOnlyChange -= this.OnFingersOnlyChange;
|
||||
Settings.TrackElbowsChange -= this.OnTrackElbowsChange;
|
||||
Settings.OnEnabledChanged.RemoveHandler(this.OnEnabledChanged);
|
||||
Settings.OnFingersOnlyChanged.RemoveHandler(this.OnFingersOnlyChanged);
|
||||
Settings.OnTrackElbowsChanged.RemoveHandler(this.OnTrackElbowsChanged);
|
||||
|
||||
GameEvents.OnAvatarClear.RemoveHandler(this.OnAvatarClear);
|
||||
GameEvents.OnAvatarSetup.RemoveHandler(this.OnAvatarSetup);
|
||||
GameEvents.OnAvatarReuse.RemoveHandler(this.OnAvatarReuse);
|
||||
}
|
||||
|
||||
void Update()
|
||||
|
@ -245,7 +250,7 @@ namespace ml_lme
|
|||
}
|
||||
|
||||
// Game events
|
||||
internal void OnAvatarClear()
|
||||
void OnAvatarClear()
|
||||
{
|
||||
m_vrIK = null;
|
||||
m_hips = null;
|
||||
|
@ -269,10 +274,8 @@ namespace ml_lme
|
|||
m_rightFingerOffsets.Clear();
|
||||
}
|
||||
|
||||
internal void OnAvatarSetup()
|
||||
void OnAvatarSetup()
|
||||
{
|
||||
m_inVR = Utils.IsInVR();
|
||||
|
||||
if(PlayerSetup.Instance._animator.isHuman)
|
||||
{
|
||||
Utils.SetAvatarTPose();
|
||||
|
@ -293,27 +296,26 @@ namespace ml_lme
|
|||
m_vrIK = PlayerSetup.Instance._animator.GetComponent<VRIK>();
|
||||
if(m_vrIK != null)
|
||||
{
|
||||
m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreUpdate);
|
||||
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate);
|
||||
m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreSolverUpdate);
|
||||
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostSolverUpdate);
|
||||
}
|
||||
else
|
||||
SetupArmIK();
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnAvatarReinitialize()
|
||||
void OnAvatarReuse()
|
||||
{
|
||||
// Old VRIK is destroyed by game
|
||||
m_inVR = Utils.IsInVR();
|
||||
m_vrIK = PlayerSetup.Instance._animator.GetComponent<VRIK>();
|
||||
|
||||
if(m_inVR)
|
||||
if(Utils.IsInVR())
|
||||
RemoveArmIK();
|
||||
|
||||
if(m_vrIK != null)
|
||||
{
|
||||
m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreUpdate);
|
||||
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate);
|
||||
m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreSolverUpdate);
|
||||
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostSolverUpdate);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -323,7 +325,7 @@ namespace ml_lme
|
|||
}
|
||||
|
||||
// VRIK updates
|
||||
void OnIKPreUpdate()
|
||||
void OnIKPreSolverUpdate()
|
||||
{
|
||||
if(m_leftTargetActive)
|
||||
{
|
||||
|
@ -354,7 +356,7 @@ namespace ml_lme
|
|||
m_vrIK.solver.rightArm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
|
||||
}
|
||||
}
|
||||
void OnIKPostUpdate()
|
||||
void OnIKPostSolverUpdate()
|
||||
{
|
||||
if(m_leftTargetActive)
|
||||
{
|
||||
|
@ -375,7 +377,7 @@ namespace ml_lme
|
|||
}
|
||||
|
||||
// Settings
|
||||
void OnEnabledChange(bool p_state)
|
||||
void OnEnabledChanged(bool p_state)
|
||||
{
|
||||
m_enabled = p_state;
|
||||
|
||||
|
@ -383,7 +385,7 @@ namespace ml_lme
|
|||
ResetTargetsStates();
|
||||
}
|
||||
|
||||
void OnFingersOnlyChange(bool p_state)
|
||||
void OnFingersOnlyChanged(bool p_state)
|
||||
{
|
||||
m_fingersOnly = p_state;
|
||||
|
||||
|
@ -391,7 +393,7 @@ namespace ml_lme
|
|||
ResetTargetsStates();
|
||||
}
|
||||
|
||||
void OnTrackElbowsChange(bool p_state)
|
||||
void OnTrackElbowsChanged(bool p_state)
|
||||
{
|
||||
m_trackElbows = p_state;
|
||||
|
||||
|
|
|
@ -62,23 +62,27 @@ namespace ml_lme
|
|||
m_leapHandRight = new LeapHand(m_leapHands.transform.Find("HandR"), false);
|
||||
}
|
||||
|
||||
Settings.DesktopOffsetChange += this.OnDesktopOffsetChange;
|
||||
Settings.ModelVisibilityChange += this.OnModelVisibilityChange;
|
||||
Settings.VisualHandsChange += this.OnVisualHandsChange;
|
||||
Settings.TrackingModeChange += this.OnTrackingModeChange;
|
||||
Settings.RootAngleChange += this.OnRootAngleChange;
|
||||
Settings.HeadAttachChange += this.OnHeadAttachChange;
|
||||
Settings.HeadOffsetChange += this.OnHeadOffsetChange;
|
||||
OnModelVisibilityChanged(Settings.ModelVisibility);
|
||||
OnVisualHandsChanged(Settings.VisualHands);
|
||||
OnTrackingModeChanged(Settings.TrackingMode);
|
||||
OnRootAngleChanged(Settings.RootAngle);
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
|
||||
|
||||
OnModelVisibilityChange(Settings.ModelVisibility);
|
||||
OnVisualHandsChange(Settings.VisualHands);
|
||||
OnTrackingModeChange(Settings.TrackingMode);
|
||||
OnRootAngleChange(Settings.RootAngle);
|
||||
VRModeSwitchEvents.OnInitializeXR.AddListener(this.OnAvatarSetup);
|
||||
VRModeSwitchEvents.OnDeinitializeXR.AddListener(this.OnAvatarSetup);
|
||||
|
||||
VRModeSwitchEvents.OnInitializeXR.AddListener(this.OnModeSwitch);
|
||||
VRModeSwitchEvents.OnDeinitializeXR.AddListener(this.OnModeSwitch);
|
||||
Settings.OnDesktopOffsetChanged.AddHandler(this.OnDesktopOffsetChanged);
|
||||
Settings.OnModelVisibilityChanged.AddHandler(this.OnModelVisibilityChanged);
|
||||
Settings.OnVisualHandsChanged.AddHandler(this.OnVisualHandsChanged);
|
||||
Settings.OnTrackingModeChanged.AddHandler(this.OnTrackingModeChanged);
|
||||
Settings.OnRootAngleChanged.AddHandler(this.OnRootAngleChanged);
|
||||
Settings.OnHeadAttachChanged.AddHandler(this.OnHeadAttachChanged);
|
||||
Settings.OnHeadOffsetChanged.AddHandler(this.OnHeadOffsetChanged);
|
||||
|
||||
GameEvents.OnAvatarClear.AddHandler(this.OnAvatarClear);
|
||||
GameEvents.OnAvatarSetup.AddHandler(this.OnAvatarSetup);
|
||||
GameEvents.OnPlayspaceScale.AddHandler(this.OnPlayspaceScale);
|
||||
}
|
||||
|
||||
IEnumerator WaitForLocalPlayer()
|
||||
|
@ -86,7 +90,7 @@ namespace ml_lme
|
|||
while(PlayerSetup.Instance == null)
|
||||
yield return null;
|
||||
|
||||
OnHeadAttachChange(Settings.HeadAttach);
|
||||
OnHeadAttachChanged(Settings.HeadAttach);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
|
@ -112,16 +116,20 @@ namespace ml_lme
|
|||
Object.Destroy(m_leapControllerModel);
|
||||
m_leapControllerModel = null;
|
||||
|
||||
Settings.DesktopOffsetChange -= this.OnDesktopOffsetChange;
|
||||
Settings.ModelVisibilityChange -= this.OnModelVisibilityChange;
|
||||
Settings.VisualHandsChange -= this.OnVisualHandsChange;
|
||||
Settings.TrackingModeChange -= this.OnTrackingModeChange;
|
||||
Settings.RootAngleChange -= this.OnRootAngleChange;
|
||||
Settings.HeadAttachChange -= this.OnHeadAttachChange;
|
||||
Settings.HeadOffsetChange -= this.OnHeadOffsetChange;
|
||||
VRModeSwitchEvents.OnInitializeXR.RemoveListener(this.OnAvatarSetup);
|
||||
VRModeSwitchEvents.OnDeinitializeXR.RemoveListener(this.OnAvatarSetup);
|
||||
|
||||
VRModeSwitchEvents.OnInitializeXR.RemoveListener(this.OnModeSwitch);
|
||||
VRModeSwitchEvents.OnDeinitializeXR.RemoveListener(this.OnModeSwitch);
|
||||
Settings.OnDesktopOffsetChanged.RemoveHandler(this.OnDesktopOffsetChanged);
|
||||
Settings.OnModelVisibilityChanged.RemoveHandler(this.OnModelVisibilityChanged);
|
||||
Settings.OnVisualHandsChanged.RemoveHandler(this.OnVisualHandsChanged);
|
||||
Settings.OnTrackingModeChanged.RemoveHandler(this.OnTrackingModeChanged);
|
||||
Settings.OnRootAngleChanged.RemoveHandler(this.OnRootAngleChanged);
|
||||
Settings.OnHeadAttachChanged.RemoveHandler(this.OnHeadAttachChanged);
|
||||
Settings.OnHeadOffsetChanged.RemoveHandler(this.OnHeadOffsetChanged);
|
||||
|
||||
GameEvents.OnAvatarClear.RemoveHandler(this.OnAvatarClear);
|
||||
GameEvents.OnAvatarSetup.RemoveHandler(this.OnAvatarSetup);
|
||||
GameEvents.OnPlayspaceScale.RemoveHandler(this.OnPlayspaceScale);
|
||||
}
|
||||
|
||||
void Update()
|
||||
|
@ -142,7 +150,7 @@ namespace ml_lme
|
|||
OrientationAdjustment(ref l_data.m_leftHand.m_elbowPosition, ref ms_dummyRotation, Settings.TrackingMode);
|
||||
m_leapElbowLeft.localPosition = l_data.m_leftHand.m_elbowPosition;
|
||||
|
||||
m_leapHandLeft?.Update(l_data.m_leftHand);
|
||||
m_leapHandLeft.Update(l_data.m_leftHand);
|
||||
}
|
||||
|
||||
if(l_data.m_rightHand.m_present)
|
||||
|
@ -157,7 +165,7 @@ namespace ml_lme
|
|||
OrientationAdjustment(ref l_data.m_rightHand.m_elbowPosition, ref ms_dummyRotation, Settings.TrackingMode);
|
||||
m_leapElbowRight.localPosition = l_data.m_rightHand.m_elbowPosition;
|
||||
|
||||
m_leapHandRight?.Update(l_data.m_rightHand);
|
||||
m_leapHandRight.Update(l_data.m_rightHand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -173,24 +181,24 @@ namespace ml_lme
|
|||
}
|
||||
|
||||
// Settings
|
||||
void OnDesktopOffsetChange(Vector3 p_offset)
|
||||
void OnDesktopOffsetChanged(Vector3 p_offset)
|
||||
{
|
||||
if(!Settings.HeadAttach)
|
||||
this.transform.localPosition = p_offset * (!m_inVR ? m_scaleRelation : 1f);
|
||||
}
|
||||
|
||||
void OnModelVisibilityChange(bool p_state)
|
||||
void OnModelVisibilityChanged(bool p_state)
|
||||
{
|
||||
m_leapControllerModel.SetActive(p_state);
|
||||
}
|
||||
|
||||
void OnVisualHandsChange(bool p_state)
|
||||
void OnVisualHandsChanged(bool p_state)
|
||||
{
|
||||
m_leapHandLeft?.SetMeshActive(p_state);
|
||||
m_leapHandRight?.SetMeshActive(p_state);
|
||||
}
|
||||
|
||||
void OnTrackingModeChange(Settings.LeapTrackingMode p_mode)
|
||||
void OnTrackingModeChanged(Settings.LeapTrackingMode p_mode)
|
||||
{
|
||||
switch(p_mode)
|
||||
{
|
||||
|
@ -206,12 +214,12 @@ namespace ml_lme
|
|||
}
|
||||
}
|
||||
|
||||
void OnRootAngleChange(Vector3 p_angle)
|
||||
void OnRootAngleChanged(Vector3 p_angle)
|
||||
{
|
||||
this.transform.localRotation = Quaternion.Euler(p_angle);
|
||||
}
|
||||
|
||||
void OnHeadAttachChange(bool p_state)
|
||||
void OnHeadAttachChanged(bool p_state)
|
||||
{
|
||||
if(!m_inVR)
|
||||
{
|
||||
|
@ -228,35 +236,29 @@ namespace ml_lme
|
|||
this.transform.localRotation = Quaternion.Euler(Settings.RootAngle);
|
||||
}
|
||||
|
||||
void OnHeadOffsetChange(Vector3 p_offset)
|
||||
void OnHeadOffsetChanged(Vector3 p_offset)
|
||||
{
|
||||
if(Settings.HeadAttach)
|
||||
this.transform.localPosition = p_offset * (!m_inVR ? m_scaleRelation : 1f);
|
||||
}
|
||||
|
||||
// Game events
|
||||
internal void OnAvatarClear()
|
||||
void OnAvatarClear()
|
||||
{
|
||||
m_scaleRelation = 1f;
|
||||
OnHeadAttachChange(Settings.HeadAttach);
|
||||
OnHeadAttachChanged(Settings.HeadAttach);
|
||||
}
|
||||
|
||||
internal void OnAvatarSetup()
|
||||
void OnAvatarSetup()
|
||||
{
|
||||
m_inVR = Utils.IsInVR();
|
||||
OnHeadAttachChange(Settings.HeadAttach);
|
||||
OnHeadAttachChanged(Settings.HeadAttach);
|
||||
}
|
||||
|
||||
internal void OnPlayspaceScale(float p_relation)
|
||||
void OnPlayspaceScale(float p_relation)
|
||||
{
|
||||
m_scaleRelation = p_relation;
|
||||
OnHeadAttachChange(Settings.HeadAttach);
|
||||
}
|
||||
|
||||
void OnModeSwitch()
|
||||
{
|
||||
m_inVR = Utils.IsInVR();
|
||||
OnHeadAttachChange(Settings.HeadAttach);
|
||||
OnHeadAttachChanged(Settings.HeadAttach);
|
||||
}
|
||||
|
||||
// Utils
|
||||
|
|
135
ml_lme/Main.cs
135
ml_lme/Main.cs
|
@ -1,8 +1,4 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_lme
|
||||
|
@ -10,61 +6,21 @@ namespace ml_lme
|
|||
|
||||
public class LeapMotionExtension : MelonLoader.MelonMod
|
||||
{
|
||||
static LeapMotionExtension ms_instance = null;
|
||||
|
||||
LeapManager m_leapManager = null;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
if(ms_instance == null)
|
||||
ms_instance = this;
|
||||
|
||||
DependenciesHandler.ExtractDependencies();
|
||||
Settings.Init();
|
||||
AssetsHandler.Load();
|
||||
|
||||
// Patches
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetControllerRayScale)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnRayScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod("SetPlaySpaceScale", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnPlayspaceScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
|
||||
typeof(CVRPickupObject).GetMethod(nameof(CVRPickupObject.Grab), BindingFlags.Public | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnPickupGrab_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
GameEvents.Init(HarmonyInstance);
|
||||
ModSupporter.Init();
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForRootLogic());
|
||||
}
|
||||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
if(m_leapManager != null)
|
||||
Object.Destroy(m_leapManager);
|
||||
m_leapManager = null;
|
||||
|
@ -77,90 +33,5 @@ namespace ml_lme
|
|||
|
||||
m_leapManager = new GameObject("LeapMotionManager").AddComponent<LeapManager>();
|
||||
}
|
||||
|
||||
// Patches
|
||||
static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear();
|
||||
void OnAvatarClear()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_leapManager != null)
|
||||
m_leapManager.OnAvatarClear();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar();
|
||||
void OnSetupAvatar()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_leapManager != null)
|
||||
m_leapManager.OnAvatarSetup();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarReinitialize_Postfix() => ms_instance?.OnAvatarReinitialize();
|
||||
void OnAvatarReinitialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_leapManager != null)
|
||||
m_leapManager.OnAvatarReinitialize();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnRayScale_Postfix(float __0) => ms_instance?.OnRayScale(__0);
|
||||
void OnRayScale(float p_scale)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_leapManager != null)
|
||||
m_leapManager.OnRayScale(p_scale);
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnPlayspaceScale_Postfix(float ____avatarScaleRelation) => ms_instance?.OnPlayspaceScale(____avatarScaleRelation);
|
||||
void OnPlayspaceScale(float p_relation)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_leapManager != null)
|
||||
m_leapManager.OnPlayspaceScale(p_relation);
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnPickupGrab_Postfix(ref CVRPickupObject __instance) => ms_instance?.OnPickupGrab(__instance);
|
||||
void OnPickupGrab(CVRPickupObject p_pickup)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_leapManager != null)
|
||||
m_leapManager.OnPickupGrab(p_pickup);
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.4.9", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.5.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||
[assembly: MelonLoader.MelonOptionalDependencies("ml_pmc")]
|
||||
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||
|
|
|
@ -7,6 +7,14 @@ namespace ml_lme
|
|||
{
|
||||
static class Settings
|
||||
{
|
||||
internal class SettingEvent<T>
|
||||
{
|
||||
event Action<T> m_action;
|
||||
public void AddHandler(Action<T> p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action<T> p_listener) => m_action -= p_listener;
|
||||
public void Invoke(T p_value) => m_action?.Invoke(p_value);
|
||||
}
|
||||
|
||||
public enum LeapTrackingMode
|
||||
{
|
||||
Screentop = 0,
|
||||
|
@ -58,21 +66,21 @@ namespace ml_lme
|
|||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
||||
public static event Action<bool> EnabledChange;
|
||||
public static event Action<Vector3> DesktopOffsetChange;
|
||||
public static event Action<bool> FingersOnlyChange;
|
||||
public static event Action<bool> ModelVisibilityChange;
|
||||
public static event Action<LeapTrackingMode> TrackingModeChange;
|
||||
public static event Action<Vector3> RootAngleChange;
|
||||
public static event Action<bool> HeadAttachChange;
|
||||
public static event Action<Vector3> HeadOffsetChange;
|
||||
public static event Action<bool> TrackElbowsChange;
|
||||
public static event Action<bool> InteractionChange;
|
||||
public static event Action<bool> GesturesChange;
|
||||
public static event Action<float> InteractThreadholdChange;
|
||||
public static event Action<float> GripThreadholdChange;
|
||||
public static event Action<bool> VisualHandsChange;
|
||||
public static event Action<bool> MechanimFilterChange;
|
||||
public static readonly SettingEvent<bool> OnEnabledChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<Vector3> OnDesktopOffsetChanged = new SettingEvent<Vector3>();
|
||||
public static readonly SettingEvent<bool> OnFingersOnlyChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnModelVisibilityChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<LeapTrackingMode> OnTrackingModeChanged = new SettingEvent<LeapTrackingMode>();
|
||||
public static readonly SettingEvent<Vector3> OnRootAngleChanged = new SettingEvent<Vector3>();
|
||||
public static readonly SettingEvent<bool> OnHeadAttachChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<Vector3> OnHeadOffsetChanged = new SettingEvent<Vector3>();
|
||||
public static readonly SettingEvent<bool> OnTrackElbowsChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnInteractionChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnGesturesChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<float> OnInteractThreadholdChanged = new SettingEvent<float>();
|
||||
public static readonly SettingEvent<float> OnGripThreadholdChanged = new SettingEvent<float>();
|
||||
public static readonly SettingEvent<bool> OnVisualHandsChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnMechanimFilterChanged = new SettingEvent<bool>();
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
|
@ -103,7 +111,33 @@ namespace ml_lme
|
|||
ms_category.CreateEntry(ModSetting.MechanimFilter.ToString(), MechanimFilter)
|
||||
};
|
||||
|
||||
Load();
|
||||
Enabled = (bool)ms_entries[(int)ModSetting.Enabled].BoxedValue;
|
||||
DesktopOffset = new Vector3(
|
||||
(int)ms_entries[(int)ModSetting.DesktopX].BoxedValue,
|
||||
(int)ms_entries[(int)ModSetting.DesktopY].BoxedValue,
|
||||
(int)ms_entries[(int)ModSetting.DesktopZ].BoxedValue
|
||||
) * 0.01f;
|
||||
FingersOnly = (bool)ms_entries[(int)ModSetting.FingersOnly].BoxedValue;
|
||||
ModelVisibility = (bool)ms_entries[(int)ModSetting.Model].BoxedValue;
|
||||
TrackingMode = (LeapTrackingMode)(int)ms_entries[(int)ModSetting.Mode].BoxedValue;
|
||||
RootAngle = new Vector3(
|
||||
(int)ms_entries[(int)ModSetting.AngleX].BoxedValue,
|
||||
(int)ms_entries[(int)ModSetting.AngleY].BoxedValue,
|
||||
(int)ms_entries[(int)ModSetting.AngleZ].BoxedValue
|
||||
);
|
||||
HeadAttach = (bool)ms_entries[(int)ModSetting.Head].BoxedValue;
|
||||
HeadOffset = new Vector3(
|
||||
(int)ms_entries[(int)ModSetting.HeadX].BoxedValue,
|
||||
(int)ms_entries[(int)ModSetting.HeadY].BoxedValue,
|
||||
(int)ms_entries[(int)ModSetting.HeadZ].BoxedValue
|
||||
) * 0.01f;
|
||||
TrackElbows = (bool)ms_entries[(int)ModSetting.TrackElbows].BoxedValue;
|
||||
Interaction = (bool)ms_entries[(int)ModSetting.Interaction].BoxedValue;
|
||||
Gestures = (bool)ms_entries[(int)ModSetting.Gestures].BoxedValue;
|
||||
InteractThreadhold = (int)ms_entries[(int)ModSetting.InteractThreadhold].BoxedValue * 0.01f;
|
||||
GripThreadhold = (int)ms_entries[(int)ModSetting.GripThreadhold].BoxedValue * 0.01f;
|
||||
VisualHands = (bool)ms_entries[(int)ModSetting.VisualHands].BoxedValue;
|
||||
MechanimFilter = (bool)ms_entries[(int)ModSetting.MechanimFilter].BoxedValue;
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitMainMenuUi());
|
||||
}
|
||||
|
@ -132,38 +166,9 @@ namespace ml_lme
|
|||
};
|
||||
}
|
||||
|
||||
static void Load()
|
||||
{
|
||||
Enabled = (bool)ms_entries[(int)ModSetting.Enabled].BoxedValue;
|
||||
DesktopOffset = new Vector3(
|
||||
(int)ms_entries[(int)ModSetting.DesktopX].BoxedValue,
|
||||
(int)ms_entries[(int)ModSetting.DesktopY].BoxedValue,
|
||||
(int)ms_entries[(int)ModSetting.DesktopZ].BoxedValue
|
||||
) * 0.01f;
|
||||
FingersOnly = (bool)ms_entries[(int)ModSetting.FingersOnly].BoxedValue;
|
||||
ModelVisibility = (bool)ms_entries[(int)ModSetting.Model].BoxedValue;
|
||||
TrackingMode = (LeapTrackingMode)(int)ms_entries[(int)ModSetting.Mode].BoxedValue;
|
||||
RootAngle = new Vector3(
|
||||
(int)ms_entries[(int)ModSetting.AngleX].BoxedValue,
|
||||
(int)ms_entries[(int)ModSetting.AngleY].BoxedValue,
|
||||
(int)ms_entries[(int)ModSetting.AngleZ].BoxedValue
|
||||
);
|
||||
HeadAttach = (bool)ms_entries[(int)ModSetting.Head].BoxedValue;
|
||||
HeadOffset = new Vector3(
|
||||
(int)ms_entries[(int)ModSetting.HeadX].BoxedValue,
|
||||
(int)ms_entries[(int)ModSetting.HeadY].BoxedValue,
|
||||
(int)ms_entries[(int)ModSetting.HeadZ].BoxedValue
|
||||
) * 0.01f;
|
||||
TrackElbows = (bool)ms_entries[(int)ModSetting.TrackElbows].BoxedValue;
|
||||
Interaction = (bool)ms_entries[(int)ModSetting.Interaction].BoxedValue;
|
||||
Gestures = (bool)ms_entries[(int)ModSetting.Gestures].BoxedValue;
|
||||
InteractThreadhold = (int)ms_entries[(int)ModSetting.InteractThreadhold].BoxedValue * 0.01f;
|
||||
GripThreadhold = (int)ms_entries[(int)ModSetting.GripThreadhold].BoxedValue * 0.01f;
|
||||
VisualHands = (bool)ms_entries[(int)ModSetting.VisualHands].BoxedValue;
|
||||
MechanimFilter = (bool)ms_entries[(int)ModSetting.MechanimFilter].BoxedValue;
|
||||
}
|
||||
|
||||
static void OnToggleUpdate(string p_name, string p_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
|
@ -172,63 +177,63 @@ namespace ml_lme
|
|||
case ModSetting.Enabled:
|
||||
{
|
||||
Enabled = bool.Parse(p_value);
|
||||
EnabledChange?.Invoke(Enabled);
|
||||
OnEnabledChanged.Invoke(Enabled);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.FingersOnly:
|
||||
{
|
||||
FingersOnly = bool.Parse(p_value);
|
||||
FingersOnlyChange?.Invoke(FingersOnly);
|
||||
OnFingersOnlyChanged.Invoke(FingersOnly);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.Model:
|
||||
{
|
||||
ModelVisibility = bool.Parse(p_value);
|
||||
ModelVisibilityChange?.Invoke(ModelVisibility);
|
||||
OnModelVisibilityChanged.Invoke(ModelVisibility);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.Head:
|
||||
{
|
||||
HeadAttach = bool.Parse(p_value);
|
||||
HeadAttachChange?.Invoke(HeadAttach);
|
||||
OnHeadAttachChanged.Invoke(HeadAttach);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.TrackElbows:
|
||||
{
|
||||
TrackElbows = bool.Parse(p_value);
|
||||
TrackElbowsChange?.Invoke(TrackElbows);
|
||||
OnTrackElbowsChanged.Invoke(TrackElbows);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.Interaction:
|
||||
{
|
||||
Interaction = bool.Parse(p_value);
|
||||
InteractionChange?.Invoke(Interaction);
|
||||
OnInteractionChanged.Invoke(Interaction);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.Gestures:
|
||||
{
|
||||
Gestures = bool.Parse(p_value);
|
||||
GesturesChange?.Invoke(Gestures);
|
||||
OnGesturesChanged.Invoke(Gestures);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.VisualHands:
|
||||
{
|
||||
VisualHands = bool.Parse(p_value);
|
||||
VisualHandsChange?.Invoke(VisualHands);
|
||||
OnVisualHandsChanged.Invoke(VisualHands);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.MechanimFilter:
|
||||
{
|
||||
MechanimFilter = bool.Parse(p_value);
|
||||
MechanimFilterChange?.Invoke(MechanimFilter);
|
||||
OnMechanimFilterChanged.Invoke(MechanimFilter);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -236,8 +241,15 @@ namespace ml_lme
|
|||
ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSliderUpdate(string p_name, string p_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
|
@ -248,7 +260,7 @@ namespace ml_lme
|
|||
Vector3 l_current = DesktopOffset;
|
||||
l_current.x = int.Parse(p_value) * 0.01f;
|
||||
DesktopOffset = l_current;
|
||||
DesktopOffsetChange?.Invoke(l_current);
|
||||
OnDesktopOffsetChanged.Invoke(l_current);
|
||||
}
|
||||
break;
|
||||
case ModSetting.DesktopY:
|
||||
|
@ -256,7 +268,7 @@ namespace ml_lme
|
|||
Vector3 l_current = DesktopOffset;
|
||||
l_current.y = int.Parse(p_value) * 0.01f;
|
||||
DesktopOffset = l_current;
|
||||
DesktopOffsetChange?.Invoke(l_current);
|
||||
OnDesktopOffsetChanged.Invoke(l_current);
|
||||
}
|
||||
break;
|
||||
case ModSetting.DesktopZ:
|
||||
|
@ -264,7 +276,7 @@ namespace ml_lme
|
|||
Vector3 l_current = DesktopOffset;
|
||||
l_current.z = int.Parse(p_value) * 0.01f;
|
||||
DesktopOffset = l_current;
|
||||
DesktopOffsetChange?.Invoke(l_current);
|
||||
OnDesktopOffsetChanged.Invoke(l_current);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -273,7 +285,7 @@ namespace ml_lme
|
|||
Vector3 l_current = RootAngle;
|
||||
l_current.x = int.Parse(p_value);
|
||||
RootAngle = l_current;
|
||||
RootAngleChange?.Invoke(l_current);
|
||||
OnRootAngleChanged.Invoke(l_current);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -282,7 +294,7 @@ namespace ml_lme
|
|||
Vector3 l_current = RootAngle;
|
||||
l_current.y = int.Parse(p_value);
|
||||
RootAngle = l_current;
|
||||
RootAngleChange?.Invoke(l_current);
|
||||
OnRootAngleChanged.Invoke(l_current);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -291,7 +303,7 @@ namespace ml_lme
|
|||
Vector3 l_current = RootAngle;
|
||||
l_current.z = int.Parse(p_value);
|
||||
RootAngle = l_current;
|
||||
RootAngleChange?.Invoke(l_current);
|
||||
OnRootAngleChanged.Invoke(l_current);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -300,7 +312,7 @@ namespace ml_lme
|
|||
Vector3 l_current = HeadOffset;
|
||||
l_current.x = int.Parse(p_value) * 0.01f;
|
||||
HeadOffset = l_current;
|
||||
HeadOffsetChange?.Invoke(l_current);
|
||||
OnHeadOffsetChanged.Invoke(l_current);
|
||||
}
|
||||
break;
|
||||
case ModSetting.HeadY:
|
||||
|
@ -308,7 +320,7 @@ namespace ml_lme
|
|||
Vector3 l_current = HeadOffset;
|
||||
l_current.y = int.Parse(p_value) * 0.01f;
|
||||
HeadOffset = l_current;
|
||||
HeadOffsetChange?.Invoke(l_current);
|
||||
OnHeadOffsetChanged.Invoke(l_current);
|
||||
}
|
||||
break;
|
||||
case ModSetting.HeadZ:
|
||||
|
@ -316,19 +328,19 @@ namespace ml_lme
|
|||
Vector3 l_current = HeadOffset;
|
||||
l_current.z = int.Parse(p_value) * 0.01f;
|
||||
HeadOffset = l_current;
|
||||
HeadOffsetChange?.Invoke(l_current);
|
||||
OnHeadOffsetChanged.Invoke(l_current);
|
||||
}
|
||||
break;
|
||||
case ModSetting.InteractThreadhold:
|
||||
{
|
||||
InteractThreadhold = int.Parse(p_value) * 0.01f;
|
||||
InteractThreadholdChange?.Invoke(InteractThreadhold);
|
||||
OnInteractThreadholdChanged.Invoke(InteractThreadhold);
|
||||
}
|
||||
break;
|
||||
case ModSetting.GripThreadhold:
|
||||
{
|
||||
GripThreadhold = int.Parse(p_value) * 0.01f;
|
||||
GripThreadholdChange?.Invoke(GripThreadhold);
|
||||
OnGripThreadholdChanged.Invoke(GripThreadhold);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -336,8 +348,15 @@ namespace ml_lme
|
|||
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnDropdownUpdate(string p_name, string p_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
|
@ -346,7 +365,7 @@ namespace ml_lme
|
|||
case ModSetting.Mode:
|
||||
{
|
||||
TrackingMode = (LeapTrackingMode)int.Parse(p_value);
|
||||
TrackingModeChange?.Invoke(TrackingMode);
|
||||
OnTrackingModeChanged.Invoke(TrackingMode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -354,5 +373,10 @@ namespace ml_lme
|
|||
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
<PackageId>LeapMotionExtension</PackageId>
|
||||
<Version>1.4.9</Version>
|
||||
<Version>1.5.0</Version>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>LeapMotionExtension</Product>
|
||||
|
@ -93,6 +93,11 @@
|
|||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.JSONSerializeModule">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.JSONSerializeModule.dll</HintPath>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.XRModule">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.XRModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
|
|
6
ml_lme/vendor/LeapCSharp/Config.cs
vendored
6
ml_lme/vendor/LeapCSharp/Config.cs
vendored
|
@ -30,7 +30,7 @@ namespace Leap
|
|||
/// Note that the Controller.Config provides a properly initialized Config object already.
|
||||
/// @since 3.0
|
||||
/// </summary>
|
||||
[Obsolete("Config.cs is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
public Config(Connection.Key connectionKey)
|
||||
{
|
||||
_connection = Connection.GetConnection(connectionKey);
|
||||
|
@ -38,9 +38,10 @@ namespace Leap
|
|||
_connection.LeapConfigResponse += handleConfigResponse;
|
||||
}
|
||||
|
||||
[Obsolete("Config.cs is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
public Config(int connectionId) : this(new Connection.Key(connectionId)) { }
|
||||
|
||||
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
private void handleConfigChange(object sender, ConfigChangeEventArgs eventArgs)
|
||||
{
|
||||
object actionDelegate;
|
||||
|
@ -52,6 +53,7 @@ namespace Leap
|
|||
}
|
||||
}
|
||||
|
||||
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
private void handleConfigResponse(object sender, SetConfigResponseEventArgs eventArgs)
|
||||
{
|
||||
object actionDelegate = new object();
|
||||
|
|
149
ml_lme/vendor/LeapCSharp/Connection.cs
vendored
149
ml_lme/vendor/LeapCSharp/Connection.cs
vendored
|
@ -72,13 +72,9 @@ namespace LeapInternal
|
|||
|
||||
private IntPtr _leapConnection;
|
||||
private volatile bool _isRunning = false;
|
||||
public bool IsRunning { get { return _isRunning; } }
|
||||
private Thread _polster;
|
||||
|
||||
/// <summary>
|
||||
/// Has the connection been set up in multi device aware mode
|
||||
/// </summary>
|
||||
private bool _multiDeviceAwareConnection = false;
|
||||
|
||||
/// <summary>
|
||||
/// Minimum service version that support setting the tracking mode on a per dervice basis
|
||||
/// </summary>
|
||||
|
@ -88,6 +84,7 @@ namespace LeapInternal
|
|||
private Dictionary<uint, UInt64> _activePolicies = new Dictionary<uint, ulong>();
|
||||
|
||||
//Config change status
|
||||
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
private Dictionary<uint, string> _configRequests = new Dictionary<uint, string>();
|
||||
|
||||
//Connection events
|
||||
|
@ -124,13 +121,16 @@ namespace LeapInternal
|
|||
public EventHandler<FrameEventArgs> LeapFrame;
|
||||
public EventHandler<InternalFrameEventArgs> LeapInternalFrame;
|
||||
public EventHandler<LogEventArgs> LeapLogEvent;
|
||||
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
public EventHandler<SetConfigResponseEventArgs> LeapConfigResponse;
|
||||
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
public EventHandler<ConfigChangeEventArgs> LeapConfigChange;
|
||||
public EventHandler<DistortionEventArgs> LeapDistortionChange;
|
||||
public EventHandler<DroppedFrameEventArgs> LeapDroppedFrame;
|
||||
public EventHandler<ImageEventArgs> LeapImage;
|
||||
public EventHandler<PointMappingChangeEventArgs> LeapPointMappingChange;
|
||||
public EventHandler<HeadPoseEventArgs> LeapHeadPoseChange;
|
||||
public EventHandler<FiducialPoseEventArgs> LeapFiducialPose;
|
||||
|
||||
public Action<BeginProfilingForThreadArgs> LeapBeginProfilingForThread;
|
||||
public Action<EndProfilingForThreadArgs> LeapEndProfilingForThread;
|
||||
|
@ -151,10 +151,6 @@ namespace LeapInternal
|
|||
if (_disposed)
|
||||
return;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
}
|
||||
|
||||
Stop();
|
||||
LeapC.DestroyConnection(_leapConnection);
|
||||
_leapConnection = IntPtr.Zero;
|
||||
|
@ -181,9 +177,8 @@ namespace LeapInternal
|
|||
{
|
||||
LEAP_CONNECTION_CONFIG config = new LEAP_CONNECTION_CONFIG();
|
||||
config.server_namespace = Marshal.StringToHGlobalAnsi(serverNamespace);
|
||||
config.flags = multiDeviceAware ? (uint)eLeapConnectionFlag.eLeapConnectionFlag_MultipleDevicesAware : 0;
|
||||
config.flags = (uint)eLeapConnectionFlag.eLeapConnectionFlag_MultipleDevicesAware;
|
||||
config.size = (uint)Marshal.SizeOf(config);
|
||||
_multiDeviceAwareConnection = multiDeviceAware;
|
||||
Start(config);
|
||||
}
|
||||
|
||||
|
@ -210,7 +205,18 @@ namespace LeapInternal
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Produce metadata to send before connection is opened
|
||||
string metadata = MetadataUtil.GetMetaData();
|
||||
UIntPtr uIntPtr = new UIntPtr((uint)metadata.Length);
|
||||
|
||||
if (metadata != null && metadata != "")
|
||||
{
|
||||
LeapC.SetConnectionMetadata(_leapConnection, metadata, uIntPtr);
|
||||
}
|
||||
|
||||
result = LeapC.OpenConnection(_leapConnection);
|
||||
|
||||
if (result != eLeapRS.eLeapRS_Success)
|
||||
{
|
||||
reportAbnormalResults("LeapC OpenConnection call was ", result);
|
||||
|
@ -308,7 +314,6 @@ namespace LeapInternal
|
|||
{
|
||||
case eLeapEventType.eLeapEventType_None:
|
||||
break;
|
||||
|
||||
case eLeapEventType.eLeapEventType_Connection:
|
||||
LEAP_CONNECTION_EVENT connection_evt;
|
||||
StructMarshal<LEAP_CONNECTION_EVENT>.PtrToStruct(_msg.eventStructPtr, out connection_evt);
|
||||
|
@ -319,13 +324,11 @@ namespace LeapInternal
|
|||
StructMarshal<LEAP_CONNECTION_LOST_EVENT>.PtrToStruct(_msg.eventStructPtr, out connection_lost_evt);
|
||||
handleConnectionLost(ref connection_lost_evt);
|
||||
break;
|
||||
|
||||
case eLeapEventType.eLeapEventType_Device:
|
||||
LEAP_DEVICE_EVENT device_evt;
|
||||
StructMarshal<LEAP_DEVICE_EVENT>.PtrToStruct(_msg.eventStructPtr, out device_evt);
|
||||
handleDevice(ref device_evt);
|
||||
break;
|
||||
|
||||
// Note that unplugging a device generates an eLeapEventType_DeviceLost event
|
||||
// message, not a failure message. DeviceLost is further down.
|
||||
case eLeapEventType.eLeapEventType_DeviceFailure:
|
||||
|
@ -333,7 +336,6 @@ namespace LeapInternal
|
|||
StructMarshal<LEAP_DEVICE_FAILURE_EVENT>.PtrToStruct(_msg.eventStructPtr, out device_failure_evt);
|
||||
handleFailedDevice(ref device_failure_evt);
|
||||
break;
|
||||
|
||||
case eLeapEventType.eLeapEventType_Policy:
|
||||
LEAP_POLICY_EVENT policy_evt;
|
||||
StructMarshal<LEAP_POLICY_EVENT>.PtrToStruct(_msg.eventStructPtr, out policy_evt);
|
||||
|
@ -354,11 +356,6 @@ namespace LeapInternal
|
|||
StructMarshal<LEAP_DEVICE_EVENT>.PtrToStruct(_msg.eventStructPtr, out device_lost_evt);
|
||||
handleLostDevice(ref device_lost_evt);
|
||||
break;
|
||||
case eLeapEventType.eLeapEventType_ConfigChange:
|
||||
LEAP_CONFIG_CHANGE_EVENT config_change_evt;
|
||||
StructMarshal<LEAP_CONFIG_CHANGE_EVENT>.PtrToStruct(_msg.eventStructPtr, out config_change_evt);
|
||||
handleConfigChange(ref config_change_evt);
|
||||
break;
|
||||
case eLeapEventType.eLeapEventType_DroppedFrame:
|
||||
LEAP_DROPPED_FRAME_EVENT dropped_frame_evt;
|
||||
StructMarshal<LEAP_DROPPED_FRAME_EVENT>.PtrToStruct(_msg.eventStructPtr, out dropped_frame_evt);
|
||||
|
@ -374,16 +371,21 @@ namespace LeapInternal
|
|||
StructMarshal<LEAP_POINT_MAPPING_CHANGE_EVENT>.PtrToStruct(_msg.eventStructPtr, out point_mapping_change_evt);
|
||||
handlePointMappingChange(ref point_mapping_change_evt);
|
||||
break;
|
||||
case eLeapEventType.eLeapEventType_HeadPose:
|
||||
LEAP_HEAD_POSE_EVENT head_pose_event;
|
||||
StructMarshal<LEAP_HEAD_POSE_EVENT>.PtrToStruct(_msg.eventStructPtr, out head_pose_event);
|
||||
handleHeadPoseChange(ref head_pose_event);
|
||||
break;
|
||||
case eLeapEventType.eLeapEventType_DeviceStatusChange:
|
||||
LEAP_DEVICE_STATUS_CHANGE_EVENT status_evt;
|
||||
StructMarshal<LEAP_DEVICE_STATUS_CHANGE_EVENT>.PtrToStruct(_msg.eventStructPtr, out status_evt);
|
||||
handleDeviceStatusEvent(ref status_evt);
|
||||
break;
|
||||
case eLeapEventType.eLeapEventType_NewDeviceTransform:
|
||||
LEAP_NEW_DEVICE_TRANSFORM new_transform_evt;
|
||||
StructMarshal<LEAP_NEW_DEVICE_TRANSFORM>.PtrToStruct(_msg.eventStructPtr, out new_transform_evt);
|
||||
handleNewDeviceTransform(ref new_transform_evt, _msg.deviceID);
|
||||
break;
|
||||
case eLeapEventType.eLeapEventType_Fiducial:
|
||||
LEAP_FIDUCIAL_POSE_EVENT fiducial_event;
|
||||
StructMarshal<LEAP_FIDUCIAL_POSE_EVENT>.PtrToStruct(_msg.eventStructPtr, out fiducial_event);
|
||||
handleFiducialPoseEvent(ref fiducial_event);
|
||||
break;
|
||||
} //switch on _msg.type
|
||||
|
||||
if (LeapEndProfilingBlock != null && hasBegunProfilingForThread)
|
||||
|
@ -582,7 +584,6 @@ namespace LeapInternal
|
|||
}
|
||||
|
||||
Marshal.FreeHGlobal(trackingBuffer);
|
||||
|
||||
}
|
||||
|
||||
public void GetInterpolatedLeftRightTransform(Int64 time,
|
||||
|
@ -622,6 +623,15 @@ namespace LeapInternal
|
|||
device.UpdateStatus(statusEvent.status);
|
||||
}
|
||||
|
||||
private void handleFiducialPoseEvent(ref LEAP_FIDUCIAL_POSE_EVENT fiducialPoseEvent)
|
||||
{
|
||||
if (LeapFiducialPose != null)
|
||||
{
|
||||
LeapFiducialPose.DispatchOnContext(this, EventContext,
|
||||
new FiducialPoseEventArgs(fiducialPoseEvent));
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDevice(ref LEAP_DEVICE_EVENT deviceMsg)
|
||||
{
|
||||
IntPtr deviceHandle = deviceMsg.device.handle;
|
||||
|
@ -733,19 +743,6 @@ namespace LeapInternal
|
|||
}
|
||||
}
|
||||
|
||||
private void handleConfigChange(ref LEAP_CONFIG_CHANGE_EVENT configEvent)
|
||||
{
|
||||
string config_key = "";
|
||||
_configRequests.TryGetValue(configEvent.requestId, out config_key);
|
||||
if (config_key != null)
|
||||
_configRequests.Remove(configEvent.requestId);
|
||||
if (LeapConfigChange != null)
|
||||
{
|
||||
LeapConfigChange.DispatchOnContext(this, EventContext,
|
||||
new ConfigChangeEventArgs(config_key, configEvent.status != false, configEvent.requestId));
|
||||
}
|
||||
}
|
||||
|
||||
private void reportLogMessage(ref LEAP_LOG_EVENT logMsg)
|
||||
{
|
||||
if (LeapLogEvent != null)
|
||||
|
@ -866,29 +863,30 @@ namespace LeapInternal
|
|||
_activePolicies[deviceID] = policyMsg.current_policy;
|
||||
}
|
||||
|
||||
private void handleNewDeviceTransform(ref LEAP_NEW_DEVICE_TRANSFORM deviceTransformMsg, UInt32 deviceID)
|
||||
{
|
||||
Device device = _devices.FindDeviceByID(deviceID);
|
||||
|
||||
if (device != null)
|
||||
{
|
||||
device.FindDeviceTransform();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void SetAndClearPolicy(Controller.PolicyFlag set, Controller.PolicyFlag clear, Device device = null)
|
||||
{
|
||||
UInt64 setFlags = (ulong)FlagForPolicy(set);
|
||||
UInt64 clearFlags = (ulong)FlagForPolicy(clear);
|
||||
eLeapRS result;
|
||||
|
||||
if (device == null || !_multiDeviceAwareConnection)
|
||||
if (device != null && Controller.CheckRequiredServiceVersion(MinServiceVersionForMultiModeSupport, this))
|
||||
{
|
||||
result = LeapC.SetPolicyFlags(_leapConnection, setFlags, clearFlags);
|
||||
result = LeapC.SetPolicyFlagsEx(_leapConnection, device.Handle, setFlags, clearFlags);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Controller.CheckRequiredServiceVersion(MinServiceVersionForMultiModeSupport, this))
|
||||
{
|
||||
UnityEngine.Debug.LogWarning(String.Format("Your current tracking service does not support setting policy flags on a per device basis (min version is {0}.{1}.{2}). Please update your service: https://developer.leapmotion.com/tracking-software-download",
|
||||
MinServiceVersionForMultiModeSupport.major,
|
||||
MinServiceVersionForMultiModeSupport.minor,
|
||||
MinServiceVersionForMultiModeSupport.patch));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
result = LeapC.SetPolicyFlagsEx(_leapConnection, device.Handle, setFlags, clearFlags);
|
||||
result = LeapC.SetPolicyFlags(_leapConnection, setFlags, clearFlags);
|
||||
}
|
||||
|
||||
reportAbnormalResults("LeapC SetAndClearPolicy call was ", result);
|
||||
|
@ -900,23 +898,13 @@ namespace LeapInternal
|
|||
|
||||
eLeapRS result;
|
||||
|
||||
if (device == null || !_multiDeviceAwareConnection)
|
||||
if (device != null && Controller.CheckRequiredServiceVersion(MinServiceVersionForMultiModeSupport, this))
|
||||
{
|
||||
result = LeapC.SetPolicyFlags(_leapConnection, setFlags, 0);
|
||||
result = LeapC.SetPolicyFlagsEx(_leapConnection, device.Handle, setFlags, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Controller.CheckRequiredServiceVersion(MinServiceVersionForMultiModeSupport, this))
|
||||
{
|
||||
UnityEngine.Debug.LogWarning(String.Format("Your current tracking service does not support setting policy flags on a per device basis (min version is {0}.{1}.{2}). Please update your service: https://developer.leapmotion.com/tracking-software-download",
|
||||
MinServiceVersionForMultiModeSupport.major,
|
||||
MinServiceVersionForMultiModeSupport.minor,
|
||||
MinServiceVersionForMultiModeSupport.patch));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
result = LeapC.SetPolicyFlagsEx(_leapConnection, device.Handle, setFlags, 0);
|
||||
result = LeapC.SetPolicyFlags(_leapConnection, setFlags, 0);
|
||||
}
|
||||
|
||||
reportAbnormalResults("LeapC SetPolicyFlags call was ", result);
|
||||
|
@ -928,23 +916,13 @@ namespace LeapInternal
|
|||
|
||||
eLeapRS result;
|
||||
|
||||
if (device == null || !_multiDeviceAwareConnection)
|
||||
if (device != null && Controller.CheckRequiredServiceVersion(MinServiceVersionForMultiModeSupport, this))
|
||||
{
|
||||
result = LeapC.SetPolicyFlags(_leapConnection, 0, clearFlags);
|
||||
result = LeapC.SetPolicyFlagsEx(_leapConnection, device.Handle, 0, clearFlags);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Controller.CheckRequiredServiceVersion(MinServiceVersionForMultiModeSupport, this))
|
||||
{
|
||||
UnityEngine.Debug.LogWarning(String.Format("Your current tracking service does not support clearing policy flags on a per device basis (min version is {0}.{1}.{2}). Please update your service: https://developer.leapmotion.com/tracking-software-download",
|
||||
MinServiceVersionForMultiModeSupport.major,
|
||||
MinServiceVersionForMultiModeSupport.minor,
|
||||
MinServiceVersionForMultiModeSupport.patch));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
result = LeapC.SetPolicyFlagsEx(_leapConnection, device.Handle, 0, clearFlags);
|
||||
result = LeapC.SetPolicyFlags(_leapConnection, 0, clearFlags);
|
||||
}
|
||||
|
||||
reportAbnormalResults("LeapC SetPolicyFlags call was ", result);
|
||||
|
@ -1071,6 +1049,7 @@ namespace LeapInternal
|
|||
return _activePolicies.ContainsKey(deviceID);
|
||||
}
|
||||
|
||||
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
public uint GetConfigValue(string config_key)
|
||||
{
|
||||
uint requestId = 0;
|
||||
|
@ -1080,6 +1059,7 @@ namespace LeapInternal
|
|||
return requestId;
|
||||
}
|
||||
|
||||
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
public uint SetConfigValue<T>(string config_key, T value) where T : IConvertible
|
||||
{
|
||||
uint requestId = 0;
|
||||
|
@ -1322,6 +1302,19 @@ namespace LeapInternal
|
|||
Marshal.FreeHGlobal(buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a specific set of hints to hDevice, if this does not include previously set ones, they will be cleared.
|
||||
/// </summary>
|
||||
/// <param name="hDevice">The Device pointer for the trcking device to set the hints for</param>
|
||||
/// <param name="hints">The array of hints</param>
|
||||
public void RequestHandTrackingHintsOnDevice(IntPtr hDevice, string[] hints)
|
||||
{
|
||||
eLeapRS result;
|
||||
result = LeapC.SetDeviceHints(_leapConnection, hDevice, hints);
|
||||
|
||||
reportAbnormalResults("LeapC SetDeviceHints call was ", result);
|
||||
}
|
||||
|
||||
private eLeapRS _lastResult; //Used to avoid repeating the same log message, ie. for events like time out
|
||||
private void reportAbnormalResults(string context, eLeapRS result)
|
||||
{
|
||||
|
|
43
ml_lme/vendor/LeapCSharp/Controller.cs
vendored
43
ml_lme/vendor/LeapCSharp/Controller.cs
vendored
|
@ -10,6 +10,7 @@ namespace Leap
|
|||
{
|
||||
using LeapInternal;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
|
||||
|
@ -41,7 +42,6 @@ namespace Leap
|
|||
{
|
||||
Connection _connection;
|
||||
bool _disposed = false;
|
||||
bool _supportsMultipleDevices = true;
|
||||
string _serverNamespace = "Leap Service";
|
||||
|
||||
/// <summary>
|
||||
|
@ -232,6 +232,7 @@ namespace Leap
|
|||
/// Dispatched when a configuration setting changes.
|
||||
/// @since 3.0
|
||||
/// </summary>
|
||||
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
public event EventHandler<ConfigChangeEventArgs> ConfigChange
|
||||
{
|
||||
add
|
||||
|
@ -403,6 +404,21 @@ namespace Leap
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispatched when a Fiducial Marker has been tracked.
|
||||
/// </summary>
|
||||
public event EventHandler<FiducialPoseEventArgs> FiducialPose
|
||||
{
|
||||
add
|
||||
{
|
||||
_connection.LeapFiducialPose += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
_connection.LeapFiducialPose -= value;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
|
@ -446,14 +462,16 @@ namespace Leap
|
|||
_connection = Connection.GetConnection(new Connection.Key(connectionKey, serverNamespace));
|
||||
_connection.EventContext = SynchronizationContext.Current;
|
||||
|
||||
if (_connection.IsRunning)
|
||||
_hasInitialized = true;
|
||||
|
||||
_connection.LeapInit += OnInit;
|
||||
_connection.LeapConnection += OnConnect;
|
||||
_connection.LeapConnectionLost += OnDisconnect;
|
||||
|
||||
_supportsMultipleDevices = supportsMultipleDevices;
|
||||
_serverNamespace = serverNamespace;
|
||||
|
||||
_connection.Start(serverNamespace, supportsMultipleDevices);
|
||||
StartConnection();
|
||||
}
|
||||
|
||||
|
||||
|
@ -467,7 +485,7 @@ namespace Leap
|
|||
/// </summary>
|
||||
public void StartConnection()
|
||||
{
|
||||
_connection.Start(_serverNamespace, _supportsMultipleDevices);
|
||||
_connection.Start(_serverNamespace);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -621,6 +639,21 @@ namespace Leap
|
|||
return _connection.IsDeviceAvailable(device);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a specific set of hints, if this does not include previously set ones, they will be cleared.
|
||||
/// </summary>
|
||||
/// <param name="hints">The hints you wish to send</param>
|
||||
/// <param name="device">An optional specific Device, otherwise the first found will be used</param>
|
||||
public void RequestHandTrackingHints(string[] hints, Device device = null)
|
||||
{
|
||||
if (device == null)
|
||||
{
|
||||
device = Devices.ActiveDevices.FirstOrDefault();
|
||||
}
|
||||
|
||||
_connection.RequestHandTrackingHintsOnDevice(device.Handle, hints);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// In most cases you should get Frame objects using the LeapProvider.CurrentFrame
|
||||
/// property. The data in Frame objects taken directly from a Leap.Controller instance
|
||||
|
@ -870,7 +903,7 @@ namespace Leap
|
|||
///
|
||||
/// @since 1.0
|
||||
/// </summary>
|
||||
[Obsolete("Config.cs is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
public Config Config
|
||||
{
|
||||
get
|
||||
|
|
|
@ -14,12 +14,30 @@ namespace LeapInternal
|
|||
{
|
||||
public static readonly float MM_TO_M = 1e-3f;
|
||||
|
||||
public static bool leapToUnityTransformSet = false;
|
||||
private static LeapTransform leapToUnityTransform;
|
||||
|
||||
/**
|
||||
* Provides a static LeapTransform that converts from Leap units and coordinates to Unity
|
||||
*/
|
||||
public static LeapTransform LeapToUnityTransform
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!leapToUnityTransformSet)
|
||||
{
|
||||
leapToUnityTransform = new LeapTransform(Vector3.zero, Quaternion.identity, new Vector3(MM_TO_M, MM_TO_M, MM_TO_M));
|
||||
leapToUnityTransform.MirrorZ();
|
||||
leapToUnityTransformSet = true;
|
||||
}
|
||||
|
||||
return leapToUnityTransform;
|
||||
}
|
||||
}
|
||||
|
||||
public static void TransformToUnityUnits(this Hand hand)
|
||||
{
|
||||
LeapTransform leapTransform = new LeapTransform(Vector3.zero, Quaternion.identity, new Vector3(MM_TO_M, MM_TO_M, MM_TO_M));
|
||||
leapTransform.MirrorZ();
|
||||
|
||||
hand.Transform(leapTransform);
|
||||
hand.Transform(LeapToUnityTransform);
|
||||
}
|
||||
|
||||
|
||||
|
|
51
ml_lme/vendor/LeapCSharp/Device.cs
vendored
51
ml_lme/vendor/LeapCSharp/Device.cs
vendored
|
@ -255,22 +255,37 @@ namespace Leap
|
|||
return devicePose;
|
||||
}
|
||||
|
||||
bool deviceTransformAvailable = LeapC.GetDeviceTransformAvailable(Handle);
|
||||
return FindDeviceTransform();
|
||||
}
|
||||
}
|
||||
|
||||
if (!deviceTransformAvailable)
|
||||
internal Pose FindDeviceTransform()
|
||||
{
|
||||
// Check the service has valid support for device transforms
|
||||
LEAP_VERSION minimumServiceVersion = new LEAP_VERSION { major = 5, minor = 19, patch = 0 };
|
||||
if (!ServerStatus.IsServiceVersionValid(minimumServiceVersion))
|
||||
{
|
||||
devicePose = Pose.identity;
|
||||
poseSet = true;
|
||||
return Pose.identity;
|
||||
}
|
||||
|
||||
// Check the device transform is available before asking for one
|
||||
bool deviceTransformAvailable = LeapC.GetDeviceTransformAvailable(Handle);
|
||||
|
||||
if (!deviceTransformAvailable)
|
||||
{
|
||||
devicePose = Pose.identity;
|
||||
return Pose.identity;
|
||||
}
|
||||
|
||||
// Get the device transform data and check it is valid as data
|
||||
float[] data = new float[16];
|
||||
eLeapRS result = LeapC.GetDeviceTransform(Handle, data);
|
||||
|
||||
if (result != eLeapRS.eLeapRS_Success || data == null)
|
||||
{
|
||||
devicePose = Pose.identity;
|
||||
poseSet = true;
|
||||
return Pose.identity;
|
||||
}
|
||||
|
||||
|
@ -282,39 +297,35 @@ namespace Leap
|
|||
new Vector4(data[8], data[9], data[10], data[11]),
|
||||
new Vector4(data[12], data[13], data[14], data[15]));
|
||||
|
||||
|
||||
// An example of the expected matrix if it were 8cm forward from the head origin
|
||||
// Unitys matrices are generated as 4 columns:
|
||||
////An example of the expected matrix if it were 8cm forward from the head origin
|
||||
//// Unitys matrices are generated as 4 columns:
|
||||
//Matrix4x4 deviceTransform = new Matrix4x4(
|
||||
// new Vector4(-0.001f, 0, 0, 0),
|
||||
// new Vector4(0, 0, -0.001f, 0),
|
||||
// new Vector4(0, -0.001f, 0, 0),
|
||||
// new Vector4(0, 0, -0.08f, 1));
|
||||
|
||||
if (deviceTransform == Matrix4x4.identity)
|
||||
{
|
||||
devicePose = Pose.identity;
|
||||
poseSet = true;
|
||||
return Pose.identity;
|
||||
}
|
||||
//// An example of applying a rotation to the existing device transform
|
||||
//Matrix4x4 rotationMatrix = Matrix4x4.Rotate(Quaternion.Euler(0, 90, 0));
|
||||
//deviceTransform = deviceTransform * rotationMatrix;
|
||||
|
||||
Matrix4x4 openXRToUnity = new Matrix4x4(
|
||||
new Vector4(1f, 0, 0, 0),
|
||||
new Vector4(0, 1f, 0, 0),
|
||||
Matrix4x4 openXRToUnitySwizzle = new Matrix4x4(
|
||||
new Vector4(1.0f, 0, 0, 0),
|
||||
new Vector4(0, 1.0f, 0, 0),
|
||||
new Vector4(0, 0, -1f, 0),
|
||||
new Vector4(0, 0, 0, 1));
|
||||
new Vector4(0, 0, 0, 1f));
|
||||
|
||||
deviceTransform = openXRToUnity * deviceTransform;
|
||||
// Converts device transform from openxr space to unity space
|
||||
deviceTransform = openXRToUnitySwizzle.inverse * deviceTransform * openXRToUnitySwizzle;
|
||||
|
||||
Vector3 outputPos = deviceTransform.GetPosition();
|
||||
//Quaternion outputRot = deviceTransform.rotation; // Note: the matrices we receive are not rotatrion matrices. This produces unexpected results
|
||||
Quaternion outputRot = deviceTransform.rotation;
|
||||
|
||||
devicePose = new Pose(outputPos, Quaternion.identity);
|
||||
devicePose = new Pose(outputPos, outputRot);
|
||||
|
||||
poseSet = true;
|
||||
return devicePose;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the internal status field of the current device
|
||||
|
|
32
ml_lme/vendor/LeapCSharp/Events.cs
vendored
32
ml_lme/vendor/LeapCSharp/Events.cs
vendored
|
@ -10,6 +10,7 @@ namespace Leap
|
|||
{
|
||||
using LeapInternal;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
/// <summary>
|
||||
/// An enumeration defining the types of Leap Motion events.
|
||||
|
@ -35,7 +36,8 @@ namespace Leap
|
|||
EVENT_DROPPED_FRAME,
|
||||
EVENT_IMAGE, //!< An unrequested image is available
|
||||
EVENT_POINT_MAPPING_CHANGE,
|
||||
EVENT_HEAD_POSE
|
||||
EVENT_HEAD_POSE,
|
||||
EVENT_FIDUCIAL_POSE
|
||||
};
|
||||
/// <summary>
|
||||
/// A generic object with no arguments beyond the event type.
|
||||
|
@ -159,6 +161,7 @@ namespace Leap
|
|||
/// Provides the configuration key, whether the change was successful, and the id of the original change request.
|
||||
/// @since 3.0
|
||||
/// </summary>
|
||||
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
public class ConfigChangeEventArgs : LeapEventArgs
|
||||
{
|
||||
public ConfigChangeEventArgs(string config_key, bool succeeded, uint requestId) : base(LeapEvent.EVENT_CONFIG_CHANGE)
|
||||
|
@ -308,6 +311,33 @@ namespace Leap
|
|||
public LEAP_QUATERNION headOrientation { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispatched when a Fiducial Marker is tracked
|
||||
///
|
||||
/// Note: Family and Size are not currently implemented
|
||||
/// </summary>
|
||||
public class FiducialPoseEventArgs : LeapEventArgs
|
||||
{
|
||||
public FiducialPoseEventArgs(LEAP_FIDUCIAL_POSE_EVENT poseEvent) : base(LeapEvent.EVENT_FIDUCIAL_POSE)
|
||||
{
|
||||
this.id = poseEvent.id;
|
||||
this.family = ""; // TODO: Marshal.PtrToStringAnsi(poseEvent.family); - when ptr is implemented in LeapC
|
||||
this.size = poseEvent.size;
|
||||
this.timestamp = poseEvent.timestamp;
|
||||
this.estimated_error = poseEvent.estimated_error;
|
||||
this.translation = poseEvent.translation;
|
||||
this.rotation = poseEvent.rotation;
|
||||
}
|
||||
|
||||
public int id { get; set; }
|
||||
public string family { get; set; }
|
||||
public float size { get; set; }
|
||||
public float timestamp { get; set; }
|
||||
public float estimated_error { get; set; }
|
||||
public LEAP_VECTOR translation { get; set; }
|
||||
public LEAP_QUATERNION rotation { get; set; }
|
||||
}
|
||||
|
||||
public struct BeginProfilingForThreadArgs
|
||||
{
|
||||
public string threadName;
|
||||
|
|
1
ml_lme/vendor/LeapCSharp/IController.cs
vendored
1
ml_lme/vendor/LeapCSharp/IController.cs
vendored
|
@ -37,6 +37,7 @@ namespace Leap
|
|||
|
||||
//new
|
||||
event EventHandler<PolicyEventArgs> PolicyChange;
|
||||
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
event EventHandler<ConfigChangeEventArgs> ConfigChange;
|
||||
event EventHandler<DistortionEventArgs> DistortionChange;
|
||||
event EventHandler<ImageEventArgs> ImageReady;
|
||||
|
|
84
ml_lme/vendor/LeapCSharp/LeapC.cs
vendored
84
ml_lme/vendor/LeapCSharp/LeapC.cs
vendored
|
@ -532,15 +532,26 @@ namespace LeapInternal
|
|||
/// <summary>
|
||||
/// A new head pose is available.
|
||||
/// </summary>
|
||||
[Obsolete("Head pose events are not supported and will never be raised")]
|
||||
eLeapEventType_HeadPose,
|
||||
/// <summary>
|
||||
/// A new head pose is available.
|
||||
/// </summary>
|
||||
[Obsolete("Eye pose events are not supported and will never be raised")]
|
||||
eLeapEventType_Eyes,
|
||||
/// <summary>
|
||||
/// A new head pose is available.
|
||||
/// A new IMU information frame is available.
|
||||
/// </summary>
|
||||
eLeapEventType_IMU
|
||||
eLeapEventType_IMU,
|
||||
/// <summary>
|
||||
/// Notification that the service received a new device transformation matrix
|
||||
/// Use LeapGetDeviceTransform to update your cached information.
|
||||
/// </summary>
|
||||
eLeapEventType_NewDeviceTransform,
|
||||
/// <summary>
|
||||
/// An event provided when a fiducial marker has been tracked
|
||||
/// </summary>
|
||||
eLeapEventType_Fiducial
|
||||
};
|
||||
|
||||
public enum eLeapDeviceFlag : uint
|
||||
|
@ -718,6 +729,12 @@ namespace LeapInternal
|
|||
public LEAP_VECTOR head_angular_velocity;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct LEAP_NEW_DEVICE_TRANSFORM
|
||||
{
|
||||
public UInt32 reserved;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct LEAP_CONNECTION_MESSAGE
|
||||
{
|
||||
|
@ -974,6 +991,18 @@ namespace LeapInternal
|
|||
public string zoneName;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
|
||||
public struct LEAP_FIDUCIAL_POSE_EVENT
|
||||
{
|
||||
public int id;
|
||||
public IntPtr family; // char*
|
||||
public float size;
|
||||
public Int64 timestamp;
|
||||
public float estimated_error;
|
||||
public LEAP_VECTOR translation;
|
||||
public LEAP_QUATERNION rotation;
|
||||
}
|
||||
|
||||
public class LeapC
|
||||
{
|
||||
private LeapC() { }
|
||||
|
@ -1023,6 +1052,9 @@ namespace LeapInternal
|
|||
[DllImport("LeapC", EntryPoint = "LeapOpenConnection")]
|
||||
public static extern eLeapRS OpenConnection(IntPtr hConnection);
|
||||
|
||||
[DllImport("LeapC", EntryPoint = "LeapSetConnectionMetadata")]
|
||||
public static extern eLeapRS SetConnectionMetadata(IntPtr hConnection, string metadata, UIntPtr len);
|
||||
|
||||
[DllImport("LeapC", EntryPoint = "LeapSetAllocator")]
|
||||
public static extern eLeapRS SetAllocator(IntPtr hConnection, ref LEAP_ALLOCATOR pAllocator);
|
||||
|
||||
|
@ -1122,12 +1154,15 @@ namespace LeapInternal
|
|||
[DllImport("LeapC", EntryPoint = "LeapDestroyConnection")]
|
||||
public static extern void DestroyConnection(IntPtr connection);
|
||||
|
||||
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
[DllImport("LeapC", EntryPoint = "LeapSaveConfigValue")]
|
||||
private static extern eLeapRS SaveConfigValue(IntPtr hConnection, string key, IntPtr value, out UInt32 requestId);
|
||||
|
||||
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
[DllImport("LeapC", EntryPoint = "LeapRequestConfigValue")]
|
||||
public static extern eLeapRS RequestConfigValue(IntPtr hConnection, string name, out UInt32 request_id);
|
||||
|
||||
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
public static eLeapRS SaveConfigValue(IntPtr hConnection, string key, bool value, out UInt32 requestId)
|
||||
{
|
||||
LEAP_VARIANT_VALUE_TYPE valueStruct = new LEAP_VARIANT_VALUE_TYPE(); //This is a C# approximation of a C union
|
||||
|
@ -1135,6 +1170,7 @@ namespace LeapInternal
|
|||
valueStruct.boolValue = value ? 1 : 0;
|
||||
return SaveConfigWithValueType(hConnection, key, valueStruct, out requestId);
|
||||
}
|
||||
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
public static eLeapRS SaveConfigValue(IntPtr hConnection, string key, Int32 value, out UInt32 requestId)
|
||||
{
|
||||
LEAP_VARIANT_VALUE_TYPE valueStruct = new LEAP_VARIANT_VALUE_TYPE();
|
||||
|
@ -1142,6 +1178,7 @@ namespace LeapInternal
|
|||
valueStruct.intValue = value;
|
||||
return SaveConfigWithValueType(hConnection, key, valueStruct, out requestId);
|
||||
}
|
||||
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
public static eLeapRS SaveConfigValue(IntPtr hConnection, string key, float value, out UInt32 requestId)
|
||||
{
|
||||
LEAP_VARIANT_VALUE_TYPE valueStruct = new LEAP_VARIANT_VALUE_TYPE();
|
||||
|
@ -1149,6 +1186,7 @@ namespace LeapInternal
|
|||
valueStruct.floatValue = value;
|
||||
return SaveConfigWithValueType(hConnection, key, valueStruct, out requestId);
|
||||
}
|
||||
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
public static eLeapRS SaveConfigValue(IntPtr hConnection, string key, string value, out UInt32 requestId)
|
||||
{
|
||||
LEAP_VARIANT_REF_TYPE valueStruct;
|
||||
|
@ -1156,6 +1194,8 @@ namespace LeapInternal
|
|||
valueStruct.stringValue = value;
|
||||
return SaveConfigWithRefType(hConnection, key, valueStruct, out requestId);
|
||||
}
|
||||
|
||||
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
private static eLeapRS SaveConfigWithValueType(IntPtr hConnection, string key, LEAP_VARIANT_VALUE_TYPE valueStruct, out UInt32 requestId)
|
||||
{
|
||||
IntPtr configValue = Marshal.AllocHGlobal(Marshal.SizeOf(valueStruct));
|
||||
|
@ -1171,6 +1211,8 @@ namespace LeapInternal
|
|||
}
|
||||
return callResult;
|
||||
}
|
||||
|
||||
[Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")]
|
||||
private static eLeapRS SaveConfigWithRefType(IntPtr hConnection, string key, LEAP_VARIANT_REF_TYPE valueStruct, out UInt32 requestId)
|
||||
{
|
||||
IntPtr configValue = Marshal.AllocHGlobal(Marshal.SizeOf(valueStruct));
|
||||
|
@ -1230,5 +1272,43 @@ namespace LeapInternal
|
|||
|
||||
[DllImport("LeapC", EntryPoint = "LeapGetVersion")]
|
||||
public static extern eLeapRS GetVersion(IntPtr hConnection, eLeapVersionPart versionPart, ref LEAP_VERSION pVersion);
|
||||
|
||||
|
||||
[DllImport("LeapC", EntryPoint = "LeapGetServerStatus")]
|
||||
public static extern eLeapRS GetServerStatus(UInt32 timeout, ref IntPtr status);
|
||||
|
||||
[DllImport("LeapC", EntryPoint = "LeapReleaseServerStatus")]
|
||||
public static extern eLeapRS ReleaseServerStatus(ref LEAP_SERVER_STATUS status);
|
||||
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
|
||||
public struct LEAP_SERVER_STATUS
|
||||
{
|
||||
public string version;
|
||||
public UInt32 device_count;
|
||||
public IntPtr devices;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
|
||||
public struct LEAP_SERVER_STATUS_DEVICE
|
||||
{
|
||||
public string serial;
|
||||
public string type;
|
||||
}
|
||||
|
||||
public static eLeapRS SetDeviceHints(IntPtr hConnection, IntPtr hDevice, string[] hints)
|
||||
{
|
||||
// Ensure the final element of the array is null terminated.
|
||||
if (hints.Length == 0 || hints[^1] != null)
|
||||
{
|
||||
Array.Resize(ref hints, hints.Length + 1);
|
||||
hints[^1] = null;
|
||||
}
|
||||
|
||||
return SetDeviceHintsInternal(hConnection, hDevice, hints);
|
||||
}
|
||||
|
||||
[DllImport("LeapC", EntryPoint = "LeapSetDeviceHints")]
|
||||
private static extern eLeapRS SetDeviceHintsInternal(IntPtr hConnection, IntPtr hDevice, string[] hints);
|
||||
}
|
||||
}
|
138
ml_lme/vendor/LeapCSharp/MetadataUtil.cs
vendored
Normal file
138
ml_lme/vendor/LeapCSharp/MetadataUtil.cs
vendored
Normal file
|
@ -0,0 +1,138 @@
|
|||
/******************************************************************************
|
||||
* Copyright (C) Ultraleap, Inc. 2011-2024. *
|
||||
* *
|
||||
* Use subject to the terms of the Apache License 2.0 available at *
|
||||
* http://www.apache.org/licenses/LICENSE-2.0, or another agreement *
|
||||
* between Ultraleap and you, your company or other organization. *
|
||||
******************************************************************************/
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace Leap
|
||||
{
|
||||
/// <summary>
|
||||
/// This class captures information regarding use of the Ultraleap Unity Plugin
|
||||
/// This data is anonymized and only sent to Ultraleap when you choose to allow it.
|
||||
/// You can change your analytics preferences in the Ultraleap Tracking Control Panel.
|
||||
/// "Settings > Help Improve Tracking"
|
||||
/// </summary>
|
||||
#if UNITY_EDITOR
|
||||
[UnityEditor.InitializeOnLoad]
|
||||
#endif
|
||||
public class MetadataUtil
|
||||
{
|
||||
[System.Serializable]
|
||||
private struct Analytics
|
||||
{
|
||||
public Telemetry telemetry;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private struct Telemetry
|
||||
{
|
||||
public string app_name;
|
||||
public string app_type;
|
||||
public string engine_name;
|
||||
public string engine_version;
|
||||
public string plugin_version;
|
||||
public string installation_source;
|
||||
public string interaction_system;
|
||||
public string render_pipeline;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// Fire a one-off call to capture metadata at edit time on the first editor update
|
||||
static MetadataUtil()
|
||||
{
|
||||
UnityEditor.EditorApplication.update -= FirstEditorUpdate;
|
||||
UnityEditor.EditorApplication.update += FirstEditorUpdate;
|
||||
}
|
||||
|
||||
static void FirstEditorUpdate()
|
||||
{
|
||||
UnityEditor.EditorApplication.update -= FirstEditorUpdate;
|
||||
|
||||
// This will capture some values within the editor that may not be accessible in builds
|
||||
// e.g. Plugin Source and Plugin Versions
|
||||
GetMetaData();
|
||||
}
|
||||
#endif
|
||||
|
||||
public static string GetMetaData()
|
||||
{
|
||||
Analytics analytics = new Analytics();
|
||||
analytics.telemetry = new Telemetry();
|
||||
|
||||
analytics.telemetry.app_name = Application.productName;
|
||||
analytics.telemetry.app_type = GetAppType();
|
||||
analytics.telemetry.engine_name = "Unity";
|
||||
analytics.telemetry.engine_version = Application.unityVersion;
|
||||
analytics.telemetry.plugin_version = Leap.Unity.UltraleapSettings.Instance.PluginVersion;
|
||||
analytics.telemetry.installation_source = Leap.Unity.UltraleapSettings.Instance.PluginSource;
|
||||
analytics.telemetry.interaction_system = GetInteractionSystem();
|
||||
analytics.telemetry.render_pipeline = GetRenderPipeline();
|
||||
|
||||
string json = JsonUtility.ToJson(analytics, true);
|
||||
return json;
|
||||
}
|
||||
|
||||
static string GetAppType()
|
||||
{
|
||||
string appType = "Build";
|
||||
|
||||
#if UNITY_EDITOR
|
||||
appType = "Editor";
|
||||
#endif
|
||||
|
||||
return appType;
|
||||
}
|
||||
|
||||
static string GetRenderPipeline()
|
||||
{
|
||||
string renderPipeline = "Built In";
|
||||
|
||||
if (QualitySettings.renderPipeline != null)
|
||||
{
|
||||
renderPipeline = QualitySettings.renderPipeline.GetType().ToString().Split(".").Last();
|
||||
}
|
||||
else if (GraphicsSettings.currentRenderPipeline != null)
|
||||
{
|
||||
renderPipeline = GraphicsSettings.currentRenderPipeline.GetType().ToString().Split(".").Last();
|
||||
}
|
||||
|
||||
return renderPipeline;
|
||||
}
|
||||
|
||||
static string GetInteractionSystem()
|
||||
{
|
||||
// Physical Hands
|
||||
if (GameObject.Find("Physical Hands Manager") ||
|
||||
GameObject.Find("Left HardContactHand") ||
|
||||
GameObject.Find("Left SoftContactHand") ||
|
||||
GameObject.Find("Left NoContactHand"))
|
||||
{
|
||||
return "Physical Hands";
|
||||
}
|
||||
|
||||
// Interaction Engine
|
||||
if (GameObject.Find("Interaction Hand (Left)"))
|
||||
{
|
||||
return "Interaction Engine";
|
||||
}
|
||||
|
||||
// XR Hands
|
||||
if (Leap.Unity.UltraleapSettings.Instance.leapSubsystemEnabled ||
|
||||
Leap.Unity.UltraleapSettings.Instance.updateLeapInputSystem ||
|
||||
Leap.Unity.UltraleapSettings.Instance.updateMetaInputSystem)
|
||||
{
|
||||
return "UL XR Hands";
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
}
|
112
ml_lme/vendor/LeapCSharp/ServerStatus.cs
vendored
Normal file
112
ml_lme/vendor/LeapCSharp/ServerStatus.cs
vendored
Normal file
|
@ -0,0 +1,112 @@
|
|||
/******************************************************************************
|
||||
* Copyright (C) Ultraleap, Inc. 2011-2024. *
|
||||
* *
|
||||
* Use subject to the terms of the Apache License 2.0 available at *
|
||||
* http://www.apache.org/licenses/LICENSE-2.0, or another agreement *
|
||||
* between Ultraleap and you, your company or other organization. *
|
||||
******************************************************************************/
|
||||
|
||||
namespace LeapInternal
|
||||
{
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
|
||||
public static class ServerStatus
|
||||
{
|
||||
const double requestInterval = 1.0f;
|
||||
static double lastRequestTimestamp;
|
||||
|
||||
static LeapC.LEAP_SERVER_STATUS lastStatus;
|
||||
static LeapC.LEAP_SERVER_STATUS_DEVICE[] lastDevices;
|
||||
|
||||
public static void GetStatus()
|
||||
{
|
||||
if (lastRequestTimestamp + requestInterval < Time.realtimeSinceStartup)
|
||||
{
|
||||
IntPtr statusPtr = new IntPtr();
|
||||
LeapC.GetServerStatus(1000, ref statusPtr);
|
||||
|
||||
lastStatus = Marshal.PtrToStructure<LeapC.LEAP_SERVER_STATUS>(statusPtr);
|
||||
|
||||
MarshalUnmananagedArray2Struct(lastStatus.devices, (int)lastStatus.device_count, out lastDevices);
|
||||
LeapC.ReleaseServerStatus(ref lastStatus);
|
||||
lastRequestTimestamp = Time.realtimeSinceStartup;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsServiceVersionValid(LEAP_VERSION _requiredVersion)
|
||||
{
|
||||
GetStatus();
|
||||
|
||||
if (lastStatus.version != null)
|
||||
{
|
||||
string[] versions = lastStatus.version.Split('v')[1].Split('-')[0].Split('.');
|
||||
LEAP_VERSION curVersion = new LEAP_VERSION { major = int.Parse(versions[0]), minor = int.Parse(versions[1]), patch = int.Parse(versions[2]) };
|
||||
|
||||
if (_requiredVersion.major < curVersion.major)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (_requiredVersion.major == curVersion.major)
|
||||
{
|
||||
if (_requiredVersion.minor < curVersion.minor)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (_requiredVersion.minor == curVersion.minor && _requiredVersion.patch <= curVersion.patch)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static string[] GetSerialNumbers()
|
||||
{
|
||||
GetStatus();
|
||||
|
||||
string[] serials = new string[lastDevices.Length];
|
||||
|
||||
for (int i = 0; i < lastDevices.Length; i++)
|
||||
{
|
||||
serials[i] = lastDevices[i].serial;
|
||||
}
|
||||
|
||||
return serials;
|
||||
}
|
||||
|
||||
public static string GetDeviceType(string _serial)
|
||||
{
|
||||
GetStatus();
|
||||
|
||||
if (lastDevices != null)
|
||||
{
|
||||
for (int i = 0; i < lastDevices.Length; i++)
|
||||
{
|
||||
if (_serial == "" || _serial == lastDevices[i].serial)
|
||||
{
|
||||
return lastDevices[i].type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public static void MarshalUnmananagedArray2Struct<T>(IntPtr unmanagedArray, int length, out T[] mangagedArray)
|
||||
{
|
||||
var size = Marshal.SizeOf(typeof(T));
|
||||
mangagedArray = new T[length];
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
IntPtr ins = new IntPtr(unmanagedArray.ToInt64() + i * size);
|
||||
mangagedArray[i] = Marshal.PtrToStructure<T>(ins);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
380
ml_lme/vendor/LeapCSharp/UltraleapSettings.cs
vendored
Normal file
380
ml_lme/vendor/LeapCSharp/UltraleapSettings.cs
vendored
Normal file
|
@ -0,0 +1,380 @@
|
|||
/******************************************************************************
|
||||
* Copyright (C) Ultraleap, Inc. 2011-2024. *
|
||||
* *
|
||||
* Use subject to the terms of the Apache License 2.0 available at *
|
||||
* http://www.apache.org/licenses/LICENSE-2.0, or another agreement *
|
||||
* between Ultraleap and you, your company or other organization. *
|
||||
******************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using System.IO;
|
||||
#endif
|
||||
|
||||
namespace Leap.Unity
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[CustomEditor(typeof(UltraleapSettings))]
|
||||
public class UltraleapSettingsDrawer : Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
|
||||
EditorGUILayout.Space(20);
|
||||
if (GUILayout.Button("Open Ultraleap Settings"))
|
||||
{
|
||||
SettingsService.OpenProjectSettings("Project/Ultraleap");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UNITY_EDITOR
|
||||
static class UltraleapProjectSettings
|
||||
{
|
||||
static SerializedObject settings = UltraleapSettings.GetSerializedSettings();
|
||||
|
||||
[SettingsProvider]
|
||||
public static SettingsProvider CreateUltraleapSettingsProvider()
|
||||
{
|
||||
// First parameter is the path in the Settings window.
|
||||
// Second parameter is the scope of this setting: it only appears in the Project Settings window.
|
||||
var provider = new SettingsProvider("Project/Ultraleap", SettingsScope.Project)
|
||||
{
|
||||
// By default the last token of the path is used as display name if no label is provided.
|
||||
label = "Ultraleap",
|
||||
// Create the SettingsProvider and initialize its drawing (IMGUI) function in place:
|
||||
guiHandler = (searchContext) =>
|
||||
{
|
||||
if (settings == null)
|
||||
{
|
||||
settings = UltraleapSettings.GetSerializedSettings();
|
||||
}
|
||||
|
||||
LeapSubSystemSection(settings);
|
||||
InputActionsSection(settings);
|
||||
HintingSection(settings);
|
||||
NotificationSection(settings);
|
||||
ResetSection(settings);
|
||||
|
||||
settings.ApplyModifiedProperties();
|
||||
settings.UpdateIfRequiredOrScript();
|
||||
},
|
||||
|
||||
// Populate the search keywords to enable smart search filtering and label highlighting:
|
||||
keywords = new HashSet<string>(new[] { "XRHands", "Leap", "Leap Input System", "Meta Aim System", "Subsystem", "Leap Motion", "Ultraleap", "Ultraleap Settings" })
|
||||
};
|
||||
|
||||
return provider;
|
||||
}
|
||||
|
||||
private static void LeapSubSystemSection(SerializedObject settings)
|
||||
{
|
||||
EditorGUILayout.Space(10);
|
||||
EditorGUILayout.LabelField("Leap XRHands Subsystem", EditorStyles.boldLabel);
|
||||
|
||||
EditorGUILayout.Space(5);
|
||||
EditorGUILayout.HelpBox("If using OpenXR for hand input, use the Hand Tracking Subsystem in XR Plug-in Management/OpenXR. Do not enable both subsystems." +
|
||||
"\r\n\nThis option can not be toggled at runtime.", MessageType.Info, true);
|
||||
|
||||
EditorGUILayout.Space(5);
|
||||
|
||||
using (new EditorGUI.IndentLevelScope())
|
||||
{
|
||||
SerializedProperty leapSubsystemEnabledProperty = settings.FindProperty("leapSubsystemEnabled");
|
||||
leapSubsystemEnabledProperty.boolValue = EditorGUILayout.ToggleLeft("Enable Leap XRHands Subsystem", leapSubsystemEnabledProperty.boolValue);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(30);
|
||||
|
||||
settings.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
private static void InputActionsSection(SerializedObject settings)
|
||||
{
|
||||
EditorGUILayout.LabelField("Input Actions", EditorStyles.boldLabel);
|
||||
EditorGUILayout.Space(5);
|
||||
|
||||
using (new EditorGUI.IndentLevelScope())
|
||||
{
|
||||
SerializedProperty updateLeapInputSystemProperty = settings.FindProperty("updateLeapInputSystem");
|
||||
updateLeapInputSystemProperty.boolValue = EditorGUILayout.ToggleLeft("Update Leap Input System with XRHands", updateLeapInputSystemProperty.boolValue);
|
||||
|
||||
SerializedProperty updateMetaInputSystemProperty = settings.FindProperty("updateMetaInputSystem");
|
||||
updateMetaInputSystemProperty.boolValue = EditorGUILayout.ToggleLeft("Update Meta Aim Input System with XRHands", updateMetaInputSystemProperty.boolValue);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(30);
|
||||
|
||||
settings.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
private static void HintingSection(SerializedObject settings)
|
||||
{
|
||||
EditorGUILayout.LabelField("Hand Tracking Hints", EditorStyles.boldLabel);
|
||||
EditorGUILayout.Space(5);
|
||||
|
||||
using (new EditorGUI.IndentLevelScope())
|
||||
{
|
||||
SerializedProperty hints = settings.FindProperty("startupHints");
|
||||
EditorGUILayout.PropertyField(hints, true);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(10);
|
||||
|
||||
settings.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
private static void NotificationSection(SerializedObject settings)
|
||||
{
|
||||
EditorGUILayout.LabelField("Notifications", EditorStyles.boldLabel);
|
||||
EditorGUILayout.Space(5);
|
||||
|
||||
using (new EditorGUI.IndentLevelScope())
|
||||
{
|
||||
// Android Build Warnings
|
||||
SerializedProperty showAndroidBuildArchitectureWarning = settings.FindProperty("showAndroidBuildArchitectureWarning");
|
||||
showAndroidBuildArchitectureWarning.boolValue = EditorGUILayout.ToggleLeft("Show Android Architecture build warning", showAndroidBuildArchitectureWarning.boolValue);
|
||||
|
||||
// Physical Hands Settings Warnings
|
||||
SerializedProperty showPhysicalHandsPhysicsSettingsWarning = settings.FindProperty("showPhysicalHandsPhysicsSettingsWarning");
|
||||
showPhysicalHandsPhysicsSettingsWarning.boolValue = EditorGUILayout.ToggleLeft("Show Physical Hands settings warning", showPhysicalHandsPhysicsSettingsWarning.boolValue);
|
||||
|
||||
// Attachment Hands delete content warnings
|
||||
bool curValue = !EditorUtility.GetDialogOptOutDecision(DialogOptOutDecisionType.ForThisMachine, "UL attachment hands popup");
|
||||
curValue = EditorGUILayout.ToggleLeft("Show clear Attachment Hands deletes content warning", curValue);
|
||||
EditorUtility.SetDialogOptOutDecision(DialogOptOutDecisionType.ForThisMachine, "UL attachment hands popup", !curValue);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(30);
|
||||
|
||||
settings.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
private static void ResetSection(SerializedObject settings)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
if (GUILayout.Button("Reset To Defaults", GUILayout.MaxWidth(EditorGUIUtility.currentViewWidth/2)))
|
||||
{
|
||||
if (EditorUtility.DisplayDialog("Reset all settings", "This will reset all settings in this Ultraleap settings file", "Yes", "No"))
|
||||
{
|
||||
UltraleapSettings.Instance.ResetToDefaults();
|
||||
}
|
||||
}
|
||||
GUILayout.FlexibleSpace();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
settings.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public class UltraleapSettings : ScriptableObject
|
||||
{
|
||||
static UltraleapSettings instance;
|
||||
public static UltraleapSettings Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (instance != null)
|
||||
return instance;
|
||||
else
|
||||
return instance = FindSettingsSO();
|
||||
}
|
||||
set { instance = value; }
|
||||
}
|
||||
|
||||
// XRHands and Input System
|
||||
[HideInInspector, SerializeField]
|
||||
public bool leapSubsystemEnabled = false;
|
||||
|
||||
[HideInInspector, SerializeField]
|
||||
public bool updateLeapInputSystem = false;
|
||||
|
||||
[HideInInspector, SerializeField]
|
||||
public bool updateMetaInputSystem = false;
|
||||
|
||||
[HideInInspector, SerializeField]
|
||||
public string[] startupHints = new string[] { };
|
||||
|
||||
[HideInInspector, SerializeField]
|
||||
public bool showAndroidBuildArchitectureWarning = true;
|
||||
|
||||
[HideInInspector, SerializeField]
|
||||
public bool showPhysicalHandsPhysicsSettingsWarning = true;
|
||||
|
||||
[HideInInspector, SerializeField]
|
||||
public string pluginVersion = "Unknown";
|
||||
public string PluginVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
pluginVersion = GetPluginVersion();
|
||||
#endif
|
||||
return pluginVersion;
|
||||
}
|
||||
}
|
||||
|
||||
[HideInInspector, SerializeField]
|
||||
public string pluginSource = "Unknown";
|
||||
public string PluginSource
|
||||
{
|
||||
get
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
pluginSource = GetPluginSource();
|
||||
#endif
|
||||
return pluginSource;
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetToDefaults()
|
||||
{
|
||||
leapSubsystemEnabled = false;
|
||||
updateLeapInputSystem = false;
|
||||
updateMetaInputSystem = false;
|
||||
|
||||
startupHints = new string[] { };
|
||||
|
||||
showAndroidBuildArchitectureWarning = true;
|
||||
showPhysicalHandsPhysicsSettingsWarning = true;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
static string GetPluginVersion()
|
||||
{
|
||||
if (Utils.IsPackageAvailable("com.ultraleap.tracking", out var packageInfo)) // Check the package exists so we can use package manage wizardry
|
||||
{
|
||||
return packageInfo.version;
|
||||
}
|
||||
else // We are not using package manager :( we need to look for version number elsewhere
|
||||
{
|
||||
return FindPluginVersionInAssets();
|
||||
}
|
||||
}
|
||||
|
||||
static string GetPluginSource()
|
||||
{
|
||||
if (Utils.IsPackageAvailable("com.ultraleap.tracking", out var packageInfo)) // Check the package exists so we can use package manage wizardry
|
||||
{
|
||||
if (packageInfo.source == UnityEditor.PackageManager.PackageSource.Registry &&
|
||||
packageInfo.registry != null &&
|
||||
packageInfo.registry.url.Contains("openupm"))
|
||||
{
|
||||
return "UPM OpenUPM";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "UPM " + packageInfo.source;
|
||||
}
|
||||
}
|
||||
else // We are not using package manager :( we need to look for version number elsewhere
|
||||
{
|
||||
return "Unity Package";
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("Ultraleap/Open Ultraleap Settings", false, 50)]
|
||||
private static void SelectULSettingsDropdown()
|
||||
{
|
||||
SettingsService.OpenProjectSettings("Project/Ultraleap");
|
||||
}
|
||||
|
||||
[MenuItem("Ultraleap/Help/Documentation", false, 100)]
|
||||
private static void OpenDocs()
|
||||
{
|
||||
Application.OpenURL("https://docs.ultraleap.com/unity-api/");
|
||||
}
|
||||
|
||||
[MenuItem("Ultraleap/Help/Report a Bug", false, 101)]
|
||||
private static void OpenGithubNewIssueView()
|
||||
{
|
||||
Application.OpenURL("https://github.com/ultraleap/UnityPlugin/issues/new");
|
||||
}
|
||||
|
||||
[MenuItem("Ultraleap/Help/Support/Submit a Support Request", false, 102)]
|
||||
private static void OpenSupportRequest()
|
||||
{
|
||||
Application.OpenURL("https://support.leapmotion.com/hc/en-us/requests/new");
|
||||
}
|
||||
|
||||
[MenuItem("Ultraleap/Help/Support/Join Our Discord", false, 103)]
|
||||
private static void OpenDiscord()
|
||||
{
|
||||
Application.OpenURL("https://discord.com/invite/3VCndThqxS");
|
||||
}
|
||||
#endif
|
||||
|
||||
private static UltraleapSettings FindSettingsSO()
|
||||
{
|
||||
// Try to directly load the asset
|
||||
UltraleapSettings ultraleapSettings = Resources.Load<UltraleapSettings>("Ultraleap Settings");
|
||||
|
||||
if (ultraleapSettings != null)
|
||||
{
|
||||
instance = ultraleapSettings;
|
||||
return instance;
|
||||
}
|
||||
|
||||
UltraleapSettings[] settingsSO = Resources.FindObjectsOfTypeAll(typeof(UltraleapSettings)) as UltraleapSettings[];
|
||||
|
||||
if (settingsSO != null && settingsSO.Length > 0)
|
||||
{
|
||||
instance = settingsSO[0]; // Assume there is only one settings file
|
||||
}
|
||||
else
|
||||
{
|
||||
instance = CreateSettingsSO();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
static UltraleapSettings CreateSettingsSO()
|
||||
{
|
||||
UltraleapSettings newSO = null;
|
||||
#if UNITY_EDITOR
|
||||
newSO = ScriptableObject.CreateInstance<UltraleapSettings>();
|
||||
|
||||
Directory.CreateDirectory(Application.dataPath + "/Resources/");
|
||||
AssetDatabase.CreateAsset(newSO, "Assets/Resources/Ultraleap Settings.asset");
|
||||
#endif
|
||||
return newSO;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static SerializedObject GetSerializedSettings()
|
||||
{
|
||||
return new SerializedObject(Instance);
|
||||
}
|
||||
|
||||
static string FindPluginVersionInAssets()
|
||||
{
|
||||
string pluginVersionFromAssets = "";
|
||||
|
||||
string[] fileGUIDs = AssetDatabase.FindAssets("Version");
|
||||
|
||||
foreach (var guid in fileGUIDs)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
|
||||
if (path.Contains("/Ultraleap/Tracking/Version.txt"))
|
||||
{
|
||||
string content = File.ReadAllText(path);
|
||||
|
||||
pluginVersionFromAssets = content;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return pluginVersionFromAssets;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -75,10 +75,17 @@ namespace ml_pam
|
|||
|
||||
m_enabled = Settings.Enabled;
|
||||
|
||||
Settings.EnabledChange += this.SetEnabled;
|
||||
Settings.GrabOffsetChange += this.SetGrabOffset;
|
||||
Settings.LeadingHandChange += this.OnLeadingHandChange;
|
||||
Settings.HandsExtensionChange += this.OnHandsExtensionChange;
|
||||
Settings.OnEnabledChanged.AddHandler(this.OnEnabledChanged);
|
||||
Settings.OnGrabOffsetChanged.AddHandler(this.OnGrabOffsetChanged);
|
||||
Settings.OnLeadingHandChanged.AddHandler(this.OnLeadingHandChanged);
|
||||
Settings.OnHandsExtensionChanged.AddHandler(this.OnHandsExtensionChanged);
|
||||
|
||||
GameEvents.OnAvatarClear.AddHandler(this.OnAvatarClear);
|
||||
GameEvents.OnAvatarSetup.AddHandler(this.OnAvatarSetup);
|
||||
GameEvents.OnAvatarReuse.AddHandler(this.OnAvatarReuse);
|
||||
GameEvents.OnPlayspaceScale.AddHandler(this.OnPlayspaceScale);
|
||||
GameEvents.OnPickupGrab.AddHandler(this.OnPickupGrab);
|
||||
GameEvents.OnPickupDrop.AddHandler(this.OnPickupDrop);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
|
@ -98,10 +105,17 @@ namespace ml_pam
|
|||
m_pickup = null;
|
||||
m_vrIK = null;
|
||||
|
||||
Settings.EnabledChange -= this.SetEnabled;
|
||||
Settings.GrabOffsetChange -= this.SetGrabOffset;
|
||||
Settings.LeadingHandChange -= this.OnLeadingHandChange;
|
||||
Settings.HandsExtensionChange -= this.OnHandsExtensionChange;
|
||||
Settings.OnEnabledChanged.RemoveHandler(this.OnEnabledChanged);
|
||||
Settings.OnGrabOffsetChanged.RemoveHandler(this.OnGrabOffsetChanged);
|
||||
Settings.OnLeadingHandChanged.RemoveHandler(this.OnLeadingHandChanged);
|
||||
Settings.OnHandsExtensionChanged.RemoveHandler(this.OnHandsExtensionChanged);
|
||||
|
||||
GameEvents.OnAvatarClear.RemoveHandler(this.OnAvatarClear);
|
||||
GameEvents.OnAvatarSetup.RemoveHandler(this.OnAvatarSetup);
|
||||
GameEvents.OnAvatarReuse.RemoveHandler(this.OnAvatarReuse);
|
||||
GameEvents.OnPlayspaceScale.RemoveHandler(this.OnPlayspaceScale);
|
||||
GameEvents.OnPickupGrab.RemoveHandler(this.OnPickupGrab);
|
||||
GameEvents.OnPickupDrop.RemoveHandler(this.OnPickupDrop);
|
||||
}
|
||||
|
||||
void Update()
|
||||
|
@ -221,7 +235,7 @@ namespace ml_pam
|
|||
}
|
||||
|
||||
// Settings
|
||||
void SetEnabled(bool p_state)
|
||||
void OnEnabledChanged(bool p_state)
|
||||
{
|
||||
m_enabled = p_state;
|
||||
|
||||
|
@ -232,13 +246,13 @@ namespace ml_pam
|
|||
if(m_rightHandState != HandState.Empty)
|
||||
SetArmActive(Settings.LeadHand.Right, true);
|
||||
|
||||
OnHandsExtensionChange(Settings.HandsExtension);
|
||||
OnHandsExtensionChanged(Settings.HandsExtension);
|
||||
}
|
||||
else
|
||||
SetArmActive(Settings.LeadHand.Both, false, true);
|
||||
}
|
||||
|
||||
void SetGrabOffset(float p_value)
|
||||
void OnGrabOffsetChanged(float p_value)
|
||||
{
|
||||
if(m_leftTarget != null)
|
||||
m_leftTarget.localPosition = new Vector3(c_offsetLimit * m_playspaceScale * -p_value, 0f, 0f);
|
||||
|
@ -246,7 +260,7 @@ namespace ml_pam
|
|||
m_rightTarget.localPosition = new Vector3(c_offsetLimit * m_playspaceScale * p_value, 0f, 0f);
|
||||
}
|
||||
|
||||
void OnLeadingHandChange(Settings.LeadHand p_hand)
|
||||
void OnLeadingHandChanged(Settings.LeadHand p_hand)
|
||||
{
|
||||
if(m_pickup != null)
|
||||
{
|
||||
|
@ -281,7 +295,7 @@ namespace ml_pam
|
|||
}
|
||||
}
|
||||
|
||||
void OnHandsExtensionChange(bool p_state)
|
||||
void OnHandsExtensionChanged(bool p_state)
|
||||
{
|
||||
if(m_enabled)
|
||||
{
|
||||
|
@ -315,7 +329,7 @@ namespace ml_pam
|
|||
}
|
||||
|
||||
// Game events
|
||||
internal void OnAvatarClear()
|
||||
void OnAvatarClear()
|
||||
{
|
||||
m_vrIK = null;
|
||||
m_armIKLeft = null;
|
||||
|
@ -323,7 +337,7 @@ namespace ml_pam
|
|||
m_armLength = 0f;
|
||||
}
|
||||
|
||||
internal void OnAvatarSetup()
|
||||
void OnAvatarSetup()
|
||||
{
|
||||
m_inVR = Utils.IsInVR();
|
||||
m_vrIK = PlayerSetup.Instance._animator.GetComponent<VRIK>();
|
||||
|
@ -351,10 +365,10 @@ namespace ml_pam
|
|||
SetupArmIK();
|
||||
}
|
||||
|
||||
SetEnabled(m_enabled);
|
||||
OnEnabledChanged(m_enabled);
|
||||
}
|
||||
|
||||
internal void OnAvatarReinitialize()
|
||||
void OnAvatarReuse()
|
||||
{
|
||||
// Old VRIK is destroyed by game
|
||||
m_inVR = Utils.IsInVR();
|
||||
|
@ -373,12 +387,12 @@ namespace ml_pam
|
|||
else if(!m_inVR)
|
||||
SetupArmIK();
|
||||
|
||||
SetEnabled(m_enabled);
|
||||
OnEnabledChanged(m_enabled);
|
||||
}
|
||||
|
||||
internal void OnPickupGrab(CVRPickupObject p_pickup, Vector3 p_hit)
|
||||
void OnPickupGrab(CVRPickupObject p_pickup, Vector3 p_hit)
|
||||
{
|
||||
if(p_pickup.ControllerRay == ViewManager.Instance.desktopControllerRay)
|
||||
if(p_pickup.IsGrabbedByMe && (p_pickup.ControllerRay == ViewManager.Instance.desktopControllerRay))
|
||||
{
|
||||
m_pickup = p_pickup;
|
||||
|
||||
|
@ -416,7 +430,7 @@ namespace ml_pam
|
|||
}
|
||||
}
|
||||
|
||||
internal void OnPickupDrop(CVRPickupObject p_pickup)
|
||||
void OnPickupDrop(CVRPickupObject p_pickup)
|
||||
{
|
||||
if(m_pickup == p_pickup)
|
||||
{
|
||||
|
@ -440,10 +454,10 @@ namespace ml_pam
|
|||
}
|
||||
}
|
||||
|
||||
internal void OnPlayspaceScale(float p_relation)
|
||||
void OnPlayspaceScale(float p_relation)
|
||||
{
|
||||
m_playspaceScale = p_relation;
|
||||
SetGrabOffset(Settings.GrabOffset);
|
||||
OnGrabOffsetChanged(Settings.GrabOffset);
|
||||
}
|
||||
|
||||
// Arbitrary
|
||||
|
|
159
ml_pam/GameEvents.cs
Normal file
159
ml_pam/GameEvents.cs
Normal file
|
@ -0,0 +1,159 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_pam
|
||||
{
|
||||
static class GameEvents
|
||||
{
|
||||
internal class GameEvent
|
||||
{
|
||||
event Action m_action;
|
||||
public void AddHandler(Action p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action p_listener) => m_action -= p_listener;
|
||||
public void Invoke() => m_action?.Invoke();
|
||||
}
|
||||
internal class GameEvent<T1>
|
||||
{
|
||||
event Action<T1> m_action;
|
||||
public void AddHandler(Action<T1> p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action<T1> p_listener) => m_action -= p_listener;
|
||||
public void Invoke(T1 p_obj) => m_action?.Invoke(p_obj);
|
||||
}
|
||||
internal class GameEvent<T1, T2>
|
||||
{
|
||||
event Action<T1, T2> m_action;
|
||||
public void AddHandler(Action<T1, T2> p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action<T1, T2> p_listener) => m_action -= p_listener;
|
||||
public void Invoke(T1 p_objA, T2 p_objB) => m_action?.Invoke(p_objA, p_objB);
|
||||
}
|
||||
|
||||
public static readonly GameEvent OnAvatarSetup = new GameEvent();
|
||||
public static readonly GameEvent OnAvatarClear = new GameEvent();
|
||||
public static readonly GameEvent OnAvatarReuse = new GameEvent();
|
||||
public static readonly GameEvent<float> OnPlayspaceScale = new GameEvent<float>();
|
||||
public static readonly GameEvent<CVRPickupObject, Vector3> OnPickupGrab = new GameEvent<CVRPickupObject, Vector3>();
|
||||
public static readonly GameEvent<CVRPickupObject> OnPickupDrop = new GameEvent<CVRPickupObject>();
|
||||
|
||||
internal static void Init(HarmonyLib.Harmony p_instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
p_instance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(PlayerSetup).GetMethod("SetPlaySpaceScale", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnPlayspaceScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(CVRPickupObject).GetMethod("OnGrab", BindingFlags.Instance | BindingFlags.NonPublic),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnCVRPickupObjectGrab_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(CVRPickupObject).GetMethod("OnDrop", BindingFlags.Instance | BindingFlags.NonPublic),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnCVRPickupObjectDrop_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarClear_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarClear.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarSetup.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarReinitialize_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarReuse.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnPlayspaceScale_Postfix(float ____avatarScaleRelation)
|
||||
{
|
||||
try
|
||||
{
|
||||
OnPlayspaceScale.Invoke(____avatarScaleRelation);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCVRPickupObjectGrab_Postfix(ref CVRPickupObject __instance, Vector3 __0)
|
||||
{
|
||||
try
|
||||
{
|
||||
OnPickupGrab.Invoke(__instance, __0);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCVRPickupObjectDrop_Postfix(ref CVRPickupObject __instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
OnPickupDrop.Invoke(__instance);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
132
ml_pam/Main.cs
132
ml_pam/Main.cs
|
@ -1,56 +1,15 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.InteractionSystem;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using ABI_RC.Core.Player;
|
||||
|
||||
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(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRPickupObject).GetMethod("OnGrab", BindingFlags.Instance | BindingFlags.NonPublic),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnCVRPickupObjectGrab_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRPickupObject).GetMethod("OnDrop", BindingFlags.Instance | BindingFlags.NonPublic),
|
||||
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))
|
||||
);
|
||||
GameEvents.Init(HarmonyInstance);
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
|
||||
}
|
||||
|
@ -65,96 +24,9 @@ namespace ml_pam
|
|||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
if(m_localMover != null)
|
||||
UnityEngine.Object.Destroy(m_localMover);
|
||||
m_localMover = 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 OnAvatarReinitialize_Postfix() => ms_instance?.OnAvatarReinitialize();
|
||||
void OnAvatarReinitialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localMover != null)
|
||||
m_localMover.OnAvatarReinitialize();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCVRPickupObjectGrab_Postfix(ref CVRPickupObject __instance, Vector3 __0) => ms_instance?.OnCVRPickupObjectGrab(__instance, __0);
|
||||
void OnCVRPickupObjectGrab(CVRPickupObject p_pickup, Vector3 p_hit)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(p_pickup.IsGrabbedByMe && (m_localMover != null))
|
||||
m_localMover.OnPickupGrab(p_pickup, 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_pam.PickupArmMovement), "PickupArmMovement", "1.1.1", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_pam.PickupArmMovement), "PickupArmMovement", "1.1.2", "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)]
|
||||
|
|
|
@ -6,6 +6,14 @@ namespace ml_pam
|
|||
{
|
||||
static class Settings
|
||||
{
|
||||
internal class SettingEvent<T>
|
||||
{
|
||||
event Action<T> m_action;
|
||||
public void AddHandler(Action<T> p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action<T> p_listener) => m_action -= p_listener;
|
||||
public void Invoke(T p_value) => m_action?.Invoke(p_value);
|
||||
}
|
||||
|
||||
public enum ModSetting
|
||||
{
|
||||
Enabled = 0,
|
||||
|
@ -28,10 +36,10 @@ namespace ml_pam
|
|||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
||||
public static event Action<bool> EnabledChange;
|
||||
public static event Action<float> GrabOffsetChange;
|
||||
public static event Action<LeadHand> LeadingHandChange;
|
||||
public static event Action<bool> HandsExtensionChange;
|
||||
public static readonly SettingEvent<bool> OnEnabledChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<float> OnGrabOffsetChanged = new SettingEvent<float>();
|
||||
public static readonly SettingEvent<LeadHand> OnLeadingHandChanged = new SettingEvent<LeadHand>();
|
||||
public static readonly SettingEvent<bool> OnHandsExtensionChanged = new SettingEvent<bool>();
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
|
@ -78,6 +86,8 @@ namespace ml_pam
|
|||
}
|
||||
|
||||
static void OnToggleUpdate(string p_name, string p_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
|
@ -86,22 +96,30 @@ namespace ml_pam
|
|||
case ModSetting.Enabled:
|
||||
{
|
||||
Enabled = bool.Parse(p_value);
|
||||
EnabledChange?.Invoke(Enabled);
|
||||
OnEnabledChanged.Invoke(Enabled);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.HandsExtension:
|
||||
{
|
||||
HandsExtension = bool.Parse(p_value);
|
||||
HandsExtensionChange?.Invoke(HandsExtension);
|
||||
} break;
|
||||
OnHandsExtensionChanged.Invoke(HandsExtension);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSliderUpdate(string p_name, string p_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
|
@ -110,7 +128,7 @@ namespace ml_pam
|
|||
case ModSetting.GrabOffset:
|
||||
{
|
||||
GrabOffset = int.Parse(p_value) * 0.01f;
|
||||
GrabOffsetChange?.Invoke(GrabOffset);
|
||||
OnGrabOffsetChanged.Invoke(GrabOffset);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -118,8 +136,15 @@ namespace ml_pam
|
|||
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnDropdownUpdate(string p_name, string p_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
|
@ -128,7 +153,7 @@ namespace ml_pam
|
|||
case ModSetting.LeadHand:
|
||||
{
|
||||
LeadingHand = (LeadHand)int.Parse(p_value);
|
||||
LeadingHandChange?.Invoke(LeadingHand);
|
||||
OnLeadingHandChanged.Invoke(LeadingHand);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -136,5 +161,10 @@ namespace ml_pam
|
|||
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
<PackageId>PickupArmMovement</PackageId>
|
||||
<Version>1.1.1</Version>
|
||||
<Version>1.1.2</Version>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>PickupArmMovement</Product>
|
||||
|
|
|
@ -23,6 +23,9 @@ namespace ml_pin
|
|||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
m_soundManager = null;
|
||||
|
||||
CVRGameEventSystem.Player.OnJoin.RemoveListener(OnPlayerJoin);
|
||||
CVRGameEventSystem.Player.OnLeave.RemoveListener(OnPlayerLeave);
|
||||
}
|
||||
|
||||
IEnumerator WaitForInstances()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_pin.PlayersInstanceNotifier), "PlayersInstanceNotifier", "1.0.3", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_pin.PlayersInstanceNotifier), "PlayersInstanceNotifier", "1.0.4", "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)]
|
||||
|
|
|
@ -6,6 +6,14 @@ namespace ml_pin
|
|||
{
|
||||
static class Settings
|
||||
{
|
||||
internal class SettingEvent<T>
|
||||
{
|
||||
event Action<T> m_action;
|
||||
public void AddHandler(Action<T> p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action<T> p_listener) => m_action -= p_listener;
|
||||
public void Invoke(T p_value) => m_action?.Invoke(p_value);
|
||||
}
|
||||
|
||||
public enum NotificationType
|
||||
{
|
||||
None = 0,
|
||||
|
@ -33,12 +41,12 @@ namespace ml_pin
|
|||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
||||
public static event Action<NotificationType> NotifyTypeChange;
|
||||
public static event Action<float> VolumeChange;
|
||||
public static event Action<bool> NotifyInPublicChange;
|
||||
public static event Action<bool> NotifyInFriendsChange;
|
||||
public static event Action<bool> NotifyInPrivateChange;
|
||||
public static event Action<bool> FriendsAlwaysChange;
|
||||
public static readonly SettingEvent<NotificationType> OnNotifyTypeChanged = new SettingEvent<NotificationType>();
|
||||
public static readonly SettingEvent<float> OnVolumeChanged = new SettingEvent<float>();
|
||||
public static readonly SettingEvent<bool> OnNotifyInPublicChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnNotifyInFriendsChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnNotifyInPrivateChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnFriendsAlwaysChanged = new SettingEvent<bool>();
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
|
@ -89,6 +97,8 @@ namespace ml_pin
|
|||
}
|
||||
|
||||
static void OnToggleUpdate(string p_name, string p_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
|
@ -97,28 +107,28 @@ namespace ml_pin
|
|||
case ModSetting.NotifyInPublic:
|
||||
{
|
||||
NotifyInPublic = bool.Parse(p_value);
|
||||
NotifyInPublicChange?.Invoke(NotifyInPublic);
|
||||
OnNotifyInPublicChanged.Invoke(NotifyInPublic);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.NotifyInFriends:
|
||||
{
|
||||
NotifyInFriends = bool.Parse(p_value);
|
||||
NotifyInFriendsChange?.Invoke(NotifyInFriends);
|
||||
OnNotifyInFriendsChanged.Invoke(NotifyInFriends);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.NotifyInPrivate:
|
||||
{
|
||||
NotifyInPrivate = bool.Parse(p_value);
|
||||
NotifyInPrivateChange?.Invoke(NotifyInPrivate);
|
||||
OnNotifyInPrivateChanged.Invoke(NotifyInPrivate);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.FriendsAlways:
|
||||
{
|
||||
FriendsAlways = bool.Parse(p_value);
|
||||
FriendsAlwaysChange?.Invoke(FriendsAlways);
|
||||
OnFriendsAlwaysChanged.Invoke(FriendsAlways);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -126,8 +136,15 @@ namespace ml_pin
|
|||
ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSliderUpdate(string p_name, string p_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
|
@ -136,7 +153,7 @@ namespace ml_pin
|
|||
case ModSetting.Volume:
|
||||
{
|
||||
Volume = int.Parse(p_value) * 0.01f;
|
||||
VolumeChange?.Invoke(Volume);
|
||||
OnVolumeChanged.Invoke(Volume);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -144,8 +161,15 @@ namespace ml_pin
|
|||
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnDropdownUpdate(string p_name, string p_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
|
@ -154,7 +178,7 @@ namespace ml_pin
|
|||
case ModSetting.NotifyType:
|
||||
{
|
||||
NotifyType = (NotificationType)int.Parse(p_value);
|
||||
NotifyTypeChange?.Invoke(NotifyType);
|
||||
OnNotifyTypeChanged.Invoke(NotifyType);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -162,5 +186,10 @@ namespace ml_pin
|
|||
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>PlayersInstanceNotifier</Product>
|
||||
<Version>1.0.3</Version>
|
||||
<Version>1.0.4</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
|
99
ml_pmc/GameEvents.cs
Normal file
99
ml_pmc/GameEvents.cs
Normal file
|
@ -0,0 +1,99 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ml_pmc
|
||||
{
|
||||
static class GameEvents
|
||||
{
|
||||
internal class GameEvent
|
||||
{
|
||||
event Action m_action;
|
||||
public void AddHandler(Action p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action p_listener) => m_action -= p_listener;
|
||||
public void Invoke() => m_action?.Invoke();
|
||||
}
|
||||
|
||||
public static readonly GameEvent OnAvatarSetup = new GameEvent();
|
||||
public static readonly GameEvent OnAvatarClear = new GameEvent();
|
||||
public static readonly GameEvent OnAvatarPreReuse = new GameEvent();
|
||||
public static readonly GameEvent OnAvatarPostReuse = new GameEvent();
|
||||
|
||||
internal static void Init(HarmonyLib.Harmony p_instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
p_instance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarReinitialize_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarClear_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarClear.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarSetup.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarReinitialize_Prefix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarPreReuse.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarReinitialize_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarPostReuse.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
142
ml_pmc/Main.cs
142
ml_pmc/Main.cs
|
@ -1,55 +1,22 @@
|
|||
using ABI_RC.Core.Networking.IO.Social;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK;
|
||||
using ABI_RC.Systems.Movement;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using ABI_RC.Core.Player;
|
||||
|
||||
namespace ml_pmc
|
||||
{
|
||||
public class PlayerMovementCopycat : MelonLoader.MelonMod
|
||||
{
|
||||
static PlayerMovementCopycat ms_instance = null;
|
||||
|
||||
PoseCopycat m_localCopycat = null;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
if(ms_instance == null)
|
||||
ms_instance = this;
|
||||
|
||||
Settings.Init();
|
||||
ModUi.Init();
|
||||
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerMovementCopycat).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerMovementCopycat).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerMovementCopycat).GetMethod(nameof(OnAvatarReinitialize_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerMovementCopycat).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
GameEvents.Init(HarmonyInstance);
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
|
||||
}
|
||||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
ModUi.CopySwitch -= this.OnTargetSelect;
|
||||
|
||||
if(m_localCopycat != null)
|
||||
UnityEngine.Object.Destroy(m_localCopycat);
|
||||
m_localCopycat = null;
|
||||
|
@ -61,111 +28,6 @@ namespace ml_pmc
|
|||
yield return null;
|
||||
|
||||
m_localCopycat = PlayerSetup.Instance.gameObject.AddComponent<PoseCopycat>();
|
||||
ModUi.CopySwitch += this.OnTargetSelect;
|
||||
}
|
||||
|
||||
void OnTargetSelect(string p_id)
|
||||
{
|
||||
if(m_localCopycat != null)
|
||||
{
|
||||
if(m_localCopycat.IsActive())
|
||||
m_localCopycat.SetTarget(null);
|
||||
else
|
||||
{
|
||||
if(Friends.FriendsWith(p_id))
|
||||
{
|
||||
if(CVRPlayerManager.Instance.GetPlayerPuppetMaster(p_id, out PuppetMaster l_puppetMaster))
|
||||
{
|
||||
if(IsInSight(BetterBetterCharacterController.Instance.KinematicTriggerProxy.Collider, l_puppetMaster.GetComponent<CapsuleCollider>(), Utils.GetWorldMovementLimit()))
|
||||
m_localCopycat.SetTarget(l_puppetMaster);
|
||||
else
|
||||
ModUi.ShowAlert("Selected player is too far away or obstructed");
|
||||
}
|
||||
else
|
||||
ModUi.ShowAlert("Selected player isn't connected or ready yet");
|
||||
}
|
||||
else
|
||||
ModUi.ShowAlert("Selected player isn't your friend");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsInSight(CapsuleCollider p_source, CapsuleCollider p_target, float p_limit)
|
||||
{
|
||||
bool l_result = false;
|
||||
if((p_source != null) && (p_target != null))
|
||||
{
|
||||
Ray l_ray = new Ray();
|
||||
l_ray.origin = p_source.bounds.center;
|
||||
l_ray.direction = p_target.bounds.center - l_ray.origin;
|
||||
List<RaycastHit> l_hits = Physics.RaycastAll(l_ray, p_limit).ToList();
|
||||
if(l_hits.Count > 0)
|
||||
{
|
||||
l_hits.RemoveAll(hit => hit.collider.gameObject.layer == LayerMask.NameToLayer("UI Internal")); // Somehow layer mask in RaycastAll just ignores players entirely
|
||||
l_hits.RemoveAll(hit => hit.collider.gameObject.layer == LayerMask.NameToLayer("PlayerLocal"));
|
||||
l_hits.RemoveAll(hit => hit.collider.gameObject.layer == LayerMask.NameToLayer("PlayerClone"));
|
||||
l_hits.Sort((a, b) => ((a.distance < b.distance) ? -1 : 1));
|
||||
l_result = (l_hits.First().collider.gameObject.transform.root == p_target.transform.root);
|
||||
}
|
||||
}
|
||||
return l_result;
|
||||
}
|
||||
|
||||
// Patches
|
||||
static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear();
|
||||
void OnAvatarClear()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localCopycat != null)
|
||||
m_localCopycat.OnAvatarClear();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar();
|
||||
void OnSetupAvatar()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localCopycat != null)
|
||||
m_localCopycat.OnAvatarSetup();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarReinitialize_Prefix() => ms_instance?.OnPreAvatarReinitialize();
|
||||
void OnPreAvatarReinitialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localCopycat != null)
|
||||
m_localCopycat.OnPreAvatarReinitialize();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarReinitialize_Postfix() => ms_instance?.OnPostAvatarReinitialize();
|
||||
void OnPostAvatarReinitialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localCopycat != null)
|
||||
m_localCopycat.OnPostAvatarReinitialize();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,14 @@ namespace ml_pmc
|
|||
{
|
||||
static class ModUi
|
||||
{
|
||||
internal class UiEvent<T>
|
||||
{
|
||||
event Action<T> m_action;
|
||||
public void AddHandler(Action<T> p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action<T> p_listener) => m_action -= p_listener;
|
||||
public void Invoke(T p_value) => m_action?.Invoke(p_value);
|
||||
}
|
||||
|
||||
enum UiIndex
|
||||
{
|
||||
Toggle,
|
||||
|
@ -22,7 +30,7 @@ namespace ml_pmc
|
|||
Reset
|
||||
}
|
||||
|
||||
internal static Action<string> CopySwitch;
|
||||
public static readonly UiEvent<string> OnTargetSelect = new UiEvent<string>();
|
||||
|
||||
static List<QMUIElement> ms_uiElements = null;
|
||||
static string ms_selectedPlayer;
|
||||
|
@ -64,10 +72,10 @@ namespace ml_pmc
|
|||
(ms_uiElements[(int)UiIndex.Reset] as Button).OnPress += Reset;
|
||||
|
||||
BTKUILib.QuickMenuAPI.OnPlayerSelected += (_, id) => ms_selectedPlayer = id;
|
||||
PoseCopycat.OnActivityChange += UpdateToggleColor;
|
||||
PoseCopycat.OnCopycatChanged.AddHandler(OnCopycatChanged);
|
||||
}
|
||||
|
||||
static void OnCopySwitch() => CopySwitch?.Invoke(ms_selectedPlayer);
|
||||
static void OnCopySwitch() => OnTargetSelect.Invoke(ms_selectedPlayer);
|
||||
|
||||
static void OnToggleUpdate(UiIndex p_index, bool p_value, bool p_force = false)
|
||||
{
|
||||
|
@ -119,8 +127,7 @@ namespace ml_pmc
|
|||
|
||||
internal static void ShowAlert(string p_text) => BTKUILib.QuickMenuAPI.ShowAlertToast(p_text, 2);
|
||||
|
||||
// Currently broken in BTKUILib, waiting for fix
|
||||
static void UpdateToggleColor(bool p_state)
|
||||
static void OnCopycatChanged(bool p_state)
|
||||
{
|
||||
(ms_uiElements[(int)UiIndex.Toggle] as Button).ButtonIcon = (p_state ? "PMC-Dancing-On" : "PMC-Dancing");
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Networking.IO.Social;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK;
|
||||
using ABI_RC.Systems.IK.SubSystems;
|
||||
using ABI_RC.Systems.InputManagement;
|
||||
|
@ -11,10 +12,18 @@ namespace ml_pmc
|
|||
[DisallowMultipleComponent]
|
||||
public class PoseCopycat : MonoBehaviour
|
||||
{
|
||||
public class CopycatEvent<T1>
|
||||
{
|
||||
event System.Action<T1> m_action;
|
||||
public void AddHandler(System.Action<T1> p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(System.Action<T1> p_listener) => m_action -= p_listener;
|
||||
public void Invoke(T1 p_value) => m_action?.Invoke(p_value);
|
||||
}
|
||||
|
||||
static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f);
|
||||
|
||||
public static PoseCopycat Instance { get; private set; } = null;
|
||||
internal static System.Action<bool> OnActivityChange;
|
||||
internal static readonly CopycatEvent<bool> OnCopycatChanged = new CopycatEvent<bool>();
|
||||
|
||||
Animator m_animator = null;
|
||||
VRIK m_vrIk = null;
|
||||
|
@ -36,6 +45,13 @@ namespace ml_pmc
|
|||
{
|
||||
if(Instance == null)
|
||||
Instance = this;
|
||||
|
||||
GameEvents.OnAvatarClear.AddHandler(this.OnAvatarClear);
|
||||
GameEvents.OnAvatarSetup.AddHandler(this.OnAvatarSetup);
|
||||
GameEvents.OnAvatarPreReuse.AddHandler(this.OnAvatarPreReuse);
|
||||
GameEvents.OnAvatarPostReuse.AddHandler(this.OnAvatarPostReuse);
|
||||
|
||||
ModUi.OnTargetSelect.AddHandler(this.OnTargetSelect);
|
||||
}
|
||||
void OnDestroy()
|
||||
{
|
||||
|
@ -52,6 +68,13 @@ namespace ml_pmc
|
|||
m_animator = null;
|
||||
m_vrIk = null;
|
||||
m_lookAtIk = null;
|
||||
|
||||
GameEvents.OnAvatarClear.RemoveHandler(this.OnAvatarClear);
|
||||
GameEvents.OnAvatarSetup.RemoveHandler(this.OnAvatarSetup);
|
||||
GameEvents.OnAvatarPreReuse.RemoveHandler(this.OnAvatarPreReuse);
|
||||
GameEvents.OnAvatarPostReuse.RemoveHandler(this.OnAvatarPostReuse);
|
||||
|
||||
ModUi.OnTargetSelect.RemoveHandler(this.OnTargetSelect);
|
||||
}
|
||||
|
||||
// Unity events
|
||||
|
@ -196,14 +219,14 @@ namespace ml_pmc
|
|||
}
|
||||
}
|
||||
|
||||
// Patches
|
||||
internal void OnAvatarClear()
|
||||
// Game events
|
||||
void OnAvatarClear()
|
||||
{
|
||||
if(m_active)
|
||||
{
|
||||
RestoreIK();
|
||||
RestoreFingerTracking();
|
||||
OnActivityChange?.Invoke(false);
|
||||
OnCopycatChanged.Invoke(false);
|
||||
}
|
||||
m_active = false;
|
||||
|
||||
|
@ -222,7 +245,8 @@ namespace ml_pmc
|
|||
m_fingerTracking = false;
|
||||
m_pose = new HumanPose();
|
||||
}
|
||||
internal void OnAvatarSetup()
|
||||
|
||||
void OnAvatarSetup()
|
||||
{
|
||||
m_inVr = Utils.IsInVR();
|
||||
m_animator = PlayerSetup.Instance._animator;
|
||||
|
@ -250,12 +274,12 @@ namespace ml_pmc
|
|||
m_animator = null;
|
||||
}
|
||||
|
||||
internal void OnPreAvatarReinitialize()
|
||||
void OnAvatarPreReuse()
|
||||
{
|
||||
if(m_active)
|
||||
SetTarget(null);
|
||||
}
|
||||
internal void OnPostAvatarReinitialize()
|
||||
void OnAvatarPostReuse()
|
||||
{
|
||||
m_inVr = Utils.IsInVR();
|
||||
|
||||
|
@ -276,6 +300,35 @@ namespace ml_pmc
|
|||
}
|
||||
}
|
||||
|
||||
// Ui events
|
||||
void OnTargetSelect(string p_id)
|
||||
{
|
||||
if(m_active)
|
||||
SetTarget(null);
|
||||
else
|
||||
{
|
||||
if(m_animator != null)
|
||||
{
|
||||
if(Friends.FriendsWith(p_id))
|
||||
{
|
||||
if(CVRPlayerManager.Instance.GetPlayerPuppetMaster(p_id, out PuppetMaster l_puppetMaster))
|
||||
{
|
||||
if(Utils.IsInSight(BetterBetterCharacterController.Instance.KinematicTriggerProxy.Collider, l_puppetMaster.GetComponent<CapsuleCollider>(), Utils.GetWorldMovementLimit()))
|
||||
SetTarget(l_puppetMaster);
|
||||
else
|
||||
ModUi.ShowAlert("Selected player is too far away or obstructed");
|
||||
}
|
||||
else
|
||||
ModUi.ShowAlert("Selected player isn't connected or ready yet");
|
||||
}
|
||||
else
|
||||
ModUi.ShowAlert("Selected player isn't your friend");
|
||||
}
|
||||
else
|
||||
ModUi.ShowAlert("Local avatar isn't ready yet");
|
||||
}
|
||||
}
|
||||
|
||||
// IK updates
|
||||
void OnVRIKPreUpdate()
|
||||
{
|
||||
|
@ -319,7 +372,7 @@ namespace ml_pmc
|
|||
m_distanceLimit = Utils.GetWorldMovementLimit();
|
||||
|
||||
m_active = true;
|
||||
OnActivityChange?.Invoke(m_active);
|
||||
OnCopycatChanged.Invoke(m_active);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -341,7 +394,7 @@ namespace ml_pmc
|
|||
m_fingerTracking = false;
|
||||
|
||||
m_active = false;
|
||||
OnActivityChange?.Invoke(m_active);
|
||||
OnCopycatChanged.Invoke(m_active);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -371,7 +424,7 @@ namespace ml_pmc
|
|||
if(!CVRInputManager.Instance.individualFingerTracking)
|
||||
{
|
||||
// Left hand
|
||||
CVRInputManager.Instance.finger1StretchedLeftThumb = -0f;
|
||||
CVRInputManager.Instance.finger1StretchedLeftThumb = 0f;
|
||||
CVRInputManager.Instance.finger2StretchedLeftThumb = 0f;
|
||||
CVRInputManager.Instance.finger3StretchedLeftThumb = 0f;
|
||||
CVRInputManager.Instance.fingerSpreadLeftThumb = 0f;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_pmc.PlayerMovementCopycat), "PlayerMovementCopycat", "1.0.6", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_pmc.PlayerMovementCopycat), "PlayerMovementCopycat", "1.0.7", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||
[assembly: MelonLoader.MelonPriority(3)]
|
||||
[assembly: MelonLoader.MelonAdditionalDependencies("BTKUILib")]
|
||||
|
|
|
@ -5,6 +5,14 @@ namespace ml_pmc
|
|||
{
|
||||
static class Settings
|
||||
{
|
||||
internal class SettingEvent<T>
|
||||
{
|
||||
event Action<T> m_action;
|
||||
public void AddHandler(Action<T> p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action<T> p_listener) => m_action -= p_listener;
|
||||
public void Invoke(T p_value) => m_action?.Invoke(p_value);
|
||||
}
|
||||
|
||||
public enum ModSetting
|
||||
{
|
||||
Position,
|
||||
|
@ -24,13 +32,13 @@ namespace ml_pmc
|
|||
public static bool MirrorPosition { get; private set; } = false;
|
||||
public static bool MirrorRotation { get; private set; } = false;
|
||||
|
||||
public static Action<bool> PositionChange;
|
||||
public static Action<bool> RotationChange;
|
||||
public static Action<bool> GesturesChange;
|
||||
public static Action<bool> LookAtMixChange;
|
||||
public static Action<bool> MirrorPoseChange;
|
||||
public static Action<bool> MirrorPositionChange;
|
||||
public static Action<bool> MirrorRotationChange;
|
||||
public static readonly SettingEvent<bool> OnPositionChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnRotationChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnGesturesChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnLookAtMixChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnMirrorPoseChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnMirrorPositionChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnMirrorRotationChanged = new SettingEvent<bool>();
|
||||
|
||||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
@ -59,34 +67,36 @@ namespace ml_pmc
|
|||
}
|
||||
|
||||
public static void SetSetting(ModSetting p_setting, object p_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch(p_setting)
|
||||
{
|
||||
case ModSetting.Position:
|
||||
{
|
||||
Position = (bool)p_value;
|
||||
PositionChange?.Invoke((bool)p_value);
|
||||
OnPositionChanged.Invoke(Position);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.Rotation:
|
||||
{
|
||||
Rotation = (bool)p_value;
|
||||
RotationChange?.Invoke((bool)p_value);
|
||||
OnRotationChanged.Invoke(Rotation);
|
||||
break;
|
||||
}
|
||||
|
||||
case ModSetting.Gestures:
|
||||
{
|
||||
Gestures = (bool)p_value;
|
||||
GesturesChange?.Invoke((bool)p_value);
|
||||
OnGesturesChanged.Invoke(Gestures);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.LookAtMix:
|
||||
{
|
||||
LookAtMix = (bool)p_value;
|
||||
LookAtMixChange?.Invoke((bool)p_value);
|
||||
OnLookAtMixChanged.Invoke(LookAtMix);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -94,21 +104,21 @@ namespace ml_pmc
|
|||
case ModSetting.MirrorPose:
|
||||
{
|
||||
MirrorPose = (bool)p_value;
|
||||
MirrorPoseChange?.Invoke((bool)p_value);
|
||||
OnMirrorPoseChanged.Invoke(MirrorPose);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.MirrorPosition:
|
||||
{
|
||||
MirrorPosition = (bool)p_value;
|
||||
MirrorPositionChange?.Invoke((bool)p_value);
|
||||
OnMirrorPositionChanged.Invoke(MirrorPosition);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.MirrorRotation:
|
||||
{
|
||||
MirrorRotation = (bool)p_value;
|
||||
MirrorRotationChange?.Invoke((bool)p_value);
|
||||
OnMirrorRotationChanged.Invoke(MirrorRotation);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -116,5 +126,10 @@ namespace ml_pmc
|
|||
if(ms_entries != null)
|
||||
ms_entries[(int)p_setting].BoxedValue = p_value;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.Savior;
|
||||
using ABI_RC.Systems.InputManagement;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_pmc
|
||||
|
@ -72,5 +74,26 @@ namespace ml_pmc
|
|||
p_pose.bodyRotation.w *= -1f;
|
||||
p_pose.bodyPosition.x *= -1f;
|
||||
}
|
||||
|
||||
public static bool IsInSight(CapsuleCollider p_source, CapsuleCollider p_target, float p_limit)
|
||||
{
|
||||
bool l_result = false;
|
||||
if((p_source != null) && (p_target != null))
|
||||
{
|
||||
Ray l_ray = new Ray();
|
||||
l_ray.origin = p_source.bounds.center;
|
||||
l_ray.direction = p_target.bounds.center - l_ray.origin;
|
||||
List<RaycastHit> l_hits = Physics.RaycastAll(l_ray, p_limit).ToList();
|
||||
if(l_hits.Count > 0)
|
||||
{
|
||||
l_hits.RemoveAll(hit => hit.collider.gameObject.layer == LayerMask.NameToLayer("UI Internal")); // Somehow layer mask in RaycastAll just ignores players entirely
|
||||
l_hits.RemoveAll(hit => hit.collider.gameObject.layer == LayerMask.NameToLayer("PlayerLocal"));
|
||||
l_hits.RemoveAll(hit => hit.collider.gameObject.layer == LayerMask.NameToLayer("PlayerClone"));
|
||||
l_hits.Sort((a, b) => ((a.distance < b.distance) ? -1 : 1));
|
||||
l_result = (l_hits.First().collider.gameObject.transform.root == p_target.transform.root);
|
||||
}
|
||||
}
|
||||
return l_result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>PlayerMovementCopycat</Product>
|
||||
<Version>1.0.6</Version>
|
||||
<Version>1.0.7</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
|
253
ml_prm/GameEvents.cs
Normal file
253
ml_prm/GameEvents.cs
Normal file
|
@ -0,0 +1,253 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core;
|
||||
using ABI_RC.Core.InteractionSystem;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK;
|
||||
using ABI_RC.Systems.IK.SubSystems;
|
||||
using ABI_RC.Systems.Movement;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ml_prm
|
||||
{
|
||||
static class GameEvents
|
||||
{
|
||||
internal class EventResult
|
||||
{
|
||||
public bool m_result = false;
|
||||
}
|
||||
internal class GameEvent
|
||||
{
|
||||
event Action m_action;
|
||||
public void AddHandler(Action p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action p_listener) => m_action -= p_listener;
|
||||
public void Invoke() => m_action?.Invoke();
|
||||
}
|
||||
internal class GameEvent<T1>
|
||||
{
|
||||
event Action<T1> m_action;
|
||||
public void AddHandler(Action<T1> p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action<T1> p_listener) => m_action -= p_listener;
|
||||
public void Invoke(T1 p_obj) => m_action?.Invoke(p_obj);
|
||||
}
|
||||
|
||||
public static readonly GameEvent OnAvatarSetup = new GameEvent();
|
||||
public static readonly GameEvent OnAvatarClear = new GameEvent();
|
||||
public static readonly GameEvent OnAvatarPreReuse = new GameEvent();
|
||||
public static readonly GameEvent OnAvatarPostReuse = new GameEvent();
|
||||
public static readonly GameEvent<float> OnIKScaling = new GameEvent<float>();
|
||||
public static readonly GameEvent<CVRSeat> OnSeatPreSit = new GameEvent<CVRSeat>();
|
||||
public static readonly GameEvent OnCalibrationStart = new GameEvent();
|
||||
public static readonly GameEvent OnWorldPreSpawn = new GameEvent();
|
||||
public static readonly GameEvent OnCombatPreDown = new GameEvent();
|
||||
public static readonly GameEvent OnFlightChange = new GameEvent();
|
||||
public static readonly GameEvent<EventResult> OnIKOffsetUpdate = new GameEvent<EventResult>();
|
||||
|
||||
static readonly EventResult ms_result = new EventResult();
|
||||
|
||||
internal static void Init(HarmonyLib.Harmony p_instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
p_instance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarReinitialize_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(PlayerSetup).GetMethod("SetupIKScaling", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupIKScaling_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(CVRSeat).GetMethod(nameof(CVRSeat.SitDown)),
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnCVRSeatSitDown_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
|
||||
null
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(BodySystem).GetMethod(nameof(BodySystem.StartCalibration)),
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnStartCalibration_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
|
||||
null
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(RootLogic).GetMethod(nameof(RootLogic.SpawnOnWorldInstance)),
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnWorldSpawn_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
|
||||
null
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(CombatSystem).GetMethods().First(m => (!m.IsGenericMethod && m.Name == nameof(CombatSystem.Down))),
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnCombatDown_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
|
||||
null
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(BetterBetterCharacterController).GetMethod(nameof(BetterBetterCharacterController.ChangeFlight)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnChangeFlight_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(IKSystem).GetMethod("OnPreSolverUpdateActiveOffset", BindingFlags.Instance | BindingFlags.NonPublic),
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnOffsetUpdate_Prefix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarClear_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarClear.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarSetup.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarReinitialize_Prefix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarPreReuse.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarReinitialize_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAvatarPostReuse.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupIKScaling_Postfix(ref UnityEngine.Vector3 ___scaleDifference)
|
||||
{
|
||||
try
|
||||
{
|
||||
OnIKScaling.Invoke(1f + ___scaleDifference.y);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCVRSeatSitDown_Prefix(ref CVRSeat __instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
OnSeatPreSit.Invoke(__instance);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnStartCalibration_Prefix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnCalibrationStart.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnWorldSpawn_Prefix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnWorldPreSpawn.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCombatDown_Prefix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnCombatPreDown.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnChangeFlight_Postfix()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnFlightChange.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static bool OnOffsetUpdate_Prefix()
|
||||
{
|
||||
try
|
||||
{
|
||||
ms_result.m_result = false;
|
||||
OnIKOffsetUpdate.Invoke(ms_result);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
return !ms_result.m_result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Systems.Gravity;
|
||||
using ABI_RC.Systems.Movement;
|
||||
using UnityEngine;
|
||||
|
||||
|
|
241
ml_prm/Main.cs
241
ml_prm/Main.cs
|
@ -1,84 +1,20 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core;
|
||||
using ABI_RC.Core.InteractionSystem;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Util.AssetFiltering;
|
||||
using ABI_RC.Systems.Camera.VisualMods;
|
||||
using ABI_RC.Systems.IK;
|
||||
using ABI_RC.Systems.IK.SubSystems;
|
||||
using ABI_RC.Systems.Movement;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ml_prm
|
||||
{
|
||||
public class PlayerRagdollMod : MelonLoader.MelonMod
|
||||
{
|
||||
static readonly Type[] ms_teleportTypes = { typeof(UnityEngine.Vector3), typeof(bool), typeof(bool), typeof(UnityEngine.Quaternion?) };
|
||||
|
||||
static PlayerRagdollMod ms_instance = null;
|
||||
|
||||
RagdollController m_localController = null;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
if(ms_instance == null)
|
||||
ms_instance = this;
|
||||
|
||||
Settings.Init();
|
||||
ModUi.Init();
|
||||
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnAvatarReinitialize_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod("SetupIKScaling", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnSetupIKScaling_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRSeat).GetMethod(nameof(CVRSeat.SitDown)),
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnCVRSeatSitDown_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
|
||||
null
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(BodySystem).GetMethod(nameof(BodySystem.StartCalibration)),
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnStartCalibration_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
|
||||
null
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(RootLogic).GetMethod(nameof(RootLogic.SpawnOnWorldInstance)),
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnWorldSpawn_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
|
||||
null
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CombatSystem).GetMethods().First(m => (!m.IsGenericMethod && m.Name == nameof(CombatSystem.Down))),
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnCombatDown_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
|
||||
null
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(BetterBetterCharacterController).GetMethod(nameof(BetterBetterCharacterController.ChangeFlight)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnChangeFlight_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(IKSystem).GetMethod("OnPreSolverUpdateActiveOffset", BindingFlags.Instance | BindingFlags.NonPublic),
|
||||
new HarmonyLib.HarmonyMethod(typeof(PlayerRagdollMod).GetMethod(nameof(OnOffsetUpdate_Prefix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
GameEvents.Init(HarmonyInstance);
|
||||
|
||||
// Whitelist the toggle script
|
||||
(typeof(SharedFilter).GetField("_localComponentWhitelist", BindingFlags.NonPublic | BindingFlags.Static)?.GetValue(null) as HashSet<Type>)?.Add(typeof(RagdollToggle));
|
||||
|
@ -88,11 +24,6 @@ namespace ml_prm
|
|||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
ModUi.SwitchChange -= this.OnSwitchActivation;
|
||||
|
||||
if(m_localController != null)
|
||||
UnityEngine.Object.Destroy(m_localController);
|
||||
m_localController = null;
|
||||
|
@ -104,174 +35,6 @@ namespace ml_prm
|
|||
yield return null;
|
||||
|
||||
m_localController = PlayerSetup.Instance.gameObject.AddComponent<RagdollController>();
|
||||
ModUi.SwitchChange += this.OnSwitchActivation;
|
||||
}
|
||||
|
||||
void OnSwitchActivation()
|
||||
{
|
||||
if(m_localController != null)
|
||||
m_localController.SwitchRagdoll();
|
||||
}
|
||||
|
||||
// Patches
|
||||
static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear();
|
||||
void OnAvatarClear()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localController != null)
|
||||
m_localController.OnAvatarClear();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar();
|
||||
void OnSetupAvatar()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localController != null)
|
||||
m_localController.OnAvatarSetup();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarReinitialize_Prefix() => ms_instance?.OnPreAvatarReinitialize();
|
||||
void OnPreAvatarReinitialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localController != null)
|
||||
m_localController.OnPreAvatarReinitialize();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarReinitialize_Postfix() => ms_instance?.OnPostAvatarReinitialize();
|
||||
void OnPostAvatarReinitialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localController != null)
|
||||
m_localController.OnPostAvatarReinitialize();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupIKScaling_Postfix(ref UnityEngine.Vector3 ___scaleDifference) => ms_instance?.OnSetupIKScaling(___scaleDifference.y);
|
||||
void OnSetupIKScaling(float p_scaleDifference)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localController != null)
|
||||
m_localController.OnAvatarScaling(1f + p_scaleDifference);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCVRSeatSitDown_Prefix(ref CVRSeat __instance) => ms_instance?.OnCVRSeatSitDown(__instance);
|
||||
void OnCVRSeatSitDown(CVRSeat p_seat)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localController != null)
|
||||
m_localController.OnSeatSitDown(p_seat);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnStartCalibration_Prefix() => ms_instance?.OnStartCalibration();
|
||||
void OnStartCalibration()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localController != null)
|
||||
m_localController.OnStartCalibration();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnWorldSpawn_Prefix() => ms_instance?.OnWorldSpawn();
|
||||
void OnWorldSpawn()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localController != null)
|
||||
m_localController.OnWorldSpawn();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCombatDown_Prefix(ref CombatSystem __instance)
|
||||
{
|
||||
if((__instance == CombatSystem.Instance) && !__instance.isDown)
|
||||
ms_instance?.OnCombatDown();
|
||||
}
|
||||
void OnCombatDown()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localController != null)
|
||||
m_localController.OnCombatDown();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnChangeFlight_Postfix() => ms_instance?.OnChangeFlight();
|
||||
void OnChangeFlight()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localController != null)
|
||||
m_localController.OnChangeFlight();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static bool OnOffsetUpdate_Prefix(ref IKSystem __instance) => ms_instance.OnOffsetUpdate(__instance);
|
||||
bool OnOffsetUpdate(IKSystem p_instance)
|
||||
{
|
||||
bool l_result = true;
|
||||
try
|
||||
{
|
||||
if(m_localController != null)
|
||||
l_result = !m_localController.ShoudlDisableHeadOffset();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
return l_result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,14 @@ namespace ml_prm
|
|||
{
|
||||
static class ModUi
|
||||
{
|
||||
internal class UiEvent
|
||||
{
|
||||
event Action m_action;
|
||||
public void AddHandler(Action p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action p_listener) => m_action -= p_listener;
|
||||
public void Invoke() => m_action?.Invoke();
|
||||
}
|
||||
|
||||
enum UiIndex
|
||||
{
|
||||
Hotkey = 0,
|
||||
|
@ -29,7 +37,7 @@ namespace ml_prm
|
|||
FallLimit
|
||||
}
|
||||
|
||||
public static event Action SwitchChange;
|
||||
internal static readonly UiEvent OnSwitchChanged = new UiEvent();
|
||||
|
||||
static List<object> ms_uiElements = null;
|
||||
|
||||
|
@ -52,7 +60,7 @@ namespace ml_prm
|
|||
|
||||
var l_modCategory = l_modRoot.AddCategory("Settings");
|
||||
|
||||
l_modCategory.AddButton("Switch ragdoll", "PRM-Person", "Switch between normal and ragdoll state.").OnPress += () => SwitchChange?.Invoke();
|
||||
l_modCategory.AddButton("Switch ragdoll", "PRM-Person", "Switch between normal and ragdoll state.").OnPress += OnSwitch;
|
||||
|
||||
ms_uiElements.Add(l_modCategory.AddToggle("Use hotkey", "Switch ragdoll mode with 'R' key", Settings.Hotkey));
|
||||
(ms_uiElements[(int)UiIndex.Hotkey] as BTKUILib.UIObjects.Components.ToggleButton).OnValueUpdated += (state) => OnToggleUpdate(UiIndex.Hotkey, state);
|
||||
|
@ -108,7 +116,21 @@ namespace ml_prm
|
|||
l_modCategory.AddButton("Reset settings", "", "Reset mod settings to default").OnPress += Reset;
|
||||
}
|
||||
|
||||
static void OnSwitch()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnSwitchChanged.Invoke();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnToggleUpdate(UiIndex p_index, bool p_state, bool p_force = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch(p_index)
|
||||
{
|
||||
|
@ -164,8 +186,15 @@ namespace ml_prm
|
|||
if(p_force)
|
||||
(ms_uiElements[(int)p_index] as BTKUILib.UIObjects.Components.ToggleButton).ToggleValue = p_state;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSliderUpdate(UiIndex p_index, float p_value, bool p_force = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch(p_index)
|
||||
{
|
||||
|
@ -193,6 +222,11 @@ namespace ml_prm
|
|||
if(p_force)
|
||||
(ms_uiElements[(int)p_index] as BTKUILib.UIObjects.Components.SliderFloat).SetSliderValue(p_value);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void Reset()
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.1.4", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.1.5", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||
[assembly: MelonLoader.MelonPriority(2)]
|
||||
[assembly: MelonLoader.MelonOptionalDependencies("BTKUILib")]
|
||||
|
|
|
@ -20,7 +20,6 @@ namespace ml_prm
|
|||
|
||||
public static RagdollController Instance { get; private set; } = null;
|
||||
|
||||
bool m_inVR = false;
|
||||
VRIK m_vrIK = null;
|
||||
bool m_applyHipsPosition = false;
|
||||
bool m_applyHipsRotation = false;
|
||||
|
@ -88,15 +87,28 @@ namespace ml_prm
|
|||
m_ragdollTrigger = BetterBetterCharacterController.Instance.NonKinematicProxy.gameObject.AddComponent<RagdollTrigger>();
|
||||
m_ragdollTrigger.enabled = false;
|
||||
|
||||
Settings.MovementDragChange += this.OnMovementDragChange;
|
||||
Settings.AngularDragChange += this.OnAngularDragChange;
|
||||
Settings.GravityChange += this.OnGravityChange;
|
||||
Settings.SlipperinessChange += this.OnPhysicsMaterialChange;
|
||||
Settings.BouncinessChange += this.OnPhysicsMaterialChange;
|
||||
Settings.BuoyancyChange += this.OnBuoyancyChange;
|
||||
Settings.FallDamageChange += this.OnFallDamageChange;
|
||||
Settings.OnMovementDragChanged.AddHandler(this.OnMovementDragChanged);
|
||||
Settings.OnAngularDragChanged.AddHandler(this.OnAngularDragChanged);
|
||||
Settings.OnGravityChanged.AddHandler(this.OnGravityChanged);
|
||||
Settings.OnSlipperinessChanged.AddHandler(this.OnPhysicsMaterialChanged);
|
||||
Settings.OnBouncinessChanged.AddHandler(this.OnPhysicsMaterialChanged);
|
||||
Settings.OnBuoyancyChanged.AddHandler(this.OnBuoyancyChanged);
|
||||
Settings.OnFallDamageChanged.AddHandler(this.OnFallDamageChanged);
|
||||
|
||||
GameEvents.OnAvatarClear.AddHandler(this.OnAvatarClear);
|
||||
GameEvents.OnAvatarSetup.AddHandler(this.OnAvatarSetup);
|
||||
GameEvents.OnAvatarPreReuse.AddHandler(this.OnAvatarPreReuse);
|
||||
GameEvents.OnAvatarPostReuse.AddHandler(this.OnAvatarPostReuse);
|
||||
GameEvents.OnIKScaling.AddHandler(this.OnAvatarScaling);
|
||||
GameEvents.OnSeatPreSit.AddHandler(this.OnSeatPreSit);
|
||||
GameEvents.OnCalibrationStart.AddHandler(this.OnCalibrationStart);
|
||||
GameEvents.OnWorldPreSpawn.AddHandler(this.OnWorldPreSpawn);
|
||||
GameEvents.OnCombatPreDown.AddHandler(this.OnCombatPreDown);
|
||||
GameEvents.OnFlightChange.AddHandler(this.OnFlightChange);
|
||||
GameEvents.OnIKOffsetUpdate.AddHandler(this.OnIKOffsetUpdate);
|
||||
BetterBetterCharacterController.OnTeleport.AddListener(this.OnPlayerTeleport);
|
||||
|
||||
ModUi.OnSwitchChanged.AddHandler(this.SwitchRagdoll);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
|
@ -128,15 +140,28 @@ namespace ml_prm
|
|||
Object.Destroy(m_physicsMaterial);
|
||||
m_physicsMaterial = null;
|
||||
|
||||
Settings.MovementDragChange -= this.OnMovementDragChange;
|
||||
Settings.AngularDragChange -= this.OnAngularDragChange;
|
||||
Settings.GravityChange -= this.OnGravityChange;
|
||||
Settings.SlipperinessChange -= this.OnPhysicsMaterialChange;
|
||||
Settings.BouncinessChange -= this.OnPhysicsMaterialChange;
|
||||
Settings.BuoyancyChange -= this.OnBuoyancyChange;
|
||||
Settings.FallDamageChange -= this.OnFallDamageChange;
|
||||
Settings.OnMovementDragChanged.RemoveHandler(this.OnMovementDragChanged);
|
||||
Settings.OnAngularDragChanged.RemoveHandler(this.OnAngularDragChanged);
|
||||
Settings.OnGravityChanged.RemoveHandler(this.OnGravityChanged);
|
||||
Settings.OnSlipperinessChanged.RemoveHandler(this.OnPhysicsMaterialChanged);
|
||||
Settings.OnBouncinessChanged.RemoveHandler(this.OnPhysicsMaterialChanged);
|
||||
Settings.OnBuoyancyChanged.RemoveHandler(this.OnBuoyancyChanged);
|
||||
Settings.OnFallDamageChanged.RemoveHandler(this.OnFallDamageChanged);
|
||||
|
||||
GameEvents.OnAvatarClear.RemoveHandler(this.OnAvatarClear);
|
||||
GameEvents.OnAvatarSetup.RemoveHandler(this.OnAvatarSetup);
|
||||
GameEvents.OnAvatarPreReuse.RemoveHandler(this.OnAvatarPreReuse);
|
||||
GameEvents.OnAvatarPostReuse.RemoveHandler(this.OnAvatarPostReuse);
|
||||
GameEvents.OnIKScaling.RemoveHandler(this.OnAvatarScaling);
|
||||
GameEvents.OnSeatPreSit.RemoveHandler(this.OnSeatPreSit);
|
||||
GameEvents.OnCalibrationStart.RemoveHandler(this.OnCalibrationStart);
|
||||
GameEvents.OnWorldPreSpawn.RemoveHandler(this.OnWorldPreSpawn);
|
||||
GameEvents.OnCombatPreDown.RemoveHandler(this.OnCombatPreDown);
|
||||
GameEvents.OnFlightChange.RemoveHandler(this.OnFlightChange);
|
||||
GameEvents.OnIKOffsetUpdate.RemoveHandler(this.OnIKOffsetUpdate);
|
||||
BetterBetterCharacterController.OnTeleport.RemoveListener(this.OnPlayerTeleport);
|
||||
|
||||
ModUi.OnSwitchChanged.RemoveHandler(this.SwitchRagdoll);
|
||||
}
|
||||
|
||||
void Update()
|
||||
|
@ -234,10 +259,8 @@ namespace ml_prm
|
|||
}
|
||||
|
||||
// Game events
|
||||
internal void OnAvatarClear()
|
||||
void OnAvatarClear()
|
||||
{
|
||||
m_inVR = Utils.IsInVR();
|
||||
|
||||
if(m_initCoroutine != null)
|
||||
{
|
||||
StopCoroutine(m_initCoroutine);
|
||||
|
@ -282,10 +305,8 @@ namespace ml_prm
|
|||
m_wasSwimming = false;
|
||||
}
|
||||
|
||||
internal void OnAvatarSetup()
|
||||
void OnAvatarSetup()
|
||||
{
|
||||
m_inVR = Utils.IsInVR();
|
||||
|
||||
if(PlayerSetup.Instance._animator.isHuman)
|
||||
{
|
||||
Utils.SetAvatarTPose();
|
||||
|
@ -405,7 +426,7 @@ namespace ml_prm
|
|||
|
||||
m_vrIK = PlayerSetup.Instance._avatar.GetComponent<VRIK>();
|
||||
if(m_vrIK != null)
|
||||
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate);
|
||||
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostSolverUpdate);
|
||||
|
||||
m_avatarRagdollToggle = PlayerSetup.Instance._avatar.GetComponentInChildren<RagdollToggle>(true);
|
||||
m_ragdolledParameter = new AvatarBoolParameter("Ragdolled", PlayerSetup.Instance.animatorManager);
|
||||
|
@ -425,13 +446,13 @@ namespace ml_prm
|
|||
m_avatarReady = true;
|
||||
m_initCoroutine = null;
|
||||
|
||||
OnGravityChange(Settings.Gravity);
|
||||
OnBuoyancyChange(Settings.Buoyancy);
|
||||
OnMovementDragChange(Settings.MovementDrag);
|
||||
OnAngularDragChange(Settings.AngularDrag);
|
||||
OnGravityChanged(Settings.Gravity);
|
||||
OnBuoyancyChanged(Settings.Buoyancy);
|
||||
OnMovementDragChanged(Settings.MovementDrag);
|
||||
OnAngularDragChanged(Settings.AngularDrag);
|
||||
}
|
||||
|
||||
internal void OnPreAvatarReinitialize()
|
||||
void OnAvatarPreReuse()
|
||||
{
|
||||
if(m_avatarReady && m_enabled)
|
||||
{
|
||||
|
@ -440,16 +461,15 @@ namespace ml_prm
|
|||
m_forcedSwitch = false;
|
||||
}
|
||||
}
|
||||
internal void OnPostAvatarReinitialize()
|
||||
void OnAvatarPostReuse()
|
||||
{
|
||||
m_inVR = Utils.IsInVR();
|
||||
m_vrIK = PlayerSetup.Instance._avatar.GetComponent<VRIK>();
|
||||
|
||||
if(m_vrIK != null)
|
||||
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate);
|
||||
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostSolverUpdate);
|
||||
}
|
||||
|
||||
internal void OnAvatarScaling(float p_scaleDifference)
|
||||
void OnAvatarScaling(float p_scaleDifference)
|
||||
{
|
||||
if(m_puppetRoot != null)
|
||||
m_puppetRoot.localScale = Vector3.one * p_scaleDifference;
|
||||
|
@ -458,7 +478,7 @@ namespace ml_prm
|
|||
l_pair.Item1.connectedAnchor = l_pair.Item2 * p_scaleDifference;
|
||||
}
|
||||
|
||||
internal void OnSeatSitDown(CVRSeat p_seat)
|
||||
void OnSeatPreSit(CVRSeat p_seat)
|
||||
{
|
||||
if(m_avatarReady && m_enabled && !p_seat.occupied)
|
||||
{
|
||||
|
@ -469,7 +489,7 @@ namespace ml_prm
|
|||
}
|
||||
}
|
||||
|
||||
internal void OnStartCalibration()
|
||||
void OnCalibrationStart()
|
||||
{
|
||||
if(m_avatarReady && m_enabled)
|
||||
{
|
||||
|
@ -480,22 +500,22 @@ namespace ml_prm
|
|||
}
|
||||
}
|
||||
|
||||
internal void OnWorldSpawn()
|
||||
void OnWorldPreSpawn()
|
||||
{
|
||||
if(m_avatarReady && m_enabled)
|
||||
SwitchRagdoll();
|
||||
|
||||
ResetStates();
|
||||
|
||||
OnGravityChange(Settings.Gravity);
|
||||
OnPhysicsMaterialChange(true);
|
||||
OnMovementDragChange(Settings.MovementDrag);
|
||||
OnBuoyancyChange(Settings.Buoyancy);
|
||||
OnGravityChanged(Settings.Gravity);
|
||||
OnPhysicsMaterialChanged(true);
|
||||
OnMovementDragChanged(Settings.MovementDrag);
|
||||
OnBuoyancyChanged(Settings.Buoyancy);
|
||||
}
|
||||
|
||||
internal void OnCombatDown()
|
||||
void OnCombatPreDown()
|
||||
{
|
||||
if(m_avatarReady && !m_enabled && Settings.CombatReaction)
|
||||
if(m_avatarReady && !m_enabled && CombatSystem.Instance.isDown && Settings.CombatReaction)
|
||||
{
|
||||
m_reachedGround = true;
|
||||
m_forcedSwitch = true;
|
||||
|
@ -505,7 +525,7 @@ namespace ml_prm
|
|||
}
|
||||
}
|
||||
|
||||
internal void OnChangeFlight()
|
||||
void OnFlightChange()
|
||||
{
|
||||
if(m_avatarReady && m_enabled && BetterBetterCharacterController.Instance.IsFlying())
|
||||
{
|
||||
|
@ -532,8 +552,13 @@ namespace ml_prm
|
|||
}
|
||||
}
|
||||
|
||||
void OnIKOffsetUpdate(GameEvents.EventResult p_result)
|
||||
{
|
||||
p_result.m_result |= (m_enabled && (m_vrIK != null));
|
||||
}
|
||||
|
||||
// VRIK updates
|
||||
void OnIKPostUpdate()
|
||||
void OnIKPostSolverUpdate()
|
||||
{
|
||||
if(!m_enabled)
|
||||
{
|
||||
|
@ -543,7 +568,7 @@ namespace ml_prm
|
|||
}
|
||||
|
||||
// Settings
|
||||
void OnMovementDragChange(float p_value)
|
||||
void OnMovementDragChanged(float p_value)
|
||||
{
|
||||
if(m_avatarReady)
|
||||
{
|
||||
|
@ -558,7 +583,7 @@ namespace ml_prm
|
|||
l_influencer.airDrag = l_drag;
|
||||
}
|
||||
}
|
||||
void OnAngularDragChange(float p_value)
|
||||
void OnAngularDragChanged(float p_value)
|
||||
{
|
||||
if(m_avatarReady)
|
||||
{
|
||||
|
@ -572,7 +597,7 @@ namespace ml_prm
|
|||
l_influencer.airAngularDrag = p_value;
|
||||
}
|
||||
}
|
||||
void OnGravityChange(bool p_state)
|
||||
void OnGravityChanged(bool p_state)
|
||||
{
|
||||
if(m_avatarReady)
|
||||
{
|
||||
|
@ -584,12 +609,12 @@ namespace ml_prm
|
|||
|
||||
if(!l_gravity)
|
||||
{
|
||||
OnMovementDragChange(Settings.MovementDrag);
|
||||
OnAngularDragChange(Settings.AngularDrag);
|
||||
OnMovementDragChanged(Settings.MovementDrag);
|
||||
OnAngularDragChanged(Settings.AngularDrag);
|
||||
}
|
||||
}
|
||||
}
|
||||
void OnPhysicsMaterialChange(bool p_state)
|
||||
void OnPhysicsMaterialChanged(bool p_state)
|
||||
{
|
||||
if(m_physicsMaterial != null)
|
||||
{
|
||||
|
@ -602,7 +627,7 @@ namespace ml_prm
|
|||
m_physicsMaterial.bounceCombine = (l_bounciness ? PhysicMaterialCombine.Maximum : PhysicMaterialCombine.Average);
|
||||
}
|
||||
}
|
||||
void OnBuoyancyChange(bool p_state)
|
||||
void OnBuoyancyChanged(bool p_state)
|
||||
{
|
||||
if(m_avatarReady)
|
||||
{
|
||||
|
@ -612,12 +637,12 @@ namespace ml_prm
|
|||
|
||||
if(!l_buoyancy)
|
||||
{
|
||||
OnMovementDragChange(Settings.MovementDrag);
|
||||
OnAngularDragChange(Settings.AngularDrag);
|
||||
OnMovementDragChanged(Settings.MovementDrag);
|
||||
OnAngularDragChanged(Settings.AngularDrag);
|
||||
}
|
||||
}
|
||||
}
|
||||
void OnFallDamageChange(bool p_state)
|
||||
void OnFallDamageChanged(bool p_state)
|
||||
{
|
||||
m_inAir = false;
|
||||
m_inAirDistance = 0f;
|
||||
|
@ -713,8 +738,8 @@ namespace ml_prm
|
|||
m_downTime = float.MinValue;
|
||||
|
||||
// Restore rigidbody properties that could be affected by buoyancy
|
||||
OnMovementDragChange(Settings.MovementDrag);
|
||||
OnAngularDragChange(Settings.AngularDrag);
|
||||
OnMovementDragChanged(Settings.MovementDrag);
|
||||
OnAngularDragChanged(Settings.AngularDrag);
|
||||
|
||||
// Restore movement if was ragdolled in water and left it
|
||||
if(m_wasSwimming)
|
||||
|
@ -764,11 +789,6 @@ namespace ml_prm
|
|||
return (l_result || m_forcedSwitch);
|
||||
}
|
||||
|
||||
internal bool ShoudlDisableHeadOffset()
|
||||
{
|
||||
return (m_enabled && (m_vrIK != null));
|
||||
}
|
||||
|
||||
static void TryRestoreMovement()
|
||||
{
|
||||
bool l_state = true;
|
||||
|
|
|
@ -6,6 +6,14 @@ namespace ml_prm
|
|||
{
|
||||
static class Settings
|
||||
{
|
||||
internal class SettingEvent<T>
|
||||
{
|
||||
event Action<T> m_action;
|
||||
public void AddHandler(Action<T> p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action<T> p_listener) => m_action -= p_listener;
|
||||
public void Invoke(T p_value) => m_action?.Invoke(p_value);
|
||||
}
|
||||
|
||||
public enum ModSetting
|
||||
{
|
||||
Hotkey = 0,
|
||||
|
@ -47,24 +55,24 @@ namespace ml_prm
|
|||
public static bool FallDamage { get; private set; } = true;
|
||||
public static float FallLimit { get; private set; } = 5f;
|
||||
|
||||
public static event Action<bool> HotkeyChange;
|
||||
public static event Action<KeyCode> HotkeyKeyChange;
|
||||
public static event Action<float> VelocityMultiplierChange;
|
||||
public static event Action<float> MovementDragChange;
|
||||
public static event Action<float> AngularDragChange;
|
||||
public static event Action<bool> GravityChange;
|
||||
public static event Action<bool> PointersReactionChange;
|
||||
public static event Action<bool> IgnoreLocalChange;
|
||||
public static event Action<bool> CombatReactionChange;
|
||||
public static event Action<bool> AutoRecoverChange;
|
||||
public static event Action<float> RecoverDelayChange;
|
||||
public static event Action<bool> SlipperinessChange;
|
||||
public static event Action<bool> BouncinessChange;
|
||||
public static event Action<bool> ViewVelocityChange;
|
||||
public static event Action<bool> JumpRecoverChange;
|
||||
public static event Action<bool> BuoyancyChange;
|
||||
public static event Action<bool> FallDamageChange;
|
||||
public static event Action<float> FallLimitChange;
|
||||
public static readonly SettingEvent<bool> OnHotkeyChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<KeyCode> OnHotkeyKeyChanged = new SettingEvent<KeyCode>();
|
||||
public static readonly SettingEvent<float> OnVelocityMultiplierChanged = new SettingEvent<float>();
|
||||
public static readonly SettingEvent<float> OnMovementDragChanged = new SettingEvent<float>();
|
||||
public static readonly SettingEvent<float> OnAngularDragChanged = new SettingEvent<float>();
|
||||
public static readonly SettingEvent<bool> OnGravityChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnPointersReactionChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnIgnoreLocalChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnCombatReactionChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnAutoRecoverChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<float> OnRecoverDelayChanged = new SettingEvent<float>();
|
||||
public static readonly SettingEvent<bool> OnSlipperinessChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnBouncinessChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnViewVelocityChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnJumpRecoverChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnBuoyancyChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<bool> OnFallDamageChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<float> OnFallLimitChanged = new SettingEvent<float>();
|
||||
|
||||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
@ -118,15 +126,24 @@ namespace ml_prm
|
|||
}
|
||||
|
||||
static void OnMelonSettingSave_HotkeyKey(object p_oldValue, object p_newValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(p_newValue is KeyCode)
|
||||
{
|
||||
HotkeyKey = (KeyCode)p_newValue;
|
||||
HotkeyKeyChange?.Invoke(HotkeyKey);
|
||||
OnHotkeyKeyChanged.Invoke(HotkeyKey);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetSetting(ModSetting p_settings, object p_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch(p_settings)
|
||||
{
|
||||
|
@ -134,84 +151,84 @@ namespace ml_prm
|
|||
case ModSetting.Hotkey:
|
||||
{
|
||||
Hotkey = (bool)p_value;
|
||||
HotkeyChange?.Invoke((bool)p_value);
|
||||
OnHotkeyChanged.Invoke(Hotkey);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.Gravity:
|
||||
{
|
||||
Gravity = (bool)p_value;
|
||||
GravityChange?.Invoke((bool)p_value);
|
||||
OnGravityChanged.Invoke(Gravity);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.PointersReaction:
|
||||
{
|
||||
PointersReaction = (bool)p_value;
|
||||
PointersReactionChange?.Invoke((bool)p_value);
|
||||
OnPointersReactionChanged.Invoke(PointersReaction);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.IgnoreLocal:
|
||||
{
|
||||
IgnoreLocal = (bool)p_value;
|
||||
IgnoreLocalChange?.Invoke((bool)p_value);
|
||||
OnIgnoreLocalChanged.Invoke(IgnoreLocal);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.CombatReaction:
|
||||
{
|
||||
CombatReaction = (bool)p_value;
|
||||
CombatReactionChange?.Invoke((bool)p_value);
|
||||
OnCombatReactionChanged.Invoke(CombatReaction);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.AutoRecover:
|
||||
{
|
||||
AutoRecover = (bool)p_value;
|
||||
AutoRecoverChange?.Invoke((bool)p_value);
|
||||
OnAutoRecoverChanged.Invoke(AutoRecover);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.Slipperiness:
|
||||
{
|
||||
Slipperiness = (bool)p_value;
|
||||
SlipperinessChange?.Invoke((bool)p_value);
|
||||
OnSlipperinessChanged.Invoke(Slipperiness);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.Bounciness:
|
||||
{
|
||||
Bounciness = (bool)p_value;
|
||||
BouncinessChange?.Invoke((bool)p_value);
|
||||
OnBouncinessChanged.Invoke(Bounciness);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.ViewVelocity:
|
||||
{
|
||||
ViewVelocity = (bool)p_value;
|
||||
ViewVelocityChange?.Invoke((bool)p_value);
|
||||
OnViewVelocityChanged.Invoke(ViewVelocity);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.JumpRecover:
|
||||
{
|
||||
JumpRecover = (bool)p_value;
|
||||
JumpRecoverChange?.Invoke((bool)p_value);
|
||||
OnJumpRecoverChanged.Invoke(JumpRecover);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.Buoyancy:
|
||||
{
|
||||
Buoyancy = (bool)p_value;
|
||||
BuoyancyChange?.Invoke((bool)p_value);
|
||||
OnBuoyancyChanged.Invoke(Buoyancy);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.FallDamage:
|
||||
{
|
||||
FallDamage = (bool)p_value;
|
||||
FallDamageChange?.Invoke((bool)p_value);
|
||||
OnFallDamageChanged.Invoke(FallDamage);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -219,35 +236,35 @@ namespace ml_prm
|
|||
case ModSetting.VelocityMultiplier:
|
||||
{
|
||||
VelocityMultiplier = (float)p_value;
|
||||
VelocityMultiplierChange?.Invoke((float)p_value);
|
||||
OnVelocityMultiplierChanged.Invoke(VelocityMultiplier);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.MovementDrag:
|
||||
{
|
||||
MovementDrag = (float)p_value;
|
||||
MovementDragChange?.Invoke((float)p_value);
|
||||
OnMovementDragChanged.Invoke(MovementDrag);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.AngularDrag:
|
||||
{
|
||||
AngularDrag = (float)p_value;
|
||||
AngularDragChange?.Invoke((float)p_value);
|
||||
OnAngularDragChanged.Invoke(AngularDrag);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.RecoverDelay:
|
||||
{
|
||||
RecoverDelay = (float)p_value;
|
||||
RecoverDelayChange?.Invoke((float)p_value);
|
||||
OnRecoverDelayChanged.Invoke(RecoverDelay);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.FallLimit:
|
||||
{
|
||||
FallLimit = (float)p_value;
|
||||
FallLimitChange?.Invoke((float)p_value);
|
||||
OnFallLimitChanged.Invoke(FallLimit);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -255,5 +272,10 @@ namespace ml_prm
|
|||
if(ms_entries != null)
|
||||
ms_entries[(int)p_settings].BoxedValue = p_value;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
<PackageId>PlayerRagdollMod</PackageId>
|
||||
<Version>1.1.4</Version>
|
||||
<Version>1.1.5</Version>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>PlayerRagdollMod</Product>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_vei.ViveExtendedInput), "ViveExtendedInput", "1.0.2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_vei.ViveExtendedInput), "ViveExtendedInput", "1.0.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)]
|
||||
|
|
|
@ -6,6 +6,14 @@ namespace ml_vei
|
|||
{
|
||||
static class Settings
|
||||
{
|
||||
internal class SettingEvent<T>
|
||||
{
|
||||
event Action<T> m_action;
|
||||
public void AddHandler(Action<T> p_listener) => m_action += p_listener;
|
||||
public void RemoveHandler(Action<T> p_listener) => m_action -= p_listener;
|
||||
public void Invoke(T p_value) => m_action?.Invoke(p_value);
|
||||
}
|
||||
|
||||
enum ModSetting
|
||||
{
|
||||
Gestures = 0,
|
||||
|
@ -26,9 +34,9 @@ namespace ml_vei
|
|||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
||||
public static event Action<bool> GesturesChange;
|
||||
public static event Action<bool> GripTriggerChange;
|
||||
public static event Action<PriorityAxis> AxisPriorityChange;
|
||||
public static readonly SettingEvent<bool> OnGesturesChanged;
|
||||
public static readonly SettingEvent<bool> OnGripTriggerChanged;
|
||||
public static readonly SettingEvent<PriorityAxis> OnAxisPriorityChanged;
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
|
@ -72,6 +80,8 @@ namespace ml_vei
|
|||
}
|
||||
|
||||
static void OnToggleUpdate(string p_name, string p_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
|
@ -80,14 +90,14 @@ namespace ml_vei
|
|||
case ModSetting.Gestures:
|
||||
{
|
||||
Gestures = bool.Parse(p_value);
|
||||
GesturesChange?.Invoke(Gestures);
|
||||
OnGesturesChanged.Invoke(Gestures);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.GripTrigger:
|
||||
{
|
||||
GripTrigger = bool.Parse(p_value);
|
||||
GripTriggerChange?.Invoke(GripTrigger);
|
||||
OnGripTriggerChanged.Invoke(GripTrigger);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -95,8 +105,15 @@ namespace ml_vei
|
|||
ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnDropdownUpdate(string p_name, string p_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
|
@ -105,7 +122,7 @@ namespace ml_vei
|
|||
case ModSetting.AxisPriority:
|
||||
{
|
||||
AxisPriority = (PriorityAxis)int.Parse(p_value);
|
||||
AxisPriorityChange?.Invoke(AxisPriority);
|
||||
OnAxisPriorityChanged.Invoke(AxisPriority);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -113,5 +130,10 @@ namespace ml_vei
|
|||
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
<PackageId>ViveExtendedInput</PackageId>
|
||||
<Version>1.0.2</Version>
|
||||
<Version>1.0.3</Version>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>ViveExtendedInput</Product>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue