Merge branch 'master' into experimental

This commit is contained in:
SDraw 2023-07-27 10:14:53 +03:00
commit 3c33452379
No known key found for this signature in database
GPG key ID: BB95B4DAB2BB8BB5
30 changed files with 271 additions and 547 deletions

20
README.md Normal file
View file

@ -0,0 +1,20 @@
Merged set of MelonLoader mods for ChilloutVR.
**Table for game build 2022r171:**
| Full name | Short name | Latest version | Available in [CVRMA](https://github.com/knah/CVRMelonAssistant) |
|:---------:|:----------:|:--------------:| :----------------------------------------------------------------|
| [Avatar Motion Tweaker](/ml_amt/README.md) | ml_amt | - | ✔ Yes<br>:warning:Broken |
| [Desktop Head Tracking](/ml_dht/README.md)| ml_dht | - | ✔ Yes<br>:warning:Broken |
| [Desktop Reticle Switch](/ml_drs/README.md)| ml_drs | 1.0.1 [:arrow_down:](../../releases/latest/download/ml_drs.dll)| ✔ Yes<br>:hourglass_flowing_sand: Update review |
| [Extended Game Notifications](/ml_egn/README.md) | ml_egn | 1.0.3 [:arrow_down:](../../releases/latest/download/ml_egn.dll)| ✔ Yes<br>:hourglass_flowing_sand: Update review |
| [Leap Motion Extension](/ml_lme/README.md)| ml_lme | 1.4.0 [:arrow_down:](../../releases/latest/download/ml_lme.dll)| ✔ Yes<br>:hourglass_flowing_sand: Update review |
| [Pickup Arm Movement](/ml_pam/README.md)| ml_pam | 1.0.6 [:arrow_down:](../../releases/latest/download/ml_pam.dll)| ✔ Yes<br>:hourglass_flowing_sand: Update review |
| [Player Movement Copycat](/ml_pmc/README.md)| ml_pmc | 1.0.1 [:arrow_down:](../../releases/latest/download/ml_pmc.dll)| ✔ Yes<br>:hourglass_flowing_sand: Update review |
| [Player Ragdoll Mod](/ml_prm/README.md)| ml_prm | 1.0.6 [:arrow_down:](../../releases/latest/download/ml_prm.dll)| ✔ Yes<br>:hourglass_flowing_sand: Update review |
**Archived mods:**
| Full name | Short name | Notes |
|:---------:|:----------:|-------|
| Avatar Change Info | ml_aci | Superseded by `Extended Game Notifications`
| Four Point Tracking | ml_fpt | In-game feature since 2022r170 update
| Server Connection Info | ml_sci | Superseded by `Extended Game Notifications`

View file

@ -1,57 +0,0 @@
using ABI.CCK.Components;
using ABI_RC.Core.Player;
using ABI_RC.Systems.IK.SubSystems;
using System.Reflection;
namespace ml_amt.Fixes
{
static class FBTDetectionFix
{
static readonly MethodInfo[] ms_fbtDetouredMethods =
{
typeof(PlayerSetup).GetMethod("Update", BindingFlags.NonPublic | BindingFlags.Instance),
typeof(PlayerSetup).GetMethod("FixedUpdate", BindingFlags.NonPublic | BindingFlags.Instance),
typeof(PlayerSetup).GetMethod("UpdatePlayerAvatarMovementData", BindingFlags.NonPublic | BindingFlags.Instance),
typeof(CVRParameterStreamEntry).GetMethod(nameof(CVRParameterStreamEntry.CheckUpdate))
};
static bool ms_fbtDetour = false;
internal static void Init(HarmonyLib.Harmony p_instance)
{
// FBT detour
p_instance.Patch(
typeof(BodySystem).GetMethod(nameof(BodySystem.FBTAvailable)),
new HarmonyLib.HarmonyMethod(typeof(FBTDetectionFix).GetMethod(nameof(OnFBTAvailable_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
null
);
foreach(MethodInfo l_detoured in ms_fbtDetouredMethods)
{
p_instance.Patch(
l_detoured,
new HarmonyLib.HarmonyMethod(typeof(FBTDetectionFix).GetMethod(nameof(FBTDetour_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
new HarmonyLib.HarmonyMethod(typeof(FBTDetectionFix).GetMethod(nameof(FBTDetour_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
}
}
// FBT detection override
static void FBTDetour_Prefix()
{
ms_fbtDetour = true;
}
static void FBTDetour_Postfix()
{
ms_fbtDetour = false;
}
static bool OnFBTAvailable_Prefix(ref bool __result)
{
if(ms_fbtDetour && !BodySystem.isCalibratedAsFullBody)
{
__result = false;
return false;
}
return true;
}
}
}

View file

@ -1,123 +0,0 @@
using ABI_RC.Core.Player;
using ABI_RC.Systems.MovementSystem;
using System;
using System.Reflection;
using UnityEngine;
namespace ml_amt.Fixes
{
static class PlayerColliderFix
{
static FieldInfo ms_initialAvatarHeight = typeof(PlayerSetup).GetField("_initialAvatarHeight", BindingFlags.NonPublic | BindingFlags.Instance);
static FieldInfo ms_avatarHeight = typeof(PlayerSetup).GetField("_avatarHeight", BindingFlags.NonPublic | BindingFlags.Instance);
internal static void Init(HarmonyLib.Harmony p_instance)
{
// Alternative collider height and radius
p_instance.Patch(
typeof(MovementSystem).GetMethod("UpdateCollider", BindingFlags.NonPublic | BindingFlags.Instance),
new HarmonyLib.HarmonyMethod(typeof(PlayerColliderFix).GetMethod(nameof(OnUpdateCollider_Prefix), BindingFlags.Static | BindingFlags.NonPublic)),
null
);
p_instance.Patch(
typeof(PlayerSetup).GetMethod("SetupIKScaling", BindingFlags.NonPublic | BindingFlags.Instance),
null,
new HarmonyLib.HarmonyMethod(typeof(PlayerColliderFix).GetMethod(nameof(OnSetupIKScaling_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
Settings.CollisionScaleChange += OnCollisionScaleChange;
}
// Alternative collider size
static bool OnUpdateCollider_Prefix(
ref MovementSystem __instance,
bool __0, // updateRadius
CharacterController ___controller,
float ____avatarHeight,
float ____avatarHeightFactor,
float ____minimumColliderRadius,
Vector3 ____colliderCenter
)
{
if(!Settings.CollisionScale)
return true;
try
{
if(___controller != null)
{
float l_scaledHeight = ____avatarHeight * ____avatarHeightFactor;
float l_newRadius = (__0 ? Mathf.Max(____minimumColliderRadius, l_scaledHeight / 6f) : ___controller.radius);
float l_newHeight = Mathf.Max(l_scaledHeight, l_newRadius * 2f);
float l_currentHeight = ___controller.height;
Vector3 l_newCenter = ____colliderCenter;
l_newCenter.y = (l_newHeight + 0.075f) * 0.5f; // Idk where 0.075f has come from
Vector3 l_currentCenter = ___controller.center;
if(__0 || (Mathf.Abs(l_currentHeight - l_newHeight) > (l_currentHeight * 0.05f)) || (Vector3.Distance(l_currentCenter, l_newCenter) > (l_currentHeight * 0.05f)))
{
if(__0)
___controller.radius = l_newRadius;
___controller.height = l_newHeight;
___controller.center = l_newCenter;
__instance.groundDistance = l_newRadius;
if(__instance.proxyCollider != null)
{
if(__0)
__instance.proxyCollider.radius = l_newRadius;
__instance.proxyCollider.height = l_newHeight;
__instance.proxyCollider.center = new Vector3(0f, l_newCenter.y, 0f);
}
if(__instance.forceObject != null)
__instance.forceObject.transform.localScale = new Vector3(l_newRadius + 0.1f, l_newHeight, l_newRadius + 0.1f);
if(__instance.groundCheck != null)
__instance.groundCheck.localPosition = ____colliderCenter;
}
}
}
catch(Exception l_exception)
{
MelonLoader.MelonLogger.Error(l_exception);
}
return false;
}
static void OnSetupIKScaling_Postfix(
ref PlayerSetup __instance,
float ____avatarHeight
)
{
if(!Settings.CollisionScale)
return;
try
{
__instance._movementSystem.UpdateAvatarHeight(Mathf.Clamp(____avatarHeight, 0.05f, float.MaxValue), true);
}
catch(Exception l_exception)
{
MelonLoader.MelonLogger.Error(l_exception);
}
}
static void OnCollisionScaleChange(bool p_state)
{
try
{
if(p_state)
MovementSystem.Instance.UpdateAvatarHeight((float)ms_avatarHeight.GetValue(PlayerSetup.Instance), true);
else
MovementSystem.Instance.UpdateAvatarHeight((float)ms_initialAvatarHeight.GetValue(PlayerSetup.Instance), true);
}
catch(Exception l_exception)
{
MelonLoader.MelonLogger.Error(l_exception);
}
}
}
}

View file

@ -35,17 +35,9 @@ namespace ml_amt
null,
new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnCalibrate_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))
);
// Fixes
Fixes.AnimatorOverrideControllerFix.Init(HarmonyInstance);
Fixes.FBTDetectionFix.Init(HarmonyInstance);
Fixes.PlayerColliderFix.Init(HarmonyInstance);
Fixes.MovementJumpFix.Init(HarmonyInstance);
ModSupporter.Init();
@ -58,12 +50,8 @@ namespace ml_amt
yield return null;
m_localTweaker = PlayerSetup.Instance.gameObject.AddComponent<MotionTweaker>();
m_localTweaker.SetIKOverrideCrouch(Settings.IKOverrideCrouch);
m_localTweaker.SetCrouchLimit(Settings.CrouchLimit);
m_localTweaker.SetIKOverrideProne(Settings.IKOverrideProne);
m_localTweaker.SetProneLimit(Settings.ProneLimit);
m_localTweaker.SetPoseTransitions(Settings.PoseTransitions);
m_localTweaker.SetAdjustedMovement(Settings.AdjustedMovement);
m_localTweaker.SetIKOverrideFly(Settings.IKOverrideFly);
m_localTweaker.SetIKOverrideJump(Settings.IKOverrideJump);
m_localTweaker.SetDetectEmotes(Settings.DetectEmotes);
@ -119,19 +107,5 @@ namespace ml_amt
MelonLoader.MelonLogger.Error(l_exception);
}
}
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);
}
}
}
}

View file

@ -12,49 +12,32 @@ namespace ml_amt
[DisallowMultipleComponent]
class MotionTweaker : MonoBehaviour
{
struct IKState
{
public float m_weight;
public float m_locomotionWeight;
public bool m_plantFeet;
public bool m_bendNormalLeft;
public bool m_bendNormalRight;
}
static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f);
static readonly int ms_emoteHash = Animator.StringToHash("Emote");
enum PoseState
{
Standing = 0,
Crouching,
Proning
}
IKState m_ikState;
VRIK m_vrIk = null;
int m_locomotionLayer = 0;
float m_ikWeight = 1f; // Original weight
float m_locomotionWeight = 1f; // Original weight
bool m_plantFeet = false; // Original plant feet
float m_avatarScale = 1f; // Instantiated scale
float m_avatarScale = 1f;
Vector3 m_locomotionOffset = Vector3.zero; // Original locomotion offset
bool m_bendNormalLeft = false;
bool m_bendNormalRight = false;
Transform m_avatarHips = null;
float m_avatarHeight = 1f; // Initial avatar view height
bool m_inVR = false;
bool m_fbtAnimations = true;
bool m_avatarReady = false;
bool m_compatibleAvatar = false;
float m_upright = 1f;
PoseState m_poseState = PoseState.Standing;
bool m_grounded = false;
bool m_groundedRaw = false;
bool m_moving = false;
bool m_locomotionOverride = false;
bool m_ikOverrideCrouch = true;
float m_crouchLimit = 0.65f;
bool m_customCrouchLimit = false;
bool m_ikOverrideProne = true;
float m_proneLimit = 0.3f;
bool m_customProneLimit = false;
bool m_poseTransitions = true;
bool m_adjustedMovement = true;
bool m_ikOverrideFly = true;
bool m_ikOverrideJump = true;
@ -64,7 +47,6 @@ namespace ml_amt
bool m_followHips = true;
Vector3 m_hipsToPlayer = Vector3.zero;
Vector2 m_stepDistance = Vector2.zero;
Vector3 m_massCenter = Vector3.zero;
readonly List<AvatarParameter> m_parameters = null;
@ -79,38 +61,27 @@ namespace ml_amt
{
m_inVR = Utils.IsInVR();
Settings.IKOverrideCrouchChange += this.SetIKOverrideCrouch;
Settings.CrouchLimitChange += this.SetCrouchLimit;
Settings.IKOverrideProneChange += this.SetIKOverrideProne;
Settings.ProneLimitChange += this.SetProneLimit;
Settings.PoseTransitionsChange += this.SetPoseTransitions;
Settings.AdjustedMovementChange += this.SetAdjustedMovement;
Settings.IKOverrideFlyChange += this.SetIKOverrideFly;
Settings.IKOverrideJumpChange += this.SetIKOverrideJump;
Settings.DetectEmotesChange += this.SetDetectEmotes;
Settings.FollowHipsChange += this.SetFollowHips;
Settings.MassCenterChange += this.OnMassCenterChange;
Settings.ScaledStepsChange += this.OnScaledStepsChange;
m_fbtAnimations = MetaPort.Instance.settings.GetSettingsBool("GeneralEnableRunningAnimationFullBody");
MetaPort.Instance.settings.settingBoolChanged.AddListener(this.OnGameSettingBoolChange);
SetCrouchLimit(Settings.CrouchLimit);
SetProneLimit(Settings.ProneLimit);
}
void OnDestroy()
{
Settings.IKOverrideCrouchChange -= this.SetIKOverrideCrouch;
Settings.CrouchLimitChange -= this.SetCrouchLimit;
Settings.IKOverrideProneChange -= this.SetIKOverrideProne;
Settings.ProneLimitChange -= this.SetProneLimit;
Settings.PoseTransitionsChange -= this.SetPoseTransitions;
Settings.AdjustedMovementChange -= this.SetAdjustedMovement;
Settings.IKOverrideFlyChange -= this.SetIKOverrideFly;
Settings.IKOverrideJumpChange -= this.SetIKOverrideJump;
Settings.DetectEmotesChange -= this.SetDetectEmotes;
Settings.FollowHipsChange -= this.SetFollowHips;
Settings.MassCenterChange -= this.OnMassCenterChange;
MetaPort.Instance.settings.settingBoolChanged.RemoveListener(this.OnGameSettingBoolChange);
}
void Update()
@ -121,40 +92,12 @@ namespace ml_amt
m_groundedRaw = MovementSystem.Instance.IsGroundedRaw();
m_moving = !Mathf.Approximately(MovementSystem.Instance.movementVector.magnitude, 0f);
// Update upright
Matrix4x4 l_hmdMatrix = PlayerSetup.Instance.transform.GetMatrix().inverse * PlayerSetup.Instance.GetActiveCamera().transform.GetMatrix();
float l_currentHeight = Mathf.Clamp((l_hmdMatrix * ms_pointVector).y, 0f, float.MaxValue);
float l_avatarViewHeight = Mathf.Clamp(m_avatarHeight * GetRelativeScale(), 0f, float.MaxValue);
m_upright = Mathf.Clamp01((l_avatarViewHeight > 0f) ? (l_currentHeight / l_avatarViewHeight) : 0f);
m_poseState = (m_upright <= Mathf.Min(m_proneLimit, m_crouchLimit)) ? PoseState.Proning : ((m_upright <= Mathf.Max(m_proneLimit, m_crouchLimit)) ? PoseState.Crouching : PoseState.Standing);
if(m_avatarHips != null)
{
Vector4 l_hipsToPoint = (PlayerSetup.Instance.transform.GetMatrix().inverse * m_avatarHips.GetMatrix()) * ms_pointVector;
m_hipsToPlayer.Set(l_hipsToPoint.x, 0f, l_hipsToPoint.z);
}
if(m_inVR && (m_vrIk != null) && m_vrIk.enabled)
{
if(m_adjustedMovement)
{
MovementSystem.Instance.ChangeCrouch(m_poseState == PoseState.Crouching);
MovementSystem.Instance.ChangeProne(m_poseState == PoseState.Proning);
if(!m_poseTransitions)
{
PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Crouching", false);
PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Prone", false);
}
}
if(m_poseTransitions)
{
PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Crouching", (m_poseState == PoseState.Crouching) && !m_compatibleAvatar && (!BodySystem.isCalibratedAsFullBody || m_fbtAnimations));
PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Prone", (m_poseState == PoseState.Proning) && !m_compatibleAvatar && (!BodySystem.isCalibratedAsFullBody || m_fbtAnimations));
}
}
m_emoteActive = false;
if(m_detectEmotes && (m_locomotionLayer >= 0))
{
@ -178,10 +121,6 @@ namespace ml_amt
m_grounded = false;
m_groundedRaw = false;
m_avatarReady = false;
m_compatibleAvatar = false;
m_poseState = PoseState.Standing;
m_customCrouchLimit = false;
m_customProneLimit = false;
m_avatarScale = 1f;
m_locomotionOffset = Vector3.zero;
m_emoteActive = false;
@ -189,9 +128,7 @@ namespace ml_amt
m_locomotionOverride = false;
m_hipsToPlayer = Vector3.zero;
m_avatarHips = null;
m_avatarHeight = 1f;
m_massCenter = Vector3.zero;
m_stepDistance = Vector2.zero;
m_parameters.Clear();
}
@ -201,7 +138,7 @@ namespace ml_amt
m_vrIk = PlayerSetup.Instance._avatar.GetComponent<VRIK>();
m_locomotionLayer = PlayerSetup.Instance._animator.GetLayerIndex("Locomotion/Emotes");
m_avatarHips = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Hips);
m_avatarHeight = PlayerSetup.Instance._avatar.GetComponent<ABI.CCK.Components.CVRAvatar>().viewPosition.y;
m_avatarScale = Mathf.Abs(PlayerSetup.Instance._avatar.transform.localScale.y);
// Parse animator parameters
m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.Upright, PlayerSetup.Instance.animatorManager));
@ -209,17 +146,6 @@ namespace ml_amt
m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.Moving, PlayerSetup.Instance.animatorManager));
m_parameters.RemoveAll(p => !p.IsValid());
m_compatibleAvatar = m_parameters.Exists(p => (p.GetParameterType() == AvatarParameter.ParameterType.Upright));
m_avatarScale = Mathf.Abs(PlayerSetup.Instance._avatar.transform.localScale.y);
Transform l_customTransform = PlayerSetup.Instance._avatar.transform.Find("CrouchLimit");
m_customCrouchLimit = (l_customTransform != null);
m_crouchLimit = m_customCrouchLimit ? Mathf.Clamp01(l_customTransform.localPosition.y) : Settings.CrouchLimit;
l_customTransform = PlayerSetup.Instance._avatar.transform.Find("ProneLimit");
m_customProneLimit = (l_customTransform != null);
m_proneLimit = m_customProneLimit ? Mathf.Clamp01(l_customTransform.localPosition.y) : Settings.ProneLimit;
// Apply VRIK tweaks
if(m_vrIk != null)
{
@ -246,8 +172,6 @@ namespace ml_amt
m_vrIk.solver.locomotion.offset = (Settings.MassCenter ? m_massCenter : m_locomotionOffset);
m_stepDistance.Set(m_vrIk.solver.locomotion.stepThreshold, m_vrIk.solver.locomotion.footDistance);
m_vrIk.onPreSolverUpdate.AddListener(this.OnIKPreUpdate);
m_vrIk.onPostSolverUpdate.AddListener(this.OnIKPostUpdate);
}
@ -257,33 +181,21 @@ namespace ml_amt
internal void OnCalibrate()
{
if(m_avatarReady && BodySystem.isCalibratedAsFullBody && BodySystem.enableHipTracking && !BodySystem.enableRightFootTracking && !BodySystem.enableLeftFootTracking && !BodySystem.enableLeftKneeTracking && !BodySystem.enableRightKneeTracking)
if(m_avatarReady && (m_vrIk != null) && (m_vrIk.solver.spine.pelvisTarget != null) && (m_vrIk.solver.leftLeg.target == null) && (m_vrIk.solver.rightLeg.target == null))
{
// Do not consider 4PT as FBT (!!!)
m_vrIk.solver.spine.bodyPosStiffness = 0.55f;
m_vrIk.solver.spine.bodyRotStiffness = 0.1f;
m_vrIk.solver.spine.neckStiffness = 0.5f;
m_vrIk.solver.spine.chestClampWeight = 0.55f;
m_vrIk.solver.spine.moveBodyBackWhenCrouching = 0.5f;
m_vrIk.solver.spine.maxRootAngle = 25f;
m_vrIk.fixTransforms = false;
BodySystem.isCalibratedAsFullBody = false;
BodySystem.TrackingLeftLegEnabled = false;
BodySystem.TrackingRightLegEnabled = false;
BodySystem.TrackingLocomotionEnabled = true;
if(m_vrIk != null)
m_vrIk.solver.spine.maxRootAngle = 25f; // I need to rotate my legs, ffs!
}
}
internal void OnPlayspaceScale()
{
if(m_vrIk != null)
{
if(Settings.MassCenter)
m_vrIk.solver.locomotion.offset = m_massCenter * GetRelativeScale();
if(Settings.ScaledSteps)
{
m_vrIk.solver.locomotion.stepThreshold = m_stepDistance.x * GetRelativeScale();
m_vrIk.solver.locomotion.footDistance = m_stepDistance.y * GetRelativeScale();
m_vrIk.solver.locomotion.stepHeight.keys = Utils.GetSineKeyframes(Mathf.Clamp01(PlayerSetup.Instance.GetAvatarHeight()) * 0.03f);
m_vrIk.solver.locomotion.heelHeight.keys = Utils.GetSineKeyframes(Mathf.Clamp01(PlayerSetup.Instance.GetAvatarHeight()) * 0.03f);
}
}
}
@ -292,24 +204,24 @@ namespace ml_amt
{
bool l_locomotionOverride = false;
m_ikWeight = m_vrIk.solver.IKPositionWeight;
m_locomotionWeight = m_vrIk.solver.locomotion.weight;
m_plantFeet = m_vrIk.solver.plantFeet;
m_bendNormalLeft = m_vrIk.solver.leftLeg.useAnimatedBendNormal;
m_bendNormalRight = m_vrIk.solver.rightLeg.useAnimatedBendNormal;
m_ikState.m_weight = m_vrIk.solver.IKPositionWeight;
m_ikState.m_locomotionWeight = m_vrIk.solver.locomotion.weight;
m_ikState.m_plantFeet = m_vrIk.solver.plantFeet;
m_ikState.m_bendNormalLeft = m_vrIk.solver.leftLeg.useAnimatedBendNormal;
m_ikState.m_bendNormalRight = m_vrIk.solver.rightLeg.useAnimatedBendNormal;
if(m_detectEmotes && m_emoteActive)
m_vrIk.solver.IKPositionWeight = 0f;
if(!BodySystem.isCalibratedAsFullBody)
{
if((m_ikOverrideCrouch && (m_poseState != PoseState.Standing)) || (m_ikOverrideProne && (m_poseState == PoseState.Proning)))
if(PlayerSetup.Instance.avatarUpright <= PlayerSetup.Instance.avatarCrouchLimit)
{
m_vrIk.solver.locomotion.weight = 0f;
m_vrIk.solver.leftLeg.useAnimatedBendNormal = true;
m_vrIk.solver.rightLeg.useAnimatedBendNormal = true;
l_locomotionOverride = true;
}
if(m_ikOverrideFly && MovementSystem.Instance.flying)
{
m_vrIk.solver.locomotion.weight = 0f;
@ -327,7 +239,7 @@ namespace ml_amt
}
bool l_solverActive = !Mathf.Approximately(m_vrIk.solver.IKPositionWeight, 0f);
if(l_locomotionOverride && l_solverActive && m_followHips && (!m_moving || (m_poseState == PoseState.Proning)) && m_inVR && !BodySystem.isCalibratedAsFullBody && !ModSupporter.SkipHipsOverride())
if(l_locomotionOverride && l_solverActive && m_followHips && (!m_moving || (PlayerSetup.Instance.avatarUpright <= PlayerSetup.Instance.avatarProneLimit)) && m_inVR && !BodySystem.isCalibratedAsFullBody && !ModSupporter.SkipHipsOverride())
{
m_vrIk.solver.plantFeet = false;
IKSystem.VrikRootController.enabled = false;
@ -341,51 +253,21 @@ namespace ml_amt
void OnIKPostUpdate()
{
m_vrIk.solver.IKPositionWeight = m_ikWeight;
m_vrIk.solver.locomotion.weight = m_locomotionWeight;
m_vrIk.solver.plantFeet = m_plantFeet;
m_vrIk.solver.leftLeg.useAnimatedBendNormal = m_bendNormalLeft;
m_vrIk.solver.rightLeg.useAnimatedBendNormal = m_bendNormalRight;
m_vrIk.solver.IKPositionWeight = m_ikState.m_weight;
m_vrIk.solver.locomotion.weight = m_ikState.m_locomotionWeight;
m_vrIk.solver.plantFeet = m_ikState.m_plantFeet;
m_vrIk.solver.leftLeg.useAnimatedBendNormal = m_ikState.m_bendNormalLeft;
m_vrIk.solver.rightLeg.useAnimatedBendNormal = m_ikState.m_bendNormalRight;
}
// Settings
internal void SetIKOverrideCrouch(bool p_state)
{
m_ikOverrideCrouch = p_state;
}
internal void SetCrouchLimit(float p_value)
{
if(!m_customCrouchLimit)
m_crouchLimit = Mathf.Clamp01(p_value);
}
internal void SetIKOverrideProne(bool p_state)
{
m_ikOverrideProne = p_state;
PlayerSetup.Instance.avatarCrouchLimit = Mathf.Max(Mathf.Clamp01(p_value), PlayerSetup.Instance.avatarProneLimit);
}
internal void SetProneLimit(float p_value)
{
if(!m_customProneLimit)
m_proneLimit = Mathf.Clamp01(p_value);
}
internal void SetPoseTransitions(bool p_state)
{
m_poseTransitions = p_state;
if(!m_poseTransitions && m_avatarReady && m_inVR)
{
PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Crouching", false);
PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool("Prone", false);
}
}
internal void SetAdjustedMovement(bool p_state)
{
m_adjustedMovement = p_state;
if(!m_adjustedMovement && m_avatarReady && m_inVR)
{
MovementSystem.Instance.ChangeCrouch(false);
MovementSystem.Instance.ChangeProne(false);
}
PlayerSetup.Instance.avatarProneLimit = Mathf.Min(Mathf.Clamp01(p_value), PlayerSetup.Instance.avatarCrouchLimit);
}
internal void SetIKOverrideFly(bool p_state)
{
@ -408,32 +290,6 @@ namespace ml_amt
if(m_vrIk != null)
m_vrIk.solver.locomotion.offset = (Settings.MassCenter ? (m_massCenter * GetRelativeScale()) : m_locomotionOffset);
}
void OnScaledStepsChange(bool p_state)
{
if(m_vrIk != null)
{
if(p_state)
{
m_vrIk.solver.locomotion.stepThreshold = m_stepDistance.x * GetRelativeScale();
m_vrIk.solver.locomotion.footDistance = m_stepDistance.y * GetRelativeScale();
m_vrIk.solver.locomotion.stepHeight.keys = Utils.GetSineKeyframes(Mathf.Clamp01(PlayerSetup.Instance.GetAvatarHeight()) * 0.03f);
m_vrIk.solver.locomotion.heelHeight.keys = Utils.GetSineKeyframes(Mathf.Clamp01(PlayerSetup.Instance.GetAvatarHeight()) * 0.03f);
}
else
{
IKSystem.Instance.ApplyAvatarScaleToIk(PlayerSetup.Instance.GetAvatarHeight());
m_vrIk.solver.locomotion.stepHeight.keys = Utils.GetSineKeyframes(0.03f);
m_vrIk.solver.locomotion.heelHeight.keys = Utils.GetSineKeyframes(0.03f);
}
}
}
// Game settings
void OnGameSettingBoolChange(string p_name, bool p_state)
{
if(p_name == "GeneralEnableRunningAnimationFullBody")
m_fbtAnimations = p_state;
}
// Arbitrary
float GetRelativeScale()
@ -442,7 +298,7 @@ namespace ml_amt
}
// Parameters access
public float GetUpright() => m_upright;
public float GetUpright() => PlayerSetup.Instance.avatarUpright;
public bool GetGroundedRaw() => m_groundedRaw;
public bool GetMoving() => m_moving;
}

View file

@ -1,6 +1,6 @@
using System.Reflection;
[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.2.8", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.2.9", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
[assembly: MelonLoader.MelonOptionalDependencies("ml_prm", "ml_pmc")]
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]

View file

@ -10,38 +10,34 @@ This mod adds features for AAS animator and avatar locomotion behaviour.
# Usage
Available mod's settings in `Settings - IK - Avatar Motion Tweaker`:
* **IK override while crouching:** disables legs locomotion/autostep upon HMD reaching `Crouch limit`; default value - `true`.
* **Crouch limit:** defines crouch limit; default value - `65`.
* Note: Can be overrided by avatar. For this avatar has to have child gameobject with name `CrouchLimit`, its Y-axis location will be used as limit, should be in range [0.0, 1.0].
* **IK override while proning:** disables legs locomotion/autostep upon HMD reaching `Prone limit`; default value - `true`.
* **Prone limit:** defines prone limit; default value - `30`.
* Note: Can be overrided by avatar. For this avatar has to have child gameobject with name `ProneLimit`, its Y-axis location will be used as limit, should be in range [0.0, 1.0].
* **Crouch limit:** defines crouch limit; default value - `75`.
* **Prone limit:** defines prone limit; default value - `40`.
* **IK override while flying:** disables legs locomotion/autostep in fly mode; default value - `true`.
* **IK override while jumping:** disables legs locomotion/autostep in jump; default value - `true`.
* **Follow hips on IK override:** adjusts avatar position to overcome animation snapping on IK override; default value - `true`.
* Note: Works best with animations that have root transform position (XZ) based on center of mass.
* Note: Made for four point tracking (head, hands, hips) in mind.
* **Pose transitions:** allows regular avatars animator to transit in crouch/prone states; default value - `true`.
* Note: Avatar is considered as regular if its AAS animator doesn't have `Upright` parameter.
* **Adjusted pose movement speed:** scales movement speed upon crouching/proning; default value - `true`.
* Note: Made for four point tracking (head, hands and hips) in mind.
* **Detect animations emote tag:** disables avatar's IK entirely if current animator state has `Emote` tag; default value - `true`.
* Note: Created as example for [propoused game feature](https://feedback.abinteractive.net/p/disabling-vr-ik-for-emotes-via-animator-state-tag-7b80d963-053a-41c0-86ac-e3d53c61c1e2).
* **Adjusted locomotion mass center:** automatically changes IK locomotion center if avatar has toe bones; default value - `true`.
* Note: Compatible with [DesktopVRIK](https://github.com/NotAKidOnSteam/DesktopVRIK) and [FuckToes](https://github.com/NotAKidOnSteam/FuckToes).
* **Scaled locomotion steps:** scales VRIK locomotion steps according to avatar height and scale; default value - `true`.
* **Alternative avatar collider scale:** applies slightly different approach to avatar collider size change; default value - `true`.
#### Fixes/overhauls options
* **Scaled locomotion jump:** scales locomotion jump according to relation between your player settings height and current avatar height (includes avatar scale); default value - `false`.
* Note: Disabled in worlds that don't allow flight.
* **Fix animation overrides (chairs, etc.):** fixes animations overriding for avatars with AAS; default value - `true`.
* Note: This options is made to address [broken animator in chairs and combat worlds issue](https://feedback.abinteractive.net/p/gestures-getting-stuck-locally-upon-entering-vehicles-chairs).
* Note: This option is made to address [broken animator in chairs and combat worlds issue](https://feedback.abinteractive.net/p/gestures-getting-stuck-locally-upon-entering-vehicles-chairs).
Available additional parameters for AAS animator:
* **`Upright`:** defines linear coefficient between current viewpoint height and avatar's viewpoint height; float, range - [0.0, 1.0].
* Note: Can be set as local-only (not synced) if starts with `#` character.
* Note: Defining this parameter in AAS animator will consider avatar as compatible with mod.
* Note: Can't be used for transitions between poses in desktop mode. In desktop mode its value is driven by avatar animations. Use `CVR Parameter Stream` for detecting desktop/VR modes and change AAS animator transitions accordingly.
* **`GroundedRaw`:** defines instant grounding state of player instead of delayed default parameter `Grounded`.
* Note: Shouldn't be used for transitions between poses in desktop mode. In desktop mode its value is driven by avatar animations. Use `CVR Parameter Stream` for detecting desktop/VR modes and change AAS animator transitions accordingly.
* **`GroundedRaw`:** defines instant grounding state of player instead of delayed default parameter `Grounded`; boolean.
* Note: Can be set as local-only (not synced) if starts with `#` character.
* **`Moving`:** defines movement state of player
* **`Moving`:** defines movement state of player; boolean.
* Note: Can be set as local-only (not synced) if starts with `#` character.
Additional mod's behaviour:
* Overrides FBT behaviour in 4PT mode (head, hands, hips). Be sure to disable legs and knees tracking in `Settings - IK tab`.
* Overrides and fixes IK behaviour in 4PT mode (head, hands and hips).
# NOTE
This is testing update for game build r171, not ready for massive usage yet!

View file

@ -9,56 +9,38 @@ namespace ml_amt
{
enum ModSetting
{
IKOverrideCrouch = 0,
CrouchLimit,
IKOverrideProne,
ProneLimit,
PoseTransitions,
AdjustedMovement,
IKOverrideFly,
IKOverrideJump,
DetectEmotes,
FollowHips,
CollisionScale,
ScaledSteps,
ScaledJump,
MassCenter,
OverrideFix
};
public static bool IKOverrideCrouch { get; private set; } = true;
public static float CrouchLimit { get; private set; } = 0.65f;
public static bool IKOverrideProne { get; private set; } = true;
public static float ProneLimit { get; private set; } = 0.3f;
public static bool PoseTransitions { get; private set; } = true;
public static bool AdjustedMovement { get; private set; } = true;
public static float CrouchLimit { get; private set; } = 0.75f;
public static float ProneLimit { get; private set; } = 0.4f;
public static bool IKOverrideFly { get; private set; } = true;
public static bool IKOverrideJump { get; private set; } = true;
public static bool DetectEmotes { get; private set; } = true;
public static bool FollowHips { get; private set; } = true;
public static bool MassCenter { get; private set; } = true;
public static bool ScaledSteps { get; private set; } = true;
public static bool ScaledJump { get; private set; } = false;
public static bool CollisionScale { get; private set; } = true;
public static bool OverrideFix { get; private set; } = true;
static MelonLoader.MelonPreferences_Category ms_category = null;
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
static public event Action<bool> IKOverrideCrouchChange;
static public event Action<float> CrouchLimitChange;
static public event Action<bool> IKOverrideProneChange;
static public event Action<float> ProneLimitChange;
static public event Action<bool> PoseTransitionsChange;
static public event Action<bool> AdjustedMovementChange;
static public event Action<bool> IKOverrideFlyChange;
static public event Action<bool> IKOverrideJumpChange;
static public event Action<bool> DetectEmotesChange;
static public event Action<bool> FollowHipsChange;
static public event Action<bool> MassCenterChange;
static public event Action<bool> ScaledStepsChange;
static public event Action<bool> ScaledJumpChange;
static public event Action<bool> CollisionScaleChange;
static public event Action<bool> OverrideFixChange;
internal static void Init()
@ -67,37 +49,25 @@ namespace ml_amt
ms_entries = new List<MelonLoader.MelonPreferences_Entry>()
{
ms_category.CreateEntry(ModSetting.IKOverrideCrouch.ToString(), IKOverrideCrouch),
ms_category.CreateEntry(ModSetting.CrouchLimit.ToString(), (int)(CrouchLimit * 100f)),
ms_category.CreateEntry(ModSetting.IKOverrideProne.ToString(), IKOverrideProne),
ms_category.CreateEntry(ModSetting.ProneLimit.ToString(), (int)(ProneLimit * 100f)),
ms_category.CreateEntry(ModSetting.PoseTransitions.ToString(), PoseTransitions),
ms_category.CreateEntry(ModSetting.AdjustedMovement.ToString(), AdjustedMovement),
ms_category.CreateEntry(ModSetting.IKOverrideFly.ToString(), IKOverrideFly),
ms_category.CreateEntry(ModSetting.IKOverrideJump.ToString(), IKOverrideJump),
ms_category.CreateEntry(ModSetting.DetectEmotes.ToString(), DetectEmotes),
ms_category.CreateEntry(ModSetting.FollowHips.ToString(), FollowHips),
ms_category.CreateEntry(ModSetting.MassCenter.ToString(), MassCenter),
ms_category.CreateEntry(ModSetting.ScaledSteps.ToString(), ScaledSteps),
ms_category.CreateEntry(ModSetting.ScaledJump.ToString(), ScaledJump),
ms_category.CreateEntry(ModSetting.CollisionScale.ToString(), CollisionScale),
ms_category.CreateEntry(ModSetting.OverrideFix.ToString(), OverrideFix)
};
IKOverrideCrouch = (bool)ms_entries[(int)ModSetting.IKOverrideCrouch].BoxedValue;
CrouchLimit = ((int)ms_entries[(int)ModSetting.CrouchLimit].BoxedValue) * 0.01f;
IKOverrideProne = (bool)ms_entries[(int)ModSetting.IKOverrideProne].BoxedValue;
ProneLimit = ((int)ms_entries[(int)ModSetting.ProneLimit].BoxedValue) * 0.01f;
PoseTransitions = (bool)ms_entries[(int)ModSetting.PoseTransitions].BoxedValue;
AdjustedMovement = (bool)ms_entries[(int)ModSetting.AdjustedMovement].BoxedValue;
IKOverrideFly = (bool)ms_entries[(int)ModSetting.IKOverrideFly].BoxedValue;
IKOverrideJump = (bool)ms_entries[(int)ModSetting.IKOverrideJump].BoxedValue;
DetectEmotes = (bool)ms_entries[(int)ModSetting.DetectEmotes].BoxedValue;
FollowHips = (bool)ms_entries[(int)ModSetting.FollowHips].BoxedValue;
MassCenter = (bool)ms_entries[(int)ModSetting.MassCenter].BoxedValue;
ScaledSteps = (bool)ms_entries[(int)ModSetting.ScaledSteps].BoxedValue;
ScaledJump = (bool)ms_entries[(int)ModSetting.ScaledJump].BoxedValue;
CollisionScale = (bool)ms_entries[(int)ModSetting.CollisionScale].BoxedValue;
OverrideFix = (bool)ms_entries[(int)ModSetting.OverrideFix].BoxedValue;
MelonLoader.MelonCoroutines.Start(WaitMainMenuUi());
@ -156,34 +126,6 @@ namespace ml_amt
{
switch(l_setting)
{
case ModSetting.IKOverrideCrouch:
{
IKOverrideCrouch = bool.Parse(p_value);
IKOverrideCrouchChange?.Invoke(IKOverrideCrouch);
}
break;
case ModSetting.IKOverrideProne:
{
IKOverrideProne = bool.Parse(p_value);
IKOverrideProneChange?.Invoke(IKOverrideProne);
}
break;
case ModSetting.PoseTransitions:
{
PoseTransitions = bool.Parse(p_value);
PoseTransitionsChange?.Invoke(PoseTransitions);
}
break;
case ModSetting.AdjustedMovement:
{
AdjustedMovement = bool.Parse(p_value);
AdjustedMovementChange?.Invoke(AdjustedMovement);
}
break;
case ModSetting.IKOverrideFly:
{
IKOverrideFly = bool.Parse(p_value);
@ -219,13 +161,6 @@ namespace ml_amt
}
break;
case ModSetting.ScaledSteps:
{
ScaledSteps = bool.Parse(p_value);
ScaledStepsChange?.Invoke(ScaledSteps);
}
break;
case ModSetting.ScaledJump:
{
ScaledJump = bool.Parse(p_value);
@ -233,13 +168,6 @@ namespace ml_amt
}
break;
case ModSetting.CollisionScale:
{
CollisionScale = bool.Parse(p_value);
CollisionScaleChange?.Invoke(CollisionScale);
}
break;
case ModSetting.OverrideFix:
{
OverrideFix = bool.Parse(p_value);

View file

@ -6,7 +6,7 @@
<Company>None</Company>
<Product>AvatarMotionTweaker</Product>
<PackageId>AvatarMotionTweaker</PackageId>
<Version>1.2.8</Version>
<Version>1.2.9</Version>
<Platforms>x64</Platforms>
<AssemblyName>ml_amt</AssemblyName>
</PropertyGroup>

View file

@ -180,31 +180,17 @@ function inp_toggle_mod_amt(_obj, _callbackName) {
<div class ="subcategory-description"></div>
</div>
<div class ="row-wrapper">
<div class ="option-caption">IK override while crouching: </div>
<div class ="option-input">
<div id="IKOverrideCrouch" class ="inp_toggle no-scroll" data-current="true"></div>
</div>
</div>
<div class ="row-wrapper">
<div class ="option-caption">Crouch limit: </div>
<div class ="option-input">
<div id="CrouchLimit" class ="inp_slider no-scroll" data-min="0" data-max="100" data-current="65"></div>
</div>
</div>
<div class ="row-wrapper">
<div class ="option-caption">IK override while proning: </div>
<div class ="option-input">
<div id="IKOverrideProne" class ="inp_toggle no-scroll" data-current="true"></div>
<div id="CrouchLimit" class ="inp_slider no-scroll" data-min="0" data-max="100" data-current="75"></div>
</div>
</div>
<div class ="row-wrapper">
<div class ="option-caption">Prone limit: </div>
<div class ="option-input">
<div id="ProneLimit" class ="inp_slider no-scroll" data-min="0" data-max="100" data-current="30"></div>
<div id="ProneLimit" class ="inp_slider no-scroll" data-min="0" data-max="100" data-current="40"></div>
</div>
</div>
@ -229,20 +215,6 @@ function inp_toggle_mod_amt(_obj, _callbackName) {
</div>
</div>
<div class ="row-wrapper">
<div class ="option-caption">Pose transitions: </div>
<div class ="option-input">
<div id="PoseTransitions" class ="inp_toggle no-scroll" data-current="true"></div>
</div>
</div>
<div class ="row-wrapper">
<div class ="option-caption">Adjusted pose movement speed: </div>
<div class ="option-input">
<div id="AdjustedMovement" class ="inp_toggle no-scroll" data-current="true"></div>
</div>
</div>
<div class ="row-wrapper">
<div class ="option-caption">Detect animations emote tag: </div>
<div class ="option-input">
@ -257,13 +229,6 @@ function inp_toggle_mod_amt(_obj, _callbackName) {
</div>
</div>
<div class ="row-wrapper">
<div class ="option-caption">Scaled locomotion steps: </div>
<div class ="option-input">
<div id="ScaledSteps" class ="inp_toggle no-scroll" data-current="true"></div>
</div>
</div>
<h4><p style="color: #7F7F7F">Avatar independent game fixes/overhauls</p></h4><br>
<div class ="row-wrapper">
@ -273,13 +238,6 @@ function inp_toggle_mod_amt(_obj, _callbackName) {
</div>
</div>
<div class ="row-wrapper">
<div class ="option-caption">Alternative avatar collider: </div>
<div class ="option-input">
<div id="CollisionScale" class ="inp_toggle no-scroll" data-current="true"></div>
</div>
</div>
<div class ="row-wrapper">
<div class ="option-caption">Fix animator overrides (chairs, etc.): </div>
<div class ="option-input">

View file

@ -1,6 +1,6 @@
using System.Reflection;
[assembly: MelonLoader.MelonInfo(typeof(ml_drs.DesktopReticleSwitch), "DesktopReticleSwitch", "1.0.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonInfo(typeof(ml_drs.DesktopReticleSwitch), "DesktopReticleSwitch", "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)]

View file

@ -7,7 +7,7 @@
<Product>DesktopReticleSwitch</Product>
<Authors>SDraw</Authors>
<Company>None</Company>
<Version>1.0.0</Version>
<Version>1.0.1</Version>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

View file

@ -1,6 +1,6 @@
using System.Reflection;
[assembly: MelonLoader.MelonInfo(typeof(ml_egn.ExtendedGameNotifications), "ExtendedGameNotifications", "1.0.2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonInfo(typeof(ml_egn.ExtendedGameNotifications), "ExtendedGameNotifications", "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)]

View file

@ -4,7 +4,7 @@
<TargetFramework>netstandard2.1</TargetFramework>
<Platforms>x64</Platforms>
<PackageId>ExtendedGameNotifications</PackageId>
<Version>1.0.2</Version>
<Version>1.0.3</Version>
<Authors>SDraw</Authors>
<Company>None</Company>
<Product>ExtendedGameNotifications</Product>

View file

@ -54,6 +54,7 @@ namespace ml_lme
m_handRayRight.isInteractionRay = true;
m_handRayRight.triggerGazeEvents = false;
m_handRayRight.holderRoot = m_handRayRight.gameObject;
m_handRayLeft.attachmentDistance = 0f;
m_lineLeft = m_handRayLeft.gameObject.AddComponent<LineRenderer>();
m_lineLeft.endWidth = 1f;
@ -66,6 +67,7 @@ namespace ml_lme
m_lineLeft.enabled = false;
m_lineLeft.receiveShadows = false;
m_handRayLeft.lineRenderer = m_lineLeft;
m_handRayRight.attachmentDistance = 0f;
m_lineRight = m_handRayRight.gameObject.AddComponent<LineRenderer>();
m_lineRight.endWidth = 1f;
@ -81,9 +83,11 @@ namespace ml_lme
Settings.EnabledChange += this.OnEnableChange;
Settings.InputChange += this.OnInputChange;
Settings.GesturesChange += this.OnGesturesChange;
OnEnableChange(Settings.Enabled);
OnInputChange(Settings.Input);
OnGesturesChange(Settings.Gestures);
MelonLoader.MelonCoroutines.Start(WaitForSettings());
MelonLoader.MelonCoroutines.Start(WaitForMaterial());
@ -132,6 +136,8 @@ namespace ml_lme
{
ResetFingers(true);
m_handVisibleLeft = false;
if(Settings.Gestures)
ResetGestures(true);
}
}
@ -146,6 +152,8 @@ namespace ml_lme
{
ResetFingers(false);
m_handVisibleRight = false;
if(Settings.Gestures)
ResetGestures(false);
}
}
@ -169,11 +177,11 @@ namespace ml_lme
}
public override void Update_Interaction()
{
if(Settings.Input)
{
GestureMatcher.LeapData l_data = LeapManager.Instance.GetLatestData();
if(Settings.Input)
{
if(l_data.m_leftHand.m_present && (!m_inVR || !Utils.IsLeftHandTracked() || !Settings.FingersOnly))
{
float l_strength = l_data.m_leftHand.m_grabStrength;
@ -230,6 +238,99 @@ namespace ml_lme
}
}
}
if(Settings.Gestures)
{
// Left hand gestures
if(l_data.m_leftHand.m_present)
{
_inputManager.gestureLeftRaw = 0f;
// Finger Point & Finger Gun
if(_inputManager.fingerCurlLeftIndex < 0.2f && _inputManager.fingerCurlLeftMiddle > 0.75f &&
_inputManager.fingerCurlLeftRing > 0.75f && _inputManager.fingerCurlLeftPinky > 0.75f)
{
_inputManager.gestureLeftRaw = _inputManager.fingerCurlLeftThumb >= 0.5f ? 4f : 3f;
}
// Peace Sign
if(_inputManager.fingerCurlLeftIndex < 0.2f && _inputManager.fingerCurlLeftMiddle < 0.2f &&
_inputManager.fingerCurlLeftRing > 0.75f && _inputManager.fingerCurlLeftPinky > 0.75f)
{
_inputManager.gestureLeftRaw = 5f;
}
// Rock and Roll
if(_inputManager.fingerCurlLeftIndex < 0.2f && _inputManager.fingerCurlLeftMiddle > 0.75f &&
_inputManager.fingerCurlLeftRing > 0.75f && _inputManager.fingerCurlLeftPinky < 0.5f)
{
_inputManager.gestureLeftRaw = 6f;
}
// Fist & Thumbs Up
if(_inputManager.fingerCurlLeftIndex > 0.5f && _inputManager.fingerCurlLeftMiddle > 0.5f &&
_inputManager.fingerCurlLeftRing > 0.5f && _inputManager.fingerCurlLeftPinky > 0.5f)
{
_inputManager.gestureLeftRaw = _inputManager.fingerCurlLeftThumb >= 0.5f
? (l_data.m_rightHand.m_grabStrength - 0.5f) * 2f
: 2f;
}
// Open Hand
if(_inputManager.fingerCurlLeftIndex < 0.2f && _inputManager.fingerCurlLeftMiddle < 0.2f &&
_inputManager.fingerCurlLeftRing < 0.2f && _inputManager.fingerCurlLeftPinky < 0.2f)
{
_inputManager.gestureLeftRaw = -1f;
}
_inputManager.gestureLeft = _inputManager.gestureLeftRaw;
}
// Right hand gestures
if(l_data.m_rightHand.m_present)
{
_inputManager.gestureRightRaw = 0f;
// Finger Point & Finger Gun
if(_inputManager.fingerCurlRightIndex < 0.2f && _inputManager.fingerCurlRightMiddle > 0.75f &&
_inputManager.fingerCurlRightRing > 0.75f && _inputManager.fingerCurlRightPinky > 0.75f)
{
_inputManager.gestureRightRaw = _inputManager.fingerCurlRightThumb >= 0.5f ? 4f : 3f;
}
// Peace Sign
if(_inputManager.fingerCurlRightIndex < 0.2f && _inputManager.fingerCurlRightMiddle < 0.2f &&
_inputManager.fingerCurlRightRing > 0.75f && _inputManager.fingerCurlRightPinky > 0.75f)
{
_inputManager.gestureRightRaw = 5f;
}
// Rock and Roll
if(_inputManager.fingerCurlRightIndex < 0.2f && _inputManager.fingerCurlRightMiddle > 0.75f &&
_inputManager.fingerCurlRightRing > 0.75f && _inputManager.fingerCurlRightPinky < 0.5f)
{
_inputManager.gestureRightRaw = 6f;
}
// Fist & Thumbs Up
if(_inputManager.fingerCurlRightIndex > 0.5f && _inputManager.fingerCurlRightMiddle > 0.5f &&
_inputManager.fingerCurlRightRing > 0.5f && _inputManager.fingerCurlRightPinky > 0.5f)
{
_inputManager.gestureRightRaw = _inputManager.fingerCurlRightThumb >= 0.5f
? (l_data.m_rightHand.m_grabStrength - 0.5f) * 2f
: 2f;
}
// Open Hand
if(_inputManager.fingerCurlRightIndex < 0.2f && _inputManager.fingerCurlRightMiddle < 0.2f &&
_inputManager.fingerCurlRightRing < 0.2f && _inputManager.fingerCurlRightPinky < 0.2f)
{
_inputManager.gestureRightRaw = -1f;
}
_inputManager.gestureRight = _inputManager.gestureRightRaw;
}
}
}
// Settings changes
@ -265,6 +366,14 @@ namespace ml_lme
}
}
void OnGesturesChange(bool p_state)
{
_inputManager.gestureLeft = 0f;
_inputManager.gestureLeftRaw = 0f;
_inputManager.gestureRight = 0f;
_inputManager.gestureRightRaw = 0f;
}
// Game events
internal void OnAvatarSetup()
{
@ -351,6 +460,20 @@ namespace ml_lme
}
}
void ResetGestures(bool p_left)
{
if(p_left)
{
_inputManager.gestureLeft = 0f;
_inputManager.gestureLeftRaw = 0f;
}
else
{
_inputManager.gestureRight = 0f;
_inputManager.gestureRightRaw = 0f;
}
}
// Game settings
void OnGameSettingBoolChange(string p_name, bool p_state)
{

View file

@ -1,6 +1,6 @@
using System.Reflection;
[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.3.7", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.4.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)]

View file

@ -22,5 +22,6 @@ Available mod's settings in `Settings - Implementation - Leap Motion Tracking`:
* **Fingers tracking only:** applies only fingers tracking, disabled by default.
* **Model visibility:** shows Leap Motion controller model, useful for tracking visualizing, disabled by default.
* **Interaction input:** enables in-game interactions (props, menu and etc.); `true` by default.
* **Recognize gestures:** sets avatar gestures (fist, gun, rock'n'roll and etc.) based on current fingers pose; `false` by default.
* **Interact gesture threadhold:** activation limit for interaction based on hand gesture; 80 by default.
* **Grip gesture threadhold:** activation limit for grip based on hand gesture; 40 by default.

View file

@ -33,6 +33,7 @@ namespace ml_lme
HeadZ,
TrackElbows,
Input,
Gestures,
InteractThreadhold,
GripThreadhold,
VisualHands
@ -48,6 +49,7 @@ namespace ml_lme
public static Vector3 HeadOffset { get; private set; } = new Vector3(0f, -0.3f, 0.15f);
public static bool TrackElbows { get; private set; } = true;
public static bool Input { get; private set; } = true;
public static bool Gestures { get; private set; } = false;
public static float InteractThreadhold { get; private set; } = 0.8f;
public static float GripThreadhold { get; private set; } = 0.4f;
public static bool VisualHands { get; private set; } = false;
@ -65,6 +67,7 @@ namespace ml_lme
static public event Action<Vector3> HeadOffsetChange;
static public event Action<bool> TrackElbowsChange;
static public event Action<bool> InputChange;
static public event Action<bool> GesturesChange;
static public event Action<float> InteractThreadholdChange;
static public event Action<float> GripThreadholdChange;
static public event Action<bool> VisualHandsChange;
@ -91,6 +94,7 @@ namespace ml_lme
ms_category.CreateEntry(ModSetting.HeadZ.ToString(), (int)(HeadOffset.z * 100f)),
ms_category.CreateEntry(ModSetting.TrackElbows.ToString(), TrackElbows),
ms_category.CreateEntry(ModSetting.Input.ToString(), Input),
ms_category.CreateEntry(ModSetting.Gestures.ToString(), Gestures),
ms_category.CreateEntry(ModSetting.InteractThreadhold.ToString(), (int)(InteractThreadhold * 100f)),
ms_category.CreateEntry(ModSetting.GripThreadhold.ToString(), (int)(GripThreadhold * 100f)),
ms_category.CreateEntry(ModSetting.VisualHands.ToString(), VisualHands)
@ -148,6 +152,7 @@ namespace ml_lme
) * 0.01f;
TrackElbows = (bool)ms_entries[(int)ModSetting.TrackElbows].BoxedValue;
Input = (bool)ms_entries[(int)ModSetting.Input].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;
@ -201,6 +206,13 @@ namespace ml_lme
}
break;
case ModSetting.Gestures:
{
Gestures = bool.Parse(p_value);
GesturesChange?.Invoke(Gestures);
}
break;
case ModSetting.VisualHands:
{
VisualHands = bool.Parse(p_value);

View file

@ -10,8 +10,6 @@ namespace ml_lme
{
static class Utils
{
static FieldInfo ms_cohtmlView = typeof(CohtmlControlledViewDisposable).GetField("_view", BindingFlags.NonPublic | BindingFlags.Instance);
public static bool IsInVR() => ((CheckVR.Instance != null) && CheckVR.Instance.hasVrDeviceLoaded);
public static bool AreKnucklesInUse() => ((CVRInputManager.Instance._leftController == ABI_RC.Systems.InputManagement.XR.EXRControllerType.Index) || (CVRInputManager.Instance._rightController == ABI_RC.Systems.InputManagement.XR.EXRControllerType.Index));
public static bool IsLeftHandTracked() => (CVRInputManager.Instance._leftController != ABI_RC.Systems.InputManagement.XR.EXRControllerType.None);
@ -33,8 +31,6 @@ namespace ml_lme
}
}
public static void ExecuteScript(this CohtmlControlledViewDisposable p_instance, string p_script) => ((cohtml.Net.View)ms_cohtmlView.GetValue(p_instance))?.ExecuteScript(p_script);
public static void Swap<T>(ref T lhs, ref T rhs)
{
T temp = lhs;

View file

@ -4,7 +4,7 @@
<TargetFramework>netstandard2.1</TargetFramework>
<Platforms>x64</Platforms>
<PackageId>LeapMotionExtension</PackageId>
<Version>1.3.8</Version>
<Version>1.4.0</Version>
<Authors>SDraw</Authors>
<Company>None</Company>
<Product>LeapMotionExtension</Product>

View file

@ -399,6 +399,13 @@ function inp_dropdown_mod_lme(_obj, _callbackName) {
</div>
</div>
<div class ="row-wrapper">
<div class ="option-caption">Recognize Gestures: </div>
<div class ="option-input">
<div id="Gestures" class ="inp_toggle no-scroll" data-current="false"></div>
</div>
</div>
<div class ="row-wrapper">
<div class ="option-caption">Interact gesture threadhold: </div>
<div class ="option-input">

View file

@ -4,6 +4,10 @@ Microsoft Visual Studio Solution File, Format Version 12.00
VisualStudioVersion = 16.0.33214.272
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_amt", "ml_amt\ml_amt.csproj", "{714806A3-E6FC-46F6-9D1D-89C77FEBAF06}"
ProjectSection(ProjectDependencies) = postProject
{D27B6D36-884F-4A49-9A25-B9C121E7B65F} = {D27B6D36-884F-4A49-9A25-B9C121E7B65F}
{118675AA-9AC7-4B0C-BFB1-FA1691619502} = {118675AA-9AC7-4B0C-BFB1-FA1691619502}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_dht", "ml_dht\ml_dht.csproj", "{D805BA67-067E-4B79-87FC-6B08973F13EE}"
EndProject
@ -12,12 +16,15 @@ EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_egn", "ml_egn\ml_egn.csproj", "{8B05FAC0-5C12-40CA-BA48-9F55923E8135}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_lme", "ml_lme\ml_lme.csproj", "{77EA76B1-3709-4FC5-BDBD-8F77160E6DA3}"
ProjectSection(ProjectDependencies) = postProject
{118675AA-9AC7-4B0C-BFB1-FA1691619502} = {118675AA-9AC7-4B0C-BFB1-FA1691619502}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_pam", "ml_pam\ml_pam.csproj", "{5B614459-234A-443D-B06D-34FF81ADA67E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_prm", "ml_prm\ml_prm.csproj", "{D27B6D36-884F-4A49-9A25-B9C121E7B65F}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_prm", "ml_prm\ml_prm.csproj", "{D27B6D36-884F-4A49-9A25-B9C121E7B65F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_pmc", "ml_pmc\ml_pmc.csproj", "{118675AA-9AC7-4B0C-BFB1-FA1691619502}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_pmc", "ml_pmc\ml_pmc.csproj", "{118675AA-9AC7-4B0C-BFB1-FA1691619502}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

View file

@ -1,6 +1,6 @@
using System.Reflection;
[assembly: MelonLoader.MelonInfo(typeof(ml_pam.PickupArmMovement), "PickupArmMovement", "1.0.5", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonInfo(typeof(ml_pam.PickupArmMovement), "PickupArmMovement", "1.0.6", "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)]

View file

@ -4,7 +4,7 @@
<TargetFramework>netstandard2.1</TargetFramework>
<Platforms>x64</Platforms>
<PackageId>PickupArmMovement</PackageId>
<Version>1.0.5</Version>
<Version>1.0.6</Version>
<Authors>SDraw</Authors>
<Company>None</Company>
<Product>PickupArmMovement</Product>

View file

@ -1,6 +1,6 @@
using System.Reflection;
[assembly: MelonLoader.MelonInfo(typeof(ml_pmc.PlayerMovementCopycat), "PlayerMovementCopycat", "1.0.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonInfo(typeof(ml_pmc.PlayerMovementCopycat), "PlayerMovementCopycat", "1.0.1", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
[assembly: MelonLoader.MelonPriority(3)]
[assembly: MelonLoader.MelonAdditionalDependencies("BTKUILib")]

24
ml_pmc/README.md Normal file
View file

@ -0,0 +1,24 @@
# Player Movement Copycat
Allows to copy pose, gestures and movement of your friends.
# Installation
* Install [BTKUILib](https://github.com/BTK-Development/BTKUILib)
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
* Get [latest release DLL](../../../releases/latest):
* Put `ml_pmc.dll` in `Mods` folder of game
# Usage
Available options in BTKUILib players list upon player selection:
* **Copy movement:** starts/stops copycating of selected player.
* Note: Selected player should be your friend, be in your view range and not obstructed by other players/world objects/props.
* **Apply position:** enables/disables position changes of selected player; `true` by default.
* Note: Forcibly disabled in worlds that don't allow flight.
* **Apply rotation:** enables/disables rotation changes of selected player; `true` by default.
* **Copy gestures:** enables/disables gestures copy of selected player; `true` by default.
* **Apply LookAtIK:** enables/disables additional head rotation based on camera view in desktop mode; `true` by default.
* **Mirror pose:** enables/disables pose and gestures mirroring; `false` by default.
* **Mirror position:** enables/disables mirroring of position changes of selected player along 0XZ plane; `false` by default.
* **Mirror rotation:** enables/disables mirroring of rotation changes of selected player along 0XZ plane; `false` by default.
# Notes
* Some avatars can have unordinary avatar hierarchy (scaled, rotated or with offset armature/parent objects). Possible fixes are being made upon reports or own findings.

View file

@ -7,6 +7,7 @@
<Authors>SDraw</Authors>
<Company>None</Company>
<Product>PlayerMovementCopycat</Product>
<Version>1.0.1</Version>
</PropertyGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">

View file

@ -1,6 +1,6 @@
using System.Reflection;
[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.0.5", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.0.6", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
[assembly: MelonLoader.MelonPriority(2)]
[assembly: MelonLoader.MelonOptionalDependencies("BTKUILib")]

View file

@ -4,7 +4,7 @@
<TargetFramework>netstandard2.1</TargetFramework>
<Platforms>x64</Platforms>
<PackageId>PlayerRagdollMod</PackageId>
<Version>1.0.5</Version>
<Version>1.0.6</Version>
<Authors>SDraw</Authors>
<Company>None</Company>
<Product>PlayerRagdollMod</Product>

1
ml_prm/vendor/RootMotion/ReadMe.md vendored Normal file
View file

@ -0,0 +1 @@
Put `PuppetMaster` and `RagdollMaster` folders from [PuppetMaster asset](https://assetstore.unity.com/packages/tools/physics/puppetmaster-48977) here.