diff --git a/ml_amt/AvatarParameter.cs b/ml_amt/AvatarParameter.cs index 8553803..3870b6d 100644 --- a/ml_amt/AvatarParameter.cs +++ b/ml_amt/AvatarParameter.cs @@ -42,7 +42,7 @@ namespace ml_amt switch(m_type) { case ParameterType.Moving: - SetBoolean(p_tweaker.GetMoving()); + SetBoolean(p_tweaker.IsMoving()); break; } } diff --git a/ml_amt/GameEvents.cs b/ml_amt/GameEvents.cs new file mode 100644 index 0000000..5682d1e --- /dev/null +++ b/ml_amt/GameEvents.cs @@ -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); + } + } + } +} diff --git a/ml_amt/Main.cs b/ml_amt/Main.cs index 57e99e2..ce5d4bc 100644 --- a/ml_amt/Main.cs +++ b/ml_amt/Main.cs @@ -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); - } - } } } diff --git a/ml_amt/MotionTweaker.cs b/ml_amt/MotionTweaker.cs index c4469e8..857d42c 100644 --- a/ml_amt/MotionTweaker.cs +++ b/ml_amt/MotionTweaker.cs @@ -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; } } diff --git a/ml_amt/Properties/AssemblyInfo.cs b/ml_amt/Properties/AssemblyInfo.cs index 173b71c..a5533dd 100644 --- a/ml_amt/Properties/AssemblyInfo.cs +++ b/ml_amt/Properties/AssemblyInfo.cs @@ -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)] diff --git a/ml_amt/Settings.cs b/ml_amt/Settings.cs index b4c3404..8d3b01e 100644 --- a/ml_amt/Settings.cs +++ b/ml_amt/Settings.cs @@ -6,6 +6,14 @@ namespace ml_amt { static class Settings { + internal class SettingEvent + { + 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(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 ms_entries = null; - public static event Action CrouchLimitChange; - public static event Action ProneLimitChange; - public static event Action IKOverrideFlyChange; - public static event Action IKOverrideJumpChange; - public static event Action DetectEmotesChange; - public static event Action MassCenterChange; + public static readonly SettingEvent OnCrouchLimitChanged = new SettingEvent(); + public static readonly SettingEvent OnProneLimitChanged = new SettingEvent(); + public static readonly SettingEvent OnIKOverrideFlyChanged = new SettingEvent(); + public static readonly SettingEvent OnIKOverrideJumpChanged = new SettingEvent(); + public static readonly SettingEvent OnDetectEmotesChanged = new SettingEvent(); + public static readonly SettingEvent OnMassCenterChanged = new SettingEvent(); internal static void Init() { @@ -82,65 +90,79 @@ namespace ml_amt static void OnSliderUpdate(string p_name, string p_value) { - if(Enum.TryParse(p_name, out ModSetting l_setting)) + try { - switch(l_setting) + if(Enum.TryParse(p_name, out ModSetting l_setting)) { - case ModSetting.CrouchLimit: + switch(l_setting) { - CrouchLimit = int.Parse(p_value) * 0.01f; - CrouchLimitChange?.Invoke(CrouchLimit); - } - break; + case ModSetting.CrouchLimit: + { + CrouchLimit = int.Parse(p_value) * 0.01f; + OnCrouchLimitChanged.Invoke(CrouchLimit); + } + break; - case ModSetting.ProneLimit: - { - ProneLimit = int.Parse(p_value) * 0.01f; - ProneLimitChange?.Invoke(ProneLimit); + case ModSetting.ProneLimit: + { + ProneLimit = int.Parse(p_value) * 0.01f; + OnProneLimitChanged.Invoke(ProneLimit); + } + break; } - break; + + ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); } - - ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } } static void OnToggleUpdate(string p_name, string p_value) { - if(Enum.TryParse(p_name, out ModSetting l_setting)) + try { - switch(l_setting) + if(Enum.TryParse(p_name, out ModSetting l_setting)) { - case ModSetting.IKOverrideFly: + switch(l_setting) { - IKOverrideFly = bool.Parse(p_value); - IKOverrideFlyChange?.Invoke(IKOverrideFly); - } - break; + case ModSetting.IKOverrideFly: + { + IKOverrideFly = bool.Parse(p_value); + OnIKOverrideFlyChanged.Invoke(IKOverrideFly); + } + break; - case ModSetting.IKOverrideJump: - { - IKOverrideJump = bool.Parse(p_value); - IKOverrideJumpChange?.Invoke(IKOverrideJump); - } - break; + case ModSetting.IKOverrideJump: + { + IKOverrideJump = bool.Parse(p_value); + OnIKOverrideJumpChanged.Invoke(IKOverrideJump); + } + break; - case ModSetting.DetectEmotes: - { - DetectEmotes = bool.Parse(p_value); - DetectEmotesChange?.Invoke(DetectEmotes); - } - break; + case ModSetting.DetectEmotes: + { + DetectEmotes = bool.Parse(p_value); + OnDetectEmotesChanged.Invoke(DetectEmotes); + } + break; - case ModSetting.MassCenter: - { - MassCenter = bool.Parse(p_value); - MassCenterChange?.Invoke(MassCenter); + case ModSetting.MassCenter: + { + MassCenter = bool.Parse(p_value); + OnMassCenterChanged.Invoke(MassCenter); + } + break; } - break; + + ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); } - - ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } } } diff --git a/ml_amt/ml_amt.csproj b/ml_amt/ml_amt.csproj index 14f81ca..6a59032 100644 --- a/ml_amt/ml_amt.csproj +++ b/ml_amt/ml_amt.csproj @@ -6,7 +6,7 @@ None AvatarMotionTweaker AvatarMotionTweaker - 1.3.8 + 1.3.9 x64 ml_amt diff --git a/ml_asl/Properties/AssemblyInfo.cs b/ml_asl/Properties/AssemblyInfo.cs index 8b201f5..6813ebb 100644 --- a/ml_asl/Properties/AssemblyInfo.cs +++ b/ml_asl/Properties/AssemblyInfo.cs @@ -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)] diff --git a/ml_asl/Settings.cs b/ml_asl/Settings.cs index 52ba124..169a946 100644 --- a/ml_asl/Settings.cs +++ b/ml_asl/Settings.cs @@ -6,6 +6,14 @@ namespace ml_asl { static class Settings { + internal class SettingEvent + { + 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(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 ms_entries = null; - public static event Action EnabledChange; + public static readonly SettingEvent OnEnabledChanged = new SettingEvent(); internal static void Init() { @@ -56,19 +64,26 @@ namespace ml_asl static void OnToggleUpdate(string p_name, string p_value) { - if(Enum.TryParse(p_name, out ModSetting l_setting)) + try { - switch(l_setting) + if(Enum.TryParse(p_name, out ModSetting l_setting)) { - case ModSetting.Enabled: + switch(l_setting) { - Enabled = bool.Parse(p_value); - EnabledChange?.Invoke(Enabled); + case ModSetting.Enabled: + { + Enabled = bool.Parse(p_value); + OnEnabledChanged.Invoke(Enabled); + } + break; } - break; - } - ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); + ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); + } + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } } } diff --git a/ml_asl/ml_asl.csproj b/ml_asl/ml_asl.csproj index 3e00a97..9512234 100644 --- a/ml_asl/ml_asl.csproj +++ b/ml_asl/ml_asl.csproj @@ -7,7 +7,7 @@ SDraw None AvatarSyncedLook - 1.0.2 + 1.0.3 diff --git a/ml_bft/FingerSystem.cs b/ml_bft/FingerSystem.cs index 9bc903c..0909558 100644 --- a/ml_bft/FingerSystem.cs +++ b/ml_bft/FingerSystem.cs @@ -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(); diff --git a/ml_bft/GameEvents.cs b/ml_bft/GameEvents.cs new file mode 100644 index 0000000..d281644 --- /dev/null +++ b/ml_bft/GameEvents.cs @@ -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 + { + 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(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 OnIKSystemLateUpdate = new GameEvent(); + + 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); + } + } + } +} diff --git a/ml_bft/HandHandler.cs b/ml_bft/HandHandler.cs index 8a0ce54..8c42546 100644 --- a/ml_bft/HandHandler.cs +++ b/ml_bft/HandHandler.cs @@ -18,7 +18,7 @@ namespace ml_bft m_localRotations = new List(); m_renderers = new List(); - 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) { diff --git a/ml_bft/HandHandlerVR.cs b/ml_bft/HandHandlerVR.cs index bff8246..299add1 100644 --- a/ml_bft/HandHandlerVR.cs +++ b/ml_bft/HandHandlerVR.cs @@ -75,10 +75,10 @@ namespace ml_bft m_skeletonAction = SteamVR_Input.GetAction(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) { diff --git a/ml_bft/HandHandlerXR.cs b/ml_bft/HandHandlerXR.cs index 3f08692..9509bd5 100644 --- a/ml_bft/HandHandlerXR.cs +++ b/ml_bft/HandHandlerXR.cs @@ -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) diff --git a/ml_bft/InputHandler.cs b/ml_bft/InputHandler.cs index 1b0a9ac..c25c35a 100644 --- a/ml_bft/InputHandler.cs +++ b/ml_bft/InputHandler.cs @@ -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(); diff --git a/ml_bft/Main.cs b/ml_bft/Main.cs index 87b5a6c..8d64294 100644 --- a/ml_bft/Main.cs +++ b/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); - } - } } } diff --git a/ml_bft/Properties/AssemblyInfo.cs b/ml_bft/Properties/AssemblyInfo.cs index d5f1eae..3f70526 100644 --- a/ml_bft/Properties/AssemblyInfo.cs +++ b/ml_bft/Properties/AssemblyInfo.cs @@ -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)] diff --git a/ml_bft/Settings.cs b/ml_bft/Settings.cs index c846166..a7738dc 100644 --- a/ml_bft/Settings.cs +++ b/ml_bft/Settings.cs @@ -6,6 +6,14 @@ namespace ml_bft { static class Settings { + internal class SettingEvent + { + 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(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 ms_entries = null; - public static event Action SkeletalInputChange; - public static event Action MotionRangeChange; - public static event Action ShowHandsChange; - public static event Action MechanimFilterChange; + public static readonly SettingEvent OnSkeletalInputChanged = new SettingEvent(); + public static readonly SettingEvent OnMotionRangeChanged = new SettingEvent(); + public static readonly SettingEvent OnShowHandsChanged = new SettingEvent(); + public static readonly SettingEvent OnMechanimFilterChanged = new SettingEvent(); internal static void Init() { @@ -76,51 +84,65 @@ namespace ml_bft static void OnToggleUpdate(string p_name, string p_value) { - if(Enum.TryParse(p_name, out ModSetting l_setting)) + try { - switch(l_setting) + if(Enum.TryParse(p_name, out ModSetting l_setting)) { - case ModSetting.SkeletalInput: + switch(l_setting) { - SkeletalInput = bool.Parse(p_value); - SkeletalInputChange?.Invoke(SkeletalInput); - } - break; + case ModSetting.SkeletalInput: + { + SkeletalInput = bool.Parse(p_value); + OnSkeletalInputChanged.Invoke(SkeletalInput); + } + break; - case ModSetting.ShowHands: - { - ShowHands = bool.Parse(p_value); - ShowHandsChange?.Invoke(ShowHands); + case ModSetting.ShowHands: + { + ShowHands = bool.Parse(p_value); + OnShowHandsChanged.Invoke(ShowHands); + } + break; + + case ModSetting.MechanimFilter: + { + MechanimFilter = bool.Parse(p_value); + OnMechanimFilterChanged.Invoke(MechanimFilter); + } + break; } - break; - - case ModSetting.MechanimFilter: - { - MechanimFilter = bool.Parse(p_value); - MechanimFilterChange?.Invoke(MechanimFilter); - } - break; + + ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); } - - ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } } static void OnDropdownUpdate(string p_name, string p_value) { - if(Enum.TryParse(p_name, out ModSetting l_setting)) + try { - switch(l_setting) + if(Enum.TryParse(p_name, out ModSetting l_setting)) { - case ModSetting.MotionRange: + switch(l_setting) { - MotionRange = (MotionRangeType)int.Parse(p_value); - MotionRangeChange?.Invoke(MotionRange); + case ModSetting.MotionRange: + { + MotionRange = (MotionRangeType)int.Parse(p_value); + OnMotionRangeChanged.Invoke(MotionRange); + } + break; } - break; - } - ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); + ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); + } + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } } } diff --git a/ml_bft/ml_bft.csproj b/ml_bft/ml_bft.csproj index 102f8ff..9e90e4e 100644 --- a/ml_bft/ml_bft.csproj +++ b/ml_bft/ml_bft.csproj @@ -7,7 +7,7 @@ SDraw None BetterFingersTracking - 1.0.2 + 1.0.3 diff --git a/ml_dht/GameEvents.cs b/ml_dht/GameEvents.cs new file mode 100644 index 0000000..48a9269 --- /dev/null +++ b/ml_dht/GameEvents.cs @@ -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 + { + 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(T1 p_obj) => m_action?.Invoke(p_obj); + } + 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(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 OnEyeControllerUpdate = new GameEvent(); + public static readonly GameEvent OnFaceTrackingUpdate = new GameEvent(); + + 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; + } + } +} diff --git a/ml_dht/HeadTracked.cs b/ml_dht/HeadTracked.cs index 434a825..42d8595 100644 --- a/ml_dht/HeadTracked.cs +++ b/ml_dht/HeadTracked.cs @@ -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(); @@ -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); } diff --git a/ml_dht/Main.cs b/ml_dht/Main.cs index ae4f9f8..7778fb6 100644 --- a/ml_dht/Main.cs +++ b/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(); - - // 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; - } } } \ No newline at end of file diff --git a/ml_dht/Properties/AssemblyInfo.cs b/ml_dht/Properties/AssemblyInfo.cs index 3b78941..b554b7a 100644 --- a/ml_dht/Properties/AssemblyInfo.cs +++ b/ml_dht/Properties/AssemblyInfo.cs @@ -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)] \ No newline at end of file diff --git a/ml_dht/Settings.cs b/ml_dht/Settings.cs index c0ad6e9..182f32a 100644 --- a/ml_dht/Settings.cs +++ b/ml_dht/Settings.cs @@ -6,6 +6,14 @@ namespace ml_dht { static class Settings { + internal class SettingEvent + { + 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(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 ms_entries = null; - public static event Action EnabledChange; - public static event Action HeadTrackingChange; - public static event Action EyeTrackingChange; - public static event Action FaceTrackingChange; - public static event Action BlinkingChange; - public static event Action MirroredChange; - public static event Action SmoothingChange; + public static readonly SettingEvent OnEnabledChanged = new SettingEvent(); + public static readonly SettingEvent OnHeadTrackingChanged = new SettingEvent(); + public static readonly SettingEvent OnEyeTrackingChanged = new SettingEvent(); + public static readonly SettingEvent OnFaceTrackingChanged = new SettingEvent(); + public static readonly SettingEvent OnBlinkingChanged = new SettingEvent(); + public static readonly SettingEvent OnMirroredChanged = new SettingEvent(); + public static readonly SettingEvent OnSmoothingChanged = new SettingEvent(); internal static void Init() { @@ -87,72 +95,86 @@ namespace ml_dht static void OnSliderUpdate(string p_name, string p_value) { - if(Enum.TryParse(p_name, out ModSetting l_setting)) + try { - switch(l_setting) + if(Enum.TryParse(p_name, out ModSetting l_setting)) { - case ModSetting.Smoothing: + switch(l_setting) { - Smoothing = int.Parse(p_value) * 0.01f; - SmoothingChange?.Invoke(Smoothing); + case ModSetting.Smoothing: + { + Smoothing = int.Parse(p_value) * 0.01f; + OnSmoothingChanged.Invoke(Smoothing); + } + break; } - break; - } - ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); + ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); + } + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } } static void OnToggleUpdate(string p_name, string p_value) { - if(Enum.TryParse(p_name, out ModSetting l_setting)) + try { - switch(l_setting) + if(Enum.TryParse(p_name, out ModSetting l_setting)) { - case ModSetting.Enabled: + switch(l_setting) { - Enabled = bool.Parse(p_value); - EnabledChange?.Invoke(Enabled); - } - break; + case ModSetting.Enabled: + { + Enabled = bool.Parse(p_value); + OnEnabledChanged.Invoke(Enabled); + } + break; - case ModSetting.HeadTracking: - { - HeadTracking = bool.Parse(p_value); - HeadTrackingChange?.Invoke(HeadTracking); - } - break; + case ModSetting.HeadTracking: + { + HeadTracking = bool.Parse(p_value); + OnHeadTrackingChanged.Invoke(HeadTracking); + } + break; - case ModSetting.EyeTracking: - { - EyeTracking = bool.Parse(p_value); - EyeTrackingChange?.Invoke(EyeTracking); - } - break; + case ModSetting.EyeTracking: + { + EyeTracking = bool.Parse(p_value); + OnEyeTrackingChanged.Invoke(EyeTracking); + } + break; - case ModSetting.FaceTracking: - { - FaceTracking = bool.Parse(p_value); - FaceTrackingChange?.Invoke(FaceTracking); - } - break; + case ModSetting.FaceTracking: + { + FaceTracking = bool.Parse(p_value); + OnFaceTrackingChanged.Invoke(FaceTracking); + } + break; - case ModSetting.Blinking: - { - Blinking = bool.Parse(p_value); - BlinkingChange?.Invoke(Blinking); - } - break; + case ModSetting.Blinking: + { + Blinking = bool.Parse(p_value); + OnBlinkingChanged.Invoke(Blinking); + } + break; - case ModSetting.Mirrored: - { - Mirrored = bool.Parse(p_value); - MirroredChange?.Invoke(Mirrored); + case ModSetting.Mirrored: + { + Mirrored = bool.Parse(p_value); + OnMirroredChanged.Invoke(Mirrored); + } + break; } - break; + + ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); } - - ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } } } diff --git a/ml_dht/ml_dht.csproj b/ml_dht/ml_dht.csproj index 7b3c1c1..071f76b 100644 --- a/ml_dht/ml_dht.csproj +++ b/ml_dht/ml_dht.csproj @@ -6,7 +6,7 @@ SDraw None DesktopHeadTracking - 1.2.2 + 1.2.3 x64 diff --git a/ml_lme/GameEvents.cs b/ml_lme/GameEvents.cs new file mode 100644 index 0000000..2c518cc --- /dev/null +++ b/ml_lme/GameEvents.cs @@ -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 + { + 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(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 OnRayScale = new GameEvent(); + public static readonly GameEvent OnPlayspaceScale = new GameEvent(); + public static readonly GameEvent OnPickupGrab = 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), + 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); + } + } + } +} diff --git a/ml_lme/LeapInput.cs b/ml_lme/LeapInput.cs index 3ad041c..5a488f0 100644 --- a/ml_lme/LeapInput.cs +++ b/ml_lme/LeapInput.cs @@ -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]; } } diff --git a/ml_lme/LeapManager.cs b/ml_lme/LeapManager.cs index e6a3eab..33874c4 100644 --- a/ml_lme/LeapManager.cs +++ b/ml_lme/LeapManager.cs @@ -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().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(); 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() { diff --git a/ml_lme/LeapParser.cs b/ml_lme/LeapParser.cs index a1ed31c..847ee64 100644 --- a/ml_lme/LeapParser.cs +++ b/ml_lme/LeapParser.cs @@ -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); } } } diff --git a/ml_lme/LeapTracked.cs b/ml_lme/LeapTracked.cs index b410e22..9c0a470 100644 --- a/ml_lme/LeapTracked.cs +++ b/ml_lme/LeapTracked.cs @@ -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(); 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(); - 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; diff --git a/ml_lme/LeapTracking.cs b/ml_lme/LeapTracking.cs index 8704bef..a4519aa 100644 --- a/ml_lme/LeapTracking.cs +++ b/ml_lme/LeapTracking.cs @@ -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 diff --git a/ml_lme/Main.cs b/ml_lme/Main.cs index 2210141..db72a55 100644 --- a/ml_lme/Main.cs +++ b/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(); } - - // 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); - } - } } } diff --git a/ml_lme/Properties/AssemblyInfo.cs b/ml_lme/Properties/AssemblyInfo.cs index 936a74d..5a44bef 100644 --- a/ml_lme/Properties/AssemblyInfo.cs +++ b/ml_lme/Properties/AssemblyInfo.cs @@ -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)] diff --git a/ml_lme/Settings.cs b/ml_lme/Settings.cs index ced9738..9ee9e2f 100644 --- a/ml_lme/Settings.cs +++ b/ml_lme/Settings.cs @@ -7,6 +7,14 @@ namespace ml_lme { static class Settings { + internal class SettingEvent + { + 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(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 ms_entries = null; - public static event Action EnabledChange; - public static event Action DesktopOffsetChange; - public static event Action FingersOnlyChange; - public static event Action ModelVisibilityChange; - public static event Action TrackingModeChange; - public static event Action RootAngleChange; - public static event Action HeadAttachChange; - public static event Action HeadOffsetChange; - public static event Action TrackElbowsChange; - public static event Action InteractionChange; - public static event Action GesturesChange; - public static event Action InteractThreadholdChange; - public static event Action GripThreadholdChange; - public static event Action VisualHandsChange; - public static event Action MechanimFilterChange; + public static readonly SettingEvent OnEnabledChanged = new SettingEvent(); + public static readonly SettingEvent OnDesktopOffsetChanged = new SettingEvent(); + public static readonly SettingEvent OnFingersOnlyChanged = new SettingEvent(); + public static readonly SettingEvent OnModelVisibilityChanged = new SettingEvent(); + public static readonly SettingEvent OnTrackingModeChanged = new SettingEvent(); + public static readonly SettingEvent OnRootAngleChanged = new SettingEvent(); + public static readonly SettingEvent OnHeadAttachChanged = new SettingEvent(); + public static readonly SettingEvent OnHeadOffsetChanged = new SettingEvent(); + public static readonly SettingEvent OnTrackElbowsChanged = new SettingEvent(); + public static readonly SettingEvent OnInteractionChanged = new SettingEvent(); + public static readonly SettingEvent OnGesturesChanged = new SettingEvent(); + public static readonly SettingEvent OnInteractThreadholdChanged = new SettingEvent(); + public static readonly SettingEvent OnGripThreadholdChanged = new SettingEvent(); + public static readonly SettingEvent OnVisualHandsChanged = new SettingEvent(); + public static readonly SettingEvent OnMechanimFilterChanged = new SettingEvent(); internal static void Init() { @@ -103,7 +111,33 @@ namespace ml_lme ms_category.CreateEntry(ModSetting.MechanimFilter.ToString(), MechanimFilter) }; - Load(); + Enabled = (bool)ms_entries[(int)ModSetting.Enabled].BoxedValue; + DesktopOffset = new Vector3( + (int)ms_entries[(int)ModSetting.DesktopX].BoxedValue, + (int)ms_entries[(int)ModSetting.DesktopY].BoxedValue, + (int)ms_entries[(int)ModSetting.DesktopZ].BoxedValue + ) * 0.01f; + FingersOnly = (bool)ms_entries[(int)ModSetting.FingersOnly].BoxedValue; + ModelVisibility = (bool)ms_entries[(int)ModSetting.Model].BoxedValue; + TrackingMode = (LeapTrackingMode)(int)ms_entries[(int)ModSetting.Mode].BoxedValue; + RootAngle = new Vector3( + (int)ms_entries[(int)ModSetting.AngleX].BoxedValue, + (int)ms_entries[(int)ModSetting.AngleY].BoxedValue, + (int)ms_entries[(int)ModSetting.AngleZ].BoxedValue + ); + HeadAttach = (bool)ms_entries[(int)ModSetting.Head].BoxedValue; + HeadOffset = new Vector3( + (int)ms_entries[(int)ModSetting.HeadX].BoxedValue, + (int)ms_entries[(int)ModSetting.HeadY].BoxedValue, + (int)ms_entries[(int)ModSetting.HeadZ].BoxedValue + ) * 0.01f; + TrackElbows = (bool)ms_entries[(int)ModSetting.TrackElbows].BoxedValue; + Interaction = (bool)ms_entries[(int)ModSetting.Interaction].BoxedValue; + Gestures = (bool)ms_entries[(int)ModSetting.Gestures].BoxedValue; + InteractThreadhold = (int)ms_entries[(int)ModSetting.InteractThreadhold].BoxedValue * 0.01f; + GripThreadhold = (int)ms_entries[(int)ModSetting.GripThreadhold].BoxedValue * 0.01f; + VisualHands = (bool)ms_entries[(int)ModSetting.VisualHands].BoxedValue; + MechanimFilter = (bool)ms_entries[(int)ModSetting.MechanimFilter].BoxedValue; MelonLoader.MelonCoroutines.Start(WaitMainMenuUi()); } @@ -132,226 +166,216 @@ namespace ml_lme }; } - static void Load() - { - Enabled = (bool)ms_entries[(int)ModSetting.Enabled].BoxedValue; - DesktopOffset = new Vector3( - (int)ms_entries[(int)ModSetting.DesktopX].BoxedValue, - (int)ms_entries[(int)ModSetting.DesktopY].BoxedValue, - (int)ms_entries[(int)ModSetting.DesktopZ].BoxedValue - ) * 0.01f; - FingersOnly = (bool)ms_entries[(int)ModSetting.FingersOnly].BoxedValue; - ModelVisibility = (bool)ms_entries[(int)ModSetting.Model].BoxedValue; - TrackingMode = (LeapTrackingMode)(int)ms_entries[(int)ModSetting.Mode].BoxedValue; - RootAngle = new Vector3( - (int)ms_entries[(int)ModSetting.AngleX].BoxedValue, - (int)ms_entries[(int)ModSetting.AngleY].BoxedValue, - (int)ms_entries[(int)ModSetting.AngleZ].BoxedValue - ); - HeadAttach = (bool)ms_entries[(int)ModSetting.Head].BoxedValue; - HeadOffset = new Vector3( - (int)ms_entries[(int)ModSetting.HeadX].BoxedValue, - (int)ms_entries[(int)ModSetting.HeadY].BoxedValue, - (int)ms_entries[(int)ModSetting.HeadZ].BoxedValue - ) * 0.01f; - TrackElbows = (bool)ms_entries[(int)ModSetting.TrackElbows].BoxedValue; - Interaction = (bool)ms_entries[(int)ModSetting.Interaction].BoxedValue; - Gestures = (bool)ms_entries[(int)ModSetting.Gestures].BoxedValue; - InteractThreadhold = (int)ms_entries[(int)ModSetting.InteractThreadhold].BoxedValue * 0.01f; - GripThreadhold = (int)ms_entries[(int)ModSetting.GripThreadhold].BoxedValue * 0.01f; - VisualHands = (bool)ms_entries[(int)ModSetting.VisualHands].BoxedValue; - MechanimFilter = (bool)ms_entries[(int)ModSetting.MechanimFilter].BoxedValue; - } - static void OnToggleUpdate(string p_name, string p_value) { - if(Enum.TryParse(p_name, out ModSetting l_setting)) + try { - switch(l_setting) + if(Enum.TryParse(p_name, out ModSetting l_setting)) { - case ModSetting.Enabled: + switch(l_setting) { - Enabled = bool.Parse(p_value); - EnabledChange?.Invoke(Enabled); - } - break; + case ModSetting.Enabled: + { + Enabled = bool.Parse(p_value); + OnEnabledChanged.Invoke(Enabled); + } + break; - case ModSetting.FingersOnly: - { - FingersOnly = bool.Parse(p_value); - FingersOnlyChange?.Invoke(FingersOnly); - } - break; + case ModSetting.FingersOnly: + { + FingersOnly = bool.Parse(p_value); + OnFingersOnlyChanged.Invoke(FingersOnly); + } + break; - case ModSetting.Model: - { - ModelVisibility = bool.Parse(p_value); - ModelVisibilityChange?.Invoke(ModelVisibility); - } - break; + case ModSetting.Model: + { + ModelVisibility = bool.Parse(p_value); + OnModelVisibilityChanged.Invoke(ModelVisibility); + } + break; - case ModSetting.Head: - { - HeadAttach = bool.Parse(p_value); - HeadAttachChange?.Invoke(HeadAttach); - } - break; + case ModSetting.Head: + { + HeadAttach = bool.Parse(p_value); + OnHeadAttachChanged.Invoke(HeadAttach); + } + break; - case ModSetting.TrackElbows: - { - TrackElbows = bool.Parse(p_value); - TrackElbowsChange?.Invoke(TrackElbows); - } - break; + case ModSetting.TrackElbows: + { + TrackElbows = bool.Parse(p_value); + OnTrackElbowsChanged.Invoke(TrackElbows); + } + break; - case ModSetting.Interaction: - { - Interaction = bool.Parse(p_value); - InteractionChange?.Invoke(Interaction); - } - break; + case ModSetting.Interaction: + { + Interaction = bool.Parse(p_value); + OnInteractionChanged.Invoke(Interaction); + } + break; - case ModSetting.Gestures: - { - Gestures = bool.Parse(p_value); - GesturesChange?.Invoke(Gestures); - } - break; + case ModSetting.Gestures: + { + Gestures = bool.Parse(p_value); + OnGesturesChanged.Invoke(Gestures); + } + break; - case ModSetting.VisualHands: - { - VisualHands = bool.Parse(p_value); - VisualHandsChange?.Invoke(VisualHands); + case ModSetting.VisualHands: + { + VisualHands = bool.Parse(p_value); + OnVisualHandsChanged.Invoke(VisualHands); + } + break; + + case ModSetting.MechanimFilter: + { + MechanimFilter = bool.Parse(p_value); + OnMechanimFilterChanged.Invoke(MechanimFilter); + } + break; } - break; - - case ModSetting.MechanimFilter: - { - MechanimFilter = bool.Parse(p_value); - MechanimFilterChange?.Invoke(MechanimFilter); - } - break; + + ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); } - - ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } } static void OnSliderUpdate(string p_name, string p_value) { - if(Enum.TryParse(p_name, out ModSetting l_setting)) + try { - switch(l_setting) + if(Enum.TryParse(p_name, out ModSetting l_setting)) { - case ModSetting.DesktopX: + switch(l_setting) { - Vector3 l_current = DesktopOffset; - l_current.x = int.Parse(p_value) * 0.01f; - DesktopOffset = l_current; - DesktopOffsetChange?.Invoke(l_current); - } - break; - case ModSetting.DesktopY: - { - Vector3 l_current = DesktopOffset; - l_current.y = int.Parse(p_value) * 0.01f; - DesktopOffset = l_current; - DesktopOffsetChange?.Invoke(l_current); - } - break; - case ModSetting.DesktopZ: - { - Vector3 l_current = DesktopOffset; - l_current.z = int.Parse(p_value) * 0.01f; - DesktopOffset = l_current; - DesktopOffsetChange?.Invoke(l_current); - } - break; + case ModSetting.DesktopX: + { + Vector3 l_current = DesktopOffset; + l_current.x = int.Parse(p_value) * 0.01f; + DesktopOffset = l_current; + OnDesktopOffsetChanged.Invoke(l_current); + } + break; + case ModSetting.DesktopY: + { + Vector3 l_current = DesktopOffset; + l_current.y = int.Parse(p_value) * 0.01f; + DesktopOffset = l_current; + OnDesktopOffsetChanged.Invoke(l_current); + } + break; + case ModSetting.DesktopZ: + { + Vector3 l_current = DesktopOffset; + l_current.z = int.Parse(p_value) * 0.01f; + DesktopOffset = l_current; + OnDesktopOffsetChanged.Invoke(l_current); + } + break; - case ModSetting.AngleX: - { - Vector3 l_current = RootAngle; - l_current.x = int.Parse(p_value); - RootAngle = l_current; - RootAngleChange?.Invoke(l_current); - } - break; + case ModSetting.AngleX: + { + Vector3 l_current = RootAngle; + l_current.x = int.Parse(p_value); + RootAngle = l_current; + OnRootAngleChanged.Invoke(l_current); + } + break; - case ModSetting.AngleY: - { - Vector3 l_current = RootAngle; - l_current.y = int.Parse(p_value); - RootAngle = l_current; - RootAngleChange?.Invoke(l_current); - } - break; + case ModSetting.AngleY: + { + Vector3 l_current = RootAngle; + l_current.y = int.Parse(p_value); + RootAngle = l_current; + OnRootAngleChanged.Invoke(l_current); + } + break; - case ModSetting.AngleZ: - { - Vector3 l_current = RootAngle; - l_current.z = int.Parse(p_value); - RootAngle = l_current; - RootAngleChange?.Invoke(l_current); - } - break; + case ModSetting.AngleZ: + { + Vector3 l_current = RootAngle; + l_current.z = int.Parse(p_value); + RootAngle = l_current; + OnRootAngleChanged.Invoke(l_current); + } + break; - case ModSetting.HeadX: - { - Vector3 l_current = HeadOffset; - l_current.x = int.Parse(p_value) * 0.01f; - HeadOffset = l_current; - HeadOffsetChange?.Invoke(l_current); + case ModSetting.HeadX: + { + Vector3 l_current = HeadOffset; + l_current.x = int.Parse(p_value) * 0.01f; + HeadOffset = l_current; + OnHeadOffsetChanged.Invoke(l_current); + } + break; + case ModSetting.HeadY: + { + Vector3 l_current = HeadOffset; + l_current.y = int.Parse(p_value) * 0.01f; + HeadOffset = l_current; + OnHeadOffsetChanged.Invoke(l_current); + } + break; + case ModSetting.HeadZ: + { + Vector3 l_current = HeadOffset; + l_current.z = int.Parse(p_value) * 0.01f; + HeadOffset = l_current; + OnHeadOffsetChanged.Invoke(l_current); + } + break; + case ModSetting.InteractThreadhold: + { + InteractThreadhold = int.Parse(p_value) * 0.01f; + OnInteractThreadholdChanged.Invoke(InteractThreadhold); + } + break; + case ModSetting.GripThreadhold: + { + GripThreadhold = int.Parse(p_value) * 0.01f; + OnGripThreadholdChanged.Invoke(GripThreadhold); + } + break; } - break; - case ModSetting.HeadY: - { - Vector3 l_current = HeadOffset; - l_current.y = int.Parse(p_value) * 0.01f; - HeadOffset = l_current; - HeadOffsetChange?.Invoke(l_current); - } - break; - case ModSetting.HeadZ: - { - Vector3 l_current = HeadOffset; - l_current.z = int.Parse(p_value) * 0.01f; - HeadOffset = l_current; - HeadOffsetChange?.Invoke(l_current); - } - break; - case ModSetting.InteractThreadhold: - { - InteractThreadhold = int.Parse(p_value) * 0.01f; - InteractThreadholdChange?.Invoke(InteractThreadhold); - } - break; - case ModSetting.GripThreadhold: - { - GripThreadhold = int.Parse(p_value) * 0.01f; - GripThreadholdChange?.Invoke(GripThreadhold); - } - break; + + ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); } - - ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } } static void OnDropdownUpdate(string p_name, string p_value) { - if(Enum.TryParse(p_name, out ModSetting l_setting)) + try { - switch(l_setting) + if(Enum.TryParse(p_name, out ModSetting l_setting)) { - case ModSetting.Mode: + switch(l_setting) { - TrackingMode = (LeapTrackingMode)int.Parse(p_value); - TrackingModeChange?.Invoke(TrackingMode); + case ModSetting.Mode: + { + TrackingMode = (LeapTrackingMode)int.Parse(p_value); + OnTrackingModeChanged.Invoke(TrackingMode); + } + break; } - break; - } - ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); + ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); + } + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } } } diff --git a/ml_lme/ml_lme.csproj b/ml_lme/ml_lme.csproj index bcd3c04..82cece4 100644 --- a/ml_lme/ml_lme.csproj +++ b/ml_lme/ml_lme.csproj @@ -4,7 +4,7 @@ netstandard2.1 x64 LeapMotionExtension - 1.4.9 + 1.5.0 SDraw None LeapMotionExtension @@ -93,6 +93,11 @@ false false + + D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.JSONSerializeModule.dll + false + false + D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.XRModule.dll false diff --git a/ml_lme/vendor/LeapCSharp/Config.cs b/ml_lme/vendor/LeapCSharp/Config.cs index 7981ef8..05128d6 100644 --- a/ml_lme/vendor/LeapCSharp/Config.cs +++ b/ml_lme/vendor/LeapCSharp/Config.cs @@ -30,7 +30,7 @@ namespace Leap /// Note that the Controller.Config provides a properly initialized Config object already. /// @since 3.0 /// - [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(); diff --git a/ml_lme/vendor/LeapCSharp/Connection.cs b/ml_lme/vendor/LeapCSharp/Connection.cs index 871165e..12dcbfb 100644 --- a/ml_lme/vendor/LeapCSharp/Connection.cs +++ b/ml_lme/vendor/LeapCSharp/Connection.cs @@ -72,13 +72,9 @@ namespace LeapInternal private IntPtr _leapConnection; private volatile bool _isRunning = false; + public bool IsRunning { get { return _isRunning; } } private Thread _polster; - /// - /// Has the connection been set up in multi device aware mode - /// - private bool _multiDeviceAwareConnection = false; - /// /// Minimum service version that support setting the tracking mode on a per dervice basis /// @@ -88,6 +84,7 @@ namespace LeapInternal private Dictionary _activePolicies = new Dictionary(); //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 _configRequests = new Dictionary(); //Connection events @@ -124,13 +121,16 @@ namespace LeapInternal public EventHandler LeapFrame; public EventHandler LeapInternalFrame; public EventHandler LeapLogEvent; + [Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")] public EventHandler LeapConfigResponse; + [Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")] public EventHandler LeapConfigChange; public EventHandler LeapDistortionChange; public EventHandler LeapDroppedFrame; public EventHandler LeapImage; public EventHandler LeapPointMappingChange; public EventHandler LeapHeadPoseChange; + public EventHandler LeapFiducialPose; public Action LeapBeginProfilingForThread; public Action 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.PtrToStruct(_msg.eventStructPtr, out connection_evt); @@ -319,13 +324,11 @@ namespace LeapInternal StructMarshal.PtrToStruct(_msg.eventStructPtr, out connection_lost_evt); handleConnectionLost(ref connection_lost_evt); break; - case eLeapEventType.eLeapEventType_Device: LEAP_DEVICE_EVENT device_evt; StructMarshal.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.PtrToStruct(_msg.eventStructPtr, out device_failure_evt); handleFailedDevice(ref device_failure_evt); break; - case eLeapEventType.eLeapEventType_Policy: LEAP_POLICY_EVENT policy_evt; StructMarshal.PtrToStruct(_msg.eventStructPtr, out policy_evt); @@ -354,11 +356,6 @@ namespace LeapInternal StructMarshal.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.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.PtrToStruct(_msg.eventStructPtr, out dropped_frame_evt); @@ -374,16 +371,21 @@ namespace LeapInternal StructMarshal.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.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.PtrToStruct(_msg.eventStructPtr, out status_evt); handleDeviceStatusEvent(ref status_evt); break; + case eLeapEventType.eLeapEventType_NewDeviceTransform: + LEAP_NEW_DEVICE_TRANSFORM new_transform_evt; + StructMarshal.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.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(string config_key, T value) where T : IConvertible { uint requestId = 0; @@ -1322,6 +1302,19 @@ namespace LeapInternal Marshal.FreeHGlobal(buffer); } + /// + /// Send a specific set of hints to hDevice, if this does not include previously set ones, they will be cleared. + /// + /// The Device pointer for the trcking device to set the hints for + /// The array of hints + 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) { diff --git a/ml_lme/vendor/LeapCSharp/Controller.cs b/ml_lme/vendor/LeapCSharp/Controller.cs index 801794b..9a4c63e 100644 --- a/ml_lme/vendor/LeapCSharp/Controller.cs +++ b/ml_lme/vendor/LeapCSharp/Controller.cs @@ -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"; /// @@ -232,6 +232,7 @@ namespace Leap /// Dispatched when a configuration setting changes. /// @since 3.0 /// + [Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")] public event EventHandler ConfigChange { add @@ -403,6 +404,21 @@ namespace Leap } } + /// + /// Dispatched when a Fiducial Marker has been tracked. + /// + public event EventHandler 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 /// public void StartConnection() { - _connection.Start(_serverNamespace, _supportsMultipleDevices); + _connection.Start(_serverNamespace); } /// @@ -621,6 +639,21 @@ namespace Leap return _connection.IsDeviceAvailable(device); } + /// + /// Send a specific set of hints, if this does not include previously set ones, they will be cleared. + /// + /// The hints you wish to send + /// An optional specific Device, otherwise the first found will be used + public void RequestHandTrackingHints(string[] hints, Device device = null) + { + if (device == null) + { + device = Devices.ActiveDevices.FirstOrDefault(); + } + + _connection.RequestHandTrackingHintsOnDevice(device.Handle, hints); + } + /// /// 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 /// - [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 diff --git a/ml_lme/vendor/LeapCSharp/CopyFromLeapCExtensions.cs b/ml_lme/vendor/LeapCSharp/CopyFromLeapCExtensions.cs index 19ed17c..82d3525 100644 --- a/ml_lme/vendor/LeapCSharp/CopyFromLeapCExtensions.cs +++ b/ml_lme/vendor/LeapCSharp/CopyFromLeapCExtensions.cs @@ -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); } diff --git a/ml_lme/vendor/LeapCSharp/Device.cs b/ml_lme/vendor/LeapCSharp/Device.cs index 1ec4285..e9dc09c 100644 --- a/ml_lme/vendor/LeapCSharp/Device.cs +++ b/ml_lme/vendor/LeapCSharp/Device.cs @@ -255,67 +255,78 @@ namespace Leap return devicePose; } - bool deviceTransformAvailable = LeapC.GetDeviceTransformAvailable(Handle); - - if (!deviceTransformAvailable) - { - devicePose = Pose.identity; - poseSet = true; - return Pose.identity; - } - - float[] data = new float[16]; - eLeapRS result = LeapC.GetDeviceTransform(Handle, data); - - if (result != eLeapRS.eLeapRS_Success || data == null) - { - devicePose = Pose.identity; - poseSet = true; - return Pose.identity; - } - - // Using the LEAP->OPENXR device transform matrix - // Unitys matrices are generated as 4 columns: - Matrix4x4 deviceTransform = new Matrix4x4( - new Vector4(data[0], data[1], data[2], data[3]), - new Vector4(data[4], data[5], data[6], data[7]), - new Vector4(data[8], data[9], data[10], data[11]), - new Vector4(data[12], data[13], data[14], data[15])); - - - // An example of the expected matrix if it were 8cm forward from the head origin - // Unitys matrices are generated as 4 columns: - //Matrix4x4 deviceTransform = new Matrix4x4( - // new Vector4(-0.001f, 0, 0, 0), - // new Vector4(0, 0, -0.001f, 0), - // new Vector4(0, -0.001f, 0, 0), - // new Vector4(0, 0, -0.08f, 1)); - - if (deviceTransform == Matrix4x4.identity) - { - devicePose = Pose.identity; - poseSet = true; - return Pose.identity; - } - - Matrix4x4 openXRToUnity = new Matrix4x4( - new Vector4(1f, 0, 0, 0), - new Vector4(0, 1f, 0, 0), - new Vector4(0, 0, -1f, 0), - new Vector4(0, 0, 0, 1)); - - deviceTransform = openXRToUnity * deviceTransform; - - Vector3 outputPos = deviceTransform.GetPosition(); - //Quaternion outputRot = deviceTransform.rotation; // Note: the matrices we receive are not rotatrion matrices. This produces unexpected results - - devicePose = new Pose(outputPos, Quaternion.identity); - - poseSet = true; - return devicePose; + return FindDeviceTransform(); } } + internal Pose FindDeviceTransform() + { + // Check the service has valid support for device transforms + LEAP_VERSION minimumServiceVersion = new LEAP_VERSION { major = 5, minor = 19, patch = 0 }; + if (!ServerStatus.IsServiceVersionValid(minimumServiceVersion)) + { + devicePose = Pose.identity; + poseSet = true; + return Pose.identity; + } + + // Check the device transform is available before asking for one + bool deviceTransformAvailable = LeapC.GetDeviceTransformAvailable(Handle); + + if (!deviceTransformAvailable) + { + devicePose = Pose.identity; + return Pose.identity; + } + + // Get the device transform data and check it is valid as data + float[] data = new float[16]; + eLeapRS result = LeapC.GetDeviceTransform(Handle, data); + + if (result != eLeapRS.eLeapRS_Success || data == null) + { + devicePose = Pose.identity; + return Pose.identity; + } + + // Using the LEAP->OPENXR device transform matrix + // Unitys matrices are generated as 4 columns: + Matrix4x4 deviceTransform = new Matrix4x4( + new Vector4(data[0], data[1], data[2], data[3]), + new Vector4(data[4], data[5], data[6], data[7]), + new Vector4(data[8], data[9], data[10], data[11]), + new Vector4(data[12], data[13], data[14], data[15])); + + ////An example of the expected matrix if it were 8cm forward from the head origin + //// Unitys matrices are generated as 4 columns: + //Matrix4x4 deviceTransform = new Matrix4x4( + // new Vector4(-0.001f, 0, 0, 0), + // new Vector4(0, 0, -0.001f, 0), + // new Vector4(0, -0.001f, 0, 0), + // new Vector4(0, 0, -0.08f, 1)); + + //// An example of applying a rotation to the existing device transform + //Matrix4x4 rotationMatrix = Matrix4x4.Rotate(Quaternion.Euler(0, 90, 0)); + //deviceTransform = deviceTransform * rotationMatrix; + + Matrix4x4 openXRToUnitySwizzle = new Matrix4x4( + new Vector4(1.0f, 0, 0, 0), + new Vector4(0, 1.0f, 0, 0), + new Vector4(0, 0, -1f, 0), + new Vector4(0, 0, 0, 1f)); + + // Converts device transform from openxr space to unity space + deviceTransform = openXRToUnitySwizzle.inverse * deviceTransform * openXRToUnitySwizzle; + + Vector3 outputPos = deviceTransform.GetPosition(); + Quaternion outputRot = deviceTransform.rotation; + + devicePose = new Pose(outputPos, outputRot); + + poseSet = true; + return devicePose; + } + /// /// Returns the internal status field of the current device /// diff --git a/ml_lme/vendor/LeapCSharp/Events.cs b/ml_lme/vendor/LeapCSharp/Events.cs index c7b12d3..35a1a59 100644 --- a/ml_lme/vendor/LeapCSharp/Events.cs +++ b/ml_lme/vendor/LeapCSharp/Events.cs @@ -10,6 +10,7 @@ namespace Leap { using LeapInternal; using System; + using System.Runtime.InteropServices; /// /// 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 }; /// /// 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 /// + [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; } } + /// + /// Dispatched when a Fiducial Marker is tracked + /// + /// Note: Family and Size are not currently implemented + /// + 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; diff --git a/ml_lme/vendor/LeapCSharp/IController.cs b/ml_lme/vendor/LeapCSharp/IController.cs index 19167bf..34c7200 100644 --- a/ml_lme/vendor/LeapCSharp/IController.cs +++ b/ml_lme/vendor/LeapCSharp/IController.cs @@ -37,6 +37,7 @@ namespace Leap //new event EventHandler PolicyChange; + [Obsolete("Config is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")] event EventHandler ConfigChange; event EventHandler DistortionChange; event EventHandler ImageReady; diff --git a/ml_lme/vendor/LeapCSharp/LeapC.cs b/ml_lme/vendor/LeapCSharp/LeapC.cs index e13f95d..c7a1db4 100644 --- a/ml_lme/vendor/LeapCSharp/LeapC.cs +++ b/ml_lme/vendor/LeapCSharp/LeapC.cs @@ -532,15 +532,26 @@ namespace LeapInternal /// /// A new head pose is available. /// + [Obsolete("Head pose events are not supported and will never be raised")] eLeapEventType_HeadPose, /// /// A new head pose is available. /// + [Obsolete("Eye pose events are not supported and will never be raised")] eLeapEventType_Eyes, /// - /// A new head pose is available. + /// A new IMU information frame is available. /// - eLeapEventType_IMU + eLeapEventType_IMU, + /// + /// Notification that the service received a new device transformation matrix + /// Use LeapGetDeviceTransform to update your cached information. + /// + eLeapEventType_NewDeviceTransform, + /// + /// An event provided when a fiducial marker has been tracked + /// + 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); } } \ No newline at end of file diff --git a/ml_lme/vendor/LeapCSharp/MetadataUtil.cs b/ml_lme/vendor/LeapCSharp/MetadataUtil.cs new file mode 100644 index 0000000..38faa03 --- /dev/null +++ b/ml_lme/vendor/LeapCSharp/MetadataUtil.cs @@ -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 +{ + /// + /// 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" + /// +#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"; + } + } +} \ No newline at end of file diff --git a/ml_lme/vendor/LeapCSharp/ServerStatus.cs b/ml_lme/vendor/LeapCSharp/ServerStatus.cs new file mode 100644 index 0000000..c03c5c7 --- /dev/null +++ b/ml_lme/vendor/LeapCSharp/ServerStatus.cs @@ -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(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(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(ins); + } + } + } +} \ No newline at end of file diff --git a/ml_lme/vendor/LeapCSharp/UltraleapSettings.cs b/ml_lme/vendor/LeapCSharp/UltraleapSettings.cs new file mode 100644 index 0000000..d87fb40 --- /dev/null +++ b/ml_lme/vendor/LeapCSharp/UltraleapSettings.cs @@ -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(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("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(); + + 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 + } +} \ No newline at end of file diff --git a/ml_pam/ArmMover.cs b/ml_pam/ArmMover.cs index 1696b3d..9fc2d23 100644 --- a/ml_pam/ArmMover.cs +++ b/ml_pam/ArmMover.cs @@ -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(); @@ -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 diff --git a/ml_pam/GameEvents.cs b/ml_pam/GameEvents.cs new file mode 100644 index 0000000..c7a365e --- /dev/null +++ b/ml_pam/GameEvents.cs @@ -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 + { + 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(T1 p_obj) => m_action?.Invoke(p_obj); + } + 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(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 OnPlayspaceScale = new GameEvent(); + public static readonly GameEvent OnPickupGrab = new GameEvent(); + public static readonly GameEvent OnPickupDrop = 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), + 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); + } + } + } +} diff --git a/ml_pam/Main.cs b/ml_pam/Main.cs index fe3c046..441f5c3 100644 --- a/ml_pam/Main.cs +++ b/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); - } - } } } diff --git a/ml_pam/Properties/AssemblyInfo.cs b/ml_pam/Properties/AssemblyInfo.cs index 27a1983..3a3859a 100644 --- a/ml_pam/Properties/AssemblyInfo.cs +++ b/ml_pam/Properties/AssemblyInfo.cs @@ -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)] diff --git a/ml_pam/Settings.cs b/ml_pam/Settings.cs index c1562e4..78eb2b2 100644 --- a/ml_pam/Settings.cs +++ b/ml_pam/Settings.cs @@ -6,6 +6,14 @@ namespace ml_pam { static class Settings { + internal class SettingEvent + { + 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(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 ms_entries = null; - public static event Action EnabledChange; - public static event Action GrabOffsetChange; - public static event Action LeadingHandChange; - public static event Action HandsExtensionChange; + public static readonly SettingEvent OnEnabledChanged = new SettingEvent(); + public static readonly SettingEvent OnGrabOffsetChanged = new SettingEvent(); + public static readonly SettingEvent OnLeadingHandChanged = new SettingEvent(); + public static readonly SettingEvent OnHandsExtensionChanged = new SettingEvent(); internal static void Init() { @@ -79,61 +87,83 @@ namespace ml_pam static void OnToggleUpdate(string p_name, string p_value) { - if(Enum.TryParse(p_name, out ModSetting l_setting)) + try { - switch(l_setting) + if(Enum.TryParse(p_name, out ModSetting l_setting)) { - case ModSetting.Enabled: + switch(l_setting) { - Enabled = bool.Parse(p_value); - EnabledChange?.Invoke(Enabled); + case ModSetting.Enabled: + { + Enabled = bool.Parse(p_value); + OnEnabledChanged.Invoke(Enabled); + } + break; + + case ModSetting.HandsExtension: + { + HandsExtension = bool.Parse(p_value); + OnHandsExtensionChanged.Invoke(HandsExtension); + } + break; } - break; - case ModSetting.HandsExtension: - { - HandsExtension = bool.Parse(p_value); - HandsExtensionChange?.Invoke(HandsExtension); - } break; + ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); } - - ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } } static void OnSliderUpdate(string p_name, string p_value) { - if(Enum.TryParse(p_name, out ModSetting l_setting)) + try { - switch(l_setting) + if(Enum.TryParse(p_name, out ModSetting l_setting)) { - case ModSetting.GrabOffset: + switch(l_setting) { - GrabOffset = int.Parse(p_value) * 0.01f; - GrabOffsetChange?.Invoke(GrabOffset); + case ModSetting.GrabOffset: + { + GrabOffset = int.Parse(p_value) * 0.01f; + OnGrabOffsetChanged.Invoke(GrabOffset); + } + break; } - break; - } - ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); + ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); + } + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } } static void OnDropdownUpdate(string p_name, string p_value) { - if(Enum.TryParse(p_name, out ModSetting l_setting)) + try { - switch(l_setting) + if(Enum.TryParse(p_name, out ModSetting l_setting)) { - case ModSetting.LeadHand: + switch(l_setting) { - LeadingHand = (LeadHand)int.Parse(p_value); - LeadingHandChange?.Invoke(LeadingHand); + case ModSetting.LeadHand: + { + LeadingHand = (LeadHand)int.Parse(p_value); + OnLeadingHandChanged.Invoke(LeadingHand); + } + break; } - break; - } - ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); + ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); + } + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } } } diff --git a/ml_pam/ml_pam.csproj b/ml_pam/ml_pam.csproj index e9dad99..f7eb201 100644 --- a/ml_pam/ml_pam.csproj +++ b/ml_pam/ml_pam.csproj @@ -4,7 +4,7 @@ netstandard2.1 x64 PickupArmMovement - 1.1.1 + 1.1.2 SDraw None PickupArmMovement diff --git a/ml_pin/Main.cs b/ml_pin/Main.cs index 4a4cf1b..dce09d1 100644 --- a/ml_pin/Main.cs +++ b/ml_pin/Main.cs @@ -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() diff --git a/ml_pin/Properties/AssemblyInfo.cs b/ml_pin/Properties/AssemblyInfo.cs index 1f7d353..13e0ca2 100644 --- a/ml_pin/Properties/AssemblyInfo.cs +++ b/ml_pin/Properties/AssemblyInfo.cs @@ -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)] diff --git a/ml_pin/Settings.cs b/ml_pin/Settings.cs index a25cc10..e213ee7 100644 --- a/ml_pin/Settings.cs +++ b/ml_pin/Settings.cs @@ -6,6 +6,14 @@ namespace ml_pin { static class Settings { + internal class SettingEvent + { + 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(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 ms_entries = null; - public static event Action NotifyTypeChange; - public static event Action VolumeChange; - public static event Action NotifyInPublicChange; - public static event Action NotifyInFriendsChange; - public static event Action NotifyInPrivateChange; - public static event Action FriendsAlwaysChange; + public static readonly SettingEvent OnNotifyTypeChanged = new SettingEvent(); + public static readonly SettingEvent OnVolumeChanged = new SettingEvent(); + public static readonly SettingEvent OnNotifyInPublicChanged = new SettingEvent(); + public static readonly SettingEvent OnNotifyInFriendsChanged = new SettingEvent(); + public static readonly SettingEvent OnNotifyInPrivateChanged = new SettingEvent(); + public static readonly SettingEvent OnFriendsAlwaysChanged = new SettingEvent(); internal static void Init() { @@ -90,76 +98,97 @@ namespace ml_pin static void OnToggleUpdate(string p_name, string p_value) { - if(Enum.TryParse(p_name, out ModSetting l_setting)) + try { - switch(l_setting) + if(Enum.TryParse(p_name, out ModSetting l_setting)) { - case ModSetting.NotifyInPublic: + switch(l_setting) { - NotifyInPublic = bool.Parse(p_value); - NotifyInPublicChange?.Invoke(NotifyInPublic); - } - break; + case ModSetting.NotifyInPublic: + { + NotifyInPublic = bool.Parse(p_value); + OnNotifyInPublicChanged.Invoke(NotifyInPublic); + } + break; - case ModSetting.NotifyInFriends: - { - NotifyInFriends = bool.Parse(p_value); - NotifyInFriendsChange?.Invoke(NotifyInFriends); - } - break; + case ModSetting.NotifyInFriends: + { + NotifyInFriends = bool.Parse(p_value); + OnNotifyInFriendsChanged.Invoke(NotifyInFriends); + } + break; - case ModSetting.NotifyInPrivate: - { - NotifyInPrivate = bool.Parse(p_value); - NotifyInPrivateChange?.Invoke(NotifyInPrivate); + case ModSetting.NotifyInPrivate: + { + NotifyInPrivate = bool.Parse(p_value); + OnNotifyInPrivateChanged.Invoke(NotifyInPrivate); + } + break; + + case ModSetting.FriendsAlways: + { + FriendsAlways = bool.Parse(p_value); + OnFriendsAlwaysChanged.Invoke(FriendsAlways); + } + break; } - break; - - case ModSetting.FriendsAlways: - { - FriendsAlways = bool.Parse(p_value); - FriendsAlwaysChange?.Invoke(FriendsAlways); - } - break; + + ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); } - - ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } } static void OnSliderUpdate(string p_name, string p_value) { - if(Enum.TryParse(p_name, out ModSetting l_setting)) + try { - switch(l_setting) + if(Enum.TryParse(p_name, out ModSetting l_setting)) { - case ModSetting.Volume: + switch(l_setting) { - Volume = int.Parse(p_value) * 0.01f; - VolumeChange?.Invoke(Volume); + case ModSetting.Volume: + { + Volume = int.Parse(p_value) * 0.01f; + OnVolumeChanged.Invoke(Volume); + } + break; } - break; - } - ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); + ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); + } + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } } static void OnDropdownUpdate(string p_name, string p_value) { - if(Enum.TryParse(p_name, out ModSetting l_setting)) + try { - switch(l_setting) + if(Enum.TryParse(p_name, out ModSetting l_setting)) { - case ModSetting.NotifyType: + switch(l_setting) { - NotifyType = (NotificationType)int.Parse(p_value); - NotifyTypeChange?.Invoke(NotifyType); + case ModSetting.NotifyType: + { + NotifyType = (NotificationType)int.Parse(p_value); + OnNotifyTypeChanged.Invoke(NotifyType); + } + break; } - break; - } - ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); + ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); + } + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } } } diff --git a/ml_pin/ml_pin.csproj b/ml_pin/ml_pin.csproj index 8cd1b16..64552eb 100644 --- a/ml_pin/ml_pin.csproj +++ b/ml_pin/ml_pin.csproj @@ -7,7 +7,7 @@ SDraw None PlayersInstanceNotifier - 1.0.3 + 1.0.4 diff --git a/ml_pmc/GameEvents.cs b/ml_pmc/GameEvents.cs new file mode 100644 index 0000000..502807d --- /dev/null +++ b/ml_pmc/GameEvents.cs @@ -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); + } + } + } +} \ No newline at end of file diff --git a/ml_pmc/Main.cs b/ml_pmc/Main.cs index 0274988..c9180a8 100644 --- a/ml_pmc/Main.cs +++ b/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(); - 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(), 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 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); - } } } } diff --git a/ml_pmc/ModUi.cs b/ml_pmc/ModUi.cs index f835cfe..de98fc9 100644 --- a/ml_pmc/ModUi.cs +++ b/ml_pmc/ModUi.cs @@ -9,6 +9,14 @@ namespace ml_pmc { 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(T p_value) => m_action?.Invoke(p_value); + } + enum UiIndex { Toggle, @@ -22,7 +30,7 @@ namespace ml_pmc Reset } - internal static Action CopySwitch; + public static readonly UiEvent OnTargetSelect = new UiEvent(); static List 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"); } diff --git a/ml_pmc/PoseCopycat.cs b/ml_pmc/PoseCopycat.cs index a47734e..9c366fb 100644 --- a/ml_pmc/PoseCopycat.cs +++ b/ml_pmc/PoseCopycat.cs @@ -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 + { + event System.Action m_action; + public void AddHandler(System.Action p_listener) => m_action += p_listener; + public void RemoveHandler(System.Action 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 OnActivityChange; + internal static readonly CopycatEvent OnCopycatChanged = new CopycatEvent(); 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(), 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; diff --git a/ml_pmc/Properties/AssemblyInfo.cs b/ml_pmc/Properties/AssemblyInfo.cs index e73122e..c0668bd 100644 --- a/ml_pmc/Properties/AssemblyInfo.cs +++ b/ml_pmc/Properties/AssemblyInfo.cs @@ -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")] diff --git a/ml_pmc/Settings.cs b/ml_pmc/Settings.cs index d412dc2..76e2b0a 100644 --- a/ml_pmc/Settings.cs +++ b/ml_pmc/Settings.cs @@ -5,6 +5,14 @@ namespace ml_pmc { static class Settings { + internal class SettingEvent + { + 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(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 PositionChange; - public static Action RotationChange; - public static Action GesturesChange; - public static Action LookAtMixChange; - public static Action MirrorPoseChange; - public static Action MirrorPositionChange; - public static Action MirrorRotationChange; + public static readonly SettingEvent OnPositionChanged = new SettingEvent(); + public static readonly SettingEvent OnRotationChanged = new SettingEvent(); + public static readonly SettingEvent OnGesturesChanged = new SettingEvent(); + public static readonly SettingEvent OnLookAtMixChanged = new SettingEvent(); + public static readonly SettingEvent OnMirrorPoseChanged = new SettingEvent(); + public static readonly SettingEvent OnMirrorPositionChanged = new SettingEvent(); + public static readonly SettingEvent OnMirrorRotationChanged = new SettingEvent(); static MelonLoader.MelonPreferences_Category ms_category = null; static List ms_entries = null; @@ -60,61 +68,68 @@ namespace ml_pmc public static void SetSetting(ModSetting p_setting, object p_value) { - switch(p_setting) + try { - case ModSetting.Position: + switch(p_setting) { - Position = (bool)p_value; - PositionChange?.Invoke((bool)p_value); - } - break; + case ModSetting.Position: + { + Position = (bool)p_value; + OnPositionChanged.Invoke(Position); + } + break; - case ModSetting.Rotation: - { - Rotation = (bool)p_value; - RotationChange?.Invoke((bool)p_value); + case ModSetting.Rotation: + { + Rotation = (bool)p_value; + OnRotationChanged.Invoke(Rotation); + break; + } + + case ModSetting.Gestures: + { + Gestures = (bool)p_value; + OnGesturesChanged.Invoke(Gestures); + } + break; + + case ModSetting.LookAtMix: + { + LookAtMix = (bool)p_value; + OnLookAtMixChanged.Invoke(LookAtMix); + } + break; + + // + case ModSetting.MirrorPose: + { + MirrorPose = (bool)p_value; + OnMirrorPoseChanged.Invoke(MirrorPose); + } + break; + + case ModSetting.MirrorPosition: + { + MirrorPosition = (bool)p_value; + OnMirrorPositionChanged.Invoke(MirrorPosition); + } + break; + + case ModSetting.MirrorRotation: + { + MirrorRotation = (bool)p_value; + OnMirrorRotationChanged.Invoke(MirrorRotation); + } break; } - case ModSetting.Gestures: - { - Gestures = (bool)p_value; - GesturesChange?.Invoke((bool)p_value); - } - break; - - case ModSetting.LookAtMix: - { - LookAtMix = (bool)p_value; - LookAtMixChange?.Invoke((bool)p_value); - } - break; - - // - case ModSetting.MirrorPose: - { - MirrorPose = (bool)p_value; - MirrorPoseChange?.Invoke((bool)p_value); - } - break; - - case ModSetting.MirrorPosition: - { - MirrorPosition = (bool)p_value; - MirrorPositionChange?.Invoke((bool)p_value); - } - break; - - case ModSetting.MirrorRotation: - { - MirrorRotation = (bool)p_value; - MirrorRotationChange?.Invoke((bool)p_value); - } - break; + if(ms_entries != null) + ms_entries[(int)p_setting].BoxedValue = p_value; + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } - - if(ms_entries != null) - ms_entries[(int)p_setting].BoxedValue = p_value; } } } diff --git a/ml_pmc/Utils.cs b/ml_pmc/Utils.cs index 0235eda..34558c2 100644 --- a/ml_pmc/Utils.cs +++ b/ml_pmc/Utils.cs @@ -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 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; + } } } diff --git a/ml_pmc/ml_pmc.csproj b/ml_pmc/ml_pmc.csproj index 9a91b2a..3e1a062 100644 --- a/ml_pmc/ml_pmc.csproj +++ b/ml_pmc/ml_pmc.csproj @@ -7,7 +7,7 @@ SDraw None PlayerMovementCopycat - 1.0.6 + 1.0.7 diff --git a/ml_prm/GameEvents.cs b/ml_prm/GameEvents.cs new file mode 100644 index 0000000..6292657 --- /dev/null +++ b/ml_prm/GameEvents.cs @@ -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 + { + 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(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 OnIKScaling = new GameEvent(); + public static readonly GameEvent OnSeatPreSit = new GameEvent(); + 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 OnIKOffsetUpdate = new GameEvent(); + + 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; + } + + } +} diff --git a/ml_prm/GravityInfluencer.cs b/ml_prm/GravityInfluencer.cs index 183fb70..07167db 100644 --- a/ml_prm/GravityInfluencer.cs +++ b/ml_prm/GravityInfluencer.cs @@ -1,5 +1,4 @@ using ABI.CCK.Components; -using ABI_RC.Systems.Gravity; using ABI_RC.Systems.Movement; using UnityEngine; diff --git a/ml_prm/Main.cs b/ml_prm/Main.cs index e26d045..6568e12 100644 --- a/ml_prm/Main.cs +++ b/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)?.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(); - 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; } } } diff --git a/ml_prm/ModUi.cs b/ml_prm/ModUi.cs index 56964a8..07b5a62 100644 --- a/ml_prm/ModUi.cs +++ b/ml_prm/ModUi.cs @@ -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 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,90 +116,116 @@ 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) { - switch(p_index) + try { - case UiIndex.Hotkey: - Settings.SetSetting(Settings.ModSetting.Hotkey, p_state); - break; + switch(p_index) + { + case UiIndex.Hotkey: + Settings.SetSetting(Settings.ModSetting.Hotkey, p_state); + break; - case UiIndex.Gravity: - Settings.SetSetting(Settings.ModSetting.Gravity, p_state); - break; + case UiIndex.Gravity: + Settings.SetSetting(Settings.ModSetting.Gravity, p_state); + break; - case UiIndex.PointersReaction: - Settings.SetSetting(Settings.ModSetting.PointersReaction, p_state); - break; + case UiIndex.PointersReaction: + Settings.SetSetting(Settings.ModSetting.PointersReaction, p_state); + break; - case UiIndex.IgnoreLocal: - Settings.SetSetting(Settings.ModSetting.IgnoreLocal, p_state); - break; + case UiIndex.IgnoreLocal: + Settings.SetSetting(Settings.ModSetting.IgnoreLocal, p_state); + break; - case UiIndex.CombatReaction: - Settings.SetSetting(Settings.ModSetting.CombatReaction, p_state); - break; + case UiIndex.CombatReaction: + Settings.SetSetting(Settings.ModSetting.CombatReaction, p_state); + break; - case UiIndex.AutoRecover: - Settings.SetSetting(Settings.ModSetting.AutoRecover, p_state); - break; + case UiIndex.AutoRecover: + Settings.SetSetting(Settings.ModSetting.AutoRecover, p_state); + break; - case UiIndex.Slipperiness: - Settings.SetSetting(Settings.ModSetting.Slipperiness, p_state); - break; + case UiIndex.Slipperiness: + Settings.SetSetting(Settings.ModSetting.Slipperiness, p_state); + break; - case UiIndex.Bounciness: - Settings.SetSetting(Settings.ModSetting.Bounciness, p_state); - break; + case UiIndex.Bounciness: + Settings.SetSetting(Settings.ModSetting.Bounciness, p_state); + break; - case UiIndex.ViewVelocity: - Settings.SetSetting(Settings.ModSetting.ViewVelocity, p_state); - break; + case UiIndex.ViewVelocity: + Settings.SetSetting(Settings.ModSetting.ViewVelocity, p_state); + break; - case UiIndex.JumpRecover: - Settings.SetSetting(Settings.ModSetting.JumpRecover, p_state); - break; + case UiIndex.JumpRecover: + Settings.SetSetting(Settings.ModSetting.JumpRecover, p_state); + break; - case UiIndex.Buoyancy: - Settings.SetSetting(Settings.ModSetting.Buoyancy, p_state); - break; + case UiIndex.Buoyancy: + Settings.SetSetting(Settings.ModSetting.Buoyancy, p_state); + break; - case UiIndex.FallDamage: - Settings.SetSetting(Settings.ModSetting.FallDamage, p_state); - break; + case UiIndex.FallDamage: + Settings.SetSetting(Settings.ModSetting.FallDamage, p_state); + break; + } + + if(p_force) + (ms_uiElements[(int)p_index] as BTKUILib.UIObjects.Components.ToggleButton).ToggleValue = p_state; + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } - - if(p_force) - (ms_uiElements[(int)p_index] as BTKUILib.UIObjects.Components.ToggleButton).ToggleValue = p_state; } static void OnSliderUpdate(UiIndex p_index, float p_value, bool p_force = false) { - switch(p_index) + try { - case UiIndex.VelocityMultiplier: - Settings.SetSetting(Settings.ModSetting.VelocityMultiplier, p_value); - break; + switch(p_index) + { + case UiIndex.VelocityMultiplier: + Settings.SetSetting(Settings.ModSetting.VelocityMultiplier, p_value); + break; - case UiIndex.MovementDrag: - Settings.SetSetting(Settings.ModSetting.MovementDrag, p_value); - break; + case UiIndex.MovementDrag: + Settings.SetSetting(Settings.ModSetting.MovementDrag, p_value); + break; - case UiIndex.AngularDrag: - Settings.SetSetting(Settings.ModSetting.AngularDrag, p_value); - break; + case UiIndex.AngularDrag: + Settings.SetSetting(Settings.ModSetting.AngularDrag, p_value); + break; - case UiIndex.RecoverDelay: - Settings.SetSetting(Settings.ModSetting.RecoverDelay, p_value); - break; + case UiIndex.RecoverDelay: + Settings.SetSetting(Settings.ModSetting.RecoverDelay, p_value); + break; - case UiIndex.FallLimit: - Settings.SetSetting(Settings.ModSetting.FallLimit, p_value); - break; + case UiIndex.FallLimit: + Settings.SetSetting(Settings.ModSetting.FallLimit, p_value); + break; + } + + if(p_force) + (ms_uiElements[(int)p_index] as BTKUILib.UIObjects.Components.SliderFloat).SetSliderValue(p_value); + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } - - if(p_force) - (ms_uiElements[(int)p_index] as BTKUILib.UIObjects.Components.SliderFloat).SetSliderValue(p_value); } static void Reset() diff --git a/ml_prm/Properties/AssemblyInfo.cs b/ml_prm/Properties/AssemblyInfo.cs index 6141cae..fa32a05 100644 --- a/ml_prm/Properties/AssemblyInfo.cs +++ b/ml_prm/Properties/AssemblyInfo.cs @@ -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")] diff --git a/ml_prm/RagdollController.cs b/ml_prm/RagdollController.cs index c87f624..66343ac 100644 --- a/ml_prm/RagdollController.cs +++ b/ml_prm/RagdollController.cs @@ -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(); 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(); if(m_vrIK != null) - m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate); + m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostSolverUpdate); m_avatarRagdollToggle = PlayerSetup.Instance._avatar.GetComponentInChildren(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(); 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; @@ -635,7 +660,7 @@ namespace ml_prm m_wasSwimming = BetterBetterCharacterController.Instance.IsSwimming(); if(BetterBetterCharacterController.Instance.IsFlying()) - BetterBetterCharacterController.Instance.ChangeFlight(false,true); + BetterBetterCharacterController.Instance.ChangeFlight(false, true); BetterBetterCharacterController.Instance.SetImmobilized(true); BetterBetterCharacterController.Instance.ClearFluidVolumes(); BodySystem.TrackingPositionWeight = 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; diff --git a/ml_prm/Settings.cs b/ml_prm/Settings.cs index b241af5..4523514 100644 --- a/ml_prm/Settings.cs +++ b/ml_prm/Settings.cs @@ -6,6 +6,14 @@ namespace ml_prm { static class Settings { + internal class SettingEvent + { + 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(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 HotkeyChange; - public static event Action HotkeyKeyChange; - public static event Action VelocityMultiplierChange; - public static event Action MovementDragChange; - public static event Action AngularDragChange; - public static event Action GravityChange; - public static event Action PointersReactionChange; - public static event Action IgnoreLocalChange; - public static event Action CombatReactionChange; - public static event Action AutoRecoverChange; - public static event Action RecoverDelayChange; - public static event Action SlipperinessChange; - public static event Action BouncinessChange; - public static event Action ViewVelocityChange; - public static event Action JumpRecoverChange; - public static event Action BuoyancyChange; - public static event Action FallDamageChange; - public static event Action FallLimitChange; + public static readonly SettingEvent OnHotkeyChanged = new SettingEvent(); + public static readonly SettingEvent OnHotkeyKeyChanged = new SettingEvent(); + public static readonly SettingEvent OnVelocityMultiplierChanged = new SettingEvent(); + public static readonly SettingEvent OnMovementDragChanged = new SettingEvent(); + public static readonly SettingEvent OnAngularDragChanged = new SettingEvent(); + public static readonly SettingEvent OnGravityChanged = new SettingEvent(); + public static readonly SettingEvent OnPointersReactionChanged = new SettingEvent(); + public static readonly SettingEvent OnIgnoreLocalChanged = new SettingEvent(); + public static readonly SettingEvent OnCombatReactionChanged = new SettingEvent(); + public static readonly SettingEvent OnAutoRecoverChanged = new SettingEvent(); + public static readonly SettingEvent OnRecoverDelayChanged = new SettingEvent(); + public static readonly SettingEvent OnSlipperinessChanged = new SettingEvent(); + public static readonly SettingEvent OnBouncinessChanged = new SettingEvent(); + public static readonly SettingEvent OnViewVelocityChanged = new SettingEvent(); + public static readonly SettingEvent OnJumpRecoverChanged = new SettingEvent(); + public static readonly SettingEvent OnBuoyancyChanged = new SettingEvent(); + public static readonly SettingEvent OnFallDamageChanged = new SettingEvent(); + public static readonly SettingEvent OnFallLimitChanged = new SettingEvent(); static MelonLoader.MelonPreferences_Category ms_category = null; static List ms_entries = null; @@ -119,141 +127,155 @@ namespace ml_prm static void OnMelonSettingSave_HotkeyKey(object p_oldValue, object p_newValue) { - if(p_newValue is KeyCode) + try { - HotkeyKey = (KeyCode)p_newValue; - HotkeyKeyChange?.Invoke(HotkeyKey); + if(p_newValue is KeyCode) + { + HotkeyKey = (KeyCode)p_newValue; + OnHotkeyKeyChanged.Invoke(HotkeyKey); + } + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } } public static void SetSetting(ModSetting p_settings, object p_value) { - switch(p_settings) + try { - // Booleans - case ModSetting.Hotkey: + switch(p_settings) { - Hotkey = (bool)p_value; - HotkeyChange?.Invoke((bool)p_value); - } - break; + // Booleans + case ModSetting.Hotkey: + { + Hotkey = (bool)p_value; + OnHotkeyChanged.Invoke(Hotkey); + } + break; - case ModSetting.Gravity: - { - Gravity = (bool)p_value; - GravityChange?.Invoke((bool)p_value); - } - break; + case ModSetting.Gravity: + { + Gravity = (bool)p_value; + OnGravityChanged.Invoke(Gravity); + } + break; - case ModSetting.PointersReaction: - { - PointersReaction = (bool)p_value; - PointersReactionChange?.Invoke((bool)p_value); - } - break; + case ModSetting.PointersReaction: + { + PointersReaction = (bool)p_value; + OnPointersReactionChanged.Invoke(PointersReaction); + } + break; - case ModSetting.IgnoreLocal: - { - IgnoreLocal = (bool)p_value; - IgnoreLocalChange?.Invoke((bool)p_value); - } - break; + case ModSetting.IgnoreLocal: + { + IgnoreLocal = (bool)p_value; + OnIgnoreLocalChanged.Invoke(IgnoreLocal); + } + break; - case ModSetting.CombatReaction: - { - CombatReaction = (bool)p_value; - CombatReactionChange?.Invoke((bool)p_value); - } - break; + case ModSetting.CombatReaction: + { + CombatReaction = (bool)p_value; + OnCombatReactionChanged.Invoke(CombatReaction); + } + break; - case ModSetting.AutoRecover: - { - AutoRecover = (bool)p_value; - AutoRecoverChange?.Invoke((bool)p_value); - } - break; + case ModSetting.AutoRecover: + { + AutoRecover = (bool)p_value; + OnAutoRecoverChanged.Invoke(AutoRecover); + } + break; - case ModSetting.Slipperiness: - { - Slipperiness = (bool)p_value; - SlipperinessChange?.Invoke((bool)p_value); - } - break; + case ModSetting.Slipperiness: + { + Slipperiness = (bool)p_value; + OnSlipperinessChanged.Invoke(Slipperiness); + } + break; - case ModSetting.Bounciness: - { - Bounciness = (bool)p_value; - BouncinessChange?.Invoke((bool)p_value); - } - break; + case ModSetting.Bounciness: + { + Bounciness = (bool)p_value; + OnBouncinessChanged.Invoke(Bounciness); + } + break; - case ModSetting.ViewVelocity: - { - ViewVelocity = (bool)p_value; - ViewVelocityChange?.Invoke((bool)p_value); - } - break; + case ModSetting.ViewVelocity: + { + ViewVelocity = (bool)p_value; + OnViewVelocityChanged.Invoke(ViewVelocity); + } + break; - case ModSetting.JumpRecover: - { - JumpRecover = (bool)p_value; - JumpRecoverChange?.Invoke((bool)p_value); - } - break; + case ModSetting.JumpRecover: + { + JumpRecover = (bool)p_value; + OnJumpRecoverChanged.Invoke(JumpRecover); + } + break; - case ModSetting.Buoyancy: - { - Buoyancy = (bool)p_value; - BuoyancyChange?.Invoke((bool)p_value); - } - break; + case ModSetting.Buoyancy: + { + Buoyancy = (bool)p_value; + OnBuoyancyChanged.Invoke(Buoyancy); + } + break; - case ModSetting.FallDamage: - { - FallDamage = (bool)p_value; - FallDamageChange?.Invoke((bool)p_value); - } - break; + case ModSetting.FallDamage: + { + FallDamage = (bool)p_value; + OnFallDamageChanged.Invoke(FallDamage); + } + break; - // Floats - case ModSetting.VelocityMultiplier: - { - VelocityMultiplier = (float)p_value; - VelocityMultiplierChange?.Invoke((float)p_value); - } - break; + // Floats + case ModSetting.VelocityMultiplier: + { + VelocityMultiplier = (float)p_value; + OnVelocityMultiplierChanged.Invoke(VelocityMultiplier); + } + break; - case ModSetting.MovementDrag: - { - MovementDrag = (float)p_value; - MovementDragChange?.Invoke((float)p_value); - } - break; + case ModSetting.MovementDrag: + { + MovementDrag = (float)p_value; + OnMovementDragChanged.Invoke(MovementDrag); + } + break; - case ModSetting.AngularDrag: - { - AngularDrag = (float)p_value; - AngularDragChange?.Invoke((float)p_value); - } - break; + case ModSetting.AngularDrag: + { + AngularDrag = (float)p_value; + OnAngularDragChanged.Invoke(AngularDrag); + } + break; - case ModSetting.RecoverDelay: - { - RecoverDelay = (float)p_value; - RecoverDelayChange?.Invoke((float)p_value); - } - break; + case ModSetting.RecoverDelay: + { + RecoverDelay = (float)p_value; + OnRecoverDelayChanged.Invoke(RecoverDelay); + } + break; - case ModSetting.FallLimit: - { - FallLimit = (float)p_value; - FallLimitChange?.Invoke((float)p_value); + case ModSetting.FallLimit: + { + FallLimit = (float)p_value; + OnFallLimitChanged.Invoke(FallLimit); + } + break; } - break; + + if(ms_entries != null) + ms_entries[(int)p_settings].BoxedValue = p_value; + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } - - if(ms_entries != null) - ms_entries[(int)p_settings].BoxedValue = p_value; } } } diff --git a/ml_prm/ml_prm.csproj b/ml_prm/ml_prm.csproj index c16a89f..fbce62a 100644 --- a/ml_prm/ml_prm.csproj +++ b/ml_prm/ml_prm.csproj @@ -4,7 +4,7 @@ netstandard2.1 x64 PlayerRagdollMod - 1.1.4 + 1.1.5 SDraw None PlayerRagdollMod diff --git a/ml_vei/Properties/AssemblyInfo.cs b/ml_vei/Properties/AssemblyInfo.cs index e685211..7dde4c4 100644 --- a/ml_vei/Properties/AssemblyInfo.cs +++ b/ml_vei/Properties/AssemblyInfo.cs @@ -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)] diff --git a/ml_vei/Settings.cs b/ml_vei/Settings.cs index 9f0f435..95333b8 100644 --- a/ml_vei/Settings.cs +++ b/ml_vei/Settings.cs @@ -6,6 +6,14 @@ namespace ml_vei { static class Settings { + internal class SettingEvent + { + 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(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 ms_entries = null; - public static event Action GesturesChange; - public static event Action GripTriggerChange; - public static event Action AxisPriorityChange; + public static readonly SettingEvent OnGesturesChanged; + public static readonly SettingEvent OnGripTriggerChanged; + public static readonly SettingEvent OnAxisPriorityChanged; internal static void Init() { @@ -73,44 +81,58 @@ namespace ml_vei static void OnToggleUpdate(string p_name, string p_value) { - if(Enum.TryParse(p_name, out ModSetting l_setting)) + try { - switch(l_setting) + if(Enum.TryParse(p_name, out ModSetting l_setting)) { - case ModSetting.Gestures: + switch(l_setting) { - Gestures = bool.Parse(p_value); - GesturesChange?.Invoke(Gestures); - } - break; + case ModSetting.Gestures: + { + Gestures = bool.Parse(p_value); + OnGesturesChanged.Invoke(Gestures); + } + break; - case ModSetting.GripTrigger: - { - GripTrigger = bool.Parse(p_value); - GripTriggerChange?.Invoke(GripTrigger); + case ModSetting.GripTrigger: + { + GripTrigger = bool.Parse(p_value); + OnGripTriggerChanged.Invoke(GripTrigger); + } + break; } - break; + + ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); } - - ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } } static void OnDropdownUpdate(string p_name, string p_value) { - if(Enum.TryParse(p_name, out ModSetting l_setting)) + try { - switch(l_setting) + if(Enum.TryParse(p_name, out ModSetting l_setting)) { - case ModSetting.AxisPriority: + switch(l_setting) { - AxisPriority = (PriorityAxis)int.Parse(p_value); - AxisPriorityChange?.Invoke(AxisPriority); + case ModSetting.AxisPriority: + { + AxisPriority = (PriorityAxis)int.Parse(p_value); + OnAxisPriorityChanged.Invoke(AxisPriority); + } + break; } - break; - } - ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); + ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); + } + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); } } } diff --git a/ml_vei/ml_vei.csproj b/ml_vei/ml_vei.csproj index 42039df..775516e 100644 --- a/ml_vei/ml_vei.csproj +++ b/ml_vei/ml_vei.csproj @@ -4,7 +4,7 @@ netstandard2.1 x64 ViveExtendedInput - 1.0.2 + 1.0.3 SDraw None ViveExtendedInput