From df96194c4d56b4d901598842cbe1d9b316c74dec Mon Sep 17 00:00:00 2001 From: SDraw Date: Fri, 5 Aug 2022 20:45:17 +0300 Subject: [PATCH] New mod: AdditionalAvatarParameters --- ml_aap/Main.cs | 57 ++++++++ ml_aap/ParametersHandler.cs | 229 ++++++++++++++++++++++++++++++ ml_aap/Properties/AssemblyInfo.cs | 10 ++ ml_aap/README.md | 24 ++++ ml_aap/Utils.cs | 13 ++ ml_aap/ml_aap.csproj | 74 ++++++++++ ml_aap/ml_aap.csproj.user | 6 + ml_aci/Main.cs | 8 +- ml_aci/Properties/AssemblyInfo.cs | 6 +- ml_aci/README.md | 2 +- ml_fpt/Main.cs | 168 +++++++++++++++++++--- ml_fpt/README.md | 5 +- ml_fpt/ml_fpt.csproj | 4 +- ml_lme/Main.cs | 40 ++++-- ml_lme/Properties/AssemblyInfo.cs | 6 +- ml_mods_cvr.sln | 6 + 16 files changed, 611 insertions(+), 47 deletions(-) create mode 100644 ml_aap/Main.cs create mode 100644 ml_aap/ParametersHandler.cs create mode 100644 ml_aap/Properties/AssemblyInfo.cs create mode 100644 ml_aap/README.md create mode 100644 ml_aap/Utils.cs create mode 100644 ml_aap/ml_aap.csproj create mode 100644 ml_aap/ml_aap.csproj.user diff --git a/ml_aap/Main.cs b/ml_aap/Main.cs new file mode 100644 index 0000000..208deef --- /dev/null +++ b/ml_aap/Main.cs @@ -0,0 +1,57 @@ +using ABI_RC.Core.Player; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ml_aap +{ + public class AdditionalAvatarParameters : MelonLoader.MelonMod + { + static AdditionalAvatarParameters ms_instance = null; + + ParametersHandler m_localHandler = null; + + public override void OnApplicationStart() + { + ms_instance = this; + + HarmonyInstance.Patch( + typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)), + null, + new HarmonyLib.HarmonyMethod(typeof(AdditionalAvatarParameters).GetMethod(nameof(OnLocalAvatarClear_Postfix), System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)) + ); + + HarmonyInstance.Patch( + typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)), + null, + new HarmonyLib.HarmonyMethod(typeof(AdditionalAvatarParameters).GetMethod(nameof(OnLocalAvatarSetup_Postfix), System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)) + ); + + MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); + } + + System.Collections.IEnumerator WaitForLocalPlayer() + { + while(PlayerSetup.Instance == null) + yield return null; + + m_localHandler = PlayerSetup.Instance.gameObject.AddComponent(); + } + + static void OnLocalAvatarClear_Postfix() => ms_instance?.OnLocalAvatarClear(); + void OnLocalAvatarClear() + { + if(m_localHandler != null) + m_localHandler.OnAvatarClear(); + } + + static void OnLocalAvatarSetup_Postfix() => ms_instance?.OnLocalAvatarSetup(); + void OnLocalAvatarSetup() + { + if(m_localHandler != null) + m_localHandler.OnAvatarSetup(); + } + } +} diff --git a/ml_aap/ParametersHandler.cs b/ml_aap/ParametersHandler.cs new file mode 100644 index 0000000..3f00e1b --- /dev/null +++ b/ml_aap/ParametersHandler.cs @@ -0,0 +1,229 @@ +using ABI_RC.Core; +using ABI_RC.Core.Player; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace ml_aap +{ + class ParametersHandler : MonoBehaviour + { + enum AdditionalParameter + { + Upright, + Viseme, + Voice, + Muted, + InVR, + InHmd, + InFBT, + Zoom + } + enum AdditionalParameterSync + { + Local, + Synced + } + + struct AdditionalParameterInfo + { + public AdditionalParameter m_type; + public AdditionalParameterSync m_sync; + public string m_name; + public int m_hash; // For local only + } + + static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f); + static readonly System.Reflection.FieldInfo ms_visemeWeights = typeof(CVRVisemeController).GetField("visemeWeights", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + + readonly List m_parameters = null; + bool m_active = false; + + CVRVisemeController m_visemeController = null; + + public ParametersHandler() + { + m_parameters = new List(); + } + + void Update() + { + if(m_active) + { + foreach(AdditionalParameterInfo l_param in m_parameters) + { + switch(l_param.m_type) + { + case AdditionalParameter.Upright: + { + Matrix4x4 l_hmdMatrix = PlayerSetup.Instance.transform.GetMatrix().inverse * (PlayerSetup.Instance._inVr ? PlayerSetup.Instance.vrHeadTracker.transform.GetMatrix() : PlayerSetup.Instance.desktopCameraRig.transform.GetMatrix()); + float l_currentHeight = Mathf.Clamp((l_hmdMatrix * ms_pointVector).y, 0f, float.MaxValue); + float l_avatarViewHeight = Mathf.Clamp(PlayerSetup.Instance.GetViewPointHeight() * PlayerSetup.Instance.GetAvatarScale().y, 0f, float.MaxValue); + float l_currentUpright = Mathf.Clamp((((l_currentHeight > 0f) && (l_avatarViewHeight > 0f)) ? (l_currentHeight / l_avatarViewHeight) : 0f), 0f, 1f); + + switch(l_param.m_sync) + { + case AdditionalParameterSync.Local: + PlayerSetup.Instance._animator.SetFloat(l_param.m_hash, l_currentUpright); + break; + case AdditionalParameterSync.Synced: + PlayerSetup.Instance.changeAnimatorParam(l_param.m_name, l_currentUpright); + break; + } + } + break; + + case AdditionalParameter.Viseme: + { + float[] l_weights = (float[])ms_visemeWeights?.GetValue(m_visemeController); + if(l_weights != null) + { + int l_index = 0; + float l_maxWeight = 0f; + + for(int i = 0; i < l_weights.Length; i++) + { + if(l_maxWeight < l_weights[i]) + { + l_maxWeight = l_weights[i]; + l_index = i; + } + } + + switch(l_param.m_sync) + { + case AdditionalParameterSync.Local: + PlayerSetup.Instance._animator.SetInteger(l_param.m_hash, l_index); + break; + case AdditionalParameterSync.Synced: + PlayerSetup.Instance.changeAnimatorParam(l_param.m_name, l_index); + break; + } + } + } + break; + + case AdditionalParameter.Voice: + { + switch(l_param.m_sync) + { + case AdditionalParameterSync.Local: + PlayerSetup.Instance._animator.SetFloat(l_param.m_hash, m_visemeController.visemeLoudness); + break; + case AdditionalParameterSync.Synced: + PlayerSetup.Instance.changeAnimatorParam(l_param.m_name, m_visemeController.visemeLoudness); + break; + } + } + break; + + case AdditionalParameter.InVR: + { + switch(l_param.m_sync) + { + case AdditionalParameterSync.Local: + PlayerSetup.Instance._animator.SetBool(l_param.m_hash, PlayerSetup.Instance._inVr); + break; + case AdditionalParameterSync.Synced: + PlayerSetup.Instance.changeAnimatorParam(l_param.m_name, PlayerSetup.Instance._inVr ? 1f : 0f); + break; + } + } + break; + + case AdditionalParameter.InHmd: + { + switch(l_param.m_sync) + { + case AdditionalParameterSync.Local: + PlayerSetup.Instance._animator.SetBool(l_param.m_hash, PlayerSetup.Instance._trackerManager.headsetOnHead); + break; + case AdditionalParameterSync.Synced: + PlayerSetup.Instance.changeAnimatorParam(l_param.m_name, PlayerSetup.Instance._trackerManager.headsetOnHead ? 1f : 0f); + break; + } + } break; + + case AdditionalParameter.InFBT: + { + switch(l_param.m_sync) + { + case AdditionalParameterSync.Local: + PlayerSetup.Instance._animator.SetBool(l_param.m_hash, PlayerSetup.Instance.fullBodyActive); + break; + case AdditionalParameterSync.Synced: + PlayerSetup.Instance.changeAnimatorParam(l_param.m_name, PlayerSetup.Instance.fullBodyActive ? 1f : 0f); + break; + } + } break; + + case AdditionalParameter.Muted: + { + switch(l_param.m_sync) + { + case AdditionalParameterSync.Local: + PlayerSetup.Instance._animator.SetBool(l_param.m_hash, RootLogic.Instance.comms.IsMuted); + break; + case AdditionalParameterSync.Synced: + PlayerSetup.Instance.changeAnimatorParam(l_param.m_name, RootLogic.Instance.comms.IsMuted ? 1f : 0f); + break; + } + } + break; + + case AdditionalParameter.Zoom: + { + switch(l_param.m_sync) + { + case AdditionalParameterSync.Local: + PlayerSetup.Instance._animator.SetFloat(l_param.m_hash, CVR_DesktopCameraController.currentZoomProgress); + break; + case AdditionalParameterSync.Synced: + PlayerSetup.Instance.changeAnimatorParam(l_param.m_name, CVR_DesktopCameraController.currentZoomProgress); + break; + } + } break; + } + } + } + } + + public void OnAvatarClear() + { + m_parameters.Clear(); + m_active = false; + m_visemeController = null; + } + + public void OnAvatarSetup() + { + m_visemeController = PlayerSetup.Instance._animator.GetComponent(); + + AnimatorControllerParameter[] l_params = PlayerSetup.Instance._animator.parameters; + AdditionalParameter[] l_enumParams = (AdditionalParameter[])Enum.GetValues(typeof(AdditionalParameter)); + + foreach(var l_param in l_params) + { + foreach(var l_enumParam in l_enumParams) + { + if(l_param.name.Contains(l_enumParam.ToString()) && (m_parameters.FindIndex(p => p.m_type == l_enumParam) == -1)) + { + bool l_local = (l_param.name[0] == '#'); + + m_parameters.Add(new AdditionalParameterInfo + { + m_type = l_enumParam, + m_sync = (l_local ? AdditionalParameterSync.Local : AdditionalParameterSync.Synced), + m_name = l_param.name, + m_hash = (l_local ? l_param.nameHash : 0) + }); + + break; + } + } + } + + m_active = (m_parameters.Count > 0); + } + } +} diff --git a/ml_aap/Properties/AssemblyInfo.cs b/ml_aap/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..be4558f --- /dev/null +++ b/ml_aap/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Reflection; + +[assembly: AssemblyTitle("AdditionalAvatarParameters")] +[assembly: AssemblyVersion("1.0.0")] +[assembly: AssemblyFileVersion("1.0.0")] + +[assembly: MelonLoader.MelonInfo(typeof(ml_aap.AdditionalAvatarParameters), "AdditionalAvatarParameters", "1.0.0", "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_aap/README.md b/ml_aap/README.md new file mode 100644 index 0000000..5df0dce --- /dev/null +++ b/ml_aap/README.md @@ -0,0 +1,24 @@ +# Additional Avatar Parameters +This mod adds additional paramaters for usage in avatar's animator. + +# Installation +* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader) +* Get [latest release DLL](../../../releases/latest): + * Put `ml_aap.dll` in `Mods` folder of game + +# Usage +List of new available parameters: +| Name | Type | Note | +|------|------|------| +| Upright | float | Proportion value between avatar's viewpoint height and floor, ranged in [0,1] | +| Viseme | int | Most active viseme index, ranged in [0,14], doesn't update in offline rooms | +| Voice | float | Voice level, ranged in [0,1], doesn't update in offline rooms | +| Muted | bool | Indicates if microphone is muted or unmuted | +| InVR | bool | Indicates if player is in VR | +| InHmd | bool | Indicates if players' headset is on head, can vary between different VR headsets | +| InFBT | bool | Indicates if player is in full body tracking mode | +| Zoom | float | Zoom level of camera, ranged in [0,1], desktop only | + +# Notes +* All new parameters use additional sync data besides listed in avatar's advanced settings. + * If character `#` is added at start of parameter's name it will be interpreted as local-only, won't be synced over network and won't use additional sync data. diff --git a/ml_aap/Utils.cs b/ml_aap/Utils.cs new file mode 100644 index 0000000..19c654e --- /dev/null +++ b/ml_aap/Utils.cs @@ -0,0 +1,13 @@ +using UnityEngine; + +namespace ml_aap +{ + static class Utils + { + // Extensions + public static Matrix4x4 GetMatrix(this Transform p_transform, bool p_pos = true, bool p_rot = true, bool p_scl = false) + { + return Matrix4x4.TRS(p_pos ? p_transform.position : Vector3.zero, p_rot ? p_transform.rotation : Quaternion.identity, p_scl ? p_transform.localScale : Vector3.one); + } + } +} diff --git a/ml_aap/ml_aap.csproj b/ml_aap/ml_aap.csproj new file mode 100644 index 0000000..13d6f7f --- /dev/null +++ b/ml_aap/ml_aap.csproj @@ -0,0 +1,74 @@ + + + + + Debug + AnyCPU + {96D1D71A-23A4-4A0F-9736-25E711BA48F9} + Library + Properties + ml_aap + ml_aap + v4.7.2 + 512 + true + + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + prompt + MinimumRecommendedRules.ruleset + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + + + + F:\games\Steam\common\ChilloutVR\MelonLoader\0Harmony.dll + False + + + F:\games\Steam\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll + False + + + False + + + F:\games\Steam\common\ChilloutVR\MelonLoader\MelonLoader.dll + False + + + + + + + + + + False + + + False + + + + + + + + + + + copy /y "$(TargetPath)" "C:\Games\Steam\common\ChilloutVR\Mods\" + + \ No newline at end of file diff --git a/ml_aap/ml_aap.csproj.user b/ml_aap/ml_aap.csproj.user new file mode 100644 index 0000000..2539084 --- /dev/null +++ b/ml_aap/ml_aap.csproj.user @@ -0,0 +1,6 @@ + + + + C:\Games\Steam\common\ChilloutVR\MelonLoader\;C:\Games\Steam\common\ChilloutVR\ChilloutVR_Data\Managed\ + + \ No newline at end of file diff --git a/ml_aci/Main.cs b/ml_aci/Main.cs index fab8acc..e9cd220 100644 --- a/ml_aci/Main.cs +++ b/ml_aci/Main.cs @@ -1,5 +1,5 @@ -using ABI_RC.Core.UI; -using ABI_RC.Core.EventSystem; +using ABI_RC.Core.EventSystem; +using ABI_RC.Core.InteractionSystem; namespace ml_aci { @@ -16,8 +16,8 @@ namespace ml_aci static void OnLocalAvatarLoad() { - if(CohtmlHud.Instance != null) - CohtmlHud.Instance.ViewDropText("Avatar changed", "Please, wait ..."); + if(ViewManager.Instance != null) + ViewManager.Instance.TriggerPushNotification("Avatar changed", 1f); } } } diff --git a/ml_aci/Properties/AssemblyInfo.cs b/ml_aci/Properties/AssemblyInfo.cs index 9a3c537..ed199f6 100644 --- a/ml_aci/Properties/AssemblyInfo.cs +++ b/ml_aci/Properties/AssemblyInfo.cs @@ -1,10 +1,10 @@ using System.Reflection; [assembly: AssemblyTitle("AvatarChangeInfo")] -[assembly: AssemblyVersion("1.0.0")] -[assembly: AssemblyFileVersion("1.0.0")] +[assembly: AssemblyVersion("1.0.1")] +[assembly: AssemblyFileVersion("1.0.1")] -[assembly: MelonLoader.MelonInfo(typeof(ml_aci.AvatarChangeInfo), "AvatarChangeInfo", "1.0.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_aci.AvatarChangeInfo), "AvatarChangeInfo", "1.0.1", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")] [assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)] \ No newline at end of file diff --git a/ml_aci/README.md b/ml_aci/README.md index 263d099..778b1df 100644 --- a/ml_aci/README.md +++ b/ml_aci/README.md @@ -1,5 +1,5 @@ # Avatar Change Info -This mod shows simple notification upon local player avatar change. +This mod shows simple main menu popup upon local player avatar change. [](.github/img_01.png) diff --git a/ml_fpt/Main.cs b/ml_fpt/Main.cs index e82f4cf..20e6357 100644 --- a/ml_fpt/Main.cs +++ b/ml_fpt/Main.cs @@ -1,4 +1,6 @@ -using ABI_RC.Core.Player; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; using ABI_RC.Core.UI; using UnityEngine; @@ -6,45 +8,165 @@ namespace ml_fpt { public class FourPointTracking : MelonLoader.MelonMod { - static readonly Vector4 ms_pointVector4 = new Vector4(0f, 0f, 0f, 1f); + static FourPointTracking ms_instance = null; + + IndexIK m_indexIk = null; + CVR_IK_Calibrator m_ikCalibrator = null; + + bool m_inCalibration = false; + int m_hipsTrackerIndex = -1; + + RuntimeAnimatorController m_oldRuntimeAnimator = null; + RootMotion.FinalIK.VRIK m_origVrIk = null; + + bool m_playerReady = false; + + public override void OnApplicationStart() + { + ms_instance = this; + + HarmonyInstance.Patch( + typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)), + null, + new HarmonyLib.HarmonyMethod(typeof(FourPointTracking).GetMethod(nameof(OnAvatarClear_Postfix), System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)) + ); + + MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); + } public override void OnUpdate() { - if(Input.GetKey(KeyCode.LeftControl) && Input.GetKeyDown(KeyCode.T)) - CalibrateHipsTracker(); // Separated, awaiting for release of UI mod + if(Input.GetKeyDown(KeyCode.T) && Input.GetKey(KeyCode.LeftControl) && !m_inCalibration) + PrepareCalibration(); + + if(m_playerReady && m_inCalibration && (m_hipsTrackerIndex != -1)) + { + if(m_origVrIk != null) + m_origVrIk.enabled = false; + + m_indexIk.calibrated = false; + m_indexIk.enabled = false; + + Transform l_hips = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Hips); + PlayerSetup.Instance._trackerManager.trackers[m_hipsTrackerIndex].ShowLine(true, l_hips); + + if((CVRInputManager.Instance.interactLeftValue > 0.9f) && (CVRInputManager.Instance.interactRightValue > 0.9f)) + { + PlayerSetup.Instance._trackerManager.trackers[m_hipsTrackerIndex].target.transform.position = l_hips.position; + PlayerSetup.Instance._trackerManager.trackers[m_hipsTrackerIndex].target.transform.rotation = l_hips.rotation; + + if((m_origVrIk != null) && (m_origVrIk.solver?.spine != null)) + { + m_origVrIk.solver.spine.pelvisTarget = PlayerSetup.Instance._trackerManager.trackers[m_hipsTrackerIndex].target; + m_origVrIk.solver.spine.pelvisPositionWeight = 1f; + m_origVrIk.solver.spine.pelvisRotationWeight = 1f; + } + + m_indexIk.calibrated = true; + m_indexIk.enabled = true; + + PlayerSetup.Instance._animator.runtimeAnimatorController = m_oldRuntimeAnimator; + + m_ikCalibrator.leftHandModel.SetActive(false); + m_ikCalibrator.rightHandModel.SetActive(false); + PlayerSetup.Instance._trackerManager.trackers[m_hipsTrackerIndex].ShowTracker(false); + PlayerSetup.Instance._trackerManager.trackers[m_hipsTrackerIndex].ShowLine(false); + CVR_InteractableManager.enableInteractions = true; + + Reset(); + + ShowHudNotification("Calibration completed"); + } + } } - static void CalibrateHipsTracker() + System.Collections.IEnumerator WaitForLocalPlayer() { - bool l_result = false; + while(PlayerSetup.Instance == null) + yield return null; - if((PlayerSetup.Instance != null) && PlayerSetup.Instance._inVr && (PlayerSetup.Instance._animator != null) && PlayerSetup.Instance._animator.isHuman) + m_indexIk = PlayerSetup.Instance.gameObject.GetComponent(); + m_ikCalibrator = PlayerSetup.Instance.gameObject.GetComponent(); + + m_playerReady = true; + } + + void PrepareCalibration() + { + if(m_playerReady && !m_inCalibration && PlayerSetup.Instance._inVr && !PlayerSetup.Instance.fullBodyActive && PlayerSetup.Instance._animator.isHuman && !m_ikCalibrator.inFullbodyCalibration && m_indexIk.calibrated) { for(int i = 0; i < PlayerSetup.Instance._trackerManager.trackerNames.Length; i++) { if(PlayerSetup.Instance._trackerManager.trackerNames[i] == "vive_tracker_waist") { - Transform l_target = PlayerSetup.Instance._trackerManager.trackers[i].target; - Matrix4x4 l_offset = PlayerSetup.Instance._trackerManager.trackers[i].transform.GetMatrix().inverse * PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Hips).GetMatrix(); - l_target.localPosition = l_offset * ms_pointVector4; - l_target.localRotation = l_offset.rotation; - - var l_vrIK = PlayerSetup.Instance._avatar.GetComponent(); - if((l_vrIK != null) && (l_vrIK.solver?.spine != null)) - { - l_vrIK.solver.spine.pelvisTarget = l_target; - l_vrIK.solver.spine.pelvisPositionWeight = 1f; - l_vrIK.solver.spine.pelvisRotationWeight = 1f; - } - - l_result = true; + m_hipsTrackerIndex = i; break; } } - } + if(m_hipsTrackerIndex != -1) + { + m_oldRuntimeAnimator = PlayerSetup.Instance._animator.runtimeAnimatorController; + PlayerSetup.Instance._animator.runtimeAnimatorController = PlayerSetup.Instance.tPoseAnimatorController; + + m_origVrIk = PlayerSetup.Instance._animator.GetComponent(); + + m_ikCalibrator.leftHandModel.SetActive(true); + m_ikCalibrator.rightHandModel.SetActive(true); + PlayerSetup.Instance._trackerManager.trackers[m_hipsTrackerIndex].ShowTracker(true); + CVR_InteractableManager.enableInteractions = false; + + m_inCalibration = true; + + ViewManager.Instance.ForceUiStatus(false); + ShowHudNotification("Calibration started"); + } + else + ShowMenuAlert("No hips tracker detected. Check if tracker has waist role in SteamVR settings."); + } + else + ShowMenuAlert("Calibraton requirements aren't met: be in VR, be not in FBT or avatar calibration, humanoid avatar"); + } + + void Reset() + { + m_inCalibration = false; + m_hipsTrackerIndex = -1; + m_oldRuntimeAnimator = null; + m_origVrIk = null; + } + + static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear(); + void OnAvatarClear() + { + if(m_inCalibration) + { + m_ikCalibrator.leftHandModel.SetActive(false); + m_ikCalibrator.rightHandModel.SetActive(false); + + if(m_hipsTrackerIndex != -1) + { + PlayerSetup.Instance._trackerManager.trackers[m_hipsTrackerIndex].ShowTracker(false); + PlayerSetup.Instance._trackerManager.trackers[m_hipsTrackerIndex].ShowLine(false); + } + CVR_InteractableManager.enableInteractions = true; + + Reset(); + + ShowHudNotification("Calibration canceled"); + } + } + + static void ShowHudNotification(string p_message) + { if(CohtmlHud.Instance != null) - CohtmlHud.Instance.ViewDropText("4-Point Tracking", (l_result ? "Calibration successful" : "Calibration failed")); + CohtmlHud.Instance.ViewDropText("4-Point Tracking", p_message); + } + + static void ShowMenuAlert(string p_message) + { + if(ViewManager.Instance != null) + ViewManager.Instance.TriggerAlert("4-Point Tracking", p_message, 0, false); } } } diff --git a/ml_fpt/README.md b/ml_fpt/README.md index 56557a2..cfa9edf 100644 --- a/ml_fpt/README.md +++ b/ml_fpt/README.md @@ -10,11 +10,12 @@ This mod adds ability to use 4-point tracking. * Be sure that your tracker role is set to `Hips` in SteamVR * Adjust your avatar at forward direction * Press `LCtrl-T` keyboard combination to calibrate +* Adjust your tracker in a similar way as in FBT calibration +* Press trigger on both hands controllers # Notes * You have to recalibrate each time you change avatar # Planned -* Force avatar to T-Pose for calibration -* Show tracker in same way as for FBT calibration * No need for recalibration upon avatar change +* Main menu button for calibration diff --git a/ml_fpt/ml_fpt.csproj b/ml_fpt/ml_fpt.csproj index 1267f5a..fb0e475 100644 --- a/ml_fpt/ml_fpt.csproj +++ b/ml_fpt/ml_fpt.csproj @@ -35,6 +35,9 @@ MinimumRecommendedRules.ruleset + + False + C:\Games\Steam\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll False @@ -78,7 +81,6 @@ - diff --git a/ml_lme/Main.cs b/ml_lme/Main.cs index 76b06f2..66b4580 100644 --- a/ml_lme/Main.cs +++ b/ml_lme/Main.cs @@ -51,7 +51,12 @@ namespace ml_lme HarmonyInstance.Patch( typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)), null, - new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnAvatarSetup), System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)) + new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnAvatarSetup_Postfix), System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)) + ); + HarmonyInstance.Patch( + typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)), + null, + new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnAvatarClear_Postfix), System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)) ); MelonLoader.MelonCoroutines.Start(CreateTrackingObjects()); @@ -301,23 +306,38 @@ namespace ml_lme } // Patches - static void OnAvatarSetup(ref PlayerSetup __instance) + static void OnAvatarClear_Postfix(ref PlayerSetup __instance) { if((__instance != null) && (__instance == PlayerSetup.Instance)) - ms_instance?.OnLocalPlayerAvatarSetup(__instance._animator, __instance.GetComponent()); + ms_instance?.OnAvatarClear(); } - void OnLocalPlayerAvatarSetup(Animator p_animator, IndexIK p_indexIK) + void OnAvatarClear() { if(m_leapTracked != null) + { Object.DestroyImmediate(m_leapTracked); + m_leapTracked = null; + } + } - m_leapTracked = p_indexIK.gameObject.AddComponent(); - m_leapTracked.SetEnabled(Settings.Enabled); - m_leapTracked.SetAnimator(p_animator); - m_leapTracked.SetHands(m_leapHands[0].transform, m_leapHands[1].transform); - m_leapTracked.SetFingersOnly(Settings.FingersOnly); - OnSettingsHeadAttachChange(); + static void OnAvatarSetup_Postfix(ref PlayerSetup __instance) + { + if((__instance != null) && (__instance == PlayerSetup.Instance)) + ms_instance?.OnAvatarSetup(__instance._animator, __instance.GetComponent()); + } + void OnAvatarSetup(Animator p_animator, IndexIK p_indexIK) + { + if(m_leapTracked == null) + { + m_leapTracked = p_indexIK.gameObject.AddComponent(); + m_leapTracked.SetEnabled(Settings.Enabled); + m_leapTracked.SetAnimator(p_animator); + m_leapTracked.SetHands(m_leapHands[0].transform, m_leapHands[1].transform); + m_leapTracked.SetFingersOnly(Settings.FingersOnly); + + OnSettingsHeadAttachChange(); + } } // Utilities diff --git a/ml_lme/Properties/AssemblyInfo.cs b/ml_lme/Properties/AssemblyInfo.cs index 57416e3..93960f1 100644 --- a/ml_lme/Properties/AssemblyInfo.cs +++ b/ml_lme/Properties/AssemblyInfo.cs @@ -1,10 +1,10 @@ using System.Reflection; [assembly: AssemblyTitle("LeapMotionExtension")] -[assembly: AssemblyVersion("1.0.7")] -[assembly: AssemblyFileVersion("1.0.7")] +[assembly: AssemblyVersion("1.0.8")] +[assembly: AssemblyFileVersion("1.0.8")] -[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.0.7", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.0.8", "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_mods_cvr.sln b/ml_mods_cvr.sln index ef4975b..f687b16 100644 --- a/ml_mods_cvr.sln +++ b/ml_mods_cvr.sln @@ -11,6 +11,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_aci", "ml_aci\ml_aci.csp EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_drs", "ml_drs\ml_drs.csproj", "{06CD5155-4459-48C3-8A53-E0B91136351B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_aap", "ml_aap\ml_aap.csproj", "{96D1D71A-23A4-4A0F-9736-25E711BA48F9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -33,6 +35,10 @@ Global {06CD5155-4459-48C3-8A53-E0B91136351B}.Debug|x64.Build.0 = Debug|x64 {06CD5155-4459-48C3-8A53-E0B91136351B}.Release|x64.ActiveCfg = Release|x64 {06CD5155-4459-48C3-8A53-E0B91136351B}.Release|x64.Build.0 = Release|x64 + {96D1D71A-23A4-4A0F-9736-25E711BA48F9}.Debug|x64.ActiveCfg = Debug|x64 + {96D1D71A-23A4-4A0F-9736-25E711BA48F9}.Debug|x64.Build.0 = Debug|x64 + {96D1D71A-23A4-4A0F-9736-25E711BA48F9}.Release|x64.ActiveCfg = Release|x64 + {96D1D71A-23A4-4A0F-9736-25E711BA48F9}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE