diff --git a/IKFixes/ChatBoxExtensions.csproj b/IKFixes/ChatBoxExtensions.csproj
new file mode 100644
index 0000000..d83ed14
--- /dev/null
+++ b/IKFixes/ChatBoxExtensions.csproj
@@ -0,0 +1,21 @@
+
+
+
+
+
+ $(NoWarn);MSB3270
+
+
+
+
+
+ $(MsBuildThisFileDirectory)\..\.ManagedLibs\ml_prm.dll
+ False
+
+
+ $(MsBuildThisFileDirectory)\..\.ManagedLibs\ChatBox.dll
+ False
+
+
+
+
diff --git a/IKFixes/HarmonyPatches.cs b/IKFixes/HarmonyPatches.cs
index 0e89332..6dc8bb7 100644
--- a/IKFixes/HarmonyPatches.cs
+++ b/IKFixes/HarmonyPatches.cs
@@ -2,11 +2,11 @@
using ABI_RC.Core.Player;
using ABI_RC.Systems.IK;
using ABI_RC.Systems.IK.SubSystems;
+using ABI_RC.Systems.InputManagement;
using ABI_RC.Systems.MovementSystem;
using HarmonyLib;
using RootMotion.FinalIK;
using UnityEngine;
-using UnityEngine.Events;
namespace NAK.IKFixes.HarmonyPatches;
@@ -22,7 +22,7 @@ internal static class BodySystemPatches
{
Transform parent = null;
float offsetDistance = 0f;
-
+
switch (trackingPoint.assignedRole)
{
case TrackingPoint.TrackingRole.LeftKnee:
@@ -42,27 +42,27 @@ internal static class BodySystemPatches
offsetDistance = -0.15f;
break;
}
-
- if (parent != null)
- {
- // Set the offset transform's parent and reset its local position and rotation
- trackingPoint.offsetTransform.parent = parent;
- trackingPoint.offsetTransform.localPosition = Vector3.zero;
- trackingPoint.offsetTransform.localRotation = Quaternion.identity;
- trackingPoint.offsetTransform.parent = trackingPoint.referenceTransform;
-
- // Apply additional offset based on the assigned role
- Vector3 additionalOffset = IKSystem.vrik.references.root.forward * offsetDistance;
- trackingPoint.offsetTransform.position += additionalOffset;
-
- // Game originally sets them to about half a meter out, which fucks with slime tracker users and
- // makes the bendGoals less responsive/less accurate.
-
- //Funny thing is that IKTweaks specifically made this an option, which should be added to both CVR & Standable for the same reason.
- /// Elbow / knee / chest bend goal offset - controls how far bend goal targets will be away from the actual joint.
- /// Lower values should produce better precision with bent joint, higher values - better stability with straight joint.
- /// Sensible range of values is between 0 and 1.
- }
+
+ if (parent == null)
+ continue;
+
+ // Set the offset transform's parent and reset its local position and rotation
+ trackingPoint.offsetTransform.parent = parent;
+ trackingPoint.offsetTransform.localPosition = Vector3.zero;
+ trackingPoint.offsetTransform.localRotation = Quaternion.identity;
+ trackingPoint.offsetTransform.parent = trackingPoint.referenceTransform;
+
+ // Apply additional offset based on the assigned role
+ Vector3 additionalOffset = IKSystem.vrik.references.root.forward * offsetDistance;
+ trackingPoint.offsetTransform.position += additionalOffset;
+
+ // Game originally sets them to about half a meter out, which fucks with slime tracker users and
+ // makes the bendGoals less responsive/less accurate.
+
+ //Funny thing is that IKTweaks specifically made this an option, which should be added to both CVR & Standable for the same reason.
+ /// Elbow / knee / chest bend goal offset - controls how far bend goal targets will be away from the actual joint.
+ /// Lower values should produce better precision with bent joint, higher values - better stability with straight joint.
+ /// Sensible range of values is between 0 and 1.
}
}
@@ -73,7 +73,6 @@ internal static class BodySystemPatches
arm.shoulderRotationWeight = weight;
arm.shoulderTwistWeight = weight;
// assumed fix of bend goal weight if arms disabled with elbows (havent tested)
- // why is there no "usingElbowTracker" flag like knees? where is the consistancy???
arm.bendGoalWeight = arm.bendGoal != null ? weight : 0f;
}
@@ -130,25 +129,33 @@ internal static class BodySystemPatches
float maxRootAngle = 25f;
float rootHeadingOffset = 0f;
- if (BodySystem.isCalibratedAsFullBody || IKFixes.EntryUseFakeRootAngle.Value)
+ if (BodySystem.isCalibratedAsFullBody
+ || IKFixes.EntryUseFakeRootAngle.Value
+ || CVRInputManager.Instance.movementVector.sqrMagnitude > 0f)
maxRootAngle = 0f;
+ // fixes body being wrong direction while playing emotes (root rotation)
if (PlayerSetup.Instance._emotePlaying)
maxRootAngle = 180f;
-
+
+ // fixes feet always pointing toward head direction
if (IKFixes.EntryUseFakeRootAngle.Value && !BodySystem.isCalibratedAsFullBody)
{
float weightedAngleLimit = IKFixes.EntryFakeRootAngleLimit.Value * solver.locomotion.weight;
- float pivotAngle = MovementSystem.Instance.rotationPivot.eulerAngles.y;
- float deltaAngleRoot = Mathf.DeltaAngle(pivotAngle, _ikSimulatedRootAngle);
- float absDeltaAngleRoot = Mathf.Abs(deltaAngleRoot);
-
- deltaAngleRoot = Mathf.Clamp(deltaAngleRoot, -weightedAngleLimit, weightedAngleLimit);
- _ikSimulatedRootAngle = Mathf.MoveTowardsAngle(_ikSimulatedRootAngle, pivotAngle, absDeltaAngleRoot - weightedAngleLimit);
+ float playerDirection = MovementSystem.Instance.rotationPivot.eulerAngles.y;
+
+ float deltaAngleRoot = Mathf.DeltaAngle(playerDirection, _ikSimulatedRootAngle);
+ float angleOverLimit = Mathf.Abs(deltaAngleRoot) - weightedAngleLimit;
+ if (angleOverLimit > 0)
+ {
+ deltaAngleRoot = Mathf.Sign(deltaAngleRoot) * weightedAngleLimit;
+ _ikSimulatedRootAngle = Mathf.MoveTowardsAngle(_ikSimulatedRootAngle, playerDirection, angleOverLimit);
+ }
+
rootHeadingOffset = deltaAngleRoot;
}
-
+
solver.spine.maxRootAngle = maxRootAngle;
solver.spine.rootHeadingOffset = rootHeadingOffset;
@@ -207,7 +214,7 @@ internal static class BodySystemPatches
if (BodySystem.isCalibratedAsFullBody && BodySystem.TrackingPositionWeight > 0f)
{
- bool isRunning = MovementSystem.Instance.movementVector.magnitude > 0f;
+ bool isRunning = MovementSystem.Instance.movementVector.sqrMagnitude > 0f;
bool isGrounded = MovementSystem.Instance._isGrounded;
bool isFlying = MovementSystem.Instance.flying;
bool playRunningAnimation = BodySystem.PlayRunningAnimationInFullBody;
@@ -257,128 +264,6 @@ internal static class IKSystemPatches
__instance.applyOriginalHipPosition = true;
__instance.applyOriginalHipRotation = true;
}
-
- [HarmonyPostfix]
- [HarmonyPatch(typeof(IKSystem), nameof(IKSystem.InitializeHalfBodyIK))]
- private static void Postfix_IKSystem_InitializeHalfBodyIK(ref IKSystem __instance)
- {
- if (!IKFixes.EntryUseIKPose.Value) return;
-
- __instance._poseHandler.GetHumanPose(ref __instance.humanPose);
-
- for (int i = 0; i < IKPoseMuscles.Length; i++)
- {
- __instance.ApplyMuscleValue((MuscleIndex)i, IKPoseMuscles[i], ref __instance.humanPose.muscles);
- }
- __instance.humanPose.bodyPosition = Vector3.up;
- __instance.humanPose.bodyRotation = Quaternion.identity;
- __instance._poseHandler.SetHumanPose(ref __instance.humanPose);
-
- // recentering avatar so it doesnt need to step from random place on switch
- IKSystem.vrik.transform.localPosition = Vector3.zero;
- IKSystem.vrik.transform.localRotation = Quaternion.identity;
- // janky fix, initializing early with correct pose
- IKSystem.vrik.solver.Initiate(IKSystem.vrik.transform);
- }
-
- 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
- };
}
internal static class PlayerSetupPatches
@@ -392,34 +277,30 @@ internal static class PlayerSetupPatches
[HarmonyPatch(typeof(PlayerSetup), nameof(PlayerSetup.ResetIk))]
private static bool Prefix_PlayerSetup_ResetIk()
{
- if (IKSystem.vrik == null) return false;
+ if (IKSystem.vrik == null)
+ return false;
CVRMovementParent currentParent = MovementSystem.Instance._currentParent;
- if (currentParent != null && currentParent._referencePoint != null)
- {
- // Get current position, VR pivots around VR camera
- Vector3 currentPosition = MovementSystem.Instance.rotationPivot.transform.position;
- currentPosition.y = IKSystem.vrik.transform.position.y; // set pivot to floor
- Quaternion currentRotation = Quaternion.Euler(0f, currentParent.transform.rotation.eulerAngles.y, 0f);
+ if (currentParent == null || currentParent._referencePoint == null)
+ return true;
+
+ // Get current position, VR pivots around VR camera
+ Vector3 currentPosition = MovementSystem.Instance.rotationPivot.transform.position;
+ currentPosition.y = IKSystem.vrik.transform.position.y; // set pivot to floor
+ Quaternion currentRotation = Quaternion.Euler(0f, currentParent.transform.rotation.eulerAngles.y, 0f);
- // Convert to delta position (how much changed since last frame)
- Vector3 deltaPosition = currentPosition - lastMovementPosition;
- Quaternion deltaRotation = Quaternion.Inverse(lastMovementRotation) * currentRotation;
+ // Convert to delta position (how much changed since last frame)
+ Vector3 deltaPosition = currentPosition - lastMovementPosition;
+ Quaternion deltaRotation = Quaternion.Inverse(lastMovementRotation) * currentRotation;
- // Prevent targeting other parent position
- if (lastMovementParent == currentParent || lastMovementParent == null)
- {
- // Add platform motion to IK solver
- IKSystem.vrik.solver.AddPlatformMotion(deltaPosition, deltaRotation, currentPosition);
- }
-
- // Store for next frame
- lastMovementParent = currentParent;
- lastMovementPosition = currentPosition;
- lastMovementRotation = currentRotation;
- return false;
- }
-
- return true;
+ // Prevent targeting previous movement parent
+ if (lastMovementParent == currentParent || lastMovementParent == null)
+ IKSystem.vrik.solver.AddPlatformMotion(deltaPosition, deltaRotation, currentPosition);
+
+ lastMovementParent = currentParent;
+ lastMovementPosition = currentPosition;
+ lastMovementRotation = currentRotation;
+
+ return false;
}
}
\ No newline at end of file
diff --git a/IKFixes/IKFixes.csproj b/IKFixes/IKFixes.csproj
index 66a50a8..ddc9306 100644
--- a/IKFixes/IKFixes.csproj
+++ b/IKFixes/IKFixes.csproj
@@ -1,2 +1,11 @@
-
+
+
+
+
+ $(MsBuildThisFileDirectory)\..\.ManagedLibs\UIExpansionKit.dll
+ False
+
+
+
+
diff --git a/IKFixes/Integrations/UIExKitAddon.cs b/IKFixes/Integrations/UIExKitAddon.cs
new file mode 100644
index 0000000..bf8c4a7
--- /dev/null
+++ b/IKFixes/Integrations/UIExKitAddon.cs
@@ -0,0 +1,21 @@
+using System.Runtime.CompilerServices;
+using MelonLoader;
+using UIExpansionKit.API;
+
+namespace NAK.IKFixes.Integrations;
+
+public static class UIExKitAddon
+{
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void Initialize()
+ {
+ var settings = ExpansionKitApi.GetSettingsCategory(IKFixes.SettingsCategory);
+ settings.AddSimpleButton("Reset Settings (Only visually updates bool values, UIExpansionKit bug!)", ResetSettings);
+ }
+
+ private static void ResetSettings()
+ {
+ foreach (MelonPreferences_Entry setting in IKFixes.Category.Entries)
+ setting.ResetToDefault();
+ }
+}
\ No newline at end of file
diff --git a/IKFixes/Main.cs b/IKFixes/Main.cs
index a4d7234..ac2a1df 100644
--- a/IKFixes/Main.cs
+++ b/IKFixes/Main.cs
@@ -4,41 +4,47 @@ namespace NAK.IKFixes;
public class IKFixes : MelonMod
{
+ internal const string SettingsCategory = nameof(IKFixes);
+
public static readonly MelonPreferences_Category Category =
- MelonPreferences.CreateCategory(nameof(IKFixes));
+ MelonPreferences.CreateCategory(SettingsCategory);
public static readonly MelonPreferences_Entry EntryUseFakeRootAngle =
Category.CreateEntry("Use Fake Root Angle", true, description: "Emulates maxRootAngle. This fixes feet pointing in direction of head when looking around.");
public static readonly MelonPreferences_Entry EntryFakeRootAngleLimit =
- Category.CreateEntry("Fake Root Angle Limit", 25f, description: "Specifies the maximum angle the lower body can have relative to the head when rotating.");
+ Category.CreateEntry("Fake Root Angle Limit (25f)", 25f, description: "Specifies the maximum angle the lower body can have relative to the head when rotating.");
public static readonly MelonPreferences_Entry EntryNeckStiffness =
- Category.CreateEntry("Neck Stiffness", 0.2f, description: "Neck stiffness.");
+ Category.CreateEntry("Neck Stiffness (0.2f)", 0.2f, description: "Neck stiffness.");
public static readonly MelonPreferences_Entry EntryBodyRotStiffness =
- Category.CreateEntry("Body Rot Stiffness", 0.1f, description: "Body rotation stiffness.");
+ Category.CreateEntry("Body Rot Stiffness (0.1f)", 0.1f, description: "Body rotation stiffness.");
public static readonly MelonPreferences_Entry EntryRotateChestByHands =
- Category.CreateEntry("Rot Chest By Hands", 1f, description: "Rotate chest by hands.");
+ Category.CreateEntry("Rot Chest By Hands (1f)", 1f, description: "Rotate chest by hands.");
public static readonly MelonPreferences_Entry EntryBendToTargetWeight =
- Category.CreateEntry("Leg Bend To Target", 1f, description: "Leg bend to target weight");
+ Category.CreateEntry("Leg Bend To Target (1f)", 1f, description: "Leg bend to target weight");
public static readonly MelonPreferences_Entry EntryAssignRemainingTrackers =
- Category.CreateEntry("Assign Remaining Trackers", true, description: "Should the game calibrate any additional trackers as secondary trackers for already-tracked points?");
-
- public static readonly MelonPreferences_Entry EntryUseIKPose =
- Category.CreateEntry("Use IK Pose", true, description: "Should an IKPose be used after VRIK initialization? This can fix some issues with feet targeting.");
-
- public static readonly MelonPreferences_Entry EntryNetIKPass =
- Category.CreateEntry("Network IK Pass", true, description: "Should NetIK pass be applied? This fixes a bunch of small rotation errors after VRIK is run.");
-
+ Category.CreateEntry("Assign Remaining Trackers (true)", true, description: "Should the game calibrate any additional trackers as secondary trackers for already-tracked points?");
+
public override void OnInitializeMelon()
{
ApplyPatches(typeof(HarmonyPatches.BodySystemPatches));
ApplyPatches(typeof(HarmonyPatches.PlayerSetupPatches));
ApplyPatches(typeof(HarmonyPatches.IKSystemPatches));
+ InitializeIntegration("UI Expansion Kit", Integrations.UIExKitAddon.Initialize);
+ }
+
+ private void InitializeIntegration(string modName, Action integrationAction)
+ {
+ if (RegisteredMelons.All(it => it.Info.Name != modName))
+ return;
+
+ LoggerInstance.Msg($"Initializing {modName} integration.");
+ integrationAction.Invoke();
}
private void ApplyPatches(Type type)
diff --git a/IKFixes/Properties/AssemblyInfo.cs b/IKFixes/Properties/AssemblyInfo.cs
index 251d81f..ca5b645 100644
--- a/IKFixes/Properties/AssemblyInfo.cs
+++ b/IKFixes/Properties/AssemblyInfo.cs
@@ -25,6 +25,6 @@ using System.Reflection;
namespace NAK.IKFixes.Properties;
internal static class AssemblyInfoParams
{
- public const string Version = "1.0.6";
+ public const string Version = "1.0.7";
public const string Author = "NotAKidoS";
}
\ No newline at end of file
diff --git a/IKFixes/format.json b/IKFixes/format.json
index 5945c31..9db2229 100644
--- a/IKFixes/format.json
+++ b/IKFixes/format.json
@@ -1,23 +1,24 @@
{
"_id": 142,
"name": "IKFixes",
- "modversion": "1.0.6",
- "gameversion": "2022r170p1",
+ "modversion": "1.0.7",
+ "gameversion": "2023r171",
"loaderversion": "0.6.1",
"modtype": "Mod",
"author": "NotAKidoS",
- "description": "A few small fixes and configuration options to IK. Major ones are listed below:\n\n**FBT** - Fixes knee tracking, running animation direction, and animation bleeding into IK while calibrating/running. (no more chest tracker wiggle)\n\n**Halfbody** - Fixes footsteps while on a MovementParent, uses root angle offset to prevent feet from only pointing in head direction, and uses an IKPose to fix feet pointing upward.",
+ "description": "A few small fixes and configuration options to IK. Major ones are listed below:\n\n**FBT** - Fixes root rotation animation bleeding, chest tracking, locomotion animations, and bend goal offsets.\n\n**Halfbody** - Fixes footsteps while on a Movement Parent & feet always pointing in head direction.",
"searchtags": [
"knee",
"ik",
"tracking",
- "fix"
+ "fix",
+ "chest"
],
"requirements": [
"None"
],
"downloadlink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/download/r8/IKFixes.dll",
"sourcelink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/IKFixes/",
- "changelog": "- Added fix for animations affecting root to bleed into IK.\n- Use an IKPose after HalfbodyIK Initialization.\n- Fixed patch to leg solver that prevented lower leg rotation while using knee trackers.\n- Adjusted elbow target offsets for a balance between accuracy and stability. Makes StandableFBE-tracked elbows feel much better to use.\n- Added option to disable AssignRemainingTrackers feature.\n- Exposed a couple VRIK solver settings for more fine-tuning.",
+ "changelog": "- Updates for 2023r171\n- Removed unneeded settings (IKPose & NetIKPass).\n- Fixed halfbody fake root angle option.\n- Added Reset Settings UIExpansionKit button.",
"embedcolor": "f46e49"
}
\ No newline at end of file