mirror of
https://github.com/hanetzer/sdraw_mods_cvr.git
synced 2025-09-03 10:29:22 +00:00
Moved PlayerRagdollMod and DesktopHeadTracking to archived
Fixed for r173 game build
This commit is contained in:
parent
a232c2ce13
commit
9886bdc154
43 changed files with 3490 additions and 3600 deletions
238
ml_amt/Main.cs
238
ml_amt/Main.cs
|
@ -1,120 +1,118 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK.SubSystems;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ml_amt
|
||||
{
|
||||
public class AvatarMotionTweaker : MelonLoader.MelonMod
|
||||
{
|
||||
static AvatarMotionTweaker ms_instance = null;
|
||||
|
||||
MotionTweaker m_localTweaker = null;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
if(ms_instance == null)
|
||||
ms_instance = this;
|
||||
|
||||
Settings.Init();
|
||||
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(BodySystem).GetMethod(nameof(BodySystem.Calibrate)),
|
||||
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))
|
||||
);
|
||||
|
||||
ModSupporter.Init();
|
||||
MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
|
||||
}
|
||||
|
||||
IEnumerator WaitForLocalPlayer()
|
||||
{
|
||||
while(PlayerSetup.Instance == null)
|
||||
yield return null;
|
||||
|
||||
m_localTweaker = PlayerSetup.Instance.gameObject.AddComponent<MotionTweaker>();
|
||||
}
|
||||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
m_localTweaker = null;
|
||||
}
|
||||
|
||||
static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear();
|
||||
void OnAvatarClear()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localTweaker != null)
|
||||
m_localTweaker.OnAvatarClear();
|
||||
}
|
||||
catch(Exception l_exception)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(l_exception);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar();
|
||||
void OnSetupAvatar()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localTweaker != null)
|
||||
m_localTweaker.OnSetupAvatar();
|
||||
}
|
||||
catch(Exception l_exception)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(l_exception);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCalibrate_Postfix() => ms_instance?.OnCalibrate();
|
||||
void OnCalibrate()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localTweaker != null)
|
||||
m_localTweaker.OnCalibrate();
|
||||
}
|
||||
catch(Exception l_exception)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK.SubSystems;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ml_amt
|
||||
{
|
||||
public class AvatarMotionTweaker : MelonLoader.MelonMod
|
||||
{
|
||||
static AvatarMotionTweaker ms_instance = null;
|
||||
|
||||
MotionTweaker m_localTweaker = null;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
if(ms_instance == null)
|
||||
ms_instance = this;
|
||||
|
||||
Settings.Init();
|
||||
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(AvatarMotionTweaker).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(BodySystem).GetMethod(nameof(BodySystem.Calibrate)),
|
||||
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))
|
||||
);
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
|
||||
}
|
||||
|
||||
IEnumerator WaitForLocalPlayer()
|
||||
{
|
||||
while(PlayerSetup.Instance == null)
|
||||
yield return null;
|
||||
|
||||
m_localTweaker = PlayerSetup.Instance.gameObject.AddComponent<MotionTweaker>();
|
||||
}
|
||||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
m_localTweaker = null;
|
||||
}
|
||||
|
||||
static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear();
|
||||
void OnAvatarClear()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localTweaker != null)
|
||||
m_localTweaker.OnAvatarClear();
|
||||
}
|
||||
catch(Exception l_exception)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(l_exception);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar();
|
||||
void OnSetupAvatar()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localTweaker != null)
|
||||
m_localTweaker.OnSetupAvatar();
|
||||
}
|
||||
catch(Exception l_exception)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(l_exception);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCalibrate_Postfix() => ms_instance?.OnCalibrate();
|
||||
void OnCalibrate()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localTweaker != null)
|
||||
m_localTweaker.OnCalibrate();
|
||||
}
|
||||
catch(Exception l_exception)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
using System.Collections;
|
||||
using System.Linq;
|
||||
|
||||
namespace ml_amt
|
||||
{
|
||||
static class ModSupporter
|
||||
{
|
||||
static bool ms_ragdollMod = false;
|
||||
static bool ms_copycatMod = false;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
if(MelonLoader.MelonMod.RegisteredMelons.FirstOrDefault(m => m.Info.Name == "PlayerRagdollMod") != null)
|
||||
MelonLoader.MelonCoroutines.Start(WaitForRagdollInstance());
|
||||
if(MelonLoader.MelonMod.RegisteredMelons.FirstOrDefault(m => m.Info.Name == "PlayerMovementCopycat") != null)
|
||||
MelonLoader.MelonCoroutines.Start(WaitForCopycatInstance());
|
||||
}
|
||||
|
||||
// PlayerRagdollMod support
|
||||
static IEnumerator WaitForRagdollInstance()
|
||||
{
|
||||
while(ml_prm.RagdollController.Instance == null)
|
||||
yield return null;
|
||||
|
||||
ms_ragdollMod = true;
|
||||
}
|
||||
static bool IsRagdolled() => ml_prm.RagdollController.Instance.IsRagdolled();
|
||||
|
||||
// PlayerMovementCopycat support
|
||||
static IEnumerator WaitForCopycatInstance()
|
||||
{
|
||||
while(ml_pmc.PoseCopycat.Instance == null)
|
||||
yield return null;
|
||||
|
||||
ms_copycatMod = true;
|
||||
}
|
||||
static bool IsCopycating() => ml_pmc.PoseCopycat.Instance.IsActive();
|
||||
|
||||
public static bool SkipHipsOverride()
|
||||
{
|
||||
bool l_result = false;
|
||||
l_result |= (ms_ragdollMod && IsRagdolled());
|
||||
l_result |= (ms_copycatMod && IsCopycating());
|
||||
return l_result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,345 +1,316 @@
|
|||
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.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
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");
|
||||
|
||||
IKState m_ikState;
|
||||
VRIK m_vrIk = null;
|
||||
int m_locomotionLayer = 0;
|
||||
float m_avatarScale = 1f;
|
||||
Vector3 m_locomotionOffset = Vector3.zero; // Original locomotion offset
|
||||
Transform m_avatarHips = null;
|
||||
bool m_inVR = false;
|
||||
|
||||
bool m_avatarReady = false;
|
||||
bool m_grounded = false;
|
||||
bool m_groundedRaw = false;
|
||||
bool m_moving = false;
|
||||
bool m_locomotionOverride = false;
|
||||
|
||||
bool m_ikOverrideFly = true;
|
||||
bool m_ikOverrideJump = true;
|
||||
|
||||
bool m_detectEmotes = true;
|
||||
bool m_emoteActive = false;
|
||||
|
||||
bool m_followHips = true;
|
||||
Vector3 m_hipsToPlayer = Vector3.zero;
|
||||
|
||||
Vector3 m_massCenter = Vector3.zero;
|
||||
|
||||
Transform m_ikLimits = null;
|
||||
|
||||
readonly List<AvatarParameter> m_parameters = null;
|
||||
|
||||
internal MotionTweaker()
|
||||
{
|
||||
m_parameters = new List<AvatarParameter>();
|
||||
}
|
||||
|
||||
// Unity events
|
||||
void Start()
|
||||
{
|
||||
m_inVR = Utils.IsInVR();
|
||||
|
||||
SetCrouchLimit(Settings.CrouchLimit);
|
||||
SetProneLimit(Settings.ProneLimit);
|
||||
SetIKOverrideFly(Settings.IKOverrideFly);
|
||||
SetIKOverrideJump(Settings.IKOverrideJump);
|
||||
SetDetectEmotes(Settings.DetectEmotes);
|
||||
SetFollowHips(Settings.FollowHips);
|
||||
|
||||
Settings.CrouchLimitChange += this.SetCrouchLimit;
|
||||
Settings.ProneLimitChange += this.SetProneLimit;
|
||||
Settings.IKOverrideFlyChange += this.SetIKOverrideFly;
|
||||
Settings.IKOverrideJumpChange += this.SetIKOverrideJump;
|
||||
Settings.DetectEmotesChange += this.SetDetectEmotes;
|
||||
Settings.FollowHipsChange += this.SetFollowHips;
|
||||
Settings.MassCenterChange += this.OnMassCenterChange;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
Settings.CrouchLimitChange -= this.SetCrouchLimit;
|
||||
Settings.ProneLimitChange -= this.SetProneLimit;
|
||||
Settings.IKOverrideFlyChange -= this.SetIKOverrideFly;
|
||||
Settings.IKOverrideJumpChange -= this.SetIKOverrideJump;
|
||||
Settings.DetectEmotesChange -= this.SetDetectEmotes;
|
||||
Settings.FollowHipsChange -= this.SetFollowHips;
|
||||
Settings.MassCenterChange -= this.OnMassCenterChange;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if(m_avatarReady)
|
||||
{
|
||||
m_grounded = MovementSystem.Instance.IsGrounded();
|
||||
m_groundedRaw = MovementSystem.Instance.IsGroundedRaw();
|
||||
m_moving = !Mathf.Approximately(MovementSystem.Instance.movementVector.magnitude, 0f);
|
||||
|
||||
UpdateIKLimits();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
m_emoteActive = false;
|
||||
if(m_detectEmotes && (m_locomotionLayer >= 0))
|
||||
{
|
||||
AnimatorStateInfo l_animState = PlayerSetup.Instance._animator.GetCurrentAnimatorStateInfo(m_locomotionLayer);
|
||||
m_emoteActive = (l_animState.tagHash == ms_emoteHash);
|
||||
}
|
||||
|
||||
if(m_parameters.Count > 0)
|
||||
{
|
||||
foreach(AvatarParameter l_param in m_parameters)
|
||||
l_param.Update(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Game events
|
||||
internal void OnAvatarClear()
|
||||
{
|
||||
m_vrIk = null;
|
||||
m_locomotionLayer = -1;
|
||||
m_grounded = false;
|
||||
m_groundedRaw = false;
|
||||
m_avatarReady = false;
|
||||
m_avatarScale = 1f;
|
||||
m_locomotionOffset = Vector3.zero;
|
||||
m_emoteActive = false;
|
||||
m_moving = false;
|
||||
m_locomotionOverride = false;
|
||||
m_hipsToPlayer = Vector3.zero;
|
||||
m_avatarHips = null;
|
||||
m_massCenter = Vector3.zero;
|
||||
m_ikLimits = null;
|
||||
m_parameters.Clear();
|
||||
|
||||
PlayerSetup.Instance.avatarCrouchLimit = Mathf.Clamp01(Settings.CrouchLimit);
|
||||
PlayerSetup.Instance.avatarProneLimit = Mathf.Clamp01(Settings.ProneLimit);
|
||||
}
|
||||
|
||||
internal void OnSetupAvatar()
|
||||
{
|
||||
m_inVR = Utils.IsInVR();
|
||||
m_vrIk = PlayerSetup.Instance._avatar.GetComponent<VRIK>();
|
||||
m_locomotionLayer = PlayerSetup.Instance._animator.GetLayerIndex("Locomotion/Emotes");
|
||||
m_avatarHips = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Hips);
|
||||
m_avatarScale = Mathf.Abs(PlayerSetup.Instance._avatar.transform.localScale.y);
|
||||
|
||||
// Parse animator parameters
|
||||
m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.Upright, PlayerSetup.Instance.animatorManager));
|
||||
m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.GroundedRaw, PlayerSetup.Instance.animatorManager));
|
||||
m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.Moving, PlayerSetup.Instance.animatorManager));
|
||||
m_parameters.RemoveAll(p => !p.IsValid());
|
||||
|
||||
// Avatar custom IK limits
|
||||
m_ikLimits = PlayerSetup.Instance._avatar.transform.Find("[IKLimits]");
|
||||
UpdateIKLimits();
|
||||
|
||||
// Apply VRIK tweaks
|
||||
if(m_vrIk != null)
|
||||
{
|
||||
m_locomotionOffset = m_vrIk.solver.locomotion.offset;
|
||||
m_massCenter = m_locomotionOffset;
|
||||
|
||||
if(m_vrIk.solver.HasToes())
|
||||
{
|
||||
Transform l_foot = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftFoot);
|
||||
if(l_foot == null)
|
||||
l_foot = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightFoot);
|
||||
|
||||
Transform l_toe = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftToes);
|
||||
if(l_toe == null)
|
||||
l_toe = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightToes);
|
||||
|
||||
if((l_foot != null) && (l_toe != null))
|
||||
{
|
||||
Vector3 l_footPos = (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_foot.GetMatrix()) * ms_pointVector;
|
||||
Vector3 l_toePos = (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_toe.GetMatrix()) * ms_pointVector;
|
||||
m_massCenter = new Vector3(0f, 0f, l_toePos.z - l_footPos.z);
|
||||
}
|
||||
}
|
||||
|
||||
m_vrIk.solver.locomotion.offset = (Settings.MassCenter ? m_massCenter : m_locomotionOffset);
|
||||
|
||||
m_vrIk.onPreSolverUpdate.AddListener(this.OnIKPreUpdate);
|
||||
m_vrIk.onPostSolverUpdate.AddListener(this.OnIKPostUpdate);
|
||||
}
|
||||
|
||||
m_avatarReady = true;
|
||||
}
|
||||
|
||||
internal void OnCalibrate()
|
||||
{
|
||||
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;
|
||||
|
||||
IKSystem.Instance.applyOriginalHipRotation = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnPlayspaceScale()
|
||||
{
|
||||
if((m_vrIk != null) && Settings.MassCenter)
|
||||
m_vrIk.solver.locomotion.offset = m_massCenter * GetRelativeScale();
|
||||
}
|
||||
|
||||
// IK events
|
||||
void OnIKPreUpdate()
|
||||
{
|
||||
bool l_locomotionOverride = false;
|
||||
|
||||
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(PlayerSetup.Instance.avatarUpright <= PlayerSetup.Instance.avatarCrouchLimit)
|
||||
{
|
||||
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;
|
||||
m_vrIk.solver.leftLeg.useAnimatedBendNormal = true;
|
||||
m_vrIk.solver.rightLeg.useAnimatedBendNormal = true;
|
||||
l_locomotionOverride = true;
|
||||
}
|
||||
if(m_ikOverrideJump && !m_grounded && !MovementSystem.Instance.flying)
|
||||
{
|
||||
m_vrIk.solver.locomotion.weight = 0f;
|
||||
m_vrIk.solver.leftLeg.useAnimatedBendNormal = true;
|
||||
m_vrIk.solver.rightLeg.useAnimatedBendNormal = true;
|
||||
l_locomotionOverride = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool l_solverActive = !Mathf.Approximately(m_vrIk.solver.IKPositionWeight, 0f);
|
||||
if(l_locomotionOverride && l_solverActive && (m_followHips && !MovementSystem.Instance.sitting) && (!m_moving || (PlayerSetup.Instance.avatarUpright <= PlayerSetup.Instance.avatarCrouchLimit)) && m_inVR && !BodySystem.isCalibratedAsFullBody && !ModSupporter.SkipHipsOverride())
|
||||
{
|
||||
m_vrIk.solver.plantFeet = false;
|
||||
if((IKSystem.VrikRootController != null) && !MovementSystem.Instance.sitting)
|
||||
IKSystem.VrikRootController.enabled = false;
|
||||
PlayerSetup.Instance._avatar.transform.localPosition = m_hipsToPlayer;
|
||||
}
|
||||
|
||||
if(m_locomotionOverride && !l_locomotionOverride)
|
||||
{
|
||||
m_vrIk.solver.Reset();
|
||||
if((IKSystem.VrikRootController != null) && !MovementSystem.Instance.sitting)
|
||||
IKSystem.VrikRootController.enabled = true;
|
||||
}
|
||||
m_locomotionOverride = l_locomotionOverride;
|
||||
}
|
||||
|
||||
void OnIKPostUpdate()
|
||||
{
|
||||
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 SetCrouchLimit(float p_value)
|
||||
{
|
||||
if(m_ikLimits == null)
|
||||
PlayerSetup.Instance.avatarCrouchLimit = Mathf.Clamp01(p_value);
|
||||
}
|
||||
internal void SetProneLimit(float p_value)
|
||||
{
|
||||
if(m_ikLimits == null)
|
||||
PlayerSetup.Instance.avatarProneLimit = Mathf.Clamp01(p_value);
|
||||
}
|
||||
internal void SetIKOverrideFly(bool p_state)
|
||||
{
|
||||
m_ikOverrideFly = p_state;
|
||||
}
|
||||
internal void SetIKOverrideJump(bool p_state)
|
||||
{
|
||||
m_ikOverrideJump = p_state;
|
||||
}
|
||||
internal void SetDetectEmotes(bool p_state)
|
||||
{
|
||||
m_detectEmotes = p_state;
|
||||
}
|
||||
internal void SetFollowHips(bool p_state)
|
||||
{
|
||||
m_followHips = p_state;
|
||||
}
|
||||
void OnMassCenterChange(bool p_state)
|
||||
{
|
||||
if(m_vrIk != null)
|
||||
m_vrIk.solver.locomotion.offset = (Settings.MassCenter ? (m_massCenter * GetRelativeScale()) : m_locomotionOffset);
|
||||
}
|
||||
|
||||
// Arbitrary
|
||||
float GetRelativeScale()
|
||||
{
|
||||
return ((m_avatarScale > 0f) ? (PlayerSetup.Instance._avatar.transform.localScale.y / m_avatarScale) : 0f);
|
||||
}
|
||||
|
||||
void UpdateIKLimits()
|
||||
{
|
||||
if(m_ikLimits != null)
|
||||
{
|
||||
Vector3 l_values = m_ikLimits.localPosition;
|
||||
PlayerSetup.Instance.avatarCrouchLimit = Mathf.Clamp01(l_values.x);
|
||||
PlayerSetup.Instance.avatarProneLimit = Mathf.Clamp01(l_values.y);
|
||||
}
|
||||
}
|
||||
|
||||
// Parameters access
|
||||
public float GetUpright() => PlayerSetup.Instance.avatarUpright;
|
||||
public bool GetGroundedRaw() => m_groundedRaw;
|
||||
public bool GetMoving() => m_moving;
|
||||
}
|
||||
}
|
||||
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.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
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");
|
||||
|
||||
IKState m_ikState;
|
||||
VRIK m_vrIk = null;
|
||||
int m_locomotionLayer = 0;
|
||||
float m_avatarScale = 1f;
|
||||
Vector3 m_locomotionOffset = Vector3.zero; // Original locomotion offset
|
||||
bool m_inVR = false;
|
||||
|
||||
bool m_avatarReady = false;
|
||||
bool m_grounded = false;
|
||||
bool m_groundedRaw = false;
|
||||
bool m_moving = false;
|
||||
bool m_locomotionOverride = false;
|
||||
|
||||
bool m_ikOverrideFly = true;
|
||||
bool m_ikOverrideJump = true;
|
||||
|
||||
bool m_detectEmotes = true;
|
||||
bool m_emoteActive = false;
|
||||
|
||||
Vector3 m_massCenter = Vector3.zero;
|
||||
|
||||
Transform m_ikLimits = null;
|
||||
|
||||
readonly List<AvatarParameter> m_parameters = null;
|
||||
|
||||
internal MotionTweaker()
|
||||
{
|
||||
m_parameters = new List<AvatarParameter>();
|
||||
}
|
||||
|
||||
// Unity events
|
||||
void Start()
|
||||
{
|
||||
m_inVR = Utils.IsInVR();
|
||||
|
||||
SetCrouchLimit(Settings.CrouchLimit);
|
||||
SetProneLimit(Settings.ProneLimit);
|
||||
SetIKOverrideFly(Settings.IKOverrideFly);
|
||||
SetIKOverrideJump(Settings.IKOverrideJump);
|
||||
SetDetectEmotes(Settings.DetectEmotes);
|
||||
|
||||
Settings.CrouchLimitChange += this.SetCrouchLimit;
|
||||
Settings.ProneLimitChange += this.SetProneLimit;
|
||||
Settings.IKOverrideFlyChange += this.SetIKOverrideFly;
|
||||
Settings.IKOverrideJumpChange += this.SetIKOverrideJump;
|
||||
Settings.DetectEmotesChange += this.SetDetectEmotes;
|
||||
Settings.MassCenterChange += this.OnMassCenterChange;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
Settings.CrouchLimitChange -= this.SetCrouchLimit;
|
||||
Settings.ProneLimitChange -= this.SetProneLimit;
|
||||
Settings.IKOverrideFlyChange -= this.SetIKOverrideFly;
|
||||
Settings.IKOverrideJumpChange -= this.SetIKOverrideJump;
|
||||
Settings.DetectEmotesChange -= this.SetDetectEmotes;
|
||||
Settings.MassCenterChange -= this.OnMassCenterChange;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if(m_avatarReady)
|
||||
{
|
||||
m_grounded = MovementSystem.Instance.IsGrounded();
|
||||
m_groundedRaw = MovementSystem.Instance.IsGroundedRaw();
|
||||
m_moving = !Mathf.Approximately(MovementSystem.Instance.movementVector.magnitude, 0f);
|
||||
|
||||
UpdateIKLimits();
|
||||
|
||||
m_emoteActive = false;
|
||||
if(m_detectEmotes && (m_locomotionLayer >= 0))
|
||||
{
|
||||
AnimatorStateInfo l_animState = PlayerSetup.Instance._animator.GetCurrentAnimatorStateInfo(m_locomotionLayer);
|
||||
m_emoteActive = (l_animState.tagHash == ms_emoteHash);
|
||||
}
|
||||
|
||||
if(m_parameters.Count > 0)
|
||||
{
|
||||
foreach(AvatarParameter l_param in m_parameters)
|
||||
l_param.Update(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Game events
|
||||
internal void OnAvatarClear()
|
||||
{
|
||||
m_vrIk = null;
|
||||
m_locomotionLayer = -1;
|
||||
m_grounded = false;
|
||||
m_groundedRaw = false;
|
||||
m_avatarReady = false;
|
||||
m_avatarScale = 1f;
|
||||
m_locomotionOffset = Vector3.zero;
|
||||
m_emoteActive = false;
|
||||
m_moving = false;
|
||||
m_locomotionOverride = false;
|
||||
m_massCenter = Vector3.zero;
|
||||
m_ikLimits = null;
|
||||
m_parameters.Clear();
|
||||
|
||||
PlayerSetup.Instance.avatarCrouchLimit = Mathf.Clamp01(Settings.CrouchLimit);
|
||||
PlayerSetup.Instance.avatarProneLimit = Mathf.Clamp01(Settings.ProneLimit);
|
||||
}
|
||||
|
||||
internal void OnSetupAvatar()
|
||||
{
|
||||
m_inVR = Utils.IsInVR();
|
||||
m_vrIk = PlayerSetup.Instance._avatar.GetComponent<VRIK>();
|
||||
m_locomotionLayer = PlayerSetup.Instance._animator.GetLayerIndex("Locomotion/Emotes");
|
||||
m_avatarScale = Mathf.Abs(PlayerSetup.Instance._avatar.transform.localScale.y);
|
||||
|
||||
// Parse animator parameters
|
||||
m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.Upright, PlayerSetup.Instance.animatorManager));
|
||||
m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.GroundedRaw, PlayerSetup.Instance.animatorManager));
|
||||
m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.Moving, PlayerSetup.Instance.animatorManager));
|
||||
m_parameters.RemoveAll(p => !p.IsValid());
|
||||
|
||||
// Avatar custom IK limits
|
||||
m_ikLimits = PlayerSetup.Instance._avatar.transform.Find("[IKLimits]");
|
||||
UpdateIKLimits();
|
||||
|
||||
// Apply VRIK tweaks
|
||||
if(m_vrIk != null)
|
||||
{
|
||||
m_locomotionOffset = m_vrIk.solver.locomotion.offset;
|
||||
m_massCenter = m_locomotionOffset;
|
||||
|
||||
if(m_vrIk.solver.HasToes())
|
||||
{
|
||||
Transform l_foot = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftFoot);
|
||||
if(l_foot == null)
|
||||
l_foot = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightFoot);
|
||||
|
||||
Transform l_toe = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftToes);
|
||||
if(l_toe == null)
|
||||
l_toe = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightToes);
|
||||
|
||||
if((l_foot != null) && (l_toe != null))
|
||||
{
|
||||
Vector3 l_footPos = (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_foot.GetMatrix()) * ms_pointVector;
|
||||
Vector3 l_toePos = (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_toe.GetMatrix()) * ms_pointVector;
|
||||
m_massCenter = new Vector3(0f, 0f, l_toePos.z - l_footPos.z);
|
||||
}
|
||||
}
|
||||
|
||||
m_vrIk.solver.locomotion.offset = (Settings.MassCenter ? m_massCenter : m_locomotionOffset);
|
||||
|
||||
m_vrIk.onPreSolverUpdate.AddListener(this.OnIKPreUpdate);
|
||||
m_vrIk.onPostSolverUpdate.AddListener(this.OnIKPostUpdate);
|
||||
}
|
||||
|
||||
m_avatarReady = true;
|
||||
}
|
||||
|
||||
internal void OnCalibrate()
|
||||
{
|
||||
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;
|
||||
|
||||
IKSystem.Instance.applyOriginalHipRotation = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnPlayspaceScale()
|
||||
{
|
||||
if((m_vrIk != null) && Settings.MassCenter)
|
||||
m_vrIk.solver.locomotion.offset = m_massCenter * GetRelativeScale();
|
||||
}
|
||||
|
||||
// IK events
|
||||
void OnIKPreUpdate()
|
||||
{
|
||||
bool l_locomotionOverride = false;
|
||||
|
||||
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(PlayerSetup.Instance.avatarUpright <= PlayerSetup.Instance.avatarCrouchLimit)
|
||||
{
|
||||
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;
|
||||
m_vrIk.solver.leftLeg.useAnimatedBendNormal = true;
|
||||
m_vrIk.solver.rightLeg.useAnimatedBendNormal = true;
|
||||
l_locomotionOverride = true;
|
||||
}
|
||||
if(m_ikOverrideJump && !m_grounded && !MovementSystem.Instance.flying)
|
||||
{
|
||||
m_vrIk.solver.locomotion.weight = 0f;
|
||||
m_vrIk.solver.leftLeg.useAnimatedBendNormal = true;
|
||||
m_vrIk.solver.rightLeg.useAnimatedBendNormal = true;
|
||||
l_locomotionOverride = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_locomotionOverride && !l_locomotionOverride)
|
||||
{
|
||||
m_vrIk.solver.Reset();
|
||||
if((IKSystem.VrikRootController != null) && !MovementSystem.Instance.sitting)
|
||||
IKSystem.VrikRootController.enabled = true;
|
||||
}
|
||||
m_locomotionOverride = l_locomotionOverride;
|
||||
}
|
||||
|
||||
void OnIKPostUpdate()
|
||||
{
|
||||
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 SetCrouchLimit(float p_value)
|
||||
{
|
||||
if(m_ikLimits == null)
|
||||
PlayerSetup.Instance.avatarCrouchLimit = Mathf.Clamp01(p_value);
|
||||
}
|
||||
internal void SetProneLimit(float p_value)
|
||||
{
|
||||
if(m_ikLimits == null)
|
||||
PlayerSetup.Instance.avatarProneLimit = Mathf.Clamp01(p_value);
|
||||
}
|
||||
internal void SetIKOverrideFly(bool p_state)
|
||||
{
|
||||
m_ikOverrideFly = p_state;
|
||||
}
|
||||
internal void SetIKOverrideJump(bool p_state)
|
||||
{
|
||||
m_ikOverrideJump = p_state;
|
||||
}
|
||||
internal void SetDetectEmotes(bool p_state)
|
||||
{
|
||||
m_detectEmotes = p_state;
|
||||
}
|
||||
void OnMassCenterChange(bool p_state)
|
||||
{
|
||||
if(m_vrIk != null)
|
||||
m_vrIk.solver.locomotion.offset = (Settings.MassCenter ? (m_massCenter * GetRelativeScale()) : m_locomotionOffset);
|
||||
}
|
||||
|
||||
// Arbitrary
|
||||
float GetRelativeScale()
|
||||
{
|
||||
return ((m_avatarScale > 0f) ? (PlayerSetup.Instance._avatar.transform.localScale.y / m_avatarScale) : 0f);
|
||||
}
|
||||
|
||||
void UpdateIKLimits()
|
||||
{
|
||||
if(m_ikLimits != null)
|
||||
{
|
||||
Vector3 l_values = m_ikLimits.localPosition;
|
||||
PlayerSetup.Instance.avatarCrouchLimit = Mathf.Clamp01(l_values.x);
|
||||
PlayerSetup.Instance.avatarProneLimit = Mathf.Clamp01(l_values.y);
|
||||
}
|
||||
}
|
||||
|
||||
// Parameters access
|
||||
public float GetUpright() => PlayerSetup.Instance.avatarUpright;
|
||||
public bool GetGroundedRaw() => m_groundedRaw;
|
||||
public bool GetMoving() => m_moving;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.3.3", "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)]
|
||||
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.3.4", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
||||
|
|
|
@ -1,36 +1,33 @@
|
|||
# Avatar Motion Tweaker
|
||||
This mod adds features for AAS animator and avatar locomotion behaviour.
|
||||
|
||||

|
||||
|
||||
# Installation
|
||||
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
|
||||
* Get [latest release DLL](../../../releases/latest):
|
||||
* Put `ml_amt.dll` in `Mods` folder of game
|
||||
|
||||
# Usage
|
||||
Available mod's settings in `Settings - IK - Avatar Motion Tweaker`:
|
||||
* **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 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).
|
||||
|
||||
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: 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; boolean.
|
||||
* Note: Can be set as local-only (not synced) if starts with `#` character.
|
||||
|
||||
Additional mod's behaviour:
|
||||
* Overrides and fixes IK behaviour in 4PT mode (head, hands and hips).
|
||||
# Avatar Motion Tweaker
|
||||
This mod adds features for AAS animator and avatar locomotion behaviour.
|
||||
|
||||

|
||||
|
||||
# Installation
|
||||
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
|
||||
* Get [latest release DLL](../../../releases/latest):
|
||||
* Put `ml_amt.dll` in `Mods` folder of game
|
||||
|
||||
# Usage
|
||||
Available mod's settings in `Settings - IK - Avatar Motion Tweaker`:
|
||||
* **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`.
|
||||
* **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).
|
||||
|
||||
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: 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; boolean.
|
||||
* Note: Can be set as local-only (not synced) if starts with `#` character.
|
||||
|
||||
Additional mod's behaviour:
|
||||
* Overrides and fixes IK behaviour in 4PT mode (head, hands and hips).
|
||||
* Avatars can have controlled IK crouch and prone limits. For that create `[IKLimits]` GameObject parented to avatar's root. Its local X and Y positions will be used as crouch and prone limits respectively and can be changed via animations. Values should be in range of [0;1].
|
|
@ -1,159 +1,148 @@
|
|||
using ABI_RC.Core.InteractionSystem;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ml_amt
|
||||
{
|
||||
static class Settings
|
||||
{
|
||||
enum ModSetting
|
||||
{
|
||||
CrouchLimit,
|
||||
ProneLimit,
|
||||
IKOverrideFly,
|
||||
IKOverrideJump,
|
||||
DetectEmotes,
|
||||
FollowHips,
|
||||
MassCenter
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
||||
static public event Action<float> CrouchLimitChange;
|
||||
static public event Action<float> ProneLimitChange;
|
||||
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;
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
ms_category = MelonLoader.MelonPreferences.CreateCategory("AMT", null, true);
|
||||
|
||||
ms_entries = new List<MelonLoader.MelonPreferences_Entry>()
|
||||
{
|
||||
ms_category.CreateEntry(ModSetting.CrouchLimit.ToString(), (int)(CrouchLimit * 100f)),
|
||||
ms_category.CreateEntry(ModSetting.ProneLimit.ToString(), (int)(ProneLimit * 100f)),
|
||||
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)
|
||||
};
|
||||
|
||||
CrouchLimit = ((int)ms_entries[(int)ModSetting.CrouchLimit].BoxedValue) * 0.01f;
|
||||
ProneLimit = ((int)ms_entries[(int)ModSetting.ProneLimit].BoxedValue) * 0.01f;
|
||||
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;
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitMainMenuUi());
|
||||
}
|
||||
|
||||
static System.Collections.IEnumerator WaitMainMenuUi()
|
||||
{
|
||||
while(ViewManager.Instance == null)
|
||||
yield return null;
|
||||
while(ViewManager.Instance.gameMenuView == null)
|
||||
yield return null;
|
||||
while(ViewManager.Instance.gameMenuView.Listener == null)
|
||||
yield return null;
|
||||
|
||||
ViewManager.Instance.gameMenuView.Listener.ReadyForBindings += () =>
|
||||
{
|
||||
ViewManager.Instance.gameMenuView.View.BindCall("OnSliderUpdate_" + ms_category.Identifier, new Action<string, string>(OnSliderUpdate));
|
||||
ViewManager.Instance.gameMenuView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate));
|
||||
};
|
||||
ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) =>
|
||||
{
|
||||
ViewManager.Instance.gameMenuView.View.ExecuteScript(Scripts.GetEmbeddedScript("mods_extension.js"));
|
||||
ViewManager.Instance.gameMenuView.View.ExecuteScript(Scripts.GetEmbeddedScript("mod_menu.js"));
|
||||
foreach(var l_entry in ms_entries)
|
||||
ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString());
|
||||
};
|
||||
}
|
||||
|
||||
static void OnSliderUpdate(string p_name, string p_value)
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
switch(l_setting)
|
||||
{
|
||||
case ModSetting.CrouchLimit:
|
||||
{
|
||||
CrouchLimit = int.Parse(p_value) * 0.01f;
|
||||
CrouchLimitChange?.Invoke(CrouchLimit);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.ProneLimit:
|
||||
{
|
||||
ProneLimit = int.Parse(p_value) * 0.01f;
|
||||
ProneLimitChange?.Invoke(ProneLimit);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnToggleUpdate(string p_name, string p_value)
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
switch(l_setting)
|
||||
{
|
||||
case ModSetting.IKOverrideFly:
|
||||
{
|
||||
IKOverrideFly = bool.Parse(p_value);
|
||||
IKOverrideFlyChange?.Invoke(IKOverrideFly);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.IKOverrideJump:
|
||||
{
|
||||
IKOverrideJump = bool.Parse(p_value);
|
||||
IKOverrideJumpChange?.Invoke(IKOverrideJump);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.DetectEmotes:
|
||||
{
|
||||
DetectEmotes = bool.Parse(p_value);
|
||||
DetectEmotesChange?.Invoke(DetectEmotes);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.FollowHips:
|
||||
{
|
||||
FollowHips = bool.Parse(p_value);
|
||||
FollowHipsChange?.Invoke(FollowHips);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.MassCenter:
|
||||
{
|
||||
MassCenter = bool.Parse(p_value);
|
||||
MassCenterChange?.Invoke(MassCenter);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using ABI_RC.Core.InteractionSystem;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ml_amt
|
||||
{
|
||||
static class Settings
|
||||
{
|
||||
enum ModSetting
|
||||
{
|
||||
CrouchLimit,
|
||||
ProneLimit,
|
||||
IKOverrideFly,
|
||||
IKOverrideJump,
|
||||
DetectEmotes,
|
||||
FollowHips,
|
||||
MassCenter
|
||||
};
|
||||
|
||||
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 MassCenter { get; private set; } = true;
|
||||
|
||||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
||||
static public event Action<float> CrouchLimitChange;
|
||||
static public event Action<float> ProneLimitChange;
|
||||
static public event Action<bool> IKOverrideFlyChange;
|
||||
static public event Action<bool> IKOverrideJumpChange;
|
||||
static public event Action<bool> DetectEmotesChange;
|
||||
static public event Action<bool> MassCenterChange;
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
ms_category = MelonLoader.MelonPreferences.CreateCategory("AMT", null, true);
|
||||
|
||||
ms_entries = new List<MelonLoader.MelonPreferences_Entry>()
|
||||
{
|
||||
ms_category.CreateEntry(ModSetting.CrouchLimit.ToString(), (int)(CrouchLimit * 100f)),
|
||||
ms_category.CreateEntry(ModSetting.ProneLimit.ToString(), (int)(ProneLimit * 100f)),
|
||||
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.MassCenter.ToString(), MassCenter)
|
||||
};
|
||||
|
||||
CrouchLimit = ((int)ms_entries[(int)ModSetting.CrouchLimit].BoxedValue) * 0.01f;
|
||||
ProneLimit = ((int)ms_entries[(int)ModSetting.ProneLimit].BoxedValue) * 0.01f;
|
||||
IKOverrideFly = (bool)ms_entries[(int)ModSetting.IKOverrideFly].BoxedValue;
|
||||
IKOverrideJump = (bool)ms_entries[(int)ModSetting.IKOverrideJump].BoxedValue;
|
||||
DetectEmotes = (bool)ms_entries[(int)ModSetting.DetectEmotes].BoxedValue;
|
||||
MassCenter = (bool)ms_entries[(int)ModSetting.MassCenter].BoxedValue;
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitMainMenuUi());
|
||||
}
|
||||
|
||||
static System.Collections.IEnumerator WaitMainMenuUi()
|
||||
{
|
||||
while(ViewManager.Instance == null)
|
||||
yield return null;
|
||||
while(ViewManager.Instance.gameMenuView == null)
|
||||
yield return null;
|
||||
while(ViewManager.Instance.gameMenuView.Listener == null)
|
||||
yield return null;
|
||||
|
||||
ViewManager.Instance.gameMenuView.Listener.ReadyForBindings += () =>
|
||||
{
|
||||
ViewManager.Instance.gameMenuView.View.BindCall("OnSliderUpdate_" + ms_category.Identifier, new Action<string, string>(OnSliderUpdate));
|
||||
ViewManager.Instance.gameMenuView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate));
|
||||
};
|
||||
ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) =>
|
||||
{
|
||||
ViewManager.Instance.gameMenuView.View.ExecuteScript(Scripts.GetEmbeddedScript("mods_extension.js"));
|
||||
ViewManager.Instance.gameMenuView.View.ExecuteScript(Scripts.GetEmbeddedScript("mod_menu.js"));
|
||||
foreach(var l_entry in ms_entries)
|
||||
ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString());
|
||||
};
|
||||
}
|
||||
|
||||
static void OnSliderUpdate(string p_name, string p_value)
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
switch(l_setting)
|
||||
{
|
||||
case ModSetting.CrouchLimit:
|
||||
{
|
||||
CrouchLimit = int.Parse(p_value) * 0.01f;
|
||||
CrouchLimitChange?.Invoke(CrouchLimit);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.ProneLimit:
|
||||
{
|
||||
ProneLimit = int.Parse(p_value) * 0.01f;
|
||||
ProneLimitChange?.Invoke(ProneLimit);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnToggleUpdate(string p_name, string p_value)
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
switch(l_setting)
|
||||
{
|
||||
case ModSetting.IKOverrideFly:
|
||||
{
|
||||
IKOverrideFly = bool.Parse(p_value);
|
||||
IKOverrideFlyChange?.Invoke(IKOverrideFly);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.IKOverrideJump:
|
||||
{
|
||||
IKOverrideJump = bool.Parse(p_value);
|
||||
IKOverrideJumpChange?.Invoke(IKOverrideJump);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.DetectEmotes:
|
||||
{
|
||||
DetectEmotes = bool.Parse(p_value);
|
||||
DetectEmotesChange?.Invoke(DetectEmotes);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.MassCenter:
|
||||
{
|
||||
MassCenter = bool.Parse(p_value);
|
||||
MassCenterChange?.Invoke(MassCenter);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,95 +1,87 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>AvatarMotionTweaker</Product>
|
||||
<PackageId>AvatarMotionTweaker</PackageId>
|
||||
<Version>1.3.3</Version>
|
||||
<Platforms>x64</Platforms>
|
||||
<AssemblyName>ml_amt</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DebugType>none</DebugType>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Test.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="AvatarMotionTweaker.json" />
|
||||
<None Remove="resources\mod_menu.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="resources\mod_menu.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="..\js\mods_extension.js" Link="resources\mods_extension.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\0Harmony.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp-firstpass">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="cohtml.Net">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\cohtml.Net.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Cohtml.Runtime">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="MelonLoader">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\MelonLoader.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="ml_pmc">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\Mods\ml_pmc.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="ml_prm">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\Mods\ml_prm.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.AnimationModule">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.PhysicsModule">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\"" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>AvatarMotionTweaker</Product>
|
||||
<PackageId>AvatarMotionTweaker</PackageId>
|
||||
<Version>1.3.4</Version>
|
||||
<Platforms>x64</Platforms>
|
||||
<AssemblyName>ml_amt</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DebugType>none</DebugType>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Test.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="AvatarMotionTweaker.json" />
|
||||
<None Remove="resources\mod_menu.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="resources\mod_menu.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="..\js\mods_extension.js" Link="resources\mods_extension.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\0Harmony.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp-firstpass">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="cohtml.Net">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\cohtml.Net.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Cohtml.Runtime">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="MelonLoader">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\MelonLoader.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.AnimationModule">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.PhysicsModule">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\"" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -1,68 +1,61 @@
|
|||
// Add own menu
|
||||
{
|
||||
let l_block = document.createElement('div');
|
||||
l_block.innerHTML = `
|
||||
<div class ="settings-subcategory">
|
||||
<div class ="subcategory-name">Avatar Motion Tweaker</div>
|
||||
<div class ="subcategory-description"></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="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="40"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class ="row-wrapper">
|
||||
<div class ="option-caption">IK override while flying: </div>
|
||||
<div class ="option-input">
|
||||
<div id="IKOverrideFly" class ="inp_toggle no-scroll" data-current="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class ="row-wrapper">
|
||||
<div class ="option-caption">IK override while jumping: </div>
|
||||
<div class ="option-input">
|
||||
<div id="IKOverrideJump" class ="inp_toggle no-scroll" data-current="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class ="row-wrapper">
|
||||
<div class ="option-caption">Follow hips on IK override: </div>
|
||||
<div class ="option-input">
|
||||
<div id="FollowHips" 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">
|
||||
<div id="DetectEmotes" class ="inp_toggle no-scroll" data-current="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class ="row-wrapper">
|
||||
<div class ="option-caption">Adjusted locomotion mass center: </div>
|
||||
<div class ="option-input">
|
||||
<div id="MassCenter" class ="inp_toggle no-scroll" data-current="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
document.getElementById('settings-ik').appendChild(l_block);
|
||||
|
||||
// Toggles
|
||||
for (let l_toggle of l_block.querySelectorAll('.inp_toggle'))
|
||||
modsExtension.addSetting('AMT', l_toggle.id, modsExtension.createToggle(l_toggle, 'OnToggleUpdate_AMT'));
|
||||
|
||||
// Sliders
|
||||
for (let l_slider of l_block.querySelectorAll('.inp_slider'))
|
||||
modsExtension.addSetting('AMT', l_slider.id, modsExtension.createSlider(l_slider, 'OnSliderUpdate_AMT'));
|
||||
}
|
||||
// Add own menu
|
||||
{
|
||||
let l_block = document.createElement('div');
|
||||
l_block.innerHTML = `
|
||||
<div class ="settings-subcategory">
|
||||
<div class ="subcategory-name">Avatar Motion Tweaker</div>
|
||||
<div class ="subcategory-description"></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="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="40"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class ="row-wrapper">
|
||||
<div class ="option-caption">IK override while flying: </div>
|
||||
<div class ="option-input">
|
||||
<div id="IKOverrideFly" class ="inp_toggle no-scroll" data-current="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class ="row-wrapper">
|
||||
<div class ="option-caption">Follow hips on IK override: </div>
|
||||
<div class ="option-input">
|
||||
<div id="FollowHips" 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">
|
||||
<div id="DetectEmotes" class ="inp_toggle no-scroll" data-current="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class ="row-wrapper">
|
||||
<div class ="option-caption">Adjusted locomotion mass center: </div>
|
||||
<div class ="option-input">
|
||||
<div id="MassCenter" class ="inp_toggle no-scroll" data-current="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
document.getElementById('settings-ik').appendChild(l_block);
|
||||
|
||||
// Toggles
|
||||
for (let l_toggle of l_block.querySelectorAll('.inp_toggle'))
|
||||
modsExtension.addSetting('AMT', l_toggle.id, modsExtension.createToggle(l_toggle, 'OnToggleUpdate_AMT'));
|
||||
|
||||
// Sliders
|
||||
for (let l_slider of l_block.querySelectorAll('.inp_slider'))
|
||||
modsExtension.addSetting('AMT', l_slider.id, modsExtension.createSlider(l_slider, 'OnSliderUpdate_AMT'));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue