diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index 5e73a26..a63d9ce 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -1,169 +1,149 @@ -using ABI.CCK.Components; -using ABI_RC.Core.Player; +using ABI_RC.Core.Player; using ABI_RC.Systems.IK; using ABI_RC.Systems.IK.SubSystems; using ABI_RC.Systems.MovementSystem; using RootMotion.FinalIK; +using System.Reflection; using UnityEngine; -using UnityEngine.Events; namespace NAK.Melons.DesktopVRIK; public class DesktopVRIK : MonoBehaviour { public static DesktopVRIK Instance; + public DesktopVRIKCalibrator Calibrator; - public static bool - Setting_Enabled, - Setting_EnforceViewPosition, - Setting_EmoteVRIK, - Setting_EmoteLookAtIK; + // DesktopVRIK Settings + public bool + Setting_Enabled = true, + Setting_HipMovement = true, + Setting_ResetOnLand = true, + Setting_PlantFeet = true, + Setting_EnforceViewPosition; + public float + Setting_BodyLeanWeight, + Setting_BodyHeadingLimit, + Setting_PelvisHeadingWeight, + Setting_ChestHeadingWeight; - public static float - Setting_BodyLeanWeight = 0.5f, - Setting_BodyAngleLimit = 0f; - - public Transform viewpoint; - public Vector3 eyeOffset; + // Internal Stuff + private float + ik_SimulatedRootAngle; + private bool + ms_lastGrounded, + ps_emoteIsPlaying; + static readonly FieldInfo ms_isGrounded = typeof(MovementSystem).GetField("_isGrounded", BindingFlags.NonPublic | BindingFlags.Instance); void Start() { + Calibrator = new DesktopVRIKCalibrator(); Instance = this; + DesktopVRIKMod.UpdateAllSettings(); } - public void ChangeViewpointHandling(bool enabled) + public void OnSetupAvatarDesktop() { - if (Setting_EnforceViewPosition == enabled) return; - Setting_EnforceViewPosition = enabled; - if (enabled) - { - PlayerSetup.Instance.desktopCamera.transform.localPosition = Vector3.zero; - return; - } - PlayerSetup.Instance.desktopCamera.transform.localPosition = eyeOffset; + if (!Setting_Enabled) return; + Calibrator.SetupDesktopVRIK(); + ik_SimulatedRootAngle = transform.eulerAngles.y; } - public void AlternativeOnPreSolverUpdate() + //public void OnReCalibrateAvatar() + //{ + // Calibrator.RecalibrateDesktopVRIK(); + // ik_SimulatedRootAngle = transform.eulerAngles.y; + //} + + public bool OnApplyAvatarScaleToIk(float height) { - //this order matters, rotation offset will be choppy if avatar is not cenetered first - - DesktopVRIK_Helper.Instance?.OnUpdateVRIK(); - - //Reset avatar offset (VRIK will literally make you walk away from root otherwise) - IKSystem.vrik.transform.localPosition = Vector3.zero; - IKSystem.vrik.transform.localRotation = Quaternion.identity; - - IKSystem.vrik.solver.plantFeet = true; + if (Calibrator.vrik != null) + { + Calibrator.vrik.solver.locomotion.footDistance = Calibrator.initialFootDistance * height; + Calibrator.vrik.solver.locomotion.stepThreshold = Calibrator.initialStepThreshold * height; + return true; + } + return false; } - public Animator animator; - - public VRIK AlternativeCalibration(CVRAvatar avatar) + public void OnPlayerSetupUpdate(bool isEmotePlaying) { - animator = avatar.GetComponent(); - Transform avatarHeadBone = animator.GetBoneTransform(HumanBodyBones.Head); - - //Stuff to make bad armatures work (Fuck you Default Robot Kyle) - avatar.transform.localPosition = Vector3.zero; - - //ikpose layer (specified by avatar author) - int ikposeLayerIndex = animator.GetLayerIndex("IKPose"); - int locoLayerIndex = animator.GetLayerIndex("Locomotion/Emotes"); - if (ikposeLayerIndex != -1) + bool changed = isEmotePlaying != ps_emoteIsPlaying; + if (changed) { - animator.SetLayerWeight(ikposeLayerIndex, 1f); - if (locoLayerIndex != -1) + ps_emoteIsPlaying = isEmotePlaying; + Calibrator.vrik.transform.localPosition = Vector3.zero; + Calibrator.vrik.transform.localRotation = Quaternion.identity; + if (Calibrator.lookAtIK != null) { - animator.SetLayerWeight(locoLayerIndex, 0f); + Calibrator.lookAtIK.enabled = !isEmotePlaying; } - animator.Update(0f); + BodySystem.TrackingEnabled = !isEmotePlaying; + Calibrator.vrik.solver?.Reset(); + } + } + + public void OnPreSolverUpdate() + { + if (ps_emoteIsPlaying) return; + + bool isGrounded = (bool)ms_isGrounded.GetValue(MovementSystem.Instance); + + // Calculate everything that affects weight + float weight = Calibrator.vrik.solver.IKPositionWeight; + weight *= (1 - MovementSystem.Instance.movementVector.magnitude); + weight *= isGrounded ? 1f : 0f; + + // Reset avatar offset (VRIK will literally make you walk away from root otherwise) + Calibrator.vrik.transform.localPosition = Vector3.zero; + Calibrator.vrik.transform.localRotation = Quaternion.identity; + + // Plant feet is nice for Desktop + Calibrator.vrik.solver.plantFeet = Setting_PlantFeet; + + // This is nice for walk cycles + //Calibrator.vrik.solver.spine.rotateChestByHands = Setting_RotateChestByHands * weight; + + //reset solver if weight changes dramatically + if (Setting_ResetOnLand) + { + if (isGrounded && !ms_lastGrounded) + { + Calibrator.vrik.solver.Reset(); + } + ms_lastGrounded = isGrounded; } - VRIK vrik = avatar.gameObject.AddComponent(); - vrik.AutoDetectReferences(); - - //fuck toes - vrik.references.leftToes = null; - vrik.references.rightToes = null; - - vrik.fixTransforms = true; - vrik.solver.plantFeet = false; - vrik.solver.locomotion.angleThreshold = 30f; - vrik.solver.locomotion.maxLegStretch = 0.75f; - vrik.solver.spine.minHeadHeight = -100f; - - vrik.solver.spine.bodyRotStiffness = 0.15f; - vrik.solver.spine.headClampWeight = 1f; - vrik.solver.spine.maintainPelvisPosition = 1f; - vrik.solver.spine.neckStiffness = 0f; - - vrik.solver.locomotion.weight = 0f; - vrik.solver.spine.bodyPosStiffness = 0f; - vrik.solver.spine.positionWeight = 0f; - vrik.solver.spine.pelvisPositionWeight = 0f; - vrik.solver.leftArm.positionWeight = 0f; - vrik.solver.leftArm.rotationWeight = 0f; - vrik.solver.rightArm.positionWeight = 0f; - vrik.solver.rightArm.rotationWeight = 0f; - vrik.solver.leftLeg.positionWeight = 0f; - vrik.solver.leftLeg.rotationWeight = 0f; - vrik.solver.rightLeg.positionWeight = 0f; - vrik.solver.rightLeg.rotationWeight = 0f; - vrik.solver.IKPositionWeight = 0f; - - BodySystem.TrackingLeftArmEnabled = false; - BodySystem.TrackingRightArmEnabled = false; - BodySystem.TrackingLeftLegEnabled = false; - BodySystem.TrackingRightLegEnabled = false; - BodySystem.TrackingPositionWeight = 0f; - - //Custom funky AF head ik shit - foreach (Transform transform in DesktopVRIK_Helper.Instance.ik_HeadFollower) + // Old VRChat hip movement emulation + if (Setting_BodyLeanWeight > 0) { - if (transform.name == "Head IK Target") - { - Destroy(transform.gameObject); - } + float weightedAngle = Setting_BodyLeanWeight * weight; + float angle = PlayerSetup.Instance.desktopCamera.transform.localEulerAngles.x; + angle = (angle > 180) ? angle - 360 : angle; + Quaternion rotation = Quaternion.AngleAxis(angle * weightedAngle, IKSystem.Instance.avatar.transform.right); + Calibrator.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Head, rotation); } - DesktopVRIK_Helper.Instance.avatar_HeadBone = avatarHeadBone; - DesktopVRIK_Helper.Instance.ik_HeadFollower.position = avatarHeadBone.position; - DesktopVRIK_Helper.Instance.ik_HeadFollower.rotation = Quaternion.identity; - VRIKCalibrator.CalibrateHead(vrik, DesktopVRIK_Helper.Instance.ik_HeadFollower.transform, IKSystem.Instance.headAnchorPositionOffset, IKSystem.Instance.headAnchorRotationOffset); - DesktopVRIK_Helper.Instance.ik_HeadFollower.localRotation = Quaternion.identity; - - //force immediate calibration before animator decides to fuck us - vrik.solver.SetToReferences(vrik.references); - vrik.solver.Initiate(vrik.transform); - - if (ikposeLayerIndex != -1) + // Make root heading follow within a set limit + if (Setting_BodyHeadingLimit > 0) { - animator.SetLayerWeight(ikposeLayerIndex, 0f); - if (locoLayerIndex != -1) + float weightedAngleLimit = Setting_BodyHeadingLimit * weight; + float currentAngle = Mathf.DeltaAngle(transform.eulerAngles.y, ik_SimulatedRootAngle); + float angleMaxDelta = Mathf.Abs(currentAngle); + if (angleMaxDelta > weightedAngleLimit) { - animator.SetLayerWeight(locoLayerIndex, 1f); + currentAngle = Mathf.Sign(currentAngle) * weightedAngleLimit; + ik_SimulatedRootAngle = Mathf.MoveTowardsAngle(ik_SimulatedRootAngle, transform.eulerAngles.y, angleMaxDelta - weightedAngleLimit); + } + Calibrator.vrik.solver.spine.rootHeadingOffset = currentAngle; + if (Setting_PelvisHeadingWeight > 0) + { + Calibrator.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Pelvis, new Vector3(0f, currentAngle * Setting_PelvisHeadingWeight, 0f)); + Calibrator.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Chest, new Vector3(0f, -currentAngle * Setting_PelvisHeadingWeight, 0f)); + } + if (Setting_ChestHeadingWeight > 0) + { + Calibrator.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Chest, new Vector3(0f, currentAngle * Setting_ChestHeadingWeight, 0f)); } } - - //Find eyeoffset - eyeOffset = PlayerSetup.Instance.desktopCamera.transform.localPosition; - viewpoint = avatarHeadBone.Find("LocalHeadPoint"); - ChangeViewpointHandling(Setting_EnforceViewPosition); - - //reset ikpose layer - if (ikposeLayerIndex != -1) - { - animator.SetLayerWeight(ikposeLayerIndex, 0f); - if (locoLayerIndex != -1) - { - animator.SetLayerWeight(locoLayerIndex, 1f); - } - } - - vrik?.onPreSolverUpdate.AddListener(new UnityAction(this.AlternativeOnPreSolverUpdate)); - - DesktopVRIK_Helper.Instance?.OnResetIK(); - - return vrik; } } \ No newline at end of file diff --git a/DesktopVRIK/DesktopVRIK.csproj b/DesktopVRIK/DesktopVRIK.csproj index 5a31a95..ea97a04 100644 --- a/DesktopVRIK/DesktopVRIK.csproj +++ b/DesktopVRIK/DesktopVRIK.csproj @@ -18,9 +18,6 @@ C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll - - C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\BTKUILib.dll - C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll @@ -44,6 +41,10 @@ + + + + diff --git a/DesktopVRIK/DesktopVRIKCalibrator.cs b/DesktopVRIK/DesktopVRIKCalibrator.cs new file mode 100644 index 0000000..e16340f --- /dev/null +++ b/DesktopVRIK/DesktopVRIKCalibrator.cs @@ -0,0 +1,450 @@ +using ABI.CCK.Components; +using ABI_RC.Core; +using ABI_RC.Core.Base; +using ABI_RC.Core.Player; +using ABI_RC.Systems.IK; +using ABI_RC.Systems.IK.SubSystems; +using HarmonyLib; +using RootMotion.FinalIK; +using UnityEngine; +using UnityEngine.Events; + +namespace NAK.Melons.DesktopVRIK; + +public class DesktopVRIKCalibrator +{ + public DesktopVRIKCalibrator() + { + // Get base game scripts. + ikSystem = IKSystem.Instance; + playerSetup = PlayerSetup.Instance; + + // Get traverse to private shit in iksystem. + _vrikTraverse = Traverse.Create(ikSystem).Field("_vrik"); + _avatarTraverse = Traverse.Create(ikSystem).Field("_avatar"); + _animatorManagerTraverse = Traverse.Create(ikSystem).Field("_animatorManager"); + _poseHandlerTraverse = Traverse.Create(ikSystem).Field("_poseHandler"); + _avatarRootHeightTraverse = Traverse.Create(ikSystem).Field("_avatarRootHeight"); + + // Get traverse to private shit in playersetup. + _lookIKTraverse = Traverse.Create(playerSetup).Field("lookIK"); + } + + //Settings + public bool Setting_UseVRIKToes = true; + public bool Setting_FindUnmappedToes = true; + + //DesktopVRIK + public CVRAvatar avatar; + public Animator animator; + public Transform avatarTransform; + public VRIK vrik; + public LookAtIK lookAtIK; + public HumanPoseHandler humanPoseHandler; + public HumanPose initialHumanPose; + public bool fixTransformsRequired; + public float initialFootDistance; + public float initialStepThreshold; + + //Traverse + private IKSystem ikSystem; + private PlayerSetup playerSetup; + private Traverse _vrikTraverse; + private Traverse _lookIKTraverse; + private Traverse _avatarTraverse; + private Traverse _animatorManagerTraverse; + private Traverse _poseHandlerTraverse; + private Traverse _avatarRootHeightTraverse; + + //public void RecalibrateDesktopVRIK() + //{ + // if (avatar != null) + // { + // //calibrate VRIK + // CalibrateDesktopVRIK(); + // } + // else + // { + // //we never calibrated + // SetupDesktopVRIK(); + // } + //} + + public void SetupDesktopVRIK() + { + //store avatar root transform & center it + avatar = playerSetup._avatar.GetComponent(); + animator = avatar.GetComponent(); + avatarTransform = avatar.transform; + avatarTransform.localPosition = Vector3.zero; + lookAtIK = _lookIKTraverse.GetValue(); + + //prepare for VRIK + PrepareIKSystem(); + CalibrateDesktopVRIK(); + + //add presolver update listener + vrik.onPreSolverUpdate.AddListener(new UnityAction(DesktopVRIK.Instance.OnPreSolverUpdate)); + } + + private void CalibrateDesktopVRIK() + { + //calibrate VRIK + PrepareAvatarVRIK(); + SetAvatarIKPose(true); + CalculateInitialIKScaling(); + CalibrateHeadIK(); + ForceInitiateVRIKSolver(); + SetAvatarIKPose(false); + } + + private void PrepareIKSystem() + { + // Get the animator manager and human pose handler + var animatorManager = _animatorManagerTraverse.GetValue(); + humanPoseHandler = _poseHandlerTraverse.GetValue(); + + // Store the avatar component + _avatarTraverse.SetValue(avatar); + + // Set the animator for the IK system + ikSystem.animator = animator; + if (ikSystem.animator != null) + { + animatorManager.SetAnimator(ikSystem.animator, ikSystem.animator.runtimeAnimatorController); + } + + // Set the avatar height float + float avatarHeight = ikSystem.vrPlaySpace.transform.InverseTransformPoint(avatarTransform.position).y; + _avatarRootHeightTraverse.SetValue(avatarHeight); + + // Create a new human pose handler and dispose the old one + if (humanPoseHandler != null) + { + humanPoseHandler.Dispose(); + _poseHandlerTraverse.SetValue(null); + } + humanPoseHandler = new HumanPoseHandler(ikSystem.animator.avatar, avatarTransform); + _poseHandlerTraverse.SetValue(humanPoseHandler); + + // Find valid human bones + IKSystem.BoneExists.Clear(); + foreach (HumanBodyBones bone in Enum.GetValues(typeof(HumanBodyBones))) + { + if (bone != HumanBodyBones.LastBone) + { + IKSystem.BoneExists.Add(bone, ikSystem.animator.GetBoneTransform(bone) != null); + } + } + + // Prepare BodySystem for calibration + BodySystem.TrackingLeftArmEnabled = false; + BodySystem.TrackingRightArmEnabled = false; + BodySystem.TrackingLeftLegEnabled = false; + BodySystem.TrackingRightLegEnabled = false; + BodySystem.TrackingPositionWeight = 0f; + } + + private void PrepareAvatarVRIK() + { + //add and configure VRIK + vrik = avatar.gameObject.AddComponentIfMissing(); + vrik.AutoDetectReferences(); + ConfigureVRIKReferences(); + _vrikTraverse.SetValue(vrik); + + //in testing, not really needed + //only required if Setting_FindUnmappedToes + //and non-human mapped toes are found + vrik.fixTransforms = fixTransformsRequired; + + //default solver settings + vrik.solver.locomotion.weight = 0f; + vrik.solver.locomotion.angleThreshold = 30f; + vrik.solver.locomotion.maxLegStretch = 0.75f; + vrik.solver.spine.minHeadHeight = 0f; + vrik.solver.IKPositionWeight = 1f; + //disable to not bleed into anims + vrik.solver.spine.chestClampWeight = 0f; + vrik.solver.spine.maintainPelvisPosition = 0f; + //for body leaning + vrik.solver.spine.neckStiffness = 0.0001f; //cannot be 0 + vrik.solver.spine.bodyPosStiffness = 1f; + vrik.solver.spine.bodyRotStiffness = 0.2f; + //disable so avatar doesnt try and walk away + //fixes nameplate spazzing on remote + vrik.solver.locomotion.velocityFactor = 0f; + vrik.solver.locomotion.maxVelocity = 0f; + //disable so PAM & BID dont make body shake + vrik.solver.spine.rotateChestByHands = 0f; + //enable so knees on fucked models work better + vrik.solver.leftLeg.useAnimatedBendNormal = true; + vrik.solver.rightLeg.useAnimatedBendNormal = true; + //enable to prioritize LookAtIK + vrik.solver.spine.headClampWeight = 0.2f; + //disable to not go on tippytoes + vrik.solver.spine.positionWeight = 0f; + vrik.solver.spine.rotationWeight = 1f; + + //vrik.solver.spine.maintainPelvisPosition = 1f; + //vrik.solver.locomotion.weight = 0f; + //vrik.solver.spine.positionWeight = 0f; + //vrik.solver.spine.pelvisPositionWeight = 0f; + //vrik.solver.leftArm.positionWeight = 0f; + //vrik.solver.leftArm.rotationWeight = 0f; + //vrik.solver.rightArm.positionWeight = 0f; + //vrik.solver.rightArm.rotationWeight = 0f; + //vrik.solver.leftLeg.positionWeight = 0f; + //vrik.solver.leftLeg.rotationWeight = 0f; + //vrik.solver.rightLeg.positionWeight = 0f; + //vrik.solver.rightLeg.rotationWeight = 0f; + //vrik.solver.IKPositionWeight = 0f; + + //THESE ARE CONFIGURABLE IN GAME IK SETTINGS + //vrik.solver.leftLeg.target = null; + //vrik.solver.leftLeg.bendGoal = null; + //vrik.solver.leftLeg.positionWeight = 0f; + //vrik.solver.leftLeg.bendGoalWeight = 0f; + //vrik.solver.rightLeg.target = null; + //vrik.solver.rightLeg.bendGoal = null; + //vrik.solver.rightLeg.positionWeight = 0f; + //vrik.solver.rightLeg.bendGoalWeight = 0f; + //vrik.solver.spine.pelvisTarget = null; + //vrik.solver.spine.chestGoal = null; + //vrik.solver.spine.positionWeight = 0f; + //vrik.solver.spine.rotationWeight = 0f; + //vrik.solver.spine.pelvisPositionWeight = 0f; + //vrik.solver.spine.pelvisRotationWeight = 0f; + //vrik.solver.spine.chestGoalWeight = 0f; + } + + private void CalculateInitialIKScaling() + { + // Get distance between feets and thighs (fixes some weird armatures) + float footDistance = Vector3.Distance(vrik.references.leftFoot.position, vrik.references.rightFoot.position); + float thighDistance = Vector3.Distance(vrik.references.leftThigh.position, vrik.references.rightThigh.position); + float greatestDistance = Mathf.Min(footDistance, thighDistance); + initialFootDistance = greatestDistance * 0.5f; + initialStepThreshold = greatestDistance * 0.4f; + + //set initial values now, as avatars without scaling dont apply it + vrik.solver.locomotion.footDistance = initialFootDistance; + vrik.solver.locomotion.stepThreshold = initialStepThreshold; + } + + private void CalibrateHeadIK() + { + // Lazy HeadIKTarget calibration + if (vrik.solver.spine.headTarget == null) + { + vrik.solver.spine.headTarget = new GameObject("Head IK Target").transform; + } + vrik.solver.spine.headTarget.parent = vrik.references.head; + vrik.solver.spine.headTarget.localPosition = Vector3.zero; + vrik.solver.spine.headTarget.localRotation = Quaternion.identity; + } + + private void SetAvatarIKPose(bool enforceTPose) + { + int ikposeLayerIndex = animator.GetLayerIndex("IKPose"); + int locoLayerIndex = animator.GetLayerIndex("Locomotion/Emotes"); + + // Use custom IKPose if found. + if (ikposeLayerIndex != -1 && locoLayerIndex != -1) + { + animator.SetLayerWeight(ikposeLayerIndex, enforceTPose ? 1f : 0f); + animator.SetLayerWeight(locoLayerIndex, enforceTPose ? 0f : 1f); + animator.Update(0f); + return; + } + + // Otherwise use DesktopVRIK IKPose & revert afterwards. + if (enforceTPose) + { + humanPoseHandler.GetHumanPose(ref initialHumanPose); + humanPoseHandler.GetHumanPose(ref ikSystem.humanPose); + for (int i = 0; i < IKPoseMuscles.Length; i++) + { + IKSystem.Instance.ApplyMuscleValue((MuscleIndex)i, IKPoseMuscles[i], ref ikSystem.humanPose.muscles); + } + humanPoseHandler.SetHumanPose(ref ikSystem.humanPose); + } + else + { + humanPoseHandler.SetHumanPose(ref initialHumanPose); + } + } + + private void ForceInitiateVRIKSolver() + { + //force immediate calibration before animator decides to fuck us + vrik.solver.SetToReferences(vrik.references); + vrik.solver.Initiate(vrik.transform); + } + + private void ConfigureVRIKReferences() + { + fixTransformsRequired = false; + + Transform leftShoulderBone = vrik.references.leftShoulder; + Transform rightShoulderBone = vrik.references.rightShoulder; + Transform assumedChest = leftShoulderBone?.parent; + + // Repair chest & spine bone references (valve models were messed up) + if (assumedChest != null && rightShoulderBone.parent == assumedChest && + vrik.references.chest != assumedChest) + { + vrik.references.chest = assumedChest; + vrik.references.spine = assumedChest.parent; + } + + if (!Setting_UseVRIKToes) + { + vrik.references.leftToes = null; + vrik.references.rightToes = null; + } + else if (Setting_FindUnmappedToes) + { + Transform leftToes = vrik.references.leftToes; + Transform rightToes = vrik.references.rightToes; + if (leftToes == null && rightToes == null) + { + leftToes = FindUnmappedToe(vrik.references.leftFoot); + rightToes = FindUnmappedToe(vrik.references.rightFoot); + if (leftToes != null && rightToes != null) + { + fixTransformsRequired = true; + vrik.references.leftToes = leftToes; + vrik.references.rightToes = rightToes; + } + } + } + + // Fix error when there is no finger bones + // Making up bullshit cause VRIK is evil otherwise + if (vrik.references.leftHand.childCount == 0) + { + vrik.solver.leftArm.wristToPalmAxis = Vector3.up; + vrik.solver.leftArm.palmToThumbAxis = -Vector3.forward; + } + if (vrik.references.rightHand.childCount == 0) + { + vrik.solver.rightArm.wristToPalmAxis = Vector3.up; + vrik.solver.rightArm.palmToThumbAxis = Vector3.forward; + } + } + + private Transform FindUnmappedToe(Transform foot) + { + foreach (Transform bone in foot) + { + if (bone.name.ToLowerInvariant().Contains("toe") || + bone.name.ToLowerInvariant().EndsWith("_end")) + { + return bone; + } + } + + return null; + } + + private static readonly float[] IKPoseMuscles = new float[] + { + 0.00133321f, + 8.195831E-06f, + 8.537738E-07f, + -0.002669832f, + -7.651234E-06f, + -0.001659694f, + 0f, + 0f, + 0f, + 0.04213953f, + 0.0003007996f, + -0.008032114f, + -0.03059979f, + -0.0003182998f, + 0.009640567f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0.5768794f, + 0.01061097f, + -0.1127839f, + 0.9705755f, + 0.07972051f, + -0.0268422f, + 0.007237188f, + 0f, + 0.5768792f, + 0.01056608f, + -0.1127519f, + 0.9705756f, + 0.07971933f, + -0.02682396f, + 0.007229362f, + 0f, + -5.651802E-06f, + -3.034899E-07f, + 0.4100508f, + 0.3610304f, + -0.0838329f, + 0.9262537f, + 0.1353517f, + -0.03578902f, + 0.06005657f, + -4.95989E-06f, + -1.43007E-06f, + 0.4096187f, + 0.363263f, + -0.08205152f, + 0.9250782f, + 0.1345718f, + -0.03572125f, + 0.06055461f, + -1.079177f, + 0.2095419f, + 0.6140652f, + 0.6365265f, + 0.6683931f, + -0.4764312f, + 0.8099416f, + 0.8099371f, + 0.6658203f, + -0.7327053f, + 0.8113618f, + 0.8114051f, + 0.6643661f, + -0.40341f, + 0.8111364f, + 0.8111367f, + 0.6170399f, + -0.2524227f, + 0.8138723f, + 0.8110135f, + -1.079171f, + 0.2095456f, + 0.6140658f, + 0.6365255f, + 0.6683878f, + -0.4764301f, + 0.8099402f, + 0.8099376f, + 0.6658241f, + -0.7327023f, + 0.8113653f, + 0.8113793f, + 0.664364f, + -0.4034042f, + 0.811136f, + 0.8111364f, + 0.6170469f, + -0.2524345f, + 0.8138595f, + 0.8110138f + }; +} + diff --git a/DesktopVRIK/DesktopVRIK_Helper.cs b/DesktopVRIK/DesktopVRIK_Helper.cs deleted file mode 100644 index ae4f433..0000000 --- a/DesktopVRIK/DesktopVRIK_Helper.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using UnityEngine; -using ABI_RC.Core.Player; -using ABI_RC.Systems.IK; -using ABI_RC.Systems.IK.SubSystems; -using ABI_RC.Systems.MovementSystem; -using RootMotion.FinalIK; - -namespace NAK.Melons.DesktopVRIK; - -internal class DesktopVRIK_Helper : MonoBehaviour -{ - public static DesktopVRIK_Helper Instance; - - //Avatar - public Transform avatar_HeadBone; - - //DesktopVRIK - public Transform ik_HeadFollower; - public Quaternion ik_HeadRotation; - - public static void CreateInstance() - { - Transform helper = new GameObject("[DesktopVRIK] Virtual Rig").transform; - helper.parent = PlayerSetup.Instance.transform; - helper.localPosition = Vector3.zero; - helper.localRotation = Quaternion.identity; - helper.gameObject.AddComponent(); - } - - void Start() - { - Instance = this; - - Transform headFollower = new GameObject("HeadBone_Follower").transform; - headFollower.parent = transform; - headFollower.localPosition = new Vector3(0f, 1.8f, 0f); - headFollower.localRotation = Quaternion.identity; - ik_HeadFollower = headFollower; - } - - public void OnUpdateVRIK() - { - if (avatar_HeadBone != null) - { - float globalWeight = (1 - MovementSystem.Instance.movementVector.magnitude); - globalWeight *= IKSystem.vrik.solver.locomotion.weight; - - //the most important thing ever - //IKSystem.vrik.solver.spine.rotationWeight = globalWeight; - - HeadIK_FollowPosition(); - - HeadIK_RotateWithWeight(globalWeight); - HeadIK_FollowWithinAngle(globalWeight); - ik_HeadFollower.rotation = ik_HeadRotation; - } - } - - public void OnResetIK() - { - ik_HeadRotation = Quaternion.Euler(transform.eulerAngles.x, transform.eulerAngles.y, transform.eulerAngles.z); - } - - public void HeadIK_FollowPosition() - { - ik_HeadFollower.position = new Vector3(transform.position.x, avatar_HeadBone.position.y, transform.position.z); - } - - public void HeadIK_FollowWithinAngle(float weight) - { - if (DesktopVRIK.Setting_BodyAngleLimit != 0) - { - float weightedAngle = DesktopVRIK.Setting_BodyAngleLimit * weight; - float currentAngle = Mathf.DeltaAngle(transform.eulerAngles.y, ik_HeadRotation.eulerAngles.y); - if (Mathf.Abs(currentAngle) > weightedAngle) - { - float fixedCurrentAngle = currentAngle > 0 ? currentAngle : -currentAngle; - float clampedAngle = Mathf.MoveTowardsAngle(ik_HeadRotation.eulerAngles.y, transform.eulerAngles.y, fixedCurrentAngle - weightedAngle); - ik_HeadRotation = Quaternion.Euler(ik_HeadRotation.eulerAngles.x, clampedAngle, 0); - } - } - else - { - ik_HeadRotation = Quaternion.Euler(ik_HeadRotation.eulerAngles.x, transform.eulerAngles.y, transform.eulerAngles.z); - } - } - - public void HeadIK_RotateWithWeight(float weight) - { - //VRChat hip movement emulation - if (DesktopVRIK.Setting_BodyLeanWeight != 0) - { - float angle = PlayerSetup.Instance.desktopCamera.transform.localEulerAngles.x; - if (angle > 180) angle -= 360; - float leanAmount = angle * weight * DesktopVRIK.Setting_BodyLeanWeight; - ik_HeadRotation = Quaternion.Euler(leanAmount * 0.33f, ik_HeadRotation.eulerAngles.y, 0); - } - else - { - ik_HeadRotation = Quaternion.Euler(transform.eulerAngles.x, ik_HeadRotation.eulerAngles.y, transform.eulerAngles.z); - } - } -} \ No newline at end of file diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index 2a9a6b1..2a9562e 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -1,34 +1,21 @@ -using ABI.CCK.Components; -using ABI_RC.Core.Player; -using ABI_RC.Core.Savior; +using ABI_RC.Core.Player; using ABI_RC.Systems.IK; -using ABI_RC.Systems.IK.SubSystems; -using ABI_RC.Systems.MovementSystem; using HarmonyLib; -using RootMotion.FinalIK; using UnityEngine; /** The process of calibrating VRIK is fucking painful. - Immediatly doing GetHumanPose() and then SetHumanPose() fixed heels in ground for all avatars. - - Setting the avatars rotation to identity, head rotation offset to head bone world rotation, and then calibrating head IK target (kinda) fixed only robot kyle. - - Enforcing a TPose only fixed my ferret avatars right shoulder. - - Mix and matching these, and changing order, fucks with random specific avatars with fucky armatures. - MOST AVATARS DONT EVEN CHANGE, ITS JUST THESE FEW SPECIFIC ONES - I NEED to look into an IKPose controller... - Avatars of Note: - TurtleNeck Ferret- broken/inverted right shoulder - Space Robot Kyle- head ik target is rotated -90 90 0, so body/neck is fucked (Fuck you Default Robot Kyle) - Exteratta- the knees bend backwards like a fucking chicken... what the fuck im enforcing a tpose nowww + TurtleNeck Ferret- close feet, far shoulders, nonideal rig. + Space Robot Kyle- the worst bone rolls on the planet, tpose/headikcalibration fixed it mostly... ish. + Exteratta- knees bend backwards without proper tpose. + Chito- left foot is far back without proper tpose & foot ik distance, was uploaded in falling anim state. + Atlas (portal2)- Wide stance, proper feet distance needed to be calculated. + Freddy (gmod)- Doesn't have any fingers, wristToPalmAxis & palmToThumbAxis needed to be set manually. - Most other avatars play just fine. Never changes even when adding Tpose, rotating the avatar, headikrotationoffset, ect... - WHY (Fuck you Default Robot Kyle) + Most other avatars play just fine. **/ @@ -36,210 +23,44 @@ namespace NAK.Melons.DesktopVRIK.HarmonyPatches; class PlayerSetupPatches { - private static bool emotePlayed = false; - [HarmonyPostfix] - [HarmonyPatch(typeof(PlayerSetup), "SetupAvatarGeneral")] - static void SetupDesktopIKSystem(ref CVRAvatar ____avatarDescriptor, ref Animator ____animator) + [HarmonyPatch(typeof(PlayerSetup), "SetupAvatarDesktop")] + static void Postfix_PlayerSetup_SetupAvatarDesktop(ref Animator ____animator) { - if (!MetaPort.Instance.isUsingVr && DesktopVRIK.Setting_Enabled) + if (____animator != null && ____animator.avatar != null && ____animator.avatar.isHuman) { - if (____avatarDescriptor != null && ____animator != null && ____animator.isHuman) - { - //this will stop at the useless isVr return (the function is only ever called by vr anyways...) - IKSystem.Instance.InitializeAvatar(____avatarDescriptor); - } + DesktopVRIK.Instance?.OnSetupAvatarDesktop(); } } [HarmonyPostfix] [HarmonyPatch(typeof(PlayerSetup), "Update")] - private static void CorrectVRIK(ref bool ____emotePlaying, ref LookAtIK ___lookIK) + static void Postfix_PlayerSetup_Update(ref bool ____emotePlaying) { - if (!MetaPort.Instance.isUsingVr && DesktopVRIK.Setting_Enabled) - { - bool changed = ____emotePlaying != emotePlayed; - if (changed) - { - emotePlayed = ____emotePlaying; - IKSystem.vrik.transform.localPosition = Vector3.zero; - IKSystem.vrik.transform.localRotation = Quaternion.identity; - if (DesktopVRIK.Setting_EmoteLookAtIK && ___lookIK != null) - { - ___lookIK.enabled = !____emotePlaying; - } - if (DesktopVRIK.Setting_EmoteVRIK) - { - BodySystem.TrackingEnabled = !____emotePlaying; - IKSystem.vrik.solver?.Reset(); - DesktopVRIK_Helper.Instance?.OnResetIK(); - } - } - } + DesktopVRIK.Instance?.OnPlayerSetupUpdate(____emotePlaying); } - - //should probably patch movement system instead - [HarmonyPrefix] - [HarmonyPatch(typeof(PlayerSetup), "HandleDesktopCameraPosition")] - private static void Prefix_PlayerSetup_HandleDesktopCameraPosition - ( - bool ignore, - ref PlayerSetup __instance, - ref MovementSystem - ____movementSystem, - ref int ___headBobbingLevel - ) - { - if (___headBobbingLevel != 2) - { - return; - } - - if (!DesktopVRIK.Setting_Enabled || !DesktopVRIK.Setting_EnforceViewPosition) - { - return; - } - - if (____movementSystem.disableCameraControl && !ignore) - { - return; - } - - if (DesktopVRIK.Instance.viewpoint == null) - { - return; - } - - __instance.desktopCamera.transform.position = DesktopVRIK.Instance.viewpoint.position; - return; - } + //[HarmonyPostfix] + //[HarmonyPatch(typeof(PlayerSetup), "ReCalibrateAvatar")] + //static void Postfix_PlayerSetup_ReCalibrateAvatar() + //{ + // DesktopVRIK.Instance?.OnReCalibrateAvatar(); + //} } class IKSystemPatches { [HarmonyPostfix] - [HarmonyPatch(typeof(IKSystem), "InitializeAvatar")] - private static void InitializeDesktopAvatarVRIK(CVRAvatar avatar, ref VRIK ____vrik, ref HumanPoseHandler ____poseHandler, ref HumanPose ___humanPose) + [HarmonyPatch(typeof(IKSystem), "Start")] + private static void Postfix_IKSystem_Start(ref IKSystem __instance) { - if (!MetaPort.Instance.isUsingVr && DesktopVRIK.Setting_Enabled) - { - if (IKSystem.Instance.animator != null && IKSystem.Instance.animator.avatar != null && IKSystem.Instance.animator.avatar.isHuman) - { - if (____poseHandler == null) - { - ____poseHandler = new HumanPoseHandler(IKSystem.Instance.animator.avatar, IKSystem.Instance.animator.transform); - } - - ____poseHandler.GetHumanPose(ref ___humanPose); - for (int i = 0; i < IKPoseMuscles.Length; i++) - { - IKSystem.Instance.ApplyMuscleValue((MuscleIndex)i, IKPoseMuscles[i], ref ___humanPose.muscles); - } - ____poseHandler.SetHumanPose(ref ___humanPose); - - ____vrik = DesktopVRIK.Instance.AlternativeCalibration(avatar); - IKSystem.Instance.ApplyAvatarScaleToIk(avatar.viewPosition.y); - } - } + __instance.gameObject.AddComponent(); } - private static readonly float[] IKPoseMuscles = new float[] + [HarmonyPrefix] + [HarmonyPatch(typeof(IKSystem), "ApplyAvatarScaleToIk")] + private static bool Prefix_IKSystem_ApplyAvatarScaleToIk(float height) { - 0.00133321f, - 8.195831E-06f, - 8.537738E-07f, - -0.002669832f, - -7.651234E-06f, - -0.001659694f, - 0f, - 0f, - 0f, - 0.04213953f, - 0.0003007996f, - -0.008032114f, - -0.03059979f, - -0.0003182998f, - 0.009640567f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0.5768794f, - 0.01061097f, - -0.1127839f, - 0.9705755f, - 0.07972051f, - -0.0268422f, - 0.007237188f, - 0f, - 0.5768792f, - 0.01056608f, - -0.1127519f, - 0.9705756f, - 0.07971933f, - -0.02682396f, - 0.007229362f, - 0f, - -5.651802E-06f, - -3.034899E-07f, - 0.4100508f, - 0.3610304f, - -0.0838329f, - 0.9262537f, - 0.1353517f, - -0.03578902f, - 0.06005657f, - -4.95989E-06f, - -1.43007E-06f, - 0.4096187f, - 0.363263f, - -0.08205152f, - 0.9250782f, - 0.1345718f, - -0.03572125f, - 0.06055461f, - -1.079177f, - 0.2095419f, - 0.6140652f, - 0.6365265f, - 0.6683931f, - -0.4764312f, - 0.8099416f, - 0.8099371f, - 0.6658203f, - -0.7327053f, - 0.8113618f, - 0.8114051f, - 0.6643661f, - -0.40341f, - 0.8111364f, - 0.8111367f, - 0.6170399f, - -0.2524227f, - 0.8138723f, - 0.8110135f, - -1.079171f, - 0.2095456f, - 0.6140658f, - 0.6365255f, - 0.6683878f, - -0.4764301f, - 0.8099402f, - 0.8099376f, - 0.6658241f, - -0.7327023f, - 0.8113653f, - 0.8113793f, - 0.664364f, - -0.4034042f, - 0.811136f, - 0.8111364f, - 0.6170469f, - -0.2524345f, - 0.8138595f, - 0.8110138f - }; + return !(bool)DesktopVRIK.Instance?.OnApplyAvatarScaleToIk(height); + } } diff --git a/DesktopVRIK/Integrations/BTKUIAddon.cs b/DesktopVRIK/Integrations/BTKUIAddon.cs deleted file mode 100644 index e2ab2ab..0000000 --- a/DesktopVRIK/Integrations/BTKUIAddon.cs +++ /dev/null @@ -1,48 +0,0 @@ -using BTKUILib; -using BTKUILib.UIObjects; -using System.Runtime.CompilerServices; - -namespace NAK.Melons.DesktopVRIK; - -public static class BTKUIAddon -{ - [MethodImpl(MethodImplOptions.NoInlining)] - public static void Init() - { - //Add myself to the Misc Menu - - Page miscPage = QuickMenuAPI.MiscTabPage; - Category miscCategory = miscPage.AddCategory(DesktopVRIKMod.SettingsCategory); - - AddMelonToggle(ref miscCategory, DesktopVRIKMod.m_entryEnabled); - - //Add my own page to not clog up Misc Menu - - Page desktopVRIKPage = miscCategory.AddPage("DesktopVRIK Settings", "", "Configure the settings for DesktopVRIK.", "DesktopVRIK"); - desktopVRIKPage.MenuTitle = "DesktopVRIK Settings"; - desktopVRIKPage.MenuSubtitle = "Simplified settings for VRIK on Desktop."; - - Category desktopVRIKCategory = desktopVRIKPage.AddCategory("DesktopVRIK"); - - AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.m_entryEnabled); - - AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.m_entryEnforceViewPosition); - - AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.m_entryEmoteVRIK); - - AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.m_entryEmoteLookAtIK); - - AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.m_entryBodyLeanWeight, 0, 1f); - - AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.m_entryBodyAngleLimit, 0, 90f); - } - private static void AddMelonToggle(ref Category category, MelonLoader.MelonPreferences_Entry entry) - { - category.AddToggle(entry.DisplayName, entry.Description, entry.Value).OnValueUpdated += b => entry.Value = b; - } - - private static void AddMelonSlider(ref Page page, MelonLoader.MelonPreferences_Entry entry, float min, float max) - { - page.AddSlider(entry.DisplayName, entry.Description, entry.Value, min, max).OnValueUpdated += f => entry.Value = f; - } -} \ No newline at end of file diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index 524f85b..4f2aec4 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -1,5 +1,4 @@ -using ABI_RC.Core.Player; -using MelonLoader; +using MelonLoader; using UnityEngine; namespace NAK.Melons.DesktopVRIK; @@ -8,69 +7,71 @@ public class DesktopVRIKMod : MelonMod { internal const string SettingsCategory = "DesktopVRIK"; internal static MelonPreferences_Category m_categoryDesktopVRIK; - internal static MelonPreferences_Entry m_entryEnabled, + internal static MelonPreferences_Entry + m_entryEnabled, m_entryEnforceViewPosition, - m_entryEmoteVRIK, - m_entryEmoteLookAtIK; + m_entryResetIKOnLand, + m_entryPlantFeet, + m_entryUseVRIKToes, + m_entryFindUnmappedToes; internal static MelonPreferences_Entry m_entryBodyLeanWeight, - m_entryBodyAngleLimit; + m_entryBodyHeadingLimit, + m_entryPelvisHeadingWeight, + m_entryChestHeadingWeight; public override void OnInitializeMelon() { m_categoryDesktopVRIK = MelonPreferences.CreateCategory(SettingsCategory); m_entryEnabled = m_categoryDesktopVRIK.CreateEntry("Enabled", true, description: "Toggle DesktopVRIK entirely. Requires avatar reload."); m_entryEnforceViewPosition = m_categoryDesktopVRIK.CreateEntry("Enforce View Position", false, description: "Corrects view position to use VRIK offsets."); - m_entryEmoteVRIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote VRIK", true, description: "Disable VRIK while emoting. Only disable if you are ok with looking dumb."); - m_entryEmoteLookAtIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote LookAtIK", true, description: "Disable LookAtIK while emoting. This setting doesn't really matter, as LookAtIK isn't networked while doing an emote."); + m_entryResetIKOnLand = m_categoryDesktopVRIK.CreateEntry("Reset IK On Land", true, description: "Reset Solver IK when landing on the ground."); + m_entryPlantFeet = m_categoryDesktopVRIK.CreateEntry("Enforce Plant Feet", true, description: "Forces VRIK Plant Feet enabled. This prevents the little hover when you stop moving."); + m_entryUseVRIKToes = m_categoryDesktopVRIK.CreateEntry("Use VRIK Toes", false, description: "Should VRIK use your humanoid toes for IK solving? This can cause your feet to idle behind you."); + m_entryFindUnmappedToes = m_categoryDesktopVRIK.CreateEntry("Find Unmapped Toes", false, description: "Should DesktopVRIK look for unmapped toe bones if humanoid rig does not have any?"); m_entryBodyLeanWeight = m_categoryDesktopVRIK.CreateEntry("Body Lean Weight", 0.5f, description: "Emulates old VRChat-like body leaning when looking up/down. Set to 0 to disable."); - m_entryBodyAngleLimit = m_categoryDesktopVRIK.CreateEntry("Body Angle Limit", 0f, description: "Emulates VRChat-like body and head offset when rotating left/right. Set to 0 to disable. (this setting only affects the feet due to chillout not setting up the player controller for VRIK)"); + m_entryBodyHeadingLimit = m_categoryDesktopVRIK.CreateEntry("Body Heading Limit", 20f, description: "Emulates VRChat-like body and head offset when rotating left/right. Set to 0 to disable."); + m_entryPelvisHeadingWeight = m_categoryDesktopVRIK.CreateEntry("Pelvis Heading Weight", 0.25f, description: "How much the pelvis will face the heading limit. Set to 0 to align with head."); + m_entryChestHeadingWeight = m_categoryDesktopVRIK.CreateEntry("Chest Heading Weight", 0.75f, description: "How much the chest will face the heading limit. Set to 0 to align with head."); foreach (var setting in m_categoryDesktopVRIK.Entries) { setting.OnEntryValueChangedUntyped.Subscribe(OnUpdateSettings); } - //BTKUILib Misc Support - if (MelonMod.RegisteredMelons.Any(it => it.Info.Name == "BTKUILib")) - { - MelonLogger.Msg("Initializing BTKUILib support."); - BTKUIAddon.Init(); - } - - //Apply patches (i stole) ApplyPatches(typeof(HarmonyPatches.PlayerSetupPatches)); ApplyPatches(typeof(HarmonyPatches.IKSystemPatches)); - MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); + InitializeIntegrations(); } - System.Collections.IEnumerator WaitForLocalPlayer() - { - while (PlayerSetup.Instance == null) - yield return null; - - DesktopVRIK_Helper.CreateInstance(); - PlayerSetup.Instance.gameObject.AddComponent(); - - while (DesktopVRIK.Instance == null) - yield return null; - UpdateAllSettings(); - } - - private void UpdateAllSettings() + internal static void UpdateAllSettings() { if (!DesktopVRIK.Instance) return; - DesktopVRIK.Setting_Enabled = m_entryEnabled.Value; - DesktopVRIK.Setting_BodyLeanWeight = Mathf.Clamp01(m_entryBodyLeanWeight.Value); - DesktopVRIK.Setting_BodyAngleLimit = Mathf.Clamp(m_entryBodyAngleLimit.Value, 0f, 90f); - DesktopVRIK.Setting_EmoteVRIK = m_entryEmoteVRIK.Value; - DesktopVRIK.Setting_EmoteLookAtIK = m_entryEmoteLookAtIK.Value; - DesktopVRIK.Instance.ChangeViewpointHandling(m_entryEnforceViewPosition.Value); + // DesktopVRIK Settings + DesktopVRIK.Instance.Setting_Enabled = m_entryEnabled.Value; + DesktopVRIK.Instance.Setting_BodyLeanWeight = Mathf.Clamp01(m_entryBodyLeanWeight.Value); + DesktopVRIK.Instance.Setting_ResetOnLand = m_entryResetIKOnLand.Value; + DesktopVRIK.Instance.Setting_PlantFeet = m_entryPlantFeet.Value; + DesktopVRIK.Instance.Setting_BodyHeadingLimit = Mathf.Clamp(m_entryBodyHeadingLimit.Value, 0f, 90f); + DesktopVRIK.Instance.Setting_PelvisHeadingWeight = (1f - Mathf.Clamp01(m_entryPelvisHeadingWeight.Value)); + DesktopVRIK.Instance.Setting_ChestHeadingWeight = (1f - Mathf.Clamp01(m_entryChestHeadingWeight.Value)); + // Calibration Settings + DesktopVRIK.Instance.Calibrator.Setting_UseVRIKToes = m_entryUseVRIKToes.Value; + DesktopVRIK.Instance.Calibrator.Setting_FindUnmappedToes = m_entryFindUnmappedToes.Value; } - private void OnUpdateSettings(object arg1, object arg2) => UpdateAllSettings(); + private static void InitializeIntegrations() + { + //BTKUILib Misc Tab + if (MelonMod.RegisteredMelons.Any(it => it.Info.Name == "BTKUILib")) + { + MelonLogger.Msg("Initializing BTKUILib support."); + //BTKUIAddon.Init(); + } + } + private void ApplyPatches(Type type) { try diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs index 2494ba3..879ab4b 100644 --- a/DesktopVRIK/Properties/AssemblyInfo.cs +++ b/DesktopVRIK/Properties/AssemblyInfo.cs @@ -1,8 +1,7 @@ -using DesktopVRIK.Properties; -using MelonLoader; +using MelonLoader; +using NAK.Melons.DesktopVRIK.Properties; using System.Reflection; - [assembly: AssemblyVersion(AssemblyInfoParams.Version)] [assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] [assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] @@ -24,9 +23,9 @@ using System.Reflection; [assembly: MelonOptionalDependencies("BTKUILib")] [assembly: HarmonyDontPatchAll] -namespace DesktopVRIK.Properties; +namespace NAK.Melons.DesktopVRIK.Properties; internal static class AssemblyInfoParams { - public const string Version = "2.0.5"; + public const string Version = "4.0.0"; public const string Author = "NotAKidoS"; } \ No newline at end of file