Removed Upright

Leading hand option
Hands extension with `Q`/`E`
Joints fix
Update to LeapSDK 5.16
This commit is contained in:
SDraw 2023-11-26 19:24:11 +03:00
parent b6a200d44c
commit aebf6c2c4e
No known key found for this signature in database
GPG key ID: BB95B4DAB2BB8BB5
22 changed files with 9131 additions and 6719 deletions

View file

@ -3,9 +3,9 @@ Merged set of MelonLoader mods for ChilloutVR.
**Table for game build 2023r173:** **Table for game build 2023r173:**
| Full name | Short name | Latest version | Available in [CVRMA](https://github.com/knah/CVRMelonAssistant) | | Full name | Short name | Latest version | Available in [CVRMA](https://github.com/knah/CVRMelonAssistant) |
|:---------:|:----------:|:--------------:| :----------------------------------------------------------------| |:---------:|:----------:|:--------------:| :----------------------------------------------------------------|
| [Avatar Motion Tweaker](/ml_amt/README.md) | ml_amt | 1.3.4 [:arrow_down:](../../releases/latest/download/ml_amt.dll)| ✔ Yes | | [Avatar Motion Tweaker](/ml_amt/README.md) | ml_amt | 1.3.5 [:arrow_down:](../../releases/latest/download/ml_amt.dll)| ✔ Yes<br>⌛ Update review |
| [Leap Motion Extension](/ml_lme/README.md)| ml_lme | 1.4.4 [:arrow_down:](../../releases/latest/download/ml_lme.dll)| ✔ Yes | | [Leap Motion Extension](/ml_lme/README.md)| ml_lme | 1.4.5 [:arrow_down:](../../releases/latest/download/ml_lme.dll)| ✔ Yes<br>⌛ Update review |
| [Pickup Arm Movement](/ml_pam/README.md)| ml_pam | 1.0.8 [:arrow_down:](../../releases/latest/download/ml_pam.dll)| ✔ Yes | | [Pickup Arm Movement](/ml_pam/README.md)| ml_pam | 1.0.9 [:arrow_down:](../../releases/latest/download/ml_pam.dll)| ✔ Yes<br>⌛ Update review |
| [Player Movement Copycat](/ml_pmc/README.md)| ml_pmc | 1.0.4 [:arrow_down:](../../releases/latest/download/ml_pmc.dll)| ✔ Yes<br>⌛ Update review | | [Player Movement Copycat](/ml_pmc/README.md)| ml_pmc | 1.0.4 [:arrow_down:](../../releases/latest/download/ml_pmc.dll)| ✔ Yes<br>⌛ Update review |
| [Player Ragdoll Mod](/ml_prm/README.md) | ml_prm | 1.1.1 [:arrow_down:](../../releases/latest/download/ml_prm.dll)| ✔ Yes<br>⌛ Update review | | [Player Ragdoll Mod](/ml_prm/README.md) | ml_prm | 1.1.1 [:arrow_down:](../../releases/latest/download/ml_prm.dll)| ✔ Yes<br>⌛ Update review |
| [Vive Extended Input](/ml_vei/README.md) | ml_vei | 1.0.0 [:arrow_down:](../../releases/latest/download/ml_vei.dll)| ✔ Yes | | [Vive Extended Input](/ml_vei/README.md) | ml_vei | 1.0.0 [:arrow_down:](../../releases/latest/download/ml_vei.dll)| ✔ Yes |

View file

@ -8,7 +8,6 @@ namespace ml_amt
{ {
public enum ParameterType public enum ParameterType
{ {
Upright,
GroundedRaw, GroundedRaw,
Moving Moving
} }
@ -43,10 +42,6 @@ namespace ml_amt
{ {
switch(m_type) switch(m_type)
{ {
case ParameterType.Upright:
SetFloat(p_tweaker.GetUpright());
break;
case ParameterType.GroundedRaw: case ParameterType.GroundedRaw:
SetBoolean(p_tweaker.GetGroundedRaw()); SetBoolean(p_tweaker.GetGroundedRaw());
break; break;

View file

@ -136,7 +136,6 @@ namespace ml_amt
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.Upright, PlayerSetup.Instance.animatorManager));
m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.GroundedRaw, PlayerSetup.Instance.animatorManager)); m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.GroundedRaw, PlayerSetup.Instance.animatorManager));
m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.Moving, PlayerSetup.Instance.animatorManager)); m_parameters.Add(new AvatarParameter(AvatarParameter.ParameterType.Moving, PlayerSetup.Instance.animatorManager));
m_parameters.RemoveAll(p => !p.IsValid()); m_parameters.RemoveAll(p => !p.IsValid());
@ -246,11 +245,7 @@ namespace ml_amt
} }
if(m_locomotionOverride && !l_locomotionOverride) if(m_locomotionOverride && !l_locomotionOverride)
{
m_vrIk.solver.Reset(); m_vrIk.solver.Reset();
if((IKSystem.VrikRootController != null) && !MovementSystem.Instance.sitting)
IKSystem.VrikRootController.enabled = true;
}
m_locomotionOverride = l_locomotionOverride; m_locomotionOverride = l_locomotionOverride;
} }

View file

@ -1,4 +1,4 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.3.4", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.3.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)]

View file

@ -2,6 +2,7 @@
using ABI_RC.Core.UI; using ABI_RC.Core.UI;
using ABI_RC.Systems.MovementSystem; using ABI_RC.Systems.MovementSystem;
using RootMotion.FinalIK; using RootMotion.FinalIK;
using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using UnityEngine; using UnityEngine;

View file

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

View file

@ -14,7 +14,7 @@ namespace ml_lme
static readonly Quaternion ms_offsetRight = Quaternion.Euler(0f, 270f, 0f); static readonly Quaternion ms_offsetRight = Quaternion.Euler(0f, 270f, 0f);
VRIK m_vrIK = null; VRIK m_vrIK = null;
Vector4 m_armsWeights = Vector2.zero; Vector4 m_vrIKWeights = Vector2.zero;
bool m_inVR = false; bool m_inVR = false;
Transform m_hips = null; Transform m_hips = null;
Transform m_origLeftHand = null; Transform m_origLeftHand = null;
@ -87,35 +87,8 @@ namespace ml_lme
if((m_vrIK != null) && !m_fingersOnly) if((m_vrIK != null) && !m_fingersOnly)
{ {
if(l_data.m_leftHand.m_present && !m_leftTargetActive) m_leftTargetActive = l_data.m_leftHand.m_present;
{ m_rightTargetActive = l_data.m_rightHand.m_present;
m_vrIK.solver.leftArm.target = m_leftHandTarget;
m_vrIK.solver.leftArm.bendGoal = LeapTracking.Instance.GetLeftElbow();
m_vrIK.solver.leftArm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
m_leftTargetActive = true;
}
if(!l_data.m_leftHand.m_present && m_leftTargetActive)
{
m_vrIK.solver.leftArm.target = m_origLeftHand;
m_vrIK.solver.leftArm.bendGoal = m_origLeftElbow;
m_vrIK.solver.leftArm.bendGoalWeight = ((m_origLeftElbow != null) ? 1f : 0f);
m_leftTargetActive = false;
}
if(l_data.m_rightHand.m_present && !m_rightTargetActive)
{
m_vrIK.solver.rightArm.target = m_rightHandTarget;
m_vrIK.solver.rightArm.bendGoal = LeapTracking.Instance.GetRightElbow();
m_vrIK.solver.rightArm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
m_rightTargetActive = true;
}
if(!l_data.m_rightHand.m_present && m_rightTargetActive)
{
m_vrIK.solver.rightArm.target = m_origRightHand;
m_vrIK.solver.rightArm.bendGoal = m_origRightElbow;
m_vrIK.solver.rightArm.bendGoalWeight = ((m_origRightElbow != null) ? 1f : 0f);
m_rightTargetActive = false;
}
} }
} }
} }
@ -207,7 +180,7 @@ namespace ml_lme
m_origLeftElbow = null; m_origLeftElbow = null;
m_origRightElbow = null; m_origRightElbow = null;
m_hips = null; m_hips = null;
m_armsWeights = Vector2.zero; m_vrIKWeights = Vector2.zero;
m_leftArmIK = null; m_leftArmIK = null;
m_rightArmIK = null; m_rightArmIK = null;
m_leftTargetActive = false; m_leftTargetActive = false;
@ -329,30 +302,42 @@ namespace ml_lme
// IK updates // IK updates
void OnIKPreUpdate() void OnIKPreUpdate()
{ {
m_armsWeights.Set( m_vrIKWeights.Set(
m_vrIK.solver.leftArm.positionWeight, m_vrIK.solver.leftArm.positionWeight,
m_vrIK.solver.leftArm.rotationWeight, m_vrIK.solver.leftArm.rotationWeight,
m_vrIK.solver.rightArm.positionWeight, m_vrIK.solver.rightArm.positionWeight,
m_vrIK.solver.rightArm.rotationWeight m_vrIK.solver.rightArm.rotationWeight
); );
if(m_leftTargetActive && (Mathf.Approximately(m_armsWeights.x, 0f) || Mathf.Approximately(m_armsWeights.y, 0f))) if(m_leftTargetActive)
{ {
m_vrIK.solver.leftArm.positionWeight = 1f; m_vrIK.solver.leftArm.positionWeight = 1f;
m_vrIK.solver.leftArm.rotationWeight = 1f; m_vrIK.solver.leftArm.rotationWeight = 1f;
m_vrIK.solver.leftArm.target = m_leftHandTarget;
m_vrIK.solver.leftArm.bendGoal = LeapTracking.Instance.GetLeftElbow();
m_vrIK.solver.leftArm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
} }
if(m_rightTargetActive && (Mathf.Approximately(m_armsWeights.z, 0f) || Mathf.Approximately(m_armsWeights.w, 0f))) if(m_rightTargetActive)
{ {
m_vrIK.solver.rightArm.positionWeight = 1f; m_vrIK.solver.rightArm.positionWeight = 1f;
m_vrIK.solver.rightArm.rotationWeight = 1f; m_vrIK.solver.rightArm.rotationWeight = 1f;
m_vrIK.solver.rightArm.target = m_rightHandTarget;
m_vrIK.solver.rightArm.bendGoal = LeapTracking.Instance.GetRightElbow();
m_vrIK.solver.rightArm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
} }
} }
void OnIKPostUpdate() void OnIKPostUpdate()
{ {
m_vrIK.solver.leftArm.positionWeight = m_armsWeights.x; m_vrIK.solver.leftArm.positionWeight = m_vrIKWeights.x;
m_vrIK.solver.leftArm.rotationWeight = m_armsWeights.y; m_vrIK.solver.leftArm.rotationWeight = m_vrIKWeights.y;
m_vrIK.solver.rightArm.positionWeight = m_armsWeights.z; m_vrIK.solver.leftArm.target = m_origLeftHand;
m_vrIK.solver.rightArm.rotationWeight = m_armsWeights.w; m_vrIK.solver.leftArm.bendGoal = m_origLeftElbow;
m_vrIK.solver.leftArm.bendGoalWeight = ((m_origLeftElbow != null) ? 1f : 0f);
m_vrIK.solver.rightArm.positionWeight = m_vrIKWeights.z;
m_vrIK.solver.rightArm.rotationWeight = m_vrIKWeights.w;
m_vrIK.solver.rightArm.target = m_origRightHand;
m_vrIK.solver.rightArm.bendGoal = m_origRightElbow;
m_vrIK.solver.rightArm.bendGoalWeight = ((m_origRightElbow != null) ? 1f : 0f);
} }
// Settings // Settings
@ -392,22 +377,10 @@ namespace ml_lme
{ {
if(m_vrIK != null) if(m_vrIK != null)
{ {
if(m_leftTargetActive)
{
m_vrIK.solver.leftArm.target = m_origLeftHand;
m_vrIK.solver.leftArm.bendGoal = m_origLeftElbow;
m_vrIK.solver.leftArm.bendGoalWeight = ((m_origLeftElbow != null) ? 1f : 0f);
m_leftTargetActive = false; m_leftTargetActive = false;
}
if(m_rightTargetActive)
{
m_vrIK.solver.rightArm.target = m_origRightHand;
m_vrIK.solver.rightArm.bendGoal = m_origRightElbow;
m_vrIK.solver.rightArm.bendGoalWeight = ((m_origRightElbow != null) ? 1f : 0f);
m_rightTargetActive = false; m_rightTargetActive = false;
} }
} }
}
void RefreshArmIK() void RefreshArmIK()
{ {

View file

@ -1,4 +1,4 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.4.4", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.4.5", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
[assembly: MelonLoader.MelonOptionalDependencies("ml_pmc")] [assembly: MelonLoader.MelonOptionalDependencies("ml_pmc")]
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]

View file

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

View file

@ -98,7 +98,7 @@ cmake --build ${REPOS_BUILD_ROOT}/${BUILD_TYPE}/LeapSDK/leapc_example -j --confi
### MacOS ### MacOS
1. Open CMake using /Library/Application Support/Ultraleap/LeapSDK/samples as the source directory 1. Open CMake using /Applications/Ultraleap\ Hand\ Tracking\ Service.app/Contents/LeapSDK/samples as the source directory
2. Select a build directory (eg. ~/ultraleap-tracking-samples/build) to use 2. Select a build directory (eg. ~/ultraleap-tracking-samples/build) to use
@ -107,7 +107,7 @@ cmake --build ${REPOS_BUILD_ROOT}/${BUILD_TYPE}/LeapSDK/leapc_example -j --confi
4. Open and build the CMake generated project files. For more help, see the CMake documentation. 4. Open and build the CMake generated project files. For more help, see the CMake documentation.
* An example script would be : * An example script would be :
```bash ```bash
SRC_DIR='/Library/Application Support/Ultraleap/LeapSDK/samples' SRC_DIR='/Applications/Ultraleap\ Hand\ Tracking\ Service.app/Contents/LeapSDK/samples'
BUILD_TYPE='Release' BUILD_TYPE='Release'
REPOS_BUILD_ROOT=~/ultraleap-tracking-samples/build REPOS_BUILD_ROOT=~/ultraleap-tracking-samples/build
REPOS_INSTALL_ROOT=~/ultraleap-tracking-samples/bin REPOS_INSTALL_ROOT=~/ultraleap-tracking-samples/bin

File diff suppressed because it is too large Load diff

Binary file not shown.

View file

@ -2,7 +2,6 @@
using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.InteractionSystem;
using ABI_RC.Core.Player; using ABI_RC.Core.Player;
using RootMotion.FinalIK; using RootMotion.FinalIK;
using System.Reflection;
using UnityEngine; using UnityEngine;
namespace ml_pam namespace ml_pam
@ -10,47 +9,72 @@ namespace ml_pam
[DisallowMultipleComponent] [DisallowMultipleComponent]
class ArmMover : MonoBehaviour class ArmMover : MonoBehaviour
{ {
const float c_offsetLimit = 0.5f; enum HandState
{
Empty = 0,
Pickup,
Extended
}
const float c_offsetLimit = 0.5f;
const KeyCode c_leftKey = KeyCode.Q;
const KeyCode c_rightKey = KeyCode.E;
static readonly float[] ms_tposeMuscles = typeof(ABI_RC.Systems.IK.SubSystems.BodySystem).GetField("TPoseMuscles", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null) as float[];
static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f); static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f);
static readonly Quaternion ms_offsetRight = Quaternion.Euler(0f, 0f, 90f); static readonly Quaternion ms_offsetLeft = Quaternion.Euler(270f, 90f, 0f);
static readonly Quaternion ms_offsetRightDesktop = Quaternion.Euler(0f, 270f, 0f); static readonly Quaternion ms_offsetRight = Quaternion.Euler(270f, 270f, 0f);
static readonly Quaternion ms_palmToLeft = Quaternion.Euler(0f, 0f, -90f);
bool m_inVR = false; bool m_inVR = false;
VRIK m_vrIK = null; VRIK m_vrIK = null;
Vector2 m_armWeight = Vector2.zero; Vector4 m_vrIKWeights = Vector4.zero;
Transform m_origRightHand = null; Transform m_origRightHand = null;
Transform m_origLeftHand = null;
float m_armLength = 0f;
float m_playspaceScale = 1f; float m_playspaceScale = 1f;
bool m_enabled = true; bool m_enabled = true;
ArmIK m_armIK = null; Transform m_rootLeft = null;
Transform m_target = null; Transform m_rootRight = null;
Transform m_rotationTarget = null; Transform m_leftTarget = null;
Transform m_rightTarget = null;
ArmIK m_armIKLeft = null;
ArmIK m_armIKRight = null;
CVRPickupObject m_pickup = null; CVRPickupObject m_pickup = null;
Matrix4x4 m_offset = Matrix4x4.identity; Matrix4x4 m_offset;
bool m_targetActive = false; HandState m_leftHandState = HandState.Empty;
HandState m_rightHandState = HandState.Empty;
// Unity events // Unity events
void Start() void Start()
{ {
m_inVR = Utils.IsInVR(); m_inVR = Utils.IsInVR();
m_target = new GameObject("ArmPickupTarget").transform; m_rootLeft = new GameObject("[ArmPickupLeft]").transform;
m_target.parent = PlayerSetup.Instance.GetActiveCamera().transform; m_rootLeft.parent = PlayerSetup.Instance.GetActiveCamera().transform;
m_target.localPosition = Vector3.zero; m_rootLeft.localPosition = Vector3.zero;
m_target.localRotation = Quaternion.identity; m_rootLeft.localRotation = Quaternion.identity;
m_rotationTarget = new GameObject("RotationTarget").transform; m_leftTarget = new GameObject("Target").transform;
m_rotationTarget.parent = m_target; m_leftTarget.parent = m_rootLeft;
m_rotationTarget.localPosition = new Vector3(c_offsetLimit * Settings.GrabOffset, 0f, 0f); m_leftTarget.localPosition = new Vector3(c_offsetLimit * -Settings.GrabOffset, 0f, 0f);
m_rotationTarget.localRotation = Quaternion.identity; m_leftTarget.localRotation = Quaternion.identity;
m_rootRight = new GameObject("[ArmPickupRight]").transform;
m_rootRight.parent = PlayerSetup.Instance.GetActiveCamera().transform;
m_rootRight.localPosition = Vector3.zero;
m_rootRight.localRotation = Quaternion.identity;
m_rightTarget = new GameObject("Target").transform;
m_rightTarget.parent = m_rootRight;
m_rightTarget.localPosition = new Vector3(c_offsetLimit * Settings.GrabOffset, 0f, 0f);
m_rightTarget.localRotation = Quaternion.identity;
m_enabled = Settings.Enabled; m_enabled = Settings.Enabled;
Settings.EnabledChange += this.SetEnabled; Settings.EnabledChange += this.SetEnabled;
Settings.GrabOffsetChange += this.SetGrabOffset; Settings.GrabOffsetChange += this.SetGrabOffset;
Settings.LeadingHandChange += this.OnLeadingHandChange;
Settings.HandsExtensionChange += this.OnHandsExtensionChange;
} }
void OnDestroy() void OnDestroy()
@ -61,33 +85,106 @@ namespace ml_pam
void Update() void Update()
{ {
if(m_enabled && !ReferenceEquals(m_pickup, null)) if(!ReferenceEquals(m_pickup, null) && (m_pickup == null))
OnPickupDrop(m_pickup);
switch(m_leftHandState)
{
case HandState.Empty:
{
if(Settings.HandsExtension && Input.GetKeyDown(c_leftKey))
{
m_leftHandState = HandState.Extended;
m_rootLeft.localPosition = new Vector3(0f, 0f, m_armLength * m_playspaceScale);
SetArmActive(Settings.LeadHand.Left, true);
}
}
break;
case HandState.Extended:
{
if(Input.GetKeyUp(c_leftKey))
{
m_leftHandState = HandState.Empty;
SetArmActive(Settings.LeadHand.Left, false);
}
}
break;
case HandState.Pickup:
{ {
if(m_pickup != null) if(m_pickup != null)
{ {
Matrix4x4 l_result = m_pickup.transform.GetMatrix() * m_offset; Matrix4x4 l_result = m_pickup.transform.GetMatrix() * m_offset;
m_target.position = l_result * ms_pointVector; m_rootLeft.position = l_result * ms_pointVector;
} }
else }
this.OnPickupDrop(m_pickup); break;
}
switch(m_rightHandState)
{
case HandState.Empty:
{
if(Settings.HandsExtension && Input.GetKeyDown(c_rightKey))
{
m_rightHandState = HandState.Extended;
m_rootRight.localPosition = new Vector3(0f, 0f, m_armLength * m_playspaceScale);
SetArmActive(Settings.LeadHand.Right, true);
}
}
break;
case HandState.Extended:
{
if(Input.GetKeyUp(c_rightKey))
{
m_rightHandState = HandState.Empty;
SetArmActive(Settings.LeadHand.Right, false);
}
}
break;
case HandState.Pickup:
{
if(m_pickup != null)
{
Matrix4x4 l_result = m_pickup.transform.GetMatrix() * m_offset;
m_rootRight.position = l_result * ms_pointVector;
}
}
break;
} }
} }
// IK updates // VRIK updates
void OnIKPreUpdate() void OnIKPreUpdate()
{ {
m_armWeight.Set(m_vrIK.solver.rightArm.positionWeight, m_vrIK.solver.rightArm.rotationWeight); if(m_enabled)
{
m_vrIKWeights.Set(m_vrIK.solver.leftArm.positionWeight, m_vrIK.solver.leftArm.rotationWeight, m_vrIK.solver.rightArm.positionWeight, m_vrIK.solver.rightArm.rotationWeight);
if(m_targetActive && (Mathf.Approximately(m_armWeight.x, 0f) || Mathf.Approximately(m_armWeight.y, 0f))) if(m_leftHandState != HandState.Empty)
{
m_vrIK.solver.leftArm.positionWeight = 1f;
m_vrIK.solver.leftArm.rotationWeight = 1f;
m_vrIK.solver.leftArm.target = m_leftTarget;
}
if(m_rightHandState != HandState.Empty)
{ {
m_vrIK.solver.rightArm.positionWeight = 1f; m_vrIK.solver.rightArm.positionWeight = 1f;
m_vrIK.solver.rightArm.rotationWeight = 1f; m_vrIK.solver.rightArm.rotationWeight = 1f;
m_vrIK.solver.rightArm.target = m_rightTarget;
}
} }
} }
void OnIKPostUpdate() void OnIKPostUpdate()
{ {
m_vrIK.solver.rightArm.positionWeight = m_armWeight.x; if(m_enabled)
m_vrIK.solver.rightArm.rotationWeight = m_armWeight.y; {
m_vrIK.solver.leftArm.positionWeight = m_vrIKWeights.x;
m_vrIK.solver.leftArm.rotationWeight = m_vrIKWeights.y;
m_vrIK.solver.leftArm.target = m_origLeftHand;
m_vrIK.solver.rightArm.positionWeight = m_vrIKWeights.z;
m_vrIK.solver.rightArm.rotationWeight = m_vrIKWeights.w;
m_vrIK.solver.rightArm.target = m_origRightHand;
}
} }
// Settings // Settings
@ -95,17 +192,93 @@ namespace ml_pam
{ {
m_enabled = p_state; m_enabled = p_state;
RefreshArmIK();
if(m_enabled) if(m_enabled)
RestorePickup(); {
if(m_leftHandState != HandState.Empty)
SetArmActive(Settings.LeadHand.Left, true);
if(m_rightHandState != HandState.Empty)
SetArmActive(Settings.LeadHand.Right, true);
OnHandsExtensionChange(Settings.HandsExtension);
}
else else
RestoreVRIK(); SetArmActive(Settings.LeadHand.Both, false, true);
} }
void SetGrabOffset(float p_value) void SetGrabOffset(float p_value)
{ {
if(m_rotationTarget != null) if(m_leftTarget != null)
m_rotationTarget.localPosition = new Vector3(c_offsetLimit * m_playspaceScale * p_value, 0f, 0f); m_leftTarget.localPosition = new Vector3(c_offsetLimit * m_playspaceScale * -p_value, 0f, 0f);
if(m_rightTarget != null)
m_rightTarget.localPosition = new Vector3(c_offsetLimit * m_playspaceScale * p_value, 0f, 0f);
}
void OnLeadingHandChange(Settings.LeadHand p_hand)
{
if(m_pickup != null)
{
if(m_leftHandState == HandState.Pickup)
{
m_leftHandState = HandState.Empty;
SetArmActive(Settings.LeadHand.Left, false);
}
if(m_rightHandState == HandState.Pickup)
{
m_rightHandState = HandState.Empty;
SetArmActive(Settings.LeadHand.Right, false);
}
switch(p_hand)
{
case Settings.LeadHand.Left:
m_leftHandState = HandState.Pickup;
break;
case Settings.LeadHand.Right:
m_rightHandState = HandState.Pickup;
break;
case Settings.LeadHand.Both:
{
m_leftHandState = HandState.Pickup;
m_rightHandState = HandState.Pickup;
}
break;
}
SetArmActive(p_hand, true);
}
}
void OnHandsExtensionChange(bool p_state)
{
if(m_enabled)
{
if(p_state)
{
if((m_leftHandState == HandState.Empty) && Input.GetKey(c_leftKey))
{
m_leftHandState = HandState.Extended;
SetArmActive(Settings.LeadHand.Left, true);
}
if((m_rightHandState == HandState.Empty) && Input.GetKey(c_rightKey))
{
m_rightHandState = HandState.Extended;
SetArmActive(Settings.LeadHand.Right, true);
}
}
else
{
if(m_leftHandState == HandState.Extended)
{
m_leftHandState = HandState.Empty;
SetArmActive(Settings.LeadHand.Left, false);
}
if(m_rightHandState == HandState.Extended)
{
m_rightHandState = HandState.Empty;
SetArmActive(Settings.LeadHand.Right, false);
}
}
}
} }
// Game events // Game events
@ -113,8 +286,9 @@ namespace ml_pam
{ {
m_vrIK = null; m_vrIK = null;
m_origRightHand = null; m_origRightHand = null;
m_armIK = null; m_armIKLeft = null;
m_targetActive = false; m_armIKRight = null;
m_armLength = 0f;
} }
internal void OnAvatarSetup() internal void OnAvatarSetup()
@ -122,44 +296,30 @@ namespace ml_pam
// Recheck if user could switch to VR // Recheck if user could switch to VR
if(m_inVR != Utils.IsInVR()) if(m_inVR != Utils.IsInVR())
{ {
m_target.parent = PlayerSetup.Instance.GetActiveCamera().transform; m_rootLeft.parent = PlayerSetup.Instance.GetActiveCamera().transform;
m_target.localPosition = Vector3.zero; m_rootLeft.localPosition = Vector3.zero;
m_target.localRotation = Quaternion.identity; m_rootLeft.localRotation = Quaternion.identity;
}
m_rootRight.parent = PlayerSetup.Instance.GetActiveCamera().transform;
m_rootRight.localPosition = Vector3.zero;
m_rootRight.localRotation = Quaternion.identity;
}
m_inVR = Utils.IsInVR(); m_inVR = Utils.IsInVR();
if(!m_inVR && PlayerSetup.Instance._animator.isHuman)
{
m_vrIK = PlayerSetup.Instance._animator.GetComponent<VRIK>(); m_vrIK = PlayerSetup.Instance._animator.GetComponent<VRIK>();
if(PlayerSetup.Instance._animator.isHuman) TPoseHelper l_tpHelper = new TPoseHelper();
{ l_tpHelper.Assign(PlayerSetup.Instance._animator);
Vector3 l_hipsPos = Vector3.zero; l_tpHelper.Apply();
Transform l_hips = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Hips);
if(l_hips != null)
l_hipsPos = l_hips.localPosition;
HumanPose l_currentPose = new HumanPose(); Transform l_leftHand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand);
HumanPoseHandler l_poseHandler = null; if(l_leftHand != null)
m_leftTarget.localRotation = ms_offsetLeft * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_leftHand.GetMatrix()).rotation;
if(!m_inVR) Transform l_rightHand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand);
{ if(l_rightHand != null)
l_poseHandler = new HumanPoseHandler(PlayerSetup.Instance._animator.avatar, PlayerSetup.Instance._avatar.transform); m_rightTarget.localRotation = ms_offsetRight * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_rightHand.GetMatrix()).rotation;
l_poseHandler.GetHumanPose(ref l_currentPose);
HumanPose l_tPose = new HumanPose
{
bodyPosition = l_currentPose.bodyPosition,
bodyRotation = l_currentPose.bodyRotation,
muscles = new float[l_currentPose.muscles.Length]
};
for(int i = 0; i < l_tPose.muscles.Length; i++)
l_tPose.muscles[i] = ms_tposeMuscles[i];
l_poseHandler.SetHumanPose(ref l_tPose);
}
Transform l_hand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand);
if(l_hand != null)
m_rotationTarget.localRotation = (ms_palmToLeft * (m_inVR ? ms_offsetRight : ms_offsetRightDesktop)) * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_hand.GetMatrix()).rotation;
if(m_vrIK == null) if(m_vrIK == null)
{ {
@ -169,39 +329,56 @@ namespace ml_pam
if(l_chest == null) if(l_chest == null)
l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Spine); l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Spine);
m_armIK = PlayerSetup.Instance._avatar.AddComponent<ArmIK>(); m_armIKLeft = PlayerSetup.Instance._avatar.AddComponent<ArmIK>();
m_armIK.solver.isLeft = false; m_armIKLeft.solver.isLeft = true;
m_armIK.solver.SetChain( m_armIKLeft.solver.SetChain(
l_chest,
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftShoulder),
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftUpperArm),
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftLowerArm),
l_leftHand,
PlayerSetup.Instance._animator.transform
);
m_armIKLeft.solver.arm.target = m_leftTarget;
m_armIKLeft.solver.arm.positionWeight = 1f;
m_armIKLeft.solver.arm.rotationWeight = 1f;
m_armIKLeft.solver.IKPositionWeight = 0f;
m_armIKLeft.solver.IKRotationWeight = 0f;
m_armIKLeft.enabled = false;
m_armLength = m_armIKLeft.solver.arm.mag * 1.25f;
m_armIKRight = PlayerSetup.Instance._avatar.AddComponent<ArmIK>();
m_armIKRight.solver.isLeft = false;
m_armIKRight.solver.SetChain(
l_chest, l_chest,
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightShoulder), PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightShoulder),
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightUpperArm), PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightUpperArm),
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightLowerArm), PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightLowerArm),
l_hand, l_rightHand,
PlayerSetup.Instance._animator.transform PlayerSetup.Instance._animator.transform
); );
m_armIK.solver.arm.target = m_rotationTarget; m_armIKRight.solver.arm.target = m_rightTarget;
m_armIK.solver.arm.positionWeight = 1f; m_armIKRight.solver.arm.positionWeight = 1f;
m_armIK.solver.arm.rotationWeight = 1f; m_armIKRight.solver.arm.rotationWeight = 1f;
m_armIK.solver.IKPositionWeight = 0f; m_armIKRight.solver.IKPositionWeight = 0f;
m_armIK.solver.IKRotationWeight = 0f; m_armIKRight.solver.IKRotationWeight = 0f;
m_armIK.enabled = m_enabled; m_armIKRight.enabled = false;
} }
else else
{ {
m_origLeftHand = m_vrIK.solver.leftArm.target;
m_origRightHand = m_vrIK.solver.rightArm.target; m_origRightHand = m_vrIK.solver.rightArm.target;
m_armLength = m_vrIK.solver.leftArm.mag * 1.25f;
m_vrIK.solver.OnPreUpdate += this.OnIKPreUpdate; m_vrIK.solver.OnPreUpdate += this.OnIKPreUpdate;
m_vrIK.solver.OnPostUpdate += this.OnIKPostUpdate; m_vrIK.solver.OnPostUpdate += this.OnIKPostUpdate;
} }
l_poseHandler?.SetHumanPose(ref l_currentPose); l_tpHelper.Restore();
l_poseHandler?.Dispose(); l_tpHelper.Unassign();
if(l_hips != null)
l_hips.localPosition = l_hipsPos;
} }
if(m_enabled) SetEnabled(m_enabled);
RestorePickup();
} }
internal void OnPickupGrab(CVRPickupObject p_pickup, ControllerRay p_ray, Vector3 p_hit) internal void OnPickupGrab(CVRPickupObject p_pickup, ControllerRay p_ray, Vector3 p_hit)
@ -224,20 +401,23 @@ namespace ml_pam
else else
m_offset = m_pickup.transform.GetMatrix().inverse * Matrix4x4.Translate(p_hit); m_offset = m_pickup.transform.GetMatrix().inverse * Matrix4x4.Translate(p_hit);
if(m_enabled) switch(Settings.LeadingHand)
{ {
if((m_vrIK != null) && !m_targetActive) case Settings.LeadHand.Left:
m_leftHandState = HandState.Pickup;
break;
case Settings.LeadHand.Right:
m_rightHandState = HandState.Pickup;
break;
case Settings.LeadHand.Both:
{ {
m_vrIK.solver.rightArm.target = m_rotationTarget; m_leftHandState = HandState.Pickup;
m_targetActive = true; m_rightHandState = HandState.Pickup;
}
break;
} }
if(m_armIK != null) SetArmActive(Settings.LeadingHand, true);
{
m_armIK.solver.IKPositionWeight = 1f;
m_armIK.solver.IKRotationWeight = 1f;
}
}
} }
} }
@ -246,17 +426,22 @@ namespace ml_pam
if(m_pickup == p_pickup) if(m_pickup == p_pickup)
{ {
m_pickup = null; m_pickup = null;
switch(Settings.LeadingHand)
if(m_enabled)
{ {
RestoreVRIK(); case Settings.LeadHand.Left:
m_leftHandState = HandState.Empty;
if(m_armIK != null) break;
case Settings.LeadHand.Right:
m_rightHandState = HandState.Empty;
break;
case Settings.LeadHand.Both:
{ {
m_armIK.solver.IKPositionWeight = 0f; m_leftHandState = HandState.Empty;
m_armIK.solver.IKRotationWeight = 0f; m_rightHandState = HandState.Empty;
} }
break;
} }
SetArmActive(Settings.LeadingHand, false);
} }
} }
@ -267,33 +452,23 @@ namespace ml_pam
} }
// Arbitrary // Arbitrary
void RestorePickup() void SetArmActive(Settings.LeadHand p_hand, bool p_state, bool p_forced = false)
{ {
if((m_vrIK != null) && (m_pickup != null)) if(m_enabled || p_forced)
{ {
m_vrIK.solver.rightArm.target = m_rotationTarget; if(((p_hand == Settings.LeadHand.Left) || (p_hand == Settings.LeadHand.Both)) && (m_armIKLeft != null))
m_targetActive = true; {
m_armIKLeft.enabled = m_enabled;
m_armIKLeft.solver.IKPositionWeight = (p_state ? 1f : 0f);
m_armIKLeft.solver.IKRotationWeight = (p_state ? 1f : 0f);
} }
if((m_armIK != null) && (m_pickup != null)) if(((p_hand == Settings.LeadHand.Right) || (p_hand == Settings.LeadHand.Both)) && (m_armIKRight != null))
{ {
m_armIK.solver.IKPositionWeight = 1f; m_armIKRight.enabled = m_enabled;
m_armIK.solver.IKRotationWeight = 1f; m_armIKRight.solver.IKPositionWeight = (p_state ? 1f : 0f);
m_armIKRight.solver.IKRotationWeight = (p_state ? 1f : 0f);
} }
} }
void RestoreVRIK()
{
if((m_vrIK != null) && m_targetActive)
{
m_vrIK.solver.rightArm.target = m_origRightHand;
m_targetActive = false;
}
}
void RefreshArmIK()
{
if(m_armIK != null)
m_armIK.enabled = m_enabled;
} }
} }
} }

View file

@ -1,4 +1,4 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_pam.PickupArmMovement), "PickupArmMovement", "1.0.8", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonInfo(typeof(ml_pam.PickupArmMovement), "PickupArmMovement", "1.0.9", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
[assembly: MelonLoader.MelonPriority(1)] [assembly: MelonLoader.MelonPriority(1)]
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]

View file

@ -9,4 +9,10 @@ This mod adds arm tracking upon holding pickup in desktop mode.
# Usage # Usage
Available mod's settings in `Settings - Interactions - Pickup Arm Movement`: Available mod's settings in `Settings - Interactions - Pickup Arm Movement`:
* **Enable hand movement:** enables/disables arm tracking; default value - `true`. * **Enable hand movement:** enables/disables arm tracking; default value - `true`.
* **Grab offset:** offset from pickup grab point; defalut value - `25`. * **Grab offset:** offset from pickup grab point; default value - `25`.
* **Leading hand:** hand that will be extended when gragging pickup; available values: `Left`, `Right`, `Both`; default value - `Right`.
* **Hands extension (Q\E):** extend left and right hand if `Q` and `E` keys are pressed; default value - `true`.
# Notes
* Made for desktop mode in mind.
* Compatible with [DekstopVRIK](https://github.com/NotAKidOnSteam/NAK_CVR_Mods).

View file

@ -9,17 +9,29 @@ namespace ml_pam
public enum ModSetting public enum ModSetting
{ {
Enabled = 0, Enabled = 0,
GrabOffset GrabOffset,
LeadHand,
HandsExtension
}
public enum LeadHand
{
Left = 0,
Right,
Both
} }
public static bool Enabled { get; private set; } = true; public static bool Enabled { get; private set; } = true;
public static float GrabOffset { get; private set; } = 0.25f; public static float GrabOffset { get; private set; } = 0.25f;
public static LeadHand LeadingHand { get; private set; } = LeadHand.Right;
public static bool HandsExtension { 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;
static public event Action<bool> EnabledChange; static public event Action<bool> EnabledChange;
static public event Action<float> GrabOffsetChange; static public event Action<float> GrabOffsetChange;
static public event Action<LeadHand> LeadingHandChange;
static public event Action<bool> HandsExtensionChange;
internal static void Init() internal static void Init()
{ {
@ -29,9 +41,14 @@ namespace ml_pam
{ {
ms_category.CreateEntry(ModSetting.Enabled.ToString(), Enabled), ms_category.CreateEntry(ModSetting.Enabled.ToString(), Enabled),
ms_category.CreateEntry(ModSetting.GrabOffset.ToString(), (int)(GrabOffset * 100f)), ms_category.CreateEntry(ModSetting.GrabOffset.ToString(), (int)(GrabOffset * 100f)),
ms_category.CreateEntry(ModSetting.LeadHand.ToString(), (int)LeadHand.Right),
ms_category.CreateEntry(ModSetting.HandsExtension.ToString(), HandsExtension),
}; };
Load(); Enabled = (bool)ms_entries[(int)ModSetting.Enabled].BoxedValue;
GrabOffset = (int)ms_entries[(int)ModSetting.GrabOffset].BoxedValue * 0.01f;
LeadingHand = (LeadHand)(int)ms_entries[(int)ModSetting.LeadHand].BoxedValue;
HandsExtension = (bool)ms_entries[(int)ModSetting.HandsExtension].BoxedValue;
MelonLoader.MelonCoroutines.Start(WaitMainMenuUi()); MelonLoader.MelonCoroutines.Start(WaitMainMenuUi());
} }
@ -49,6 +66,7 @@ namespace ml_pam
{ {
ViewManager.Instance.gameMenuView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate)); ViewManager.Instance.gameMenuView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate));
ViewManager.Instance.gameMenuView.View.BindCall("OnSliderUpdate_" + ms_category.Identifier, new Action<string, string>(OnSliderUpdate)); ViewManager.Instance.gameMenuView.View.BindCall("OnSliderUpdate_" + ms_category.Identifier, new Action<string, string>(OnSliderUpdate));
ViewManager.Instance.gameMenuView.View.BindCall("OnDropdownUpdate_" + ms_category.Identifier, new Action<string, string>(OnDropdownUpdate));
}; };
ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) => ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) =>
{ {
@ -59,12 +77,6 @@ namespace ml_pam
}; };
} }
static void Load()
{
Enabled = (bool)ms_entries[(int)ModSetting.Enabled].BoxedValue;
GrabOffset = (int)ms_entries[(int)ModSetting.GrabOffset].BoxedValue * 0.01f;
}
static void OnToggleUpdate(string p_name, string p_value) static void OnToggleUpdate(string p_name, string p_value)
{ {
if(Enum.TryParse(p_name, out ModSetting l_setting)) if(Enum.TryParse(p_name, out ModSetting l_setting))
@ -77,6 +89,12 @@ namespace ml_pam
EnabledChange?.Invoke(Enabled); EnabledChange?.Invoke(Enabled);
} }
break; break;
case ModSetting.HandsExtension:
{
HandsExtension = bool.Parse(p_value);
HandsExtensionChange?.Invoke(HandsExtension);
} break;
} }
ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
@ -100,5 +118,23 @@ namespace ml_pam
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value); ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
} }
} }
static void OnDropdownUpdate(string p_name, string p_value)
{
if(Enum.TryParse(p_name, out ModSetting l_setting))
{
switch(l_setting)
{
case ModSetting.LeadHand:
{
LeadingHand = (LeadHand)int.Parse(p_value);
LeadingHandChange?.Invoke(LeadingHand);
}
break;
}
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
}
}
} }
} }

63
ml_pam/TPoseHelper.cs Normal file
View file

@ -0,0 +1,63 @@
using System.Reflection;
using UnityEngine;
using ABI_RC.Systems.IK.SubSystems;
namespace ml_pam
{
class TPoseHelper
{
static readonly float[] ms_tposeMuscles = typeof(BodySystem).GetField("TPoseMuscles", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null) as float[];
HumanPoseHandler m_poseHandler = null;
HumanPose m_oldPose;
HumanPose m_newPose;
Vector3 m_hipsLocalPos = Vector3.zero;
Transform m_hips = null;
public void Assign(Animator p_animator)
{
if(m_poseHandler != null)
{
m_poseHandler = new HumanPoseHandler(p_animator.avatar, p_animator.transform);
m_hips = p_animator.GetBoneTransform(HumanBodyBones.Hips);
}
}
public void Unassign()
{
m_poseHandler?.Dispose();
m_poseHandler = null;
m_oldPose = new HumanPose();
m_newPose = new HumanPose();
m_hips = null;
m_hipsLocalPos = Vector3.zero;
}
public void Apply()
{
if(m_hips != null)
m_hipsLocalPos = m_hips.localPosition;
if(m_poseHandler != null)
{
m_poseHandler.GetHumanPose(ref m_oldPose);
m_newPose.bodyPosition = m_oldPose.bodyPosition;
m_newPose.bodyRotation = m_oldPose.bodyRotation;
m_newPose.muscles = new float[m_oldPose.muscles.Length];
for(int i = 0, j = m_newPose.muscles.Length; i < j; i++)
m_newPose.muscles[i] = ms_tposeMuscles[i];
m_poseHandler.SetHumanPose(ref m_newPose);
}
}
public void Restore()
{
if(m_poseHandler != null)
m_poseHandler.SetHumanPose(ref m_oldPose);
if(m_hips != null)
m_hips.localPosition = m_hipsLocalPos;
}
}
}

View file

@ -4,7 +4,7 @@
<TargetFramework>netstandard2.1</TargetFramework> <TargetFramework>netstandard2.1</TargetFramework>
<Platforms>x64</Platforms> <Platforms>x64</Platforms>
<PackageId>PickupArmMovement</PackageId> <PackageId>PickupArmMovement</PackageId>
<Version>1.0.8</Version> <Version>1.0.9</Version>
<Authors>SDraw</Authors> <Authors>SDraw</Authors>
<Company>None</Company> <Company>None</Company>
<Product>PickupArmMovement</Product> <Product>PickupArmMovement</Product>
@ -65,6 +65,10 @@
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll</HintPath> <HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
<Private>false</Private> <Private>false</Private>
</Reference> </Reference>
<Reference Include="UnityEngine.InputLegacyModule">
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.InputLegacyModule.dll</HintPath>
<Private>false</Private>
</Reference>
</ItemGroup> </ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent"> <Target Name="PostBuild" AfterTargets="PostBuildEvent">

View file

@ -7,7 +7,7 @@
</div> </div>
<div class ="row-wrapper"> <div class ="row-wrapper">
<div class ="option-caption">Enable hand movement: </div> <div class ="option-caption">Enabled: </div>
<div class ="option-input"> <div class ="option-input">
<div id="Enabled" class ="inp_toggle no-scroll" data-current="true"></div> <div id="Enabled" class ="inp_toggle no-scroll" data-current="true"></div>
</div> </div>
@ -19,6 +19,20 @@
<div id="GrabOffset" class ="inp_slider no-scroll" data-min="0" data-max="100" data-current="25"></div> <div id="GrabOffset" class ="inp_slider no-scroll" data-min="0" data-max="100" data-current="25"></div>
</div> </div>
</div> </div>
<div class ="row-wrapper">
<div class ="option-caption">Leading hand: </div>
<div class ="option-input">
<div id="LeadHand" class ="inp_dropdown no-scroll" data-options="0:Left,1:Right,2:Both" data-current="1"></div>
</div>
</div>
<div class ="row-wrapper">
<div class ="option-caption">Hands extension (Q/E): </div>
<div class ="option-input">
<div id="HandsExtension" class ="inp_toggle no-scroll" data-current="true"></div>
</div>
</div>
`; `;
document.getElementById('settings-interaction').appendChild(l_block); document.getElementById('settings-interaction').appendChild(l_block);
@ -29,4 +43,8 @@
// Sliders // Sliders
for (let l_slider of l_block.querySelectorAll('.inp_slider')) for (let l_slider of l_block.querySelectorAll('.inp_slider'))
modsExtension.addSetting('PAM', l_slider.id, modsExtension.createSlider(l_slider, 'OnSliderUpdate_PAM')); modsExtension.addSetting('PAM', l_slider.id, modsExtension.createSlider(l_slider, 'OnSliderUpdate_PAM'));
// Dropdowns
for (let l_dropdown of l_block.querySelectorAll('.inp_dropdown'))
modsExtension.addSetting('PAM', l_dropdown.id, modsExtension.createDropdown(l_dropdown, 'OnDropdownUpdate_PAM'));
} }

View file

@ -364,13 +364,12 @@ namespace ml_prm
internal void OnAvatarScaling(float p_scaleDifference) internal void OnAvatarScaling(float p_scaleDifference)
{ {
if(m_avatarReady) if(m_puppetRoot != null)
{
m_puppetRoot.localScale = Vector3.one * p_scaleDifference; m_puppetRoot.localScale = Vector3.one * p_scaleDifference;
foreach(var l_pair in m_jointAnchors) foreach(var l_pair in m_jointAnchors)
l_pair.Item1.connectedAnchor = l_pair.Item2 * p_scaleDifference; l_pair.Item1.connectedAnchor = l_pair.Item2 * p_scaleDifference;
} }
}
internal void OnSeatSitDown(CVRSeat p_seat) internal void OnSeatSitDown(CVRSeat p_seat)
{ {