mirror of
https://github.com/hanetzer/sdraw_mods_cvr.git
synced 2025-09-03 10:29:22 +00:00
Minor code improvements
This commit is contained in:
parent
a2f9c1303e
commit
45557943c4
35 changed files with 557 additions and 835 deletions
|
@ -8,7 +8,9 @@ namespace ml_amt
|
||||||
{
|
{
|
||||||
public enum ParameterType
|
public enum ParameterType
|
||||||
{
|
{
|
||||||
Moving
|
Moving,
|
||||||
|
MovementSpeed,
|
||||||
|
Velocity
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly ParameterType m_type;
|
readonly ParameterType m_type;
|
||||||
|
@ -44,6 +46,14 @@ namespace ml_amt
|
||||||
case ParameterType.Moving:
|
case ParameterType.Moving:
|
||||||
SetBoolean(p_tweaker.IsMoving());
|
SetBoolean(p_tweaker.IsMoving());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ParameterType.MovementSpeed:
|
||||||
|
SetFloat(p_tweaker.GetMovementSpeed());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ParameterType.Velocity:
|
||||||
|
SetFloat(p_tweaker.GetVelocity());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,33 +1,33 @@
|
||||||
using ABI_RC.Core.Player;
|
using System.Collections;
|
||||||
using System.Collections;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace ml_amt
|
namespace ml_amt
|
||||||
{
|
{
|
||||||
public class AvatarMotionTweaker : MelonLoader.MelonMod
|
public class AvatarMotionTweaker : MelonLoader.MelonMod
|
||||||
{
|
{
|
||||||
MotionTweaker m_localTweaker = null;
|
MotionTweaker m_tweaker = null;
|
||||||
|
|
||||||
public override void OnInitializeMelon()
|
public override void OnInitializeMelon()
|
||||||
{
|
{
|
||||||
Settings.Init();
|
Settings.Init();
|
||||||
GameEvents.Init(HarmonyInstance);
|
GameEvents.Init(HarmonyInstance);
|
||||||
|
|
||||||
MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
|
MelonLoader.MelonCoroutines.Start(WaitForRootLogic());
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerator WaitForLocalPlayer()
|
IEnumerator WaitForRootLogic()
|
||||||
{
|
{
|
||||||
while(PlayerSetup.Instance == null)
|
while(ABI_RC.Core.RootLogic.Instance == null)
|
||||||
yield return null;
|
yield return null;
|
||||||
|
|
||||||
m_localTweaker = PlayerSetup.Instance.gameObject.AddComponent<MotionTweaker>();
|
m_tweaker = new GameObject("[AvatarMotionTweaker]").AddComponent<MotionTweaker>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnDeinitializeMelon()
|
public override void OnDeinitializeMelon()
|
||||||
{
|
{
|
||||||
if(m_localTweaker != null)
|
if(m_tweaker != null)
|
||||||
UnityEngine.Object.Destroy(m_localTweaker);
|
Object.Destroy(m_tweaker.gameObject);
|
||||||
m_localTweaker = null;
|
m_tweaker = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using ABI_RC.Core.Player;
|
using ABI_RC.Core.Player;
|
||||||
|
using ABI_RC.Core.Util.AnimatorManager;
|
||||||
using ABI_RC.Systems.IK.SubSystems;
|
using ABI_RC.Systems.IK.SubSystems;
|
||||||
using ABI_RC.Systems.Movement;
|
using ABI_RC.Systems.Movement;
|
||||||
using RootMotion.FinalIK;
|
using RootMotion.FinalIK;
|
||||||
|
@ -19,24 +20,13 @@ namespace ml_amt
|
||||||
public bool m_bendNormalRight;
|
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;
|
IKState m_ikState;
|
||||||
VRIK m_vrIk = null;
|
VRIK m_vrIk = null;
|
||||||
int m_locomotionLayer = 0;
|
|
||||||
float m_avatarScale = 1f;
|
float m_avatarScale = 1f;
|
||||||
Vector3 m_locomotionOffset = Vector3.zero; // Original locomotion offset
|
Vector3 m_locomotionOffset = Vector3.zero; // Original locomotion offset
|
||||||
|
|
||||||
bool m_avatarReady = false;
|
bool m_avatarReady = false;
|
||||||
bool m_grounded = false;
|
|
||||||
bool m_moving = false;
|
|
||||||
|
|
||||||
bool m_locomotionOverride = false;
|
|
||||||
bool m_emoteActive = false;
|
|
||||||
|
|
||||||
Vector3 m_massCenter = Vector3.zero;
|
Vector3 m_massCenter = Vector3.zero;
|
||||||
|
|
||||||
Transform m_ikLimits = null;
|
Transform m_ikLimits = null;
|
||||||
|
|
||||||
readonly List<AvatarParameter> m_parameters = null;
|
readonly List<AvatarParameter> m_parameters = null;
|
||||||
|
@ -49,6 +39,8 @@ namespace ml_amt
|
||||||
// Unity events
|
// Unity events
|
||||||
void Start()
|
void Start()
|
||||||
{
|
{
|
||||||
|
DontDestroyOnLoad(this);
|
||||||
|
|
||||||
OnCrouchLimitChanged(Settings.CrouchLimit);
|
OnCrouchLimitChanged(Settings.CrouchLimit);
|
||||||
OnProneLimitChanged(Settings.ProneLimit);
|
OnProneLimitChanged(Settings.ProneLimit);
|
||||||
|
|
||||||
|
@ -82,18 +74,8 @@ namespace ml_amt
|
||||||
{
|
{
|
||||||
if(m_avatarReady)
|
if(m_avatarReady)
|
||||||
{
|
{
|
||||||
m_grounded = BetterBetterCharacterController.Instance.IsGrounded();
|
|
||||||
m_moving = BetterBetterCharacterController.Instance.IsMoving();
|
|
||||||
|
|
||||||
UpdateIKLimits();
|
UpdateIKLimits();
|
||||||
|
|
||||||
m_emoteActive = false;
|
|
||||||
if(Settings.DetectEmotes && (m_locomotionLayer >= 0))
|
|
||||||
{
|
|
||||||
AnimatorStateInfo l_animState = PlayerSetup.Instance._animator.GetCurrentAnimatorStateInfo(m_locomotionLayer);
|
|
||||||
m_emoteActive = (l_animState.tagHash == ms_emoteHash);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach(AvatarParameter l_param in m_parameters)
|
foreach(AvatarParameter l_param in m_parameters)
|
||||||
l_param.Update(this);
|
l_param.Update(this);
|
||||||
}
|
}
|
||||||
|
@ -103,14 +85,9 @@ namespace ml_amt
|
||||||
void OnAvatarClear()
|
void OnAvatarClear()
|
||||||
{
|
{
|
||||||
m_vrIk = null;
|
m_vrIk = null;
|
||||||
m_locomotionLayer = -1;
|
|
||||||
m_grounded = false;
|
|
||||||
m_avatarReady = false;
|
m_avatarReady = false;
|
||||||
m_avatarScale = 1f;
|
m_avatarScale = 1f;
|
||||||
m_locomotionOffset = Vector3.zero;
|
m_locomotionOffset = Vector3.zero;
|
||||||
m_emoteActive = false;
|
|
||||||
m_moving = false;
|
|
||||||
m_locomotionOverride = false;
|
|
||||||
m_massCenter = Vector3.zero;
|
m_massCenter = Vector3.zero;
|
||||||
m_ikLimits = null;
|
m_ikLimits = null;
|
||||||
m_parameters.Clear();
|
m_parameters.Clear();
|
||||||
|
@ -124,11 +101,12 @@ namespace ml_amt
|
||||||
Utils.SetAvatarTPose();
|
Utils.SetAvatarTPose();
|
||||||
|
|
||||||
m_vrIk = PlayerSetup.Instance._avatar.GetComponent<VRIK>();
|
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);
|
m_avatarScale = Mathf.Abs(PlayerSetup.Instance._avatar.transform.localScale.y);
|
||||||
|
|
||||||
// Parse animator parameters
|
// Parse animator parameters
|
||||||
m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.Moving, PlayerSetup.Instance.animatorManager));
|
m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.Moving, PlayerSetup.Instance.animatorManager));
|
||||||
|
m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.MovementSpeed, PlayerSetup.Instance.animatorManager));
|
||||||
|
m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.Velocity, PlayerSetup.Instance.animatorManager));
|
||||||
m_parameters.RemoveAll(p => !p.IsValid());
|
m_parameters.RemoveAll(p => !p.IsValid());
|
||||||
|
|
||||||
// Avatar custom IK limits
|
// Avatar custom IK limits
|
||||||
|
@ -153,8 +131,8 @@ namespace ml_amt
|
||||||
|
|
||||||
if((l_foot != null) && (l_toe != null))
|
if((l_foot != null) && (l_toe != null))
|
||||||
{
|
{
|
||||||
Vector3 l_footPos = (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_foot.GetMatrix()) * ms_pointVector;
|
Vector3 l_footPos = (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_foot.GetMatrix()).GetPosition();
|
||||||
Vector3 l_toePos = (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_toe.GetMatrix()) * ms_pointVector;
|
Vector3 l_toePos = (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_toe.GetMatrix()).GetPosition();
|
||||||
m_massCenter = new Vector3(0f, 0f, l_toePos.z - l_footPos.z);
|
m_massCenter = new Vector3(0f, 0f, l_toePos.z - l_footPos.z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,44 +170,32 @@ namespace ml_amt
|
||||||
// IK events
|
// IK events
|
||||||
void OnIKPreSolverUpdate()
|
void OnIKPreSolverUpdate()
|
||||||
{
|
{
|
||||||
bool l_locomotionOverride = false;
|
|
||||||
|
|
||||||
m_ikState.m_weight = m_vrIk.solver.IKPositionWeight;
|
m_ikState.m_weight = m_vrIk.solver.IKPositionWeight;
|
||||||
m_ikState.m_locomotionWeight = m_vrIk.solver.locomotion.weight;
|
m_ikState.m_locomotionWeight = m_vrIk.solver.locomotion.weight;
|
||||||
m_ikState.m_plantFeet = m_vrIk.solver.plantFeet;
|
m_ikState.m_plantFeet = m_vrIk.solver.plantFeet;
|
||||||
m_ikState.m_bendNormalLeft = m_vrIk.solver.leftLeg.useAnimatedBendNormal;
|
m_ikState.m_bendNormalLeft = m_vrIk.solver.leftLeg.useAnimatedBendNormal;
|
||||||
m_ikState.m_bendNormalRight = m_vrIk.solver.rightLeg.useAnimatedBendNormal;
|
m_ikState.m_bendNormalRight = m_vrIk.solver.rightLeg.useAnimatedBendNormal;
|
||||||
|
|
||||||
if(Settings.DetectEmotes && m_emoteActive)
|
|
||||||
m_vrIk.solver.IKPositionWeight = 0f;
|
|
||||||
|
|
||||||
if(!BodySystem.isCalibratedAsFullBody)
|
if(!BodySystem.isCalibratedAsFullBody)
|
||||||
{
|
{
|
||||||
if(BetterBetterCharacterController.Instance.AvatarUpright <= BetterBetterCharacterController.Instance.avatarCrouchLimit)
|
if(BetterBetterCharacterController.Instance.AvatarUpright <= BetterBetterCharacterController.Instance.avatarCrouchLimit)
|
||||||
{
|
{
|
||||||
m_vrIk.solver.leftLeg.useAnimatedBendNormal = true;
|
m_vrIk.solver.leftLeg.useAnimatedBendNormal = true;
|
||||||
m_vrIk.solver.rightLeg.useAnimatedBendNormal = true;
|
m_vrIk.solver.rightLeg.useAnimatedBendNormal = true;
|
||||||
l_locomotionOverride = true;
|
|
||||||
}
|
}
|
||||||
if(Settings.IKOverrideFly && BetterBetterCharacterController.Instance.IsFlying())
|
if(Settings.IKOverrideFly && BetterBetterCharacterController.Instance.IsFlying())
|
||||||
{
|
{
|
||||||
m_vrIk.solver.locomotion.weight = 0f;
|
m_vrIk.solver.locomotion.weight = 0f;
|
||||||
m_vrIk.solver.leftLeg.useAnimatedBendNormal = true;
|
m_vrIk.solver.leftLeg.useAnimatedBendNormal = true;
|
||||||
m_vrIk.solver.rightLeg.useAnimatedBendNormal = true;
|
m_vrIk.solver.rightLeg.useAnimatedBendNormal = true;
|
||||||
l_locomotionOverride = true;
|
|
||||||
}
|
}
|
||||||
if(Settings.IKOverrideJump && !m_grounded && !BetterBetterCharacterController.Instance.IsFlying())
|
if(Settings.IKOverrideJump && !BetterBetterCharacterController.Instance.IsGrounded() && !BetterBetterCharacterController.Instance.IsFlying())
|
||||||
{
|
{
|
||||||
m_vrIk.solver.locomotion.weight = 0f;
|
m_vrIk.solver.locomotion.weight = 0f;
|
||||||
m_vrIk.solver.leftLeg.useAnimatedBendNormal = true;
|
m_vrIk.solver.leftLeg.useAnimatedBendNormal = true;
|
||||||
m_vrIk.solver.rightLeg.useAnimatedBendNormal = true;
|
m_vrIk.solver.rightLeg.useAnimatedBendNormal = true;
|
||||||
l_locomotionOverride = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_locomotionOverride && !l_locomotionOverride)
|
|
||||||
m_vrIk.solver.Reset();
|
|
||||||
m_locomotionOverride = l_locomotionOverride;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnIKPostSolverUpdate()
|
void OnIKPostSolverUpdate()
|
||||||
|
@ -275,6 +241,12 @@ namespace ml_amt
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parameters access
|
// Parameters access
|
||||||
public bool IsMoving() => m_moving;
|
public bool IsMoving() => BetterBetterCharacterController.Instance.IsMoving();
|
||||||
|
public float GetMovementSpeed()
|
||||||
|
{
|
||||||
|
AvatarAnimatorManager l_animatorManager = PlayerSetup.Instance.animatorManager;
|
||||||
|
return Mathf.Sqrt(l_animatorManager.MovementX * l_animatorManager.MovementX + l_animatorManager.MovementY * l_animatorManager.MovementY);
|
||||||
|
}
|
||||||
|
public float GetVelocity() => BetterBetterCharacterController.Instance.velocity.magnitude;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.4.1", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.4.2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||||
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||||
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
||||||
|
|
|
@ -6,7 +6,7 @@ This mod adds features for AAS animator and avatar locomotion behaviour.
|
||||||
# Installation
|
# Installation
|
||||||
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
|
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
|
||||||
* Get [latest release DLL](../../../releases/latest):
|
* Get [latest release DLL](../../../releases/latest):
|
||||||
* Put `ml_amt.dll` in `Mods` folder of game
|
* Put `AvatarMotionTweaker.dll` in `Mods` folder of game
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
Available mod's settings in `Settings - IK - Avatar Motion Tweaker`:
|
Available mod's settings in `Settings - IK - Avatar Motion Tweaker`:
|
||||||
|
@ -14,20 +14,15 @@ Available mod's settings in `Settings - IK - Avatar Motion Tweaker`:
|
||||||
* **Prone limit:** defines prone limit; default value - `40`.
|
* **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 flying:** disables legs locomotion/autostep in fly mode; default value - `true`.
|
||||||
* **IK override while jumping:** disables legs locomotion/autostep in jump; 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`.
|
* **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).
|
* Note: Compatible with [DesktopVRIK](https://github.com/NotAKidOnSteam/DesktopVRIK) and [FuckToes](https://github.com/NotAKidOnSteam/FuckToes).
|
||||||
|
|
||||||
Available additional parameters for AAS animator:
|
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.
|
* **`Moving`:** defines movement state of player; boolean.
|
||||||
* Note: Can be set as local-only (not synced) if starts with `#` character.
|
* **`MovementSpeed`:** length of vector made of default `MovementX` and `MovementY` parameters
|
||||||
|
* **`Velocity`:** current player's movement velocity in space
|
||||||
|
|
||||||
|
Parameters can be set as local-only (not synced) if start with `#` character.
|
||||||
|
|
||||||
Additional mod's behaviour:
|
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].
|
* 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].
|
|
@ -20,7 +20,6 @@ namespace ml_amt
|
||||||
ProneLimit,
|
ProneLimit,
|
||||||
IKOverrideFly,
|
IKOverrideFly,
|
||||||
IKOverrideJump,
|
IKOverrideJump,
|
||||||
DetectEmotes,
|
|
||||||
MassCenter
|
MassCenter
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -28,7 +27,6 @@ namespace ml_amt
|
||||||
public static float ProneLimit { get; private set; } = 0.4f;
|
public static float ProneLimit { get; private set; } = 0.4f;
|
||||||
public static bool IKOverrideFly { get; private set; } = true;
|
public static bool IKOverrideFly { get; private set; } = true;
|
||||||
public static bool IKOverrideJump { 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;
|
public static bool MassCenter { get; private set; } = true;
|
||||||
|
|
||||||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||||
|
@ -51,7 +49,6 @@ namespace ml_amt
|
||||||
ms_category.CreateEntry(ModSetting.ProneLimit.ToString(), (int)(ProneLimit * 100f)),
|
ms_category.CreateEntry(ModSetting.ProneLimit.ToString(), (int)(ProneLimit * 100f)),
|
||||||
ms_category.CreateEntry(ModSetting.IKOverrideFly.ToString(), IKOverrideFly),
|
ms_category.CreateEntry(ModSetting.IKOverrideFly.ToString(), IKOverrideFly),
|
||||||
ms_category.CreateEntry(ModSetting.IKOverrideJump.ToString(), IKOverrideJump),
|
ms_category.CreateEntry(ModSetting.IKOverrideJump.ToString(), IKOverrideJump),
|
||||||
ms_category.CreateEntry(ModSetting.DetectEmotes.ToString(), DetectEmotes),
|
|
||||||
ms_category.CreateEntry(ModSetting.MassCenter.ToString(), MassCenter)
|
ms_category.CreateEntry(ModSetting.MassCenter.ToString(), MassCenter)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -59,7 +56,6 @@ namespace ml_amt
|
||||||
ProneLimit = ((int)ms_entries[(int)ModSetting.ProneLimit].BoxedValue) * 0.01f;
|
ProneLimit = ((int)ms_entries[(int)ModSetting.ProneLimit].BoxedValue) * 0.01f;
|
||||||
IKOverrideFly = (bool)ms_entries[(int)ModSetting.IKOverrideFly].BoxedValue;
|
IKOverrideFly = (bool)ms_entries[(int)ModSetting.IKOverrideFly].BoxedValue;
|
||||||
IKOverrideJump = (bool)ms_entries[(int)ModSetting.IKOverrideJump].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;
|
MassCenter = (bool)ms_entries[(int)ModSetting.MassCenter].BoxedValue;
|
||||||
|
|
||||||
MelonLoader.MelonCoroutines.Start(WaitMainMenuUi());
|
MelonLoader.MelonCoroutines.Start(WaitMainMenuUi());
|
||||||
|
@ -142,13 +138,6 @@ namespace ml_amt
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ModSetting.DetectEmotes:
|
|
||||||
{
|
|
||||||
DetectEmotes = l_value;
|
|
||||||
OnDetectEmotesChanged.Invoke(DetectEmotes);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ModSetting.MassCenter:
|
case ModSetting.MassCenter:
|
||||||
{
|
{
|
||||||
MassCenter = l_value;
|
MassCenter = l_value;
|
||||||
|
|
|
@ -3,12 +3,12 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.1</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<Authors>SDraw</Authors>
|
<Authors>SDraw</Authors>
|
||||||
<Company>None</Company>
|
<Company>SDraw</Company>
|
||||||
<Product>AvatarMotionTweaker</Product>
|
<Product>AvatarMotionTweaker</Product>
|
||||||
<PackageId>AvatarMotionTweaker</PackageId>
|
<PackageId>AvatarMotionTweaker</PackageId>
|
||||||
<Version>1.4.1</Version>
|
<Version>1.4.2</Version>
|
||||||
<Platforms>x64</Platforms>
|
<Platforms>x64</Platforms>
|
||||||
<AssemblyName>ml_amt</AssemblyName>
|
<AssemblyName>AvatarMotionTweaker</AssemblyName>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
|
|
@ -109,23 +109,25 @@ namespace ml_bft
|
||||||
Utils.SetAvatarTPose();
|
Utils.SetAvatarTPose();
|
||||||
InputHandler.Instance.Rebind(PlayerSetup.Instance.transform.rotation);
|
InputHandler.Instance.Rebind(PlayerSetup.Instance.transform.rotation);
|
||||||
|
|
||||||
// Try to "fix" rotations of fingers
|
if(Settings.FixFingers)
|
||||||
foreach(var l_tuple in ms_rotationFixChains)
|
|
||||||
{
|
{
|
||||||
ReorientateTowards(
|
foreach(var l_tuple in ms_rotationFixChains)
|
||||||
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item1),
|
{
|
||||||
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item2),
|
ReorientateTowards(
|
||||||
InputHandler.Instance.GetSourceForBone(l_tuple.Item1, l_tuple.Item3),
|
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item1),
|
||||||
InputHandler.Instance.GetSourceForBone(l_tuple.Item2, l_tuple.Item3),
|
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item2),
|
||||||
PlaneType.OXZ
|
InputHandler.Instance.GetSourceForBone(l_tuple.Item1, l_tuple.Item3),
|
||||||
);
|
InputHandler.Instance.GetSourceForBone(l_tuple.Item2, l_tuple.Item3),
|
||||||
ReorientateTowards(
|
PlaneType.OXZ
|
||||||
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item1),
|
);
|
||||||
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item2),
|
ReorientateTowards(
|
||||||
InputHandler.Instance.GetSourceForBone(l_tuple.Item1, l_tuple.Item3),
|
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item1),
|
||||||
InputHandler.Instance.GetSourceForBone(l_tuple.Item2, l_tuple.Item3),
|
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item2),
|
||||||
PlaneType.OYX
|
InputHandler.Instance.GetSourceForBone(l_tuple.Item1, l_tuple.Item3),
|
||||||
);
|
InputHandler.Instance.GetSourceForBone(l_tuple.Item2, l_tuple.Item3),
|
||||||
|
PlaneType.OYX
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind hands
|
// Bind hands
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace ml_bft
|
|
||||||
{
|
|
||||||
class HandHandler
|
|
||||||
{
|
|
||||||
protected bool m_left = false;
|
|
||||||
protected List<Transform> m_bones = null;
|
|
||||||
protected List<Quaternion> m_localRotations = null;
|
|
||||||
protected Transform m_prefabRoot = null;
|
|
||||||
protected List<Renderer> m_renderers = null;
|
|
||||||
|
|
||||||
protected HandHandler(bool p_left)
|
|
||||||
{
|
|
||||||
m_left = p_left;
|
|
||||||
m_bones = new List<Transform>();
|
|
||||||
m_localRotations = new List<Quaternion>();
|
|
||||||
m_renderers = new List<Renderer>();
|
|
||||||
|
|
||||||
Settings.OnShowHandsChanged.AddListener(this.OnShowHandsChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Cleanup()
|
|
||||||
{
|
|
||||||
if(m_prefabRoot != null)
|
|
||||||
Object.Destroy(m_prefabRoot.gameObject);
|
|
||||||
m_prefabRoot = null;
|
|
||||||
|
|
||||||
m_bones.Clear();
|
|
||||||
m_localRotations.Clear();
|
|
||||||
m_renderers.Clear();
|
|
||||||
|
|
||||||
Settings.OnShowHandsChanged.RemoveListener(this.OnShowHandsChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Update()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Transform GetSourceForBone(HumanBodyBones p_bone)
|
|
||||||
{
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Rebind(Quaternion p_base)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void OnShowHandsChanged(bool p_state)
|
|
||||||
{
|
|
||||||
foreach(var l_render in m_renderers)
|
|
||||||
{
|
|
||||||
if(l_render != null)
|
|
||||||
l_render.enabled = p_state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +1,29 @@
|
||||||
using UnityEngine;
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
using Valve.VR;
|
using Valve.VR;
|
||||||
|
|
||||||
namespace ml_bft
|
namespace ml_bft
|
||||||
{
|
{
|
||||||
class HandHandlerVR : HandHandler
|
class HandHandlerVR
|
||||||
{
|
{
|
||||||
// 31 bones in each hand, get index at Valve.VR.SteamVR_Skeleton_JointIndexes or SteamVR_Skeleton_JointIndexEnum
|
// 31 bones in each hand, get index at Valve.VR.SteamVR_Skeleton_JointIndexes or SteamVR_Skeleton_JointIndexEnum
|
||||||
const int c_fingerBonesCount = (int)SteamVR_Skeleton_JointIndexEnum.pinkyAux + 1;
|
const int c_fingerBonesCount = (int)SteamVR_Skeleton_JointIndexEnum.pinkyAux + 1;
|
||||||
|
|
||||||
|
bool m_left = false;
|
||||||
|
readonly List<Transform> m_bones = null;
|
||||||
|
readonly List<Quaternion> m_localRotations = null;
|
||||||
|
Transform m_prefabRoot = null;
|
||||||
|
readonly List<Renderer> m_renderers = null;
|
||||||
|
|
||||||
SteamVR_Action_Skeleton m_skeletonAction;
|
SteamVR_Action_Skeleton m_skeletonAction;
|
||||||
|
|
||||||
public HandHandlerVR(Transform p_root, bool p_left) : base(p_left)
|
public HandHandlerVR(Transform p_root, bool p_left)
|
||||||
{
|
{
|
||||||
|
m_left = p_left;
|
||||||
|
m_bones = new List<Transform>();
|
||||||
|
m_localRotations = new List<Quaternion>();
|
||||||
|
m_renderers = new List<Renderer>();
|
||||||
|
|
||||||
for(int i = 0; i < c_fingerBonesCount; i++)
|
for(int i = 0; i < c_fingerBonesCount; i++)
|
||||||
{
|
{
|
||||||
m_bones.Add(null);
|
m_bones.Add(null);
|
||||||
|
@ -75,22 +87,30 @@ namespace ml_bft
|
||||||
|
|
||||||
m_skeletonAction = SteamVR_Input.GetAction<SteamVR_Action_Skeleton>(p_left ? "SkeletonLeftHand" : "SkeletonRightHand");
|
m_skeletonAction = SteamVR_Input.GetAction<SteamVR_Action_Skeleton>(p_left ? "SkeletonLeftHand" : "SkeletonRightHand");
|
||||||
|
|
||||||
base.OnShowHandsChanged(Settings.ShowHands);
|
OnShowHandsChanged(Settings.ShowHands);
|
||||||
OnMotionRangeChanged(Settings.MotionRange);
|
OnMotionRangeChanged(Settings.MotionRange);
|
||||||
|
|
||||||
|
Settings.OnShowHandsChanged.AddListener(this.OnShowHandsChanged);
|
||||||
Settings.OnMotionRangeChanged.AddListener(this.OnMotionRangeChanged);
|
Settings.OnMotionRangeChanged.AddListener(this.OnMotionRangeChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Cleanup()
|
public void Cleanup()
|
||||||
{
|
{
|
||||||
base.Cleanup();
|
if(m_prefabRoot != null)
|
||||||
|
Object.Destroy(m_prefabRoot.gameObject);
|
||||||
|
m_prefabRoot = null;
|
||||||
|
|
||||||
|
m_bones.Clear();
|
||||||
|
m_localRotations.Clear();
|
||||||
|
m_renderers.Clear();
|
||||||
|
|
||||||
m_skeletonAction = null;
|
m_skeletonAction = null;
|
||||||
|
|
||||||
|
Settings.OnShowHandsChanged.RemoveListener(this.OnShowHandsChanged);
|
||||||
Settings.OnMotionRangeChanged.RemoveListener(this.OnMotionRangeChanged);
|
Settings.OnMotionRangeChanged.RemoveListener(this.OnMotionRangeChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update()
|
public void Update()
|
||||||
{
|
{
|
||||||
if(m_skeletonAction != null)
|
if(m_skeletonAction != null)
|
||||||
{
|
{
|
||||||
|
@ -107,7 +127,7 @@ namespace ml_bft
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Transform GetSourceForBone(HumanBodyBones p_bone)
|
public Transform GetSourceForBone(HumanBodyBones p_bone)
|
||||||
{
|
{
|
||||||
Transform l_result = null;
|
Transform l_result = null;
|
||||||
switch(p_bone)
|
switch(p_bone)
|
||||||
|
@ -221,7 +241,7 @@ namespace ml_bft
|
||||||
return l_result;
|
return l_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Rebind(Quaternion p_base)
|
public void Rebind(Quaternion p_base)
|
||||||
{
|
{
|
||||||
for(int i = 0; i < c_fingerBonesCount; i++)
|
for(int i = 0; i < c_fingerBonesCount; i++)
|
||||||
{
|
{
|
||||||
|
@ -233,6 +253,16 @@ namespace ml_bft
|
||||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.root].rotation = p_base * (m_left ? Quaternion.Euler(0f, -90f, -90f) : Quaternion.Euler(0f, 90f, 90f));
|
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.root].rotation = p_base * (m_left ? Quaternion.Euler(0f, -90f, -90f) : Quaternion.Euler(0f, 90f, 90f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Settings
|
||||||
|
void OnShowHandsChanged(bool p_state)
|
||||||
|
{
|
||||||
|
foreach(var l_render in m_renderers)
|
||||||
|
{
|
||||||
|
if(l_render != null)
|
||||||
|
l_render.enabled = p_state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void OnMotionRangeChanged(Settings.MotionRangeType p_mode)
|
void OnMotionRangeChanged(Settings.MotionRangeType p_mode)
|
||||||
{
|
{
|
||||||
switch(p_mode)
|
switch(p_mode)
|
||||||
|
|
|
@ -1,229 +0,0 @@
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.XR.OpenXR;
|
|
||||||
using UnityEngine.XR.Hands;
|
|
||||||
using UnityEngine.XR;
|
|
||||||
|
|
||||||
namespace ml_bft
|
|
||||||
{
|
|
||||||
class HandHandlerXR : HandHandler
|
|
||||||
{
|
|
||||||
// 26 bones, get in XRHandJointID enum
|
|
||||||
const int c_fingerBonesCount = (int)XRHandJointID.EndMarker - 1;
|
|
||||||
|
|
||||||
public HandHandlerXR(Transform p_root, bool p_left) : base(p_left)
|
|
||||||
{
|
|
||||||
for(int i = 0; i < c_fingerBonesCount; i++)
|
|
||||||
{
|
|
||||||
m_bones.Add(null);
|
|
||||||
m_localRotations.Add(Quaternion.identity);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_prefabRoot = AssetsHandler.GetAsset(string.Format("Assets/OpenXR/Models/{0}Hand_IK.prefab", m_left ? "Left" : "Right")).transform;
|
|
||||||
m_prefabRoot.name = "[FingersTracking_XR]";
|
|
||||||
m_prefabRoot.parent = p_root;
|
|
||||||
m_prefabRoot.localPosition = Vector3.zero;
|
|
||||||
m_prefabRoot.localRotation = Quaternion.identity;
|
|
||||||
|
|
||||||
m_prefabRoot.GetComponentsInChildren(true, m_renderers);
|
|
||||||
|
|
||||||
// Ah yes, the stupid code
|
|
||||||
char l_side = (m_left ? 'L' : 'R');
|
|
||||||
m_bones[(int)XRHandJointID.Wrist - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist", l_side));
|
|
||||||
m_bones[(int)XRHandJointID.Palm - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_Palm", l_side));
|
|
||||||
|
|
||||||
m_bones[(int)XRHandJointID.ThumbMetacarpal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_ThumbMetacarpal", l_side));
|
|
||||||
m_bones[(int)XRHandJointID.ThumbProximal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_ThumbMetacarpal/{0}_Wrist/{0}_ThumbProximal", l_side));
|
|
||||||
m_bones[(int)XRHandJointID.ThumbDistal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_ThumbMetacarpal/{0}_Wrist/{0}_ThumbProximal/{0}_ThumbDistal", l_side));
|
|
||||||
m_bones[(int)XRHandJointID.ThumbTip - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_ThumbMetacarpal/{0}_Wrist/{0}_ThumbProximal/{0}_ThumbDistal/{0}_ThumbTip", l_side));
|
|
||||||
m_bones[(int)XRHandJointID.IndexMetacarpal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_IndexMetacarpal", l_side));
|
|
||||||
m_bones[(int)XRHandJointID.IndexProximal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_IndexMetacarpal/{0}_IndexProximal", l_side));
|
|
||||||
m_bones[(int)XRHandJointID.IndexIntermediate - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_IndexMetacarpal/{0}_IndexProximal/{0}_IndexIntermediate", l_side));
|
|
||||||
m_bones[(int)XRHandJointID.IndexDistal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_IndexMetacarpal/{0}_IndexProximal/{0}_IndexIntermediate/{0}_IndexDistal", l_side));
|
|
||||||
m_bones[(int)XRHandJointID.IndexTip - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_IndexMetacarpal/{0}_IndexProximal/{0}_IndexIntermediate/{0}_IndexDistal/{0}_IndexTip", l_side));
|
|
||||||
|
|
||||||
m_bones[(int)XRHandJointID.MiddleMetacarpal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_MiddleMetacarpal", l_side));
|
|
||||||
m_bones[(int)XRHandJointID.MiddleProximal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_MiddleMetacarpal/{0}_MiddleProximal", l_side));
|
|
||||||
m_bones[(int)XRHandJointID.MiddleIntermediate - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_MiddleMetacarpal/{0}_MiddleProximal/{0}_MiddleIntermediate", l_side));
|
|
||||||
m_bones[(int)XRHandJointID.MiddleDistal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_MiddleMetacarpal/{0}_MiddleProximal/{0}_MiddleIntermediate/{0}_MiddleDistal", l_side));
|
|
||||||
m_bones[(int)XRHandJointID.MiddleTip - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_MiddleMetacarpal/{0}_MiddleProximal/{0}_MiddleIntermediate/{0}_MiddleDistal/{0}_MiddleTip", l_side));
|
|
||||||
|
|
||||||
m_bones[(int)XRHandJointID.RingMetacarpal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_RingMetacarpal", l_side));
|
|
||||||
m_bones[(int)XRHandJointID.RingProximal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_RingMetacarpal/{0}_RingProximal", l_side));
|
|
||||||
m_bones[(int)XRHandJointID.RingIntermediate - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_RingMetacarpal/{0}_RingProximal/{0}_RingIntermediate", l_side));
|
|
||||||
m_bones[(int)XRHandJointID.RingDistal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_RingMetacarpal/{0}_RingProximal/{0}_RingIntermediate/{0}_RingDistal", l_side));
|
|
||||||
m_bones[(int)XRHandJointID.RingTip - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_RingMetacarpal/{0}_RingProximal/{0}_RingIntermediate/{0}_RingDistal/{0}_RingTip", l_side));
|
|
||||||
|
|
||||||
m_bones[(int)XRHandJointID.LittleMetacarpal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_LittleMetacarpal", l_side));
|
|
||||||
m_bones[(int)XRHandJointID.LittleProximal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_LittleMetacarpal/{0}_LittleProximal", l_side));
|
|
||||||
m_bones[(int)XRHandJointID.LittleIntermediate - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_LittleMetacarpal/{0}_LittleProximal/{0}_LittleIntermediate", l_side));
|
|
||||||
m_bones[(int)XRHandJointID.LittleDistal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_LittleMetacarpal/{0}_LittleProximal/{0}_LittleIntermediate/{0}_LittleDistal", l_side));
|
|
||||||
m_bones[(int)XRHandJointID.LittleTip - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_LittleMetacarpal/{0}_LittleProximal/{0}_LittleIntermediate/{0}_LittleDistal/{0}_LittleTip", l_side));
|
|
||||||
|
|
||||||
for(int i = 0; i < c_fingerBonesCount; i++)
|
|
||||||
{
|
|
||||||
if(m_bones[i] != null)
|
|
||||||
m_localRotations[i] = m_bones[i].localRotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
base.OnShowHandsChanged(Settings.ShowHands);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Transform GetSourceForBone(HumanBodyBones p_bone)
|
|
||||||
{
|
|
||||||
Transform l_result = null;
|
|
||||||
if(m_left)
|
|
||||||
{
|
|
||||||
switch(p_bone)
|
|
||||||
{
|
|
||||||
case HumanBodyBones.LeftHand:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.Wrist - 1];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.LeftThumbProximal:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.ThumbMetacarpal - 1];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.LeftThumbIntermediate:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.ThumbProximal - 1];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.LeftThumbDistal:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.ThumbDistal - 1];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HumanBodyBones.LeftIndexProximal:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.IndexProximal - 1];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.LeftIndexIntermediate:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.IndexIntermediate - 1];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.LeftIndexDistal:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.IndexDistal - 1];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HumanBodyBones.LeftMiddleProximal:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.MiddleProximal - 1];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.LeftMiddleIntermediate:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.MiddleIntermediate - 1];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.LeftMiddleDistal:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.MiddleDistal - 1];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HumanBodyBones.LeftRingProximal:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.RingProximal - 1];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.LeftRingIntermediate:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.RingIntermediate - 1];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.LeftRingDistal:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.RingDistal - 1];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HumanBodyBones.LeftLittleProximal:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.LittleProximal - 1];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.LeftLittleIntermediate:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.LittleIntermediate - 1];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.LeftLittleDistal:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.LittleDistal - 1];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch(p_bone)
|
|
||||||
{
|
|
||||||
case HumanBodyBones.RightHand:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.Wrist - 1];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.RightThumbProximal:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.ThumbMetacarpal - 1];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.RightThumbIntermediate:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.ThumbProximal - 1];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.RightThumbDistal:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.ThumbDistal - 1];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HumanBodyBones.RightIndexProximal:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.IndexProximal - 1];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.RightIndexIntermediate:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.IndexIntermediate - 1];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.RightIndexDistal:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.IndexDistal - 1];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HumanBodyBones.RightMiddleProximal:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.MiddleProximal - 1];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.RightMiddleIntermediate:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.MiddleIntermediate - 1];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.RightMiddleDistal:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.MiddleDistal - 1];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HumanBodyBones.RightRingProximal:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.RingProximal - 1];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.RightRingIntermediate:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.RingIntermediate - 1];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.RightRingDistal:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.RingDistal - 1];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HumanBodyBones.RightLittleProximal:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.LittleProximal - 1];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.RightLittleIntermediate:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.LittleIntermediate - 1];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.RightLittleDistal:
|
|
||||||
l_result = m_bones[(int)XRHandJointID.LittleDistal - 1];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return l_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Update()
|
|
||||||
{
|
|
||||||
var l_tracking = OpenXRSettings.Instance.GetFeature<HandTrackingFeature>();
|
|
||||||
var l_device = InputDevices.GetDeviceAtXRNode(m_left ? XRNode.LeftHand : XRNode.RightHand);
|
|
||||||
if((l_device != null) && l_device.TryGetFeatureValue(CommonUsages.deviceRotation, out Quaternion l_deviceRot) && (l_tracking != null))
|
|
||||||
{
|
|
||||||
Quaternion l_handInv = Quaternion.Inverse(l_deviceRot);
|
|
||||||
l_tracking.GetHandJoints(m_left ? HandTrackingFeature.Hand_Index.L : HandTrackingFeature.Hand_Index.R, out var l_positions, out var l_rotations, out _);
|
|
||||||
if(l_positions.Length >= c_fingerBonesCount)
|
|
||||||
{
|
|
||||||
// Joints rotations are in global space, locations are in ... space??? ... wth is wrong with OpenXR?
|
|
||||||
Quaternion l_prefabRot = m_prefabRoot.rotation;
|
|
||||||
for(int i = 0; i < c_fingerBonesCount; i++)
|
|
||||||
{
|
|
||||||
if(m_bones[i] != null)
|
|
||||||
{
|
|
||||||
//m_bones[i].localPosition = l_positions[i];
|
|
||||||
m_bones[i].rotation = l_prefabRot * (l_handInv * l_rotations[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Rebind(Quaternion p_base)
|
|
||||||
{
|
|
||||||
for(int i = 0; i < c_fingerBonesCount; i++)
|
|
||||||
{
|
|
||||||
if(m_bones[i] != null)
|
|
||||||
m_bones[i].localRotation = m_localRotations[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(m_bones[(int)XRHandJointID.Wrist - 1] != null)
|
|
||||||
m_bones[(int)XRHandJointID.Wrist - 1].rotation = p_base * (m_left ? Quaternion.Euler(0f, -90f, 0f) : Quaternion.Euler(0f, 90f, 0f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -12,8 +12,8 @@ namespace ml_bft
|
||||||
|
|
||||||
bool m_active = false;
|
bool m_active = false;
|
||||||
|
|
||||||
HandHandler m_leftHandHandler = null;
|
HandHandlerVR m_leftHandHandler = null;
|
||||||
HandHandler m_rightHandHandler = null;
|
HandHandlerVR m_rightHandHandler = null;
|
||||||
|
|
||||||
internal InputHandler()
|
internal InputHandler()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[assembly: MelonLoader.MelonInfo(typeof(ml_bft.BetterFingersTracking), "BetterFingersTracking", "1.0.4", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
[assembly: MelonLoader.MelonInfo(typeof(ml_bft.BetterFingersTracking), "BetterFingersTracking", "1.0.5", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||||
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||||
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
||||||
|
|
|
@ -4,7 +4,7 @@ Mod that overhauls behaviour of fingers tracking.
|
||||||
# Installation
|
# Installation
|
||||||
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
|
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
|
||||||
* Get [latest release DLL](../../../releases/latest):
|
* Get [latest release DLL](../../../releases/latest):
|
||||||
* Put `ml_bft.dll` in `Mods` folder of game
|
* Put `BetterFingersTracking.dll` in `Mods` folder of game
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
Available mod's settings in `Settings - Input & Key-Bindings - Better Fingers Tracking`:
|
Available mod's settings in `Settings - Input & Key-Bindings - Better Fingers Tracking`:
|
||||||
|
@ -13,6 +13,7 @@ Available mod's settings in `Settings - Input & Key-Bindings - Better Fingers Tr
|
||||||
* **Filter humanoid limits:** Limits fingers rotations to be valid for Unity's Mechanim; `true` by default
|
* **Filter humanoid limits:** Limits fingers rotations to be valid for Unity's Mechanim; `true` by default
|
||||||
* Note: Enabling this option ensures that visual representation of your fingers will be same for you and remote players, but it cancels out additional finger segments rotations that can be better visually in most cases.
|
* Note: Enabling this option ensures that visual representation of your fingers will be same for you and remote players, but it cancels out additional finger segments rotations that can be better visually in most cases.
|
||||||
* **Show hands model:** shows transparent hands model (mostly as debug option); `false` by default
|
* **Show hands model:** shows transparent hands model (mostly as debug option); `false` by default
|
||||||
|
* **Change fingers direction at bind:** tries to allign avatar's fingers for more accurate poses
|
||||||
|
|
||||||
# Notes
|
# Notes
|
||||||
* Currently supports only SteamVR environment, OpenXR support is planned.
|
* Currently supports only SteamVR environment, OpenXR support is planned.
|
||||||
|
|
|
@ -24,13 +24,15 @@ namespace ml_bft
|
||||||
SkeletalInput = 0,
|
SkeletalInput = 0,
|
||||||
MotionRange,
|
MotionRange,
|
||||||
ShowHands,
|
ShowHands,
|
||||||
MechanimFilter
|
MechanimFilter,
|
||||||
|
FixFingers
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool SkeletalInput { get; private set; } = false;
|
public static bool SkeletalInput { get; private set; } = false;
|
||||||
public static MotionRangeType MotionRange { get; private set; } = MotionRangeType.WithController;
|
public static MotionRangeType MotionRange { get; private set; } = MotionRangeType.WithController;
|
||||||
public static bool ShowHands { get; private set; } = false;
|
public static bool ShowHands { get; private set; } = false;
|
||||||
public static bool MechanimFilter { get; private set; } = true;
|
public static bool MechanimFilter { get; private set; } = true;
|
||||||
|
public static bool FixFingers { get; private set; } = true;
|
||||||
|
|
||||||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||||
|
@ -39,6 +41,7 @@ namespace ml_bft
|
||||||
public static readonly SettingEvent<MotionRangeType> OnMotionRangeChanged = new SettingEvent<MotionRangeType>();
|
public static readonly SettingEvent<MotionRangeType> OnMotionRangeChanged = new SettingEvent<MotionRangeType>();
|
||||||
public static readonly SettingEvent<bool> OnShowHandsChanged = new SettingEvent<bool>();
|
public static readonly SettingEvent<bool> OnShowHandsChanged = new SettingEvent<bool>();
|
||||||
public static readonly SettingEvent<bool> OnMechanimFilterChanged = new SettingEvent<bool>();
|
public static readonly SettingEvent<bool> OnMechanimFilterChanged = new SettingEvent<bool>();
|
||||||
|
public static readonly SettingEvent<bool> OnFixFingersChanged = new SettingEvent<bool>();
|
||||||
|
|
||||||
internal static void Init()
|
internal static void Init()
|
||||||
{
|
{
|
||||||
|
@ -49,12 +52,14 @@ namespace ml_bft
|
||||||
ms_category.CreateEntry(ModSetting.SkeletalInput.ToString(), SkeletalInput),
|
ms_category.CreateEntry(ModSetting.SkeletalInput.ToString(), SkeletalInput),
|
||||||
ms_category.CreateEntry(ModSetting.MotionRange.ToString(), (int)MotionRange),
|
ms_category.CreateEntry(ModSetting.MotionRange.ToString(), (int)MotionRange),
|
||||||
ms_category.CreateEntry(ModSetting.ShowHands.ToString(), ShowHands),
|
ms_category.CreateEntry(ModSetting.ShowHands.ToString(), ShowHands),
|
||||||
ms_category.CreateEntry(ModSetting.MechanimFilter.ToString(), MechanimFilter)
|
ms_category.CreateEntry(ModSetting.MechanimFilter.ToString(), MechanimFilter),
|
||||||
|
ms_category.CreateEntry(ModSetting.FixFingers.ToString(), FixFingers)
|
||||||
};
|
};
|
||||||
|
|
||||||
SkeletalInput = (bool)ms_entries[(int)ModSetting.SkeletalInput].BoxedValue;
|
SkeletalInput = (bool)ms_entries[(int)ModSetting.SkeletalInput].BoxedValue;
|
||||||
MotionRange = (MotionRangeType)(int)ms_entries[(int)ModSetting.MotionRange].BoxedValue;
|
MotionRange = (MotionRangeType)(int)ms_entries[(int)ModSetting.MotionRange].BoxedValue;
|
||||||
ShowHands = (bool)ms_entries[(int)ModSetting.ShowHands].BoxedValue;
|
ShowHands = (bool)ms_entries[(int)ModSetting.ShowHands].BoxedValue;
|
||||||
|
FixFingers = (bool)ms_entries[(int)ModSetting.FixFingers].BoxedValue;
|
||||||
|
|
||||||
MelonLoader.MelonCoroutines.Start(WaitMainMenuUi());
|
MelonLoader.MelonCoroutines.Start(WaitMainMenuUi());
|
||||||
}
|
}
|
||||||
|
@ -110,6 +115,13 @@ namespace ml_bft
|
||||||
OnMechanimFilterChanged.Invoke(MechanimFilter);
|
OnMechanimFilterChanged.Invoke(MechanimFilter);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ModSetting.FixFingers:
|
||||||
|
{
|
||||||
|
FixFingers = l_value;
|
||||||
|
OnFixFingersChanged.Invoke(FixFingers);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ms_entries[(int)l_setting].BoxedValue = l_value;
|
ms_entries[(int)l_setting].BoxedValue = l_value;
|
||||||
|
|
|
@ -5,9 +5,10 @@
|
||||||
<Platforms>x64</Platforms>
|
<Platforms>x64</Platforms>
|
||||||
<PackageId>BetterFingersTracking</PackageId>
|
<PackageId>BetterFingersTracking</PackageId>
|
||||||
<Authors>SDraw</Authors>
|
<Authors>SDraw</Authors>
|
||||||
<Company>None</Company>
|
<Company>SDraw</Company>
|
||||||
<Product>BetterFingersTracking</Product>
|
<Product>BetterFingersTracking</Product>
|
||||||
<Version>1.0.4</Version>
|
<Version>1.0.5</Version>
|
||||||
|
<AssemblyName>BetterFingersTracking</AssemblyName>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
@ -18,7 +19,6 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="resources\mod_menu.js" />
|
<EmbeddedResource Include="resources\mod_menu.js" />
|
||||||
<EmbeddedResource Include="resources\ovr_fingers.asset" />
|
<EmbeddedResource Include="resources\ovr_fingers.asset" />
|
||||||
<EmbeddedResource Include="resources\oxr_fingers.asset" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -19,6 +19,13 @@
|
||||||
<div id="MotionRange" class ="inp_dropdown no-scroll" data-options="0:With controller,1:Without controller" data-current="0"></div>
|
<div id="MotionRange" class ="inp_dropdown no-scroll" data-options="0:With controller,1:Without controller" data-current="0"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class ="row-wrapper">
|
||||||
|
<div class ="option-caption">Change fingers direction at bind: </div>
|
||||||
|
<div class ="option-input">
|
||||||
|
<div id="FixFingers" class ="inp_toggle no-scroll" data-current="true"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class ="row-wrapper">
|
<div class ="row-wrapper">
|
||||||
<div class ="option-caption">Filter humanoid limits: </div>
|
<div class ="option-caption">Filter humanoid limits: </div>
|
||||||
|
|
|
@ -107,9 +107,9 @@ namespace ml_pin
|
||||||
|
|
||||||
bool ShouldNotifyInCurrentInstance()
|
bool ShouldNotifyInCurrentInstance()
|
||||||
{
|
{
|
||||||
bool l_isInPublic = (MetaPort.Instance.CurrentInstancePrivacy.Contains("Public") && Settings.NotifyInPublic);
|
bool l_isInPublic = ((MetaPort.Instance.CurrentInstancePrivacyType == MetaPort.InstancePrivacy.Public) && Settings.NotifyInPublic);
|
||||||
bool l_isInFriends = (MetaPort.Instance.CurrentInstancePrivacy.Contains("Friends") && Settings.NotifyInFriends);
|
bool l_isInFriends = (((MetaPort.Instance.CurrentInstancePrivacyType == MetaPort.InstancePrivacy.Friends) || (MetaPort.Instance.CurrentInstancePrivacyType == MetaPort.InstancePrivacy.FriendsOfFriends)) && Settings.NotifyInFriends);
|
||||||
bool l_isInPrivate = (MetaPort.Instance.CurrentInstancePrivacy.Contains("invite") && Settings.NotifyInPrivate);
|
bool l_isInPrivate = (((MetaPort.Instance.CurrentInstancePrivacyType == MetaPort.InstancePrivacy.EveryoneCanInvite) || (MetaPort.Instance.CurrentInstancePrivacyType == MetaPort.InstancePrivacy.OwnerMustInvite)) && Settings.NotifyInPrivate);
|
||||||
return (l_isInPublic || l_isInFriends || l_isInPrivate);
|
return (l_isInPublic || l_isInFriends || l_isInPrivate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[assembly: MelonLoader.MelonInfo(typeof(ml_pin.PlayersInstanceNotifier), "PlayersInstanceNotifier", "1.0.8", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
[assembly: MelonLoader.MelonInfo(typeof(ml_pin.PlayersInstanceNotifier), "PlayersInstanceNotifier", "1.0.9", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||||
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||||
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
||||||
|
|
|
@ -5,7 +5,7 @@ This can be considered as attempt of [JoinNotifier](https://github.com/knah/VRCM
|
||||||
# Installation
|
# Installation
|
||||||
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
|
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
|
||||||
* Get [latest release DLL](../../../releases/latest):
|
* Get [latest release DLL](../../../releases/latest):
|
||||||
* Put `ml_pin.dll` in `Mods` folder of game
|
* Put `PlayersInstanceNotifier.dll` in `Mods` folder of game
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
Available mod's settings in `Settings - Audio - Players Instance Notifier`:
|
Available mod's settings in `Settings - Audio - Players Instance Notifier`:
|
||||||
|
|
|
@ -59,7 +59,7 @@ namespace ml_pin
|
||||||
((DownloadHandlerAudioClip)l_uwr.downloadHandler).streamAudio = true;
|
((DownloadHandlerAudioClip)l_uwr.downloadHandler).streamAudio = true;
|
||||||
yield return l_uwr.SendWebRequest();
|
yield return l_uwr.SendWebRequest();
|
||||||
|
|
||||||
if(l_uwr.isNetworkError || l_uwr.isHttpError)
|
if((l_uwr.result == UnityWebRequest.Result.ConnectionError) || (l_uwr.result == UnityWebRequest.Result.ProtocolError))
|
||||||
{
|
{
|
||||||
MelonLoader.MelonLogger.Warning(l_uwr.error);
|
MelonLoader.MelonLogger.Warning(l_uwr.error);
|
||||||
yield break;
|
yield break;
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
<Authors>SDraw</Authors>
|
<Authors>SDraw</Authors>
|
||||||
<Company>None</Company>
|
<Company>None</Company>
|
||||||
<Product>PlayersInstanceNotifier</Product>
|
<Product>PlayersInstanceNotifier</Product>
|
||||||
<Version>1.0.8</Version>
|
<Version>1.0.9</Version>
|
||||||
|
<AssemblyName>PlayersInstanceNotifier</AssemblyName>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
|
|
@ -8,36 +8,35 @@ namespace ml_prm
|
||||||
{
|
{
|
||||||
public class PlayerRagdollMod : MelonLoader.MelonMod
|
public class PlayerRagdollMod : MelonLoader.MelonMod
|
||||||
{
|
{
|
||||||
RagdollController m_localController = null;
|
RagdollController m_controller = null;
|
||||||
|
|
||||||
public override void OnInitializeMelon()
|
public override void OnInitializeMelon()
|
||||||
{
|
{
|
||||||
Settings.Init();
|
Settings.Init();
|
||||||
ModUi.Init();
|
ModUi.Init();
|
||||||
GameEvents.Init(HarmonyInstance);
|
GameEvents.Init(HarmonyInstance);
|
||||||
WorldHandler.Init();
|
WorldManager.Init();
|
||||||
RemoteGestureManager.Init();
|
|
||||||
|
|
||||||
MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
|
MelonLoader.MelonCoroutines.Start(WaitForRootLogic());
|
||||||
MelonLoader.MelonCoroutines.Start(WaitForWhitelist());
|
MelonLoader.MelonCoroutines.Start(WaitForWhitelist());
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnDeinitializeMelon()
|
public override void OnDeinitializeMelon()
|
||||||
{
|
{
|
||||||
WorldHandler.DeInit();
|
WorldManager.DeInit();
|
||||||
RemoteGestureManager.DeInit();
|
|
||||||
|
|
||||||
if(m_localController != null)
|
if(m_controller != null)
|
||||||
UnityEngine.Object.Destroy(m_localController);
|
UnityEngine.Object.Destroy(m_controller.gameObject);
|
||||||
m_localController = null;
|
m_controller = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
System.Collections.IEnumerator WaitForLocalPlayer()
|
System.Collections.IEnumerator WaitForRootLogic()
|
||||||
{
|
{
|
||||||
while(PlayerSetup.Instance == null)
|
while(ABI_RC.Core.RootLogic.Instance == null)
|
||||||
yield return null;
|
yield return null;
|
||||||
|
|
||||||
m_localController = PlayerSetup.Instance.gameObject.AddComponent<RagdollController>();
|
m_controller = new UnityEngine.GameObject("[PlayerRagdollMod]").AddComponent<RagdollController>();
|
||||||
|
m_controller.gameObject.AddComponent<RemoteGesturesManager>();
|
||||||
}
|
}
|
||||||
|
|
||||||
System.Collections.IEnumerator WaitForWhitelist()
|
System.Collections.IEnumerator WaitForWhitelist()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.1.9", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.2.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||||
[assembly: MelonLoader.MelonPriority(2)]
|
[assembly: MelonLoader.MelonPriority(2)]
|
||||||
[assembly: MelonLoader.MelonAdditionalDependencies("BTKUILib")]
|
[assembly: MelonLoader.MelonAdditionalDependencies("BTKUILib")]
|
||||||
|
|
|
@ -4,7 +4,7 @@ This mod turns player's avatar into ragdoll puppet.
|
||||||
# Installation
|
# Installation
|
||||||
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
|
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
|
||||||
* Get [latest release DLL](../../../releases/latest):
|
* Get [latest release DLL](../../../releases/latest):
|
||||||
* Put `ml_prm.dll` in `Mods` folder of game
|
* Put `PlayerRagdollMod.dll` in `Mods` folder of game
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
* Press `R` to turn into ragdoll and back.
|
* Press `R` to turn into ragdoll and back.
|
||||||
|
@ -73,6 +73,8 @@ You can use this mod's functions within your mod. To do this you need:
|
||||||
Available methods:
|
Available methods:
|
||||||
* ```bool IsRagdolled()```
|
* ```bool IsRagdolled()```
|
||||||
* ```void SwitchRagdoll()```
|
* ```void SwitchRagdoll()```
|
||||||
|
* ```void Ragdoll()```
|
||||||
|
* ```void Unragdoll()```
|
||||||
|
|
||||||
# Notes
|
# Notes
|
||||||
* If ragdoll state is enabled during emote, remote players see whole emote playing while local player sees ragdolling. It's tied to how game handles remote players, currently can be prevented with (choose one):
|
* If ragdoll state is enabled during emote, remote players see whole emote playing while local player sees ragdolling. It's tied to how game handles remote players, currently can be prevented with (choose one):
|
||||||
|
|
|
@ -64,6 +64,8 @@ namespace ml_prm
|
||||||
m_rigidBody.mass = mass;
|
m_rigidBody.mass = mass;
|
||||||
m_physicsInfluencer.volume = mass * 0.005f;
|
m_physicsInfluencer.volume = mass * 0.005f;
|
||||||
m_physicsInfluencer.enableLocalGravity = true;
|
m_physicsInfluencer.enableLocalGravity = true;
|
||||||
|
|
||||||
|
this.gameObject.name = string.Format("{0} [NoGizmo]", this.gameObject.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(collider != null)
|
if(collider != null)
|
||||||
|
@ -109,11 +111,11 @@ namespace ml_prm
|
||||||
|
|
||||||
void OnTriggerEnter(Collider p_col)
|
void OnTriggerEnter(Collider p_col)
|
||||||
{
|
{
|
||||||
if(Settings.PointersReaction && (RagdollController.Instance != null))
|
if(Settings.PointersReaction && (RagdollController.Instance != null) && !RagdollController.Instance.IsRagdolled())
|
||||||
{
|
{
|
||||||
CVRPointer l_pointer = p_col.GetComponent<CVRPointer>();
|
CVRPointer l_pointer = p_col.GetComponent<CVRPointer>();
|
||||||
if((l_pointer != null) && (l_pointer.type == c_ragdollPointerType) && l_pointer.enabled && !IsIgnored(l_pointer.transform) && !RagdollController.Instance.IsRagdolled())
|
if((l_pointer != null) && (l_pointer.type == c_ragdollPointerType) && l_pointer.enabled && !IsIgnored(l_pointer.transform))
|
||||||
RagdollController.Instance.SwitchRagdoll();
|
RagdollController.Instance.Ragdoll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,15 +20,17 @@ namespace ml_prm
|
||||||
|
|
||||||
public static RagdollController Instance { get; private set; } = null;
|
public static RagdollController Instance { get; private set; } = null;
|
||||||
|
|
||||||
|
Transform m_avatarTransform = null;
|
||||||
|
Transform m_hips = null;
|
||||||
VRIK m_vrIK = null;
|
VRIK m_vrIK = null;
|
||||||
bool m_applyHipsPosition = false;
|
bool m_applyHipsPosition = false;
|
||||||
bool m_applyHipsRotation = false;
|
bool m_applyHipsRotation = false;
|
||||||
|
|
||||||
bool m_enabled = false;
|
bool m_ragdolled = false;
|
||||||
bool m_forcedSwitch = false;
|
bool m_forcedSwitch = false;
|
||||||
|
|
||||||
Transform m_puppetRoot = null;
|
|
||||||
Transform m_puppet = null;
|
Transform m_puppet = null;
|
||||||
|
Transform m_puppetRoot = null;
|
||||||
BipedRagdollReferences m_puppetReferences;
|
BipedRagdollReferences m_puppetReferences;
|
||||||
readonly List<RagdollBodypartHandler> m_ragdollBodyHandlers = null;
|
readonly List<RagdollBodypartHandler> m_ragdollBodyHandlers = null;
|
||||||
readonly List<System.Tuple<Transform, Transform>> m_boneLinks = null;
|
readonly List<System.Tuple<Transform, Transform>> m_boneLinks = null;
|
||||||
|
@ -36,21 +38,17 @@ namespace ml_prm
|
||||||
|
|
||||||
bool m_avatarReady = false;
|
bool m_avatarReady = false;
|
||||||
Coroutine m_initCoroutine = null;
|
Coroutine m_initCoroutine = null;
|
||||||
Vector3 m_lastPosition = Vector3.zero;
|
|
||||||
Vector3 m_velocity = Vector3.zero;
|
|
||||||
Vector3 m_ragdollLastPos = Vector3.zero;
|
Vector3 m_ragdollLastPos = Vector3.zero;
|
||||||
bool m_wasSwimming = false;
|
|
||||||
|
|
||||||
RagdollToggle m_avatarRagdollToggle = null; // Custom component available for editor
|
RagdollToggle m_avatarRagdollToggle = null; // Custom component available for editor
|
||||||
AvatarBoolParameter m_ragdolledParameter = null;
|
AvatarBoolParameter m_ragdolledParameter = null;
|
||||||
PhysicMaterial m_physicsMaterial = null;
|
PhysicMaterial m_physicsMaterial = null;
|
||||||
|
|
||||||
|
bool m_inAir = false;
|
||||||
bool m_reachedGround = true;
|
bool m_reachedGround = true;
|
||||||
float m_groundedTime = 0f;
|
float m_groundedTime = 0f;
|
||||||
float m_downTime = float.MinValue;
|
float m_downTime = float.MinValue;
|
||||||
|
|
||||||
bool m_inAir = false;
|
|
||||||
|
|
||||||
internal RagdollController()
|
internal RagdollController()
|
||||||
{
|
{
|
||||||
m_ragdollBodyHandlers = new List<RagdollBodypartHandler>();
|
m_ragdollBodyHandlers = new List<RagdollBodypartHandler>();
|
||||||
|
@ -69,6 +67,8 @@ namespace ml_prm
|
||||||
|
|
||||||
void Start()
|
void Start()
|
||||||
{
|
{
|
||||||
|
this.gameObject.layer = LayerMask.NameToLayer("PlayerLocal");
|
||||||
|
|
||||||
m_physicsMaterial = new PhysicMaterial("Ragdoll");
|
m_physicsMaterial = new PhysicMaterial("Ragdoll");
|
||||||
m_physicsMaterial.dynamicFriction = c_defaultFriction;
|
m_physicsMaterial.dynamicFriction = c_defaultFriction;
|
||||||
m_physicsMaterial.staticFriction = c_defaultFriction;
|
m_physicsMaterial.staticFriction = c_defaultFriction;
|
||||||
|
@ -76,10 +76,10 @@ namespace ml_prm
|
||||||
m_physicsMaterial.bounciness = 0f;
|
m_physicsMaterial.bounciness = 0f;
|
||||||
m_physicsMaterial.bounceCombine = PhysicMaterialCombine.Average;
|
m_physicsMaterial.bounceCombine = PhysicMaterialCombine.Average;
|
||||||
|
|
||||||
m_puppetRoot = new GameObject("[PlayerAvatarPuppet]").transform;
|
m_puppet = new GameObject("[Puppet]").transform;
|
||||||
m_puppetRoot.parent = PlayerSetup.Instance.transform;
|
m_puppet.parent = this.transform;
|
||||||
m_puppetRoot.localPosition = Vector3.zero;
|
m_puppet.localPosition = Vector3.zero;
|
||||||
m_puppetRoot.localRotation = Quaternion.identity;
|
m_puppet.localRotation = Quaternion.identity;
|
||||||
|
|
||||||
Settings.OnMovementDragChanged.AddListener(this.OnMovementDragChanged);
|
Settings.OnMovementDragChanged.AddListener(this.OnMovementDragChanged);
|
||||||
Settings.OnAngularDragChanged.AddListener(this.OnAngularDragChanged);
|
Settings.OnAngularDragChanged.AddListener(this.OnAngularDragChanged);
|
||||||
|
@ -104,7 +104,7 @@ namespace ml_prm
|
||||||
BetterBetterCharacterController.OnTeleport.AddListener(this.OnPlayerTeleport);
|
BetterBetterCharacterController.OnTeleport.AddListener(this.OnPlayerTeleport);
|
||||||
|
|
||||||
ModUi.OnSwitchChanged.AddListener(this.SwitchRagdoll);
|
ModUi.OnSwitchChanged.AddListener(this.SwitchRagdoll);
|
||||||
RemoteGestureHandler.OnGestureState.AddListener(this.OnRemotePlayerGestureStateChanged);
|
RemoteGesturesManager.OnGestureState.AddListener(this.OnRemoteGestureStateChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnDestroy()
|
void OnDestroy()
|
||||||
|
@ -116,11 +116,11 @@ namespace ml_prm
|
||||||
StopCoroutine(m_initCoroutine);
|
StopCoroutine(m_initCoroutine);
|
||||||
m_initCoroutine = null;
|
m_initCoroutine = null;
|
||||||
|
|
||||||
if(m_puppetRoot != null)
|
if(m_puppet != null)
|
||||||
Object.Destroy(m_puppetRoot);
|
Object.Destroy(m_puppet);
|
||||||
m_puppetRoot = null;
|
|
||||||
|
|
||||||
m_puppet = null;
|
m_puppet = null;
|
||||||
|
|
||||||
|
m_puppetRoot = null;
|
||||||
m_ragdollBodyHandlers.Clear();
|
m_ragdollBodyHandlers.Clear();
|
||||||
m_boneLinks.Clear();
|
m_boneLinks.Clear();
|
||||||
m_jointAnchors.Clear();
|
m_jointAnchors.Clear();
|
||||||
|
@ -153,70 +153,66 @@ namespace ml_prm
|
||||||
BetterBetterCharacterController.OnTeleport.RemoveListener(this.OnPlayerTeleport);
|
BetterBetterCharacterController.OnTeleport.RemoveListener(this.OnPlayerTeleport);
|
||||||
|
|
||||||
ModUi.OnSwitchChanged.RemoveListener(this.SwitchRagdoll);
|
ModUi.OnSwitchChanged.RemoveListener(this.SwitchRagdoll);
|
||||||
RemoteGestureHandler.OnGestureState.RemoveListener(this.OnRemotePlayerGestureStateChanged);
|
RemoteGesturesManager.OnGestureState.RemoveListener(this.OnRemoteGestureStateChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update()
|
void Update()
|
||||||
{
|
{
|
||||||
if(m_avatarReady && !m_enabled && Settings.FallDamage && !BetterBetterCharacterController.Instance.IsFlying())
|
if(m_avatarReady)
|
||||||
{
|
{
|
||||||
bool l_grounded = BetterBetterCharacterController.Instance.IsGrounded();
|
if(!m_ragdolled && Settings.FallDamage && !BetterBetterCharacterController.Instance.IsFlying())
|
||||||
bool l_inWater = BetterBetterCharacterController.Instance.IsInWater();
|
|
||||||
if(m_inAir && l_grounded && !l_inWater && (m_velocity.magnitude >= Settings.FallLimit))
|
|
||||||
SwitchRagdoll();
|
|
||||||
|
|
||||||
m_inAir = !(l_grounded || l_inWater);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(m_avatarReady && m_enabled)
|
|
||||||
{
|
|
||||||
BodySystem.TrackingPositionWeight = 0f;
|
|
||||||
BetterBetterCharacterController.Instance.PauseGroundConstraint();
|
|
||||||
BetterBetterCharacterController.Instance.ResetAllForces();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(m_avatarReady && !m_enabled)
|
|
||||||
{
|
|
||||||
Vector3 l_pos = PlayerSetup.Instance.transform.position;
|
|
||||||
m_velocity = (m_velocity + (l_pos - m_lastPosition) / Time.deltaTime) * 0.5f;
|
|
||||||
m_lastPosition = l_pos;
|
|
||||||
|
|
||||||
if(!m_reachedGround && BetterBetterCharacterController.Instance.IsOnGround())
|
|
||||||
{
|
{
|
||||||
m_groundedTime += Time.deltaTime;
|
bool l_grounded = BetterBetterCharacterController.Instance.IsGrounded();
|
||||||
|
bool l_inWater = BetterBetterCharacterController.Instance.IsInWater();
|
||||||
|
if(m_inAir && l_grounded && !l_inWater && (BetterBetterCharacterController.Instance.characterMovement.landedVelocity.magnitude >= Settings.FallLimit))
|
||||||
|
Ragdoll();
|
||||||
|
|
||||||
|
m_inAir = !(l_grounded || l_inWater);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_ragdolled)
|
||||||
|
{
|
||||||
|
BodySystem.TrackingPositionWeight = 0f;
|
||||||
|
BetterBetterCharacterController.Instance.PauseGroundConstraint();
|
||||||
|
BetterBetterCharacterController.Instance.ResetAllForces();
|
||||||
|
PlayerSetup.Instance.animatorManager.CancelEmote = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!m_ragdolled && !m_reachedGround && (BetterBetterCharacterController.Instance.IsOnGround() || BetterBetterCharacterController.Instance.IsInWater()))
|
||||||
|
{
|
||||||
|
m_groundedTime += Time.unscaledDeltaTime;
|
||||||
if(m_groundedTime >= 0.25f)
|
if(m_groundedTime >= 0.25f)
|
||||||
m_reachedGround = true;
|
m_reachedGround = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if(m_avatarReady && m_enabled && Settings.AutoRecover)
|
if(m_ragdolled && Settings.AutoRecover)
|
||||||
{
|
|
||||||
m_downTime += Time.deltaTime;
|
|
||||||
if(m_downTime >= Settings.RecoverDelay)
|
|
||||||
{
|
{
|
||||||
SwitchRagdoll();
|
m_downTime += Time.unscaledDeltaTime;
|
||||||
m_downTime = float.MinValue; // One attempt to recover
|
if(m_downTime >= Settings.RecoverDelay)
|
||||||
|
{
|
||||||
|
Unragdoll();
|
||||||
|
m_downTime = float.MinValue; // One attempt to recover
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if((m_avatarRagdollToggle != null) && m_avatarRagdollToggle.isActiveAndEnabled && m_avatarRagdollToggle.shouldOverride && (m_ragdolled != m_avatarRagdollToggle.isOn))
|
||||||
|
SwitchRagdoll();
|
||||||
|
|
||||||
|
if(Settings.Hotkey && Input.GetKeyDown(Settings.HotkeyKey) && !ViewManager.Instance.IsAnyMenuOpen)
|
||||||
|
SwitchRagdoll();
|
||||||
|
|
||||||
|
if(m_ragdolled && CVRInputManager.Instance.jump && Settings.JumpRecover)
|
||||||
|
Unragdoll();
|
||||||
}
|
}
|
||||||
|
|
||||||
if((m_avatarRagdollToggle != null) && m_avatarRagdollToggle.isActiveAndEnabled && m_avatarRagdollToggle.shouldOverride && (m_enabled != m_avatarRagdollToggle.isOn))
|
|
||||||
SwitchRagdoll();
|
|
||||||
|
|
||||||
if(Settings.Hotkey && Input.GetKeyDown(Settings.HotkeyKey) && !ViewManager.Instance.IsAnyMenuOpen)
|
|
||||||
SwitchRagdoll();
|
|
||||||
|
|
||||||
if(m_avatarReady && m_enabled && CVRInputManager.Instance.jump && Settings.JumpRecover)
|
|
||||||
SwitchRagdoll();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FixedUpdate()
|
void FixedUpdate()
|
||||||
{
|
{
|
||||||
if(m_avatarReady && m_enabled)
|
if(m_avatarReady && m_ragdolled)
|
||||||
{
|
{
|
||||||
Vector3 l_dif = m_puppetReferences.hips.position - m_ragdollLastPos;
|
Vector3 l_currentPos = m_puppetReferences.hips.position;
|
||||||
PlayerSetup.Instance.transform.position += l_dif;
|
PlayerSetup.Instance.transform.position += (l_currentPos - m_ragdollLastPos);
|
||||||
m_puppetReferences.hips.position -= l_dif;
|
m_ragdollLastPos = l_currentPos;
|
||||||
m_ragdollLastPos = m_puppetReferences.hips.position;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,15 +220,21 @@ namespace ml_prm
|
||||||
{
|
{
|
||||||
if(m_avatarReady)
|
if(m_avatarReady)
|
||||||
{
|
{
|
||||||
if(m_enabled)
|
if(m_ragdolled)
|
||||||
{
|
{
|
||||||
foreach(var l_link in m_boneLinks)
|
foreach(var l_link in m_boneLinks)
|
||||||
l_link.Item1.CopyGlobal(l_link.Item2);
|
l_link.Item1.CopyGlobal(l_link.Item2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach(var l_link in m_boneLinks)
|
if(m_vrIK == null)
|
||||||
l_link.Item2.CopyGlobal(l_link.Item1);
|
{
|
||||||
|
m_puppetRoot.position = m_avatarTransform.position;
|
||||||
|
m_puppetRoot.rotation = m_avatarTransform.rotation;
|
||||||
|
|
||||||
|
foreach(var l_link in m_boneLinks)
|
||||||
|
l_link.Item2.CopyGlobal(l_link.Item1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -246,19 +248,21 @@ namespace ml_prm
|
||||||
m_initCoroutine = null;
|
m_initCoroutine = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_enabled)
|
if(m_ragdolled)
|
||||||
{
|
{
|
||||||
TryRestoreMovement();
|
TryRestoreMovement();
|
||||||
BodySystem.TrackingPositionWeight = 1f;
|
BodySystem.TrackingPositionWeight = 1f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_puppet != null)
|
if(m_puppetRoot != null)
|
||||||
Object.Destroy(m_puppet.gameObject);
|
Object.Destroy(m_puppetRoot.gameObject);
|
||||||
m_puppet = null;
|
m_puppetRoot = null;
|
||||||
|
|
||||||
|
m_avatarTransform = null;
|
||||||
|
m_hips = null;
|
||||||
m_vrIK = null;
|
m_vrIK = null;
|
||||||
m_applyHipsPosition = false;
|
m_applyHipsPosition = false;
|
||||||
m_enabled = false;
|
m_ragdolled = false;
|
||||||
m_avatarReady = false;
|
m_avatarReady = false;
|
||||||
m_avatarRagdollToggle = null;
|
m_avatarRagdollToggle = null;
|
||||||
m_ragdolledParameter = null;
|
m_ragdolledParameter = null;
|
||||||
|
@ -269,25 +273,26 @@ namespace ml_prm
|
||||||
m_reachedGround = true;
|
m_reachedGround = true;
|
||||||
m_groundedTime = 0f;
|
m_groundedTime = 0f;
|
||||||
m_downTime = float.MinValue;
|
m_downTime = float.MinValue;
|
||||||
m_puppetRoot.localScale = Vector3.one;
|
m_puppet.localScale = Vector3.one;
|
||||||
m_inAir = false;
|
m_inAir = false;
|
||||||
m_wasSwimming = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnAvatarSetup()
|
void OnAvatarSetup()
|
||||||
{
|
{
|
||||||
if(PlayerSetup.Instance._animator.isHuman)
|
if(PlayerSetup.Instance._animator.isHuman)
|
||||||
{
|
{
|
||||||
|
m_avatarTransform = PlayerSetup.Instance._avatar.transform;
|
||||||
|
m_hips = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Hips);
|
||||||
Utils.SetAvatarTPose();
|
Utils.SetAvatarTPose();
|
||||||
|
|
||||||
BipedRagdollReferences l_avatarReferences = BipedRagdollReferences.FromAvatar(PlayerSetup.Instance._animator);
|
BipedRagdollReferences l_avatarReferences = BipedRagdollReferences.FromAvatar(PlayerSetup.Instance._animator);
|
||||||
|
|
||||||
m_puppet = new GameObject("Root").transform;
|
m_puppetRoot = new GameObject("Root").transform;
|
||||||
m_puppet.parent = m_puppetRoot;
|
m_puppetRoot.parent = m_puppet;
|
||||||
m_puppet.localPosition = Vector3.zero;
|
m_puppetRoot.position = m_avatarTransform.position;
|
||||||
m_puppet.localRotation = Quaternion.identity;
|
m_puppetRoot.rotation = m_avatarTransform.rotation;
|
||||||
|
|
||||||
m_puppetReferences.root = m_puppet;
|
m_puppetReferences.root = m_puppetRoot;
|
||||||
m_puppetReferences.hips = CloneTransform(l_avatarReferences.hips, m_puppetReferences.root, "Hips");
|
m_puppetReferences.hips = CloneTransform(l_avatarReferences.hips, m_puppetReferences.root, "Hips");
|
||||||
m_puppetReferences.spine = CloneTransform(l_avatarReferences.spine, m_puppetReferences.hips, "Spine");
|
m_puppetReferences.spine = CloneTransform(l_avatarReferences.spine, m_puppetReferences.hips, "Spine");
|
||||||
|
|
||||||
|
@ -312,7 +317,7 @@ namespace ml_prm
|
||||||
m_puppetReferences.rightLowerLeg = CloneTransform(l_avatarReferences.rightLowerLeg, m_puppetReferences.rightUpperLeg, "RightLowerLeg");
|
m_puppetReferences.rightLowerLeg = CloneTransform(l_avatarReferences.rightLowerLeg, m_puppetReferences.rightUpperLeg, "RightLowerLeg");
|
||||||
m_puppetReferences.rightFoot = CloneTransform(l_avatarReferences.rightFoot, m_puppetReferences.rightLowerLeg, "RightFoot");
|
m_puppetReferences.rightFoot = CloneTransform(l_avatarReferences.rightFoot, m_puppetReferences.rightLowerLeg, "RightFoot");
|
||||||
|
|
||||||
// Move to world origin to overcome possible issues, maybe?
|
// Move to world origin to overcome possible issues
|
||||||
m_puppetRoot.position = Vector3.zero;
|
m_puppetRoot.position = Vector3.zero;
|
||||||
m_puppetRoot.rotation = Quaternion.identity;
|
m_puppetRoot.rotation = Quaternion.identity;
|
||||||
|
|
||||||
|
@ -350,8 +355,8 @@ namespace ml_prm
|
||||||
}
|
}
|
||||||
|
|
||||||
// And return back
|
// And return back
|
||||||
m_puppetRoot.localPosition = Vector3.zero;
|
m_puppetRoot.position = m_avatarTransform.position;
|
||||||
m_puppetRoot.localRotation = Quaternion.identity;
|
m_puppetRoot.rotation = m_avatarTransform.rotation;
|
||||||
|
|
||||||
m_vrIK = PlayerSetup.Instance._avatar.GetComponent<VRIK>();
|
m_vrIK = PlayerSetup.Instance._avatar.GetComponent<VRIK>();
|
||||||
if(m_vrIK != null)
|
if(m_vrIK != null)
|
||||||
|
@ -386,12 +391,9 @@ namespace ml_prm
|
||||||
|
|
||||||
void OnAvatarPreReuse()
|
void OnAvatarPreReuse()
|
||||||
{
|
{
|
||||||
if(m_avatarReady && m_enabled)
|
m_forcedSwitch = true;
|
||||||
{
|
Unragdoll();
|
||||||
m_forcedSwitch = true;
|
m_forcedSwitch = false;
|
||||||
SwitchRagdoll();
|
|
||||||
m_forcedSwitch = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
void OnAvatarPostReuse()
|
void OnAvatarPostReuse()
|
||||||
{
|
{
|
||||||
|
@ -412,32 +414,27 @@ namespace ml_prm
|
||||||
|
|
||||||
void OnSeatPreSit(CVRSeat p_seat)
|
void OnSeatPreSit(CVRSeat p_seat)
|
||||||
{
|
{
|
||||||
if(m_avatarReady && m_enabled && !p_seat.occupied)
|
if(!p_seat.occupied)
|
||||||
{
|
{
|
||||||
m_forcedSwitch = true;
|
m_forcedSwitch = true;
|
||||||
SwitchRagdoll();
|
Unragdoll();
|
||||||
m_forcedSwitch = false;
|
m_forcedSwitch = false;
|
||||||
ResetStates();
|
m_inAir = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnCalibrationStart()
|
void OnCalibrationStart()
|
||||||
{
|
{
|
||||||
if(m_avatarReady && m_enabled)
|
m_forcedSwitch = true;
|
||||||
{
|
Unragdoll();
|
||||||
m_forcedSwitch = true;
|
m_forcedSwitch = false;
|
||||||
SwitchRagdoll();
|
m_inAir = false;
|
||||||
m_forcedSwitch = false;
|
|
||||||
ResetStates();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnWorldPreSpawn()
|
void OnWorldPreSpawn()
|
||||||
{
|
{
|
||||||
if(m_avatarReady && m_enabled)
|
Unragdoll();
|
||||||
SwitchRagdoll();
|
m_inAir = false;
|
||||||
|
|
||||||
ResetStates();
|
|
||||||
|
|
||||||
OnGravityChanged(Settings.Gravity);
|
OnGravityChanged(Settings.Gravity);
|
||||||
OnPhysicsMaterialChanged(true);
|
OnPhysicsMaterialChanged(true);
|
||||||
|
@ -447,25 +444,24 @@ namespace ml_prm
|
||||||
|
|
||||||
void OnCombatPreDown()
|
void OnCombatPreDown()
|
||||||
{
|
{
|
||||||
if(m_avatarReady && !m_enabled && CombatSystem.Instance.isDown && Settings.CombatReaction)
|
if(CombatSystem.Instance.isDown && Settings.CombatReaction)
|
||||||
{
|
{
|
||||||
m_reachedGround = true;
|
m_reachedGround = true;
|
||||||
m_forcedSwitch = true;
|
m_forcedSwitch = true;
|
||||||
SwitchRagdoll();
|
Ragdoll();
|
||||||
m_forcedSwitch = false;
|
m_forcedSwitch = false;
|
||||||
ResetStates(false);
|
m_inAir = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnFlightChange()
|
void OnFlightChange()
|
||||||
{
|
{
|
||||||
if(m_avatarReady && m_enabled && BetterBetterCharacterController.Instance.IsFlying())
|
if(BetterBetterCharacterController.Instance.IsFlying())
|
||||||
{
|
{
|
||||||
m_forcedSwitch = true;
|
m_forcedSwitch = true;
|
||||||
SwitchRagdoll();
|
Unragdoll();
|
||||||
m_forcedSwitch = false;
|
m_forcedSwitch = false;
|
||||||
|
m_inAir = false;
|
||||||
ResetStates(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,10 +469,14 @@ namespace ml_prm
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ResetStates();
|
m_inAir = false;
|
||||||
|
|
||||||
if(m_avatarReady && m_enabled)
|
if(m_avatarReady && m_ragdolled)
|
||||||
m_ragdollLastPos = m_puppetReferences.hips.position;
|
{
|
||||||
|
Vector3 l_pos = m_hips.position;
|
||||||
|
m_puppetReferences.hips.position = l_pos;
|
||||||
|
m_ragdollLastPos = l_pos;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(System.Exception e)
|
catch(System.Exception e)
|
||||||
{
|
{
|
||||||
|
@ -486,26 +486,20 @@ namespace ml_prm
|
||||||
|
|
||||||
void OnIKOffsetUpdate(GameEvents.EventResult p_result)
|
void OnIKOffsetUpdate(GameEvents.EventResult p_result)
|
||||||
{
|
{
|
||||||
p_result.m_result |= (m_enabled && (m_vrIK != null));
|
p_result.m_result |= (m_ragdolled && (m_vrIK != null));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom game events
|
// Custom game events
|
||||||
void OnRemotePlayerGestureStateChanged(ABI_RC.Core.Player.PuppetMaster p_master, bool p_left, bool p_state)
|
void OnRemoteGestureStateChanged(ABI_RC.Core.Player.PuppetMaster p_master, RemoteGesturesManager.GestureHand p_hand, bool p_state)
|
||||||
{
|
{
|
||||||
if(m_avatarReady && m_enabled && Settings.GestureGrab && (p_master.animatorManager.Animator != null))
|
if(m_avatarReady && m_ragdolled && Settings.GestureGrab && (p_master.animatorManager.Animator != null))
|
||||||
{
|
{
|
||||||
Transform l_hand = p_master.animatorManager.Animator.GetBoneTransform(p_left ? HumanBodyBones.LeftHand : HumanBodyBones.RightHand);
|
Transform l_hand = p_master.animatorManager.Animator.GetBoneTransform((p_hand == RemoteGesturesManager.GestureHand.Left) ? HumanBodyBones.LeftHand : HumanBodyBones.RightHand);
|
||||||
Transform l_finger = p_master.animatorManager.Animator.GetBoneTransform(p_left ? HumanBodyBones.LeftMiddleProximal : HumanBodyBones.RightMiddleProximal);
|
Transform l_finger = p_master.animatorManager.Animator.GetBoneTransform((p_hand == RemoteGesturesManager.GestureHand.Left) ? HumanBodyBones.LeftMiddleProximal : HumanBodyBones.RightMiddleProximal);
|
||||||
|
|
||||||
if(l_hand != null)
|
if(l_hand != null)
|
||||||
{
|
{
|
||||||
Vector3 l_pos = l_hand.position;
|
Vector3 l_pos = (l_finger != null) ? ((l_hand.position + l_finger.position) * 0.5f) : l_hand.position;
|
||||||
if(l_finger != null)
|
|
||||||
{
|
|
||||||
l_pos += l_finger.position;
|
|
||||||
l_pos *= 0.5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach(var l_bodyHandler in m_ragdollBodyHandlers)
|
foreach(var l_bodyHandler in m_ragdollBodyHandlers)
|
||||||
{
|
{
|
||||||
if(p_state)
|
if(p_state)
|
||||||
|
@ -523,8 +517,11 @@ namespace ml_prm
|
||||||
// VRIK updates
|
// VRIK updates
|
||||||
void OnIKPostSolverUpdate()
|
void OnIKPostSolverUpdate()
|
||||||
{
|
{
|
||||||
if(!m_enabled)
|
if(!m_ragdolled)
|
||||||
{
|
{
|
||||||
|
m_puppetRoot.position = m_avatarTransform.position;
|
||||||
|
m_puppetRoot.rotation = m_avatarTransform.rotation;
|
||||||
|
|
||||||
foreach(var l_link in m_boneLinks)
|
foreach(var l_link in m_boneLinks)
|
||||||
l_link.Item2.CopyGlobal(l_link.Item1);
|
l_link.Item2.CopyGlobal(l_link.Item1);
|
||||||
}
|
}
|
||||||
|
@ -535,7 +532,7 @@ namespace ml_prm
|
||||||
{
|
{
|
||||||
if(m_avatarReady)
|
if(m_avatarReady)
|
||||||
{
|
{
|
||||||
float l_drag = (WorldHandler.IsSafeWorld() ? p_value : 1f);
|
float l_drag = (WorldManager.IsSafeWorld() ? p_value : 1f);
|
||||||
foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
|
foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
|
||||||
l_handler.SetDrag(l_drag);
|
l_handler.SetDrag(l_drag);
|
||||||
}
|
}
|
||||||
|
@ -554,7 +551,7 @@ namespace ml_prm
|
||||||
{
|
{
|
||||||
if(m_avatarReady)
|
if(m_avatarReady)
|
||||||
{
|
{
|
||||||
bool l_gravity = (!WorldHandler.IsSafeWorld() || p_state);
|
bool l_gravity = (!WorldManager.IsSafeWorld() || p_state);
|
||||||
foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
|
foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
|
||||||
l_handler.SetActiveGravity(l_gravity);
|
l_handler.SetActiveGravity(l_gravity);
|
||||||
|
|
||||||
|
@ -570,8 +567,8 @@ namespace ml_prm
|
||||||
{
|
{
|
||||||
if(m_physicsMaterial != null)
|
if(m_physicsMaterial != null)
|
||||||
{
|
{
|
||||||
bool l_slipperiness = (Settings.Slipperiness && WorldHandler.IsSafeWorld());
|
bool l_slipperiness = (Settings.Slipperiness && WorldManager.IsSafeWorld());
|
||||||
bool l_bounciness = (Settings.Bounciness && WorldHandler.IsSafeWorld());
|
bool l_bounciness = (Settings.Bounciness && WorldManager.IsSafeWorld());
|
||||||
m_physicsMaterial.dynamicFriction = (l_slipperiness ? 0f : c_defaultFriction);
|
m_physicsMaterial.dynamicFriction = (l_slipperiness ? 0f : c_defaultFriction);
|
||||||
m_physicsMaterial.staticFriction = (l_slipperiness ? 0f : c_defaultFriction);
|
m_physicsMaterial.staticFriction = (l_slipperiness ? 0f : c_defaultFriction);
|
||||||
m_physicsMaterial.frictionCombine = (l_slipperiness ? PhysicMaterialCombine.Minimum : PhysicMaterialCombine.Average);
|
m_physicsMaterial.frictionCombine = (l_slipperiness ? PhysicMaterialCombine.Minimum : PhysicMaterialCombine.Average);
|
||||||
|
@ -584,7 +581,7 @@ namespace ml_prm
|
||||||
{
|
{
|
||||||
if(m_avatarReady)
|
if(m_avatarReady)
|
||||||
{
|
{
|
||||||
bool l_buoyancy = (!WorldHandler.IsSafeWorld() || p_state);
|
bool l_buoyancy = (!WorldManager.IsSafeWorld() || p_state);
|
||||||
foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
|
foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
|
||||||
l_handler.SetBuoyancy(l_buoyancy);
|
l_handler.SetBuoyancy(l_buoyancy);
|
||||||
|
|
||||||
|
@ -603,7 +600,7 @@ namespace ml_prm
|
||||||
|
|
||||||
void OnGestureGrabChanged(bool p_state)
|
void OnGestureGrabChanged(bool p_state)
|
||||||
{
|
{
|
||||||
if(m_avatarReady && m_enabled & !p_state)
|
if(m_avatarReady && m_ragdolled & !p_state)
|
||||||
{
|
{
|
||||||
foreach(var l_hanlder in m_ragdollBodyHandlers)
|
foreach(var l_hanlder in m_ragdollBodyHandlers)
|
||||||
l_hanlder.Detach();
|
l_hanlder.Detach();
|
||||||
|
@ -611,122 +608,106 @@ namespace ml_prm
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arbitrary
|
// Arbitrary
|
||||||
|
public bool IsRagdolled() => (m_avatarReady && m_ragdolled);
|
||||||
|
|
||||||
public void SwitchRagdoll()
|
public void SwitchRagdoll()
|
||||||
{
|
{
|
||||||
if(m_avatarReady)
|
if(m_ragdolled)
|
||||||
|
Unragdoll();
|
||||||
|
else
|
||||||
|
Ragdoll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Ragdoll()
|
||||||
|
{
|
||||||
|
if(m_avatarReady && !m_ragdolled && CanRagdoll())
|
||||||
{
|
{
|
||||||
if(!m_enabled)
|
Vector3 l_velocity = Vector3.ClampMagnitude(BetterBetterCharacterController.Instance.velocity * (WorldManager.IsSafeWorld() ? Settings.VelocityMultiplier : 1f), WorldManager.GetMovementLimit());
|
||||||
|
if(Settings.ViewVelocity && WorldManager.IsSafeWorld())
|
||||||
{
|
{
|
||||||
if(CanRagdoll())
|
float l_mag = l_velocity.magnitude;
|
||||||
{
|
l_velocity = PlayerSetup.Instance.GetActiveCamera().transform.forward * l_mag;
|
||||||
m_wasSwimming = BetterBetterCharacterController.Instance.IsSwimming();
|
|
||||||
|
|
||||||
if(BetterBetterCharacterController.Instance.IsFlying())
|
|
||||||
BetterBetterCharacterController.Instance.ChangeFlight(false, true);
|
|
||||||
BetterBetterCharacterController.Instance.SetImmobilized(true);
|
|
||||||
BetterBetterCharacterController.Instance.ClearFluidVolumes();
|
|
||||||
BetterBetterCharacterController.Instance.ResetAllForces();
|
|
||||||
BetterBetterCharacterController.Instance.PauseGroundConstraint();
|
|
||||||
BodySystem.TrackingPositionWeight = 0f;
|
|
||||||
m_applyHipsPosition = IKSystem.Instance.applyOriginalHipPosition;
|
|
||||||
IKSystem.Instance.applyOriginalHipPosition = true;
|
|
||||||
m_applyHipsRotation = IKSystem.Instance.applyOriginalHipRotation;
|
|
||||||
IKSystem.Instance.applyOriginalHipRotation = true;
|
|
||||||
|
|
||||||
PlayerSetup.Instance.animatorManager.CancelEmote = true;
|
|
||||||
m_ragdolledParameter.SetValue(true);
|
|
||||||
|
|
||||||
if(!WorldHandler.IsSafeWorld())
|
|
||||||
{
|
|
||||||
m_reachedGround = false; // Force player to unragdoll and reach ground first
|
|
||||||
m_groundedTime = 0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
|
|
||||||
l_handler.SetAsKinematic(false);
|
|
||||||
|
|
||||||
m_puppetRoot.gameObject.SetActive(false); //
|
|
||||||
m_puppetRoot.gameObject.SetActive(true); // Resets rigidbodies and joints inner physics states
|
|
||||||
|
|
||||||
Vector3 l_velocity = Vector3.ClampMagnitude(m_velocity * (WorldHandler.IsSafeWorld() ? Settings.VelocityMultiplier : 1f), WorldHandler.GetMovementLimit());
|
|
||||||
if(Settings.ViewVelocity && WorldHandler.IsSafeWorld())
|
|
||||||
{
|
|
||||||
float l_mag = l_velocity.magnitude;
|
|
||||||
l_velocity = PlayerSetup.Instance.GetActiveCamera().transform.forward * l_mag;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
|
|
||||||
{
|
|
||||||
l_handler.SetVelocity(l_velocity);
|
|
||||||
l_handler.SetAngularVelocity(Vector3.zero);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_ragdollLastPos = m_puppetReferences.hips.position;
|
|
||||||
m_downTime = 0f;
|
|
||||||
|
|
||||||
m_enabled = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if(BetterBetterCharacterController.Instance.IsFlying())
|
||||||
|
BetterBetterCharacterController.Instance.ChangeFlight(false, true);
|
||||||
|
BetterBetterCharacterController.Instance.SetImmobilized(true);
|
||||||
|
BetterBetterCharacterController.Instance.ClearFluidVolumes();
|
||||||
|
BetterBetterCharacterController.Instance.ResetAllForces();
|
||||||
|
BetterBetterCharacterController.Instance.PauseGroundConstraint();
|
||||||
|
BodySystem.TrackingPositionWeight = 0f;
|
||||||
|
m_applyHipsPosition = IKSystem.Instance.applyOriginalHipPosition;
|
||||||
|
IKSystem.Instance.applyOriginalHipPosition = true;
|
||||||
|
m_applyHipsRotation = IKSystem.Instance.applyOriginalHipRotation;
|
||||||
|
IKSystem.Instance.applyOriginalHipRotation = true;
|
||||||
|
|
||||||
|
PlayerSetup.Instance.animatorManager.CancelEmote = true;
|
||||||
|
m_ragdolledParameter.SetValue(true);
|
||||||
|
|
||||||
|
if(!WorldManager.IsSafeWorld())
|
||||||
{
|
{
|
||||||
if(CanUnragdoll())
|
m_reachedGround = false; // Force player to unragdoll and reach ground first
|
||||||
{
|
m_groundedTime = 0f;
|
||||||
BetterBetterCharacterController.Instance.TeleportPlayerTo(m_puppetReferences.hips.position, PlayerSetup.Instance.GetPlayerRotation().eulerAngles, false, false);
|
|
||||||
TryRestoreMovement();
|
|
||||||
if(!WorldHandler.IsSafeWorld())
|
|
||||||
{
|
|
||||||
Vector3 l_vec = BetterBetterCharacterController.Instance.GetVelocity();
|
|
||||||
l_vec.y = Mathf.Clamp(l_vec.y, float.MinValue, 0f);
|
|
||||||
BetterBetterCharacterController.Instance.SetVelocity(l_vec);
|
|
||||||
}
|
|
||||||
BodySystem.TrackingPositionWeight = 1f;
|
|
||||||
IKSystem.Instance.applyOriginalHipPosition = m_applyHipsPosition;
|
|
||||||
IKSystem.Instance.applyOriginalHipRotation = m_applyHipsRotation;
|
|
||||||
|
|
||||||
if(m_vrIK != null)
|
|
||||||
m_vrIK.solver.Reset();
|
|
||||||
|
|
||||||
m_ragdolledParameter.SetValue(false);
|
|
||||||
|
|
||||||
m_puppetRoot.localPosition = Vector3.zero;
|
|
||||||
m_puppetRoot.localRotation = Quaternion.identity;
|
|
||||||
|
|
||||||
foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
|
|
||||||
{
|
|
||||||
l_handler.Detach();
|
|
||||||
l_handler.ClearFluidVolumes();
|
|
||||||
l_handler.SetAsKinematic(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_lastPosition = PlayerSetup.Instance.transform.position;
|
|
||||||
m_velocity = Vector3.zero;
|
|
||||||
m_downTime = float.MinValue;
|
|
||||||
|
|
||||||
// Restore rigidbody properties that could be affected by buoyancy
|
|
||||||
OnMovementDragChanged(Settings.MovementDrag);
|
|
||||||
OnAngularDragChanged(Settings.AngularDrag);
|
|
||||||
|
|
||||||
// Restore movement if was ragdolled in water and left it
|
|
||||||
if(m_wasSwimming)
|
|
||||||
BetterBetterCharacterController.Instance.SetMovementMode(ECM2.Character.MovementMode.Swimming);
|
|
||||||
|
|
||||||
m_enabled = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
|
||||||
|
l_handler.SetAsKinematic(false);
|
||||||
|
|
||||||
|
m_puppet.gameObject.SetActive(false); //
|
||||||
|
m_puppet.gameObject.SetActive(true); // Resets rigidbodies and joints inner physics states
|
||||||
|
|
||||||
|
foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
|
||||||
|
{
|
||||||
|
l_handler.SetVelocity(l_velocity);
|
||||||
|
l_handler.SetAngularVelocity(Vector3.zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ragdollLastPos = m_puppetReferences.hips.position;
|
||||||
|
m_downTime = 0f;
|
||||||
|
|
||||||
|
m_ragdolled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsRagdolled() => (m_avatarReady && m_enabled);
|
public void Unragdoll()
|
||||||
|
|
||||||
void ResetStates(bool p_resetVelocity = true)
|
|
||||||
{
|
{
|
||||||
if(p_resetVelocity)
|
if(m_avatarReady && m_ragdolled && CanUnragdoll())
|
||||||
{
|
{
|
||||||
m_lastPosition = this.transform.position;
|
BetterBetterCharacterController.Instance.TeleportPlayerTo(m_puppetReferences.hips.position, PlayerSetup.Instance.GetPlayerRotation().eulerAngles, false, false);
|
||||||
m_velocity = Vector3.zero;
|
TryRestoreMovement();
|
||||||
}
|
if(!WorldManager.IsSafeWorld())
|
||||||
|
{
|
||||||
|
Vector3 l_vec = BetterBetterCharacterController.Instance.GetVelocity();
|
||||||
|
l_vec.y = Mathf.Clamp(l_vec.y, float.MinValue, 0f);
|
||||||
|
BetterBetterCharacterController.Instance.SetVelocity(l_vec);
|
||||||
|
}
|
||||||
|
BodySystem.TrackingPositionWeight = 1f;
|
||||||
|
IKSystem.Instance.applyOriginalHipPosition = m_applyHipsPosition;
|
||||||
|
IKSystem.Instance.applyOriginalHipRotation = m_applyHipsRotation;
|
||||||
|
|
||||||
m_inAir = false;
|
if(m_vrIK != null)
|
||||||
|
m_vrIK.solver.Reset();
|
||||||
|
|
||||||
|
m_ragdolledParameter.SetValue(false);
|
||||||
|
|
||||||
|
m_puppet.localPosition = Vector3.zero;
|
||||||
|
m_puppet.localRotation = Quaternion.identity;
|
||||||
|
|
||||||
|
foreach(RagdollBodypartHandler l_handler in m_ragdollBodyHandlers)
|
||||||
|
{
|
||||||
|
l_handler.Detach();
|
||||||
|
l_handler.ClearFluidVolumes();
|
||||||
|
l_handler.SetAsKinematic(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_downTime = float.MinValue;
|
||||||
|
|
||||||
|
// Restore rigidbody properties that could be affected by buoyancy
|
||||||
|
OnMovementDragChanged(Settings.MovementDrag);
|
||||||
|
OnAngularDragChanged(Settings.AngularDrag);
|
||||||
|
|
||||||
|
m_ragdolled = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Transform CloneTransform(Transform p_source, Transform p_parent, string p_name)
|
static Transform CloneTransform(Transform p_source, Transform p_parent, string p_name)
|
||||||
|
@ -739,7 +720,7 @@ namespace ml_prm
|
||||||
|
|
||||||
bool CanRagdoll()
|
bool CanRagdoll()
|
||||||
{
|
{
|
||||||
if(WorldHandler.IsRestrictedWorld())
|
if(WorldManager.IsRestrictedWorld())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool l_result = m_reachedGround;
|
bool l_result = m_reachedGround;
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
using ABI_RC.Core.Networking.IO.Social;
|
|
||||||
using ABI_RC.Core.Player;
|
|
||||||
using System;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace ml_prm
|
|
||||||
{
|
|
||||||
class RemoteGestureHandler : MonoBehaviour
|
|
||||||
{
|
|
||||||
internal class GestureEvent<T1, T2, T3>
|
|
||||||
{
|
|
||||||
event Action<T1, T2, T3> m_action;
|
|
||||||
public void AddListener(Action<T1, T2, T3> p_listener) => m_action += p_listener;
|
|
||||||
public void RemoveListener(Action<T1, T2, T3> p_listener) => m_action -= p_listener;
|
|
||||||
public void Invoke(T1 p_objA, T2 p_objB, T3 p_objC) => m_action?.Invoke(p_objA, p_objB, p_objC);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly GestureEvent<PuppetMaster, bool, bool> OnGestureState = new GestureEvent<PuppetMaster, bool, bool>();
|
|
||||||
|
|
||||||
PuppetMaster m_puppetMaster = null;
|
|
||||||
bool m_stateLeft = false;
|
|
||||||
bool m_stateRight = false;
|
|
||||||
|
|
||||||
void Start()
|
|
||||||
{
|
|
||||||
m_puppetMaster = this.GetComponent<PuppetMaster>();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Update()
|
|
||||||
{
|
|
||||||
bool l_state = m_puppetMaster.IsLeftGrabPointerActive();
|
|
||||||
if(m_stateLeft != l_state)
|
|
||||||
{
|
|
||||||
m_stateLeft = l_state;
|
|
||||||
if(!Settings.FriendsGrab || Friends.FriendsWith(m_puppetMaster.CVRPlayerEntity.PlayerDescriptor.ownerId))
|
|
||||||
OnGestureState.Invoke(m_puppetMaster, true, m_stateLeft);
|
|
||||||
}
|
|
||||||
|
|
||||||
l_state = m_puppetMaster.IsRightGrabPointerActive();
|
|
||||||
if(m_stateRight != l_state)
|
|
||||||
{
|
|
||||||
m_stateRight = l_state;
|
|
||||||
if(!Settings.FriendsGrab || Friends.FriendsWith(m_puppetMaster.CVRPlayerEntity.PlayerDescriptor.ownerId))
|
|
||||||
OnGestureState.Invoke(m_puppetMaster, false, m_stateRight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
using ABI_RC.Core.Player;
|
|
||||||
using ABI_RC.Systems.GameEventSystem;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace ml_prm
|
|
||||||
{
|
|
||||||
static class RemoteGestureManager
|
|
||||||
{
|
|
||||||
static readonly Dictionary<CVRPlayerEntity, RemoteGestureHandler> ms_remoteHandlers = new Dictionary<CVRPlayerEntity, RemoteGestureHandler>();
|
|
||||||
|
|
||||||
internal static void Init()
|
|
||||||
{
|
|
||||||
CVRGameEventSystem.Player.OnJoinEntity.AddListener(OnRemotePlayerCreated);
|
|
||||||
CVRGameEventSystem.Player.OnLeaveEntity.AddListener(OnRemotePlayerDestroyed);
|
|
||||||
Settings.OnGestureGrabChanged.AddListener(OnGestureGrabChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void DeInit()
|
|
||||||
{
|
|
||||||
CVRGameEventSystem.Player.OnJoinEntity.RemoveListener(OnRemotePlayerCreated);
|
|
||||||
CVRGameEventSystem.Player.OnLeaveEntity.RemoveListener(OnRemotePlayerDestroyed);
|
|
||||||
Settings.OnGestureGrabChanged.RemoveListener(OnGestureGrabChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void OnRemotePlayerCreated(CVRPlayerEntity p_player)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if(Settings.GestureGrab && (p_player != null) && (p_player.PuppetMaster != null))
|
|
||||||
{
|
|
||||||
RemoteGestureHandler l_handler = p_player.PuppetMaster.gameObject.AddComponent<RemoteGestureHandler>();
|
|
||||||
ms_remoteHandlers.Add(p_player, l_handler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
MelonLoader.MelonLogger.Error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void OnRemotePlayerDestroyed(CVRPlayerEntity p_player)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if(p_player != null)
|
|
||||||
ms_remoteHandlers.Remove(p_player);
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
MelonLoader.MelonLogger.Error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void OnGestureGrabChanged(bool p_state)
|
|
||||||
{
|
|
||||||
if(p_state)
|
|
||||||
{
|
|
||||||
foreach(var l_player in CVRPlayerManager.Instance.NetworkPlayers)
|
|
||||||
{
|
|
||||||
if(!ms_remoteHandlers.ContainsKey(l_player) && (l_player.PuppetMaster != null))
|
|
||||||
{
|
|
||||||
RemoteGestureHandler l_handler = l_player.PuppetMaster.gameObject.AddComponent<RemoteGestureHandler>();
|
|
||||||
ms_remoteHandlers.Add(l_player, l_handler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach(var l_pair in ms_remoteHandlers)
|
|
||||||
{
|
|
||||||
if(l_pair.Value != null)
|
|
||||||
UnityEngine.Object.Destroy(l_pair.Value);
|
|
||||||
}
|
|
||||||
ms_remoteHandlers.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
132
ml_prm/RemoteGesturesManager.cs
Normal file
132
ml_prm/RemoteGesturesManager.cs
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
using ABI_RC.Core.Networking.IO.Social;
|
||||||
|
using ABI_RC.Core.Player;
|
||||||
|
using ABI_RC.Systems.GameEventSystem;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace ml_prm
|
||||||
|
{
|
||||||
|
[DisallowMultipleComponent]
|
||||||
|
class RemoteGesturesManager : MonoBehaviour
|
||||||
|
{
|
||||||
|
public enum GestureHand
|
||||||
|
{
|
||||||
|
Left = 0,
|
||||||
|
Right
|
||||||
|
}
|
||||||
|
internal class GestureEvent<T1, T2, T3>
|
||||||
|
{
|
||||||
|
event Action<T1, T2, T3> m_action;
|
||||||
|
public void AddListener(Action<T1, T2, T3> p_listener) => m_action += p_listener;
|
||||||
|
public void RemoveListener(Action<T1, T2, T3> p_listener) => m_action -= p_listener;
|
||||||
|
public void Invoke(T1 p_objA, T2 p_objB, T3 p_objC) => m_action?.Invoke(p_objA, p_objB, p_objC);
|
||||||
|
}
|
||||||
|
public static readonly GestureEvent<PuppetMaster, GestureHand, bool> OnGestureState = new GestureEvent<PuppetMaster, GestureHand, bool>();
|
||||||
|
|
||||||
|
class PlayerEntry
|
||||||
|
{
|
||||||
|
public CVRPlayerEntity m_entity = null;
|
||||||
|
public PuppetMaster m_puppetMaster = null;
|
||||||
|
public bool m_stateLeft = false;
|
||||||
|
public bool m_stateRight = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly List<PlayerEntry> m_entries = null;
|
||||||
|
|
||||||
|
internal RemoteGesturesManager()
|
||||||
|
{
|
||||||
|
m_entries = new List<PlayerEntry>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Start()
|
||||||
|
{
|
||||||
|
DontDestroyOnLoad(this);
|
||||||
|
|
||||||
|
CVRGameEventSystem.Player.OnJoinEntity.AddListener(OnRemotePlayerCreated);
|
||||||
|
CVRGameEventSystem.Player.OnLeaveEntity.AddListener(OnRemotePlayerDestroyed);
|
||||||
|
Settings.OnGestureGrabChanged.AddListener(OnGestureGrabChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnDestroy()
|
||||||
|
{
|
||||||
|
m_entries.Clear();
|
||||||
|
|
||||||
|
CVRGameEventSystem.Player.OnJoinEntity.RemoveListener(OnRemotePlayerCreated);
|
||||||
|
CVRGameEventSystem.Player.OnLeaveEntity.RemoveListener(OnRemotePlayerDestroyed);
|
||||||
|
Settings.OnGestureGrabChanged.RemoveListener(OnGestureGrabChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update()
|
||||||
|
{
|
||||||
|
if(Settings.GestureGrab)
|
||||||
|
{
|
||||||
|
foreach(var l_entry in m_entries)
|
||||||
|
{
|
||||||
|
bool l_state = l_entry.m_puppetMaster.IsLeftGrabPointerActive();
|
||||||
|
if(l_entry.m_stateLeft != l_state)
|
||||||
|
{
|
||||||
|
l_entry.m_stateLeft = l_state;
|
||||||
|
if(!Settings.FriendsGrab || Friends.FriendsWith(l_entry.m_entity.PlayerDescriptor.ownerId))
|
||||||
|
OnGestureState.Invoke(l_entry.m_puppetMaster, GestureHand.Left, l_entry.m_stateLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
l_state = l_entry.m_puppetMaster.IsRightGrabPointerActive();
|
||||||
|
if(l_entry.m_stateRight != l_state)
|
||||||
|
{
|
||||||
|
l_entry.m_stateRight = l_state;
|
||||||
|
if(!Settings.FriendsGrab || Friends.FriendsWith(l_entry.m_entity.PlayerDescriptor.ownerId))
|
||||||
|
OnGestureState.Invoke(l_entry.m_puppetMaster, GestureHand.Right, l_entry.m_stateRight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnRemotePlayerCreated(CVRPlayerEntity p_player)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if((p_player != null) && (p_player.PuppetMaster != null))
|
||||||
|
{
|
||||||
|
PlayerEntry l_entry = new PlayerEntry()
|
||||||
|
{
|
||||||
|
m_entity = p_player,
|
||||||
|
m_puppetMaster = p_player.PuppetMaster,
|
||||||
|
m_stateLeft = false,
|
||||||
|
m_stateRight = false
|
||||||
|
};
|
||||||
|
m_entries.Add(l_entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
MelonLoader.MelonLogger.Error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnRemotePlayerDestroyed(CVRPlayerEntity p_player)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(p_player != null)
|
||||||
|
m_entries.RemoveAll(e => ReferenceEquals(e.m_puppetMaster, p_player.PuppetMaster));
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
MelonLoader.MelonLogger.Error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnGestureGrabChanged(bool p_state)
|
||||||
|
{
|
||||||
|
if(!p_state)
|
||||||
|
{
|
||||||
|
foreach(var l_entry in m_entries)
|
||||||
|
{
|
||||||
|
l_entry.m_stateLeft = false;
|
||||||
|
l_entry.m_stateRight = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,44 +1,44 @@
|
||||||
using ABI.CCK.Components;
|
using ABI.CCK.Components;
|
||||||
using ABI_RC.Systems.GameEventSystem;
|
using ABI_RC.Systems.GameEventSystem;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace ml_prm
|
namespace ml_prm
|
||||||
{
|
{
|
||||||
static class WorldHandler
|
static class WorldManager
|
||||||
{
|
{
|
||||||
static bool ms_safeWorld = true;
|
static bool ms_safeWorld = true;
|
||||||
static bool ms_restrictedWorld = false;
|
static bool ms_restrictedWorld = false;
|
||||||
static float ms_movementLimit = 1f;
|
static float ms_movementLimit = 1f;
|
||||||
|
|
||||||
internal static void Init()
|
internal static void Init()
|
||||||
{
|
{
|
||||||
CVRGameEventSystem.World.OnLoad.AddListener(OnWorldLoad);
|
CVRGameEventSystem.World.OnLoad.AddListener(OnWorldLoad);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void DeInit()
|
internal static void DeInit()
|
||||||
{
|
{
|
||||||
CVRGameEventSystem.World.OnLoad.RemoveListener(OnWorldLoad);
|
CVRGameEventSystem.World.OnLoad.RemoveListener(OnWorldLoad);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OnWorldLoad(string p_id)
|
static void OnWorldLoad(string p_id)
|
||||||
{
|
{
|
||||||
ms_safeWorld = ((CVRWorld.Instance != null) && CVRWorld.Instance.allowFlying);
|
ms_safeWorld = ((CVRWorld.Instance != null) && CVRWorld.Instance.allowFlying);
|
||||||
ms_movementLimit = 1f;
|
ms_movementLimit = 1f;
|
||||||
|
|
||||||
GameObject l_restrictObj = GameObject.Find("[RagdollRestriction]");
|
GameObject l_restrictObj = GameObject.Find("[RagdollRestriction]");
|
||||||
ms_restrictedWorld = ((l_restrictObj == null) ? false : (l_restrictObj.scene.name != "DontDestroyOnLoad"));
|
ms_restrictedWorld = ((l_restrictObj == null) ? false : (l_restrictObj.scene.name != "DontDestroyOnLoad"));
|
||||||
|
|
||||||
if(CVRWorld.Instance != null)
|
if(CVRWorld.Instance != null)
|
||||||
{
|
{
|
||||||
ms_movementLimit = CVRWorld.Instance.baseMovementSpeed;
|
ms_movementLimit = CVRWorld.Instance.baseMovementSpeed;
|
||||||
ms_movementLimit *= CVRWorld.Instance.sprintMultiplier;
|
ms_movementLimit *= CVRWorld.Instance.sprintMultiplier;
|
||||||
ms_movementLimit *= CVRWorld.Instance.inAirMovementMultiplier;
|
ms_movementLimit *= CVRWorld.Instance.inAirMovementMultiplier;
|
||||||
ms_movementLimit *= CVRWorld.Instance.flyMultiplier;
|
ms_movementLimit *= CVRWorld.Instance.flyMultiplier;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsSafeWorld() => ms_safeWorld;
|
public static bool IsSafeWorld() => ms_safeWorld;
|
||||||
public static bool IsRestrictedWorld() => ms_restrictedWorld;
|
public static bool IsRestrictedWorld() => ms_restrictedWorld;
|
||||||
public static float GetMovementLimit() => ms_movementLimit;
|
public static float GetMovementLimit() => ms_movementLimit;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,10 +4,11 @@
|
||||||
<TargetFramework>netstandard2.1</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<Platforms>x64</Platforms>
|
<Platforms>x64</Platforms>
|
||||||
<PackageId>PlayerRagdollMod</PackageId>
|
<PackageId>PlayerRagdollMod</PackageId>
|
||||||
<Version>1.1.9</Version>
|
<Version>1.2.0</Version>
|
||||||
<Authors>SDraw</Authors>
|
<Authors>SDraw</Authors>
|
||||||
<Company>None</Company>
|
<Company>SDraw</Company>
|
||||||
<Product>PlayerRagdollMod</Product>
|
<Product>PlayerRagdollMod</Product>
|
||||||
|
<AssemblyName>PlayerRagdollMod</AssemblyName>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[assembly: MelonLoader.MelonInfo(typeof(ml_vei.ViveExtendedInput), "ViveExtendedInput", "1.0.4", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
[assembly: MelonLoader.MelonInfo(typeof(ml_vei.ViveExtendedInput), "ViveExtendedInput", "1.0.5", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||||
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||||
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
||||||
|
|
|
@ -4,7 +4,7 @@ This mod changes input behaviour for Vive controllers.
|
||||||
# Installation
|
# Installation
|
||||||
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
|
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
|
||||||
* Get [latest release DLL](../../../releases/latest):
|
* Get [latest release DLL](../../../releases/latest):
|
||||||
* Put `ml_vei.dll` in `Mods` folder of game
|
* Put `ViveExtendedInput.dll` in `Mods` folder of game
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
Available mod's settings in `Settings - Input & Key-Bindings - Vive Extended Input`:
|
Available mod's settings in `Settings - Input & Key-Bindings - Vive Extended Input`:
|
||||||
|
|
|
@ -4,10 +4,11 @@
|
||||||
<TargetFramework>netstandard2.1</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<Platforms>x64</Platforms>
|
<Platforms>x64</Platforms>
|
||||||
<PackageId>ViveExtendedInput</PackageId>
|
<PackageId>ViveExtendedInput</PackageId>
|
||||||
<Version>1.0.4</Version>
|
<Version>1.0.5</Version>
|
||||||
<Authors>SDraw</Authors>
|
<Authors>SDraw</Authors>
|
||||||
<Company>None</Company>
|
<Company>SDraw</Company>
|
||||||
<Product>ViveExtendedInput</Product>
|
<Product>ViveExtendedInput</Product>
|
||||||
|
<AssemblyName>ViveExtendedInput</AssemblyName>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue