Skip to content

Commit

Permalink
Emotes custom detection
Browse files Browse the repository at this point in the history
VRIK component checks for desktop mode
Disable head rotation when emote is active
  • Loading branch information
SDraw committed Oct 7, 2022
1 parent 71c0068 commit 4dafd9d
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 26 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ Merged set of MelonLoader mods for ChilloutVR.
| Full name | Short name | Latest version | Available in [CVRMA](https://github.com/knah/CVRMelonAssistant) | Current Status | Notes |
|-----------|------------|----------------|-----------------------------------------------------------------|----------------|-------|
| Avatar Change Info | ml_aci | 1.0.2 | Yes | Working |
| Avatar Motion Tweaker | ml_amt | 1.1.1 | On review | Working |
| Desktop Head Tracking | ml_dht | 1.0.4 | On review | Working |
| Avatar Motion Tweaker | ml_amt | 1.1.2 | On review | Working |
| Desktop Head Tracking | ml_dht | 1.0.5 | On review | Working |
| Desktop Reticle Switch | ml_drs | 1.0.0 | Yes | Working |
| Four Point Tracking | ml_fpt | 1.0.7 | On review | Working |
| Leap Motion Extension | ml_lme | 1.2.0 | On review | Working |
Expand Down
7 changes: 7 additions & 0 deletions ml_amt/Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public override void OnApplicationStart()
Settings.PoseTransitionsChange += this.OnPoseTransitonsChange;
Settings.AdjustedMovementChange += this.OnAdjustedMovementChange;
Settings.IKOverrideFlyChange += this.OnIKOverrideFlyChange;
Settings.DetectEmotesChange += this.OnDetectEmotesChange;

HarmonyInstance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
Expand Down Expand Up @@ -49,6 +50,7 @@ System.Collections.IEnumerator WaitForLocalPlayer()
m_localTweaker.SetPoseTransitions(Settings.PoseTransitions);
m_localTweaker.SetAdjustedMovement(Settings.AdjustedMovement);
m_localTweaker.SetIKOverrideFly(Settings.IKOverrideFly);
m_localTweaker.SetDetectEmotes(Settings.DetectEmotes);
}

void OnIKOverrideCrouchChange(bool p_state)
Expand Down Expand Up @@ -86,6 +88,11 @@ void OnIKOverrideFlyChange(bool p_state)
if(m_localTweaker != null)
m_localTweaker.SetIKOverrideFly(p_state);
}
void OnDetectEmotesChange(bool p_state)
{
if(m_localTweaker != null)
m_localTweaker.SetDetectEmotes(p_state);
}

static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear();
void OnAvatarClear()
Expand Down
49 changes: 40 additions & 9 deletions ml_amt/MotionTweaker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@
using ABI_RC.Systems.MovementSystem;
using RootMotion.FinalIK;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;

namespace ml_amt
{
[DisallowMultipleComponent]
class MotionTweaker : MonoBehaviour
{
static System.Reflection.FieldInfo ms_rootVelocity = typeof(IKSolverVR).GetField("rootVelocity", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
static System.Reflection.FieldInfo ms_groundedRaw = typeof(MovementSystem).GetField("_isGroundedRaw", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
static readonly FieldInfo ms_rootVelocity = typeof(IKSolverVR).GetField("rootVelocity", BindingFlags.NonPublic | BindingFlags.Instance);
static readonly FieldInfo ms_groundedRaw = typeof(MovementSystem).GetField("_isGroundedRaw", BindingFlags.NonPublic | BindingFlags.Instance);
static readonly int ms_emoteHash = Animator.StringToHash("Emote");

enum ParameterType
{
Expand Down Expand Up @@ -41,6 +44,8 @@ enum PoseState
static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f);

VRIK m_vrIk = null;
int m_locomotionLayer = 0;
float m_ikWeight = 1f; // Original weight
float m_locomotionWeight = 1f; // Original weight
float m_avatarScale = 1f; // Instantiated scale

Expand All @@ -64,6 +69,9 @@ enum PoseState
bool m_customLocomotionOffset = false;
Vector3 m_locomotionOffset = Vector3.zero;

bool m_detectEmotes = true;
bool m_emoteActive = false;

readonly List<AdditionalParameterInfo> m_parameters = null;

public MotionTweaker()
Expand All @@ -83,7 +91,7 @@ void Update()
m_upright = Mathf.Clamp(((l_avatarViewHeight > 0f) ? (l_currentHeight / l_avatarViewHeight) : 0f), 0f, 1f);
PoseState l_poseState = (m_upright <= m_proneLimit) ? PoseState.Proning : ((m_upright <= m_crouchLimit) ? PoseState.Crouching : PoseState.Standing);

if((m_vrIk != null) && m_vrIk.enabled)
if(PlayerSetup.Instance._inVr && (m_vrIk != null) && m_vrIk.enabled)
{
if(m_poseState != l_poseState)
{
Expand Down Expand Up @@ -115,6 +123,14 @@ void Update()

m_poseState = l_poseState;

if(m_detectEmotes && (m_locomotionLayer >= 0))
{
AnimatorStateInfo l_animState = PlayerSetup.Instance._animator.GetCurrentAnimatorStateInfo(m_locomotionLayer);
m_emoteActive = (l_animState.tagHash == ms_emoteHash);
}
else
m_emoteActive = false;

if(m_parameters.Count > 0)
{
foreach(AdditionalParameterInfo l_param in m_parameters)
Expand All @@ -129,7 +145,7 @@ void Update()
PlayerSetup.Instance._animator.SetFloat(l_param.m_hash, m_upright);
break;
case ParameterSyncType.Synced:
PlayerSetup.Instance.changeAnimatorParam(l_param.m_name, m_upright);
PlayerSetup.Instance.animatorManager.SetAnimatorParameterFloat(l_param.m_name, m_upright);
break;
}
}
Expand All @@ -143,7 +159,7 @@ void Update()
PlayerSetup.Instance._animator.SetBool(l_param.m_hash, (bool)ms_groundedRaw.GetValue(MovementSystem.Instance));
break;
case ParameterSyncType.Synced:
PlayerSetup.Instance.changeAnimatorParam(l_param.m_name, (bool)ms_groundedRaw.GetValue(MovementSystem.Instance) ? 1f : 0f);
PlayerSetup.Instance.animatorManager.SetAnimatorParameterBool(l_param.m_name, (bool)ms_groundedRaw.GetValue(MovementSystem.Instance));
break;
}
}
Expand All @@ -157,6 +173,7 @@ void Update()
public void OnAvatarClear()
{
m_vrIk = null;
m_locomotionLayer = -1;
m_avatarReady = false;
m_compatibleAvatar = false;
m_poseState = PoseState.Standing;
Expand All @@ -165,12 +182,14 @@ public void OnAvatarClear()
m_customLocomotionOffset = false;
m_locomotionOffset = Vector3.zero;
m_avatarScale = 1f;
m_emoteActive = false;
m_parameters.Clear();
}

public void OnCalibrateAvatar()
{
m_vrIk = PlayerSetup.Instance._avatar.GetComponent<VRIK>();
m_locomotionLayer = PlayerSetup.Instance._animator.GetLayerIndex("Locomotion/Emotes");

// Parse animator parameters
AnimatorControllerParameter[] l_params = PlayerSetup.Instance._animator.parameters;
Expand Down Expand Up @@ -227,16 +246,24 @@ public void OnCalibrateAvatar()

void OnIKPreUpdate()
{
m_ikWeight = m_vrIk.solver.IKPositionWeight;
m_locomotionWeight = m_vrIk.solver.locomotion.weight;

if((m_ikOverrideCrouch && (m_poseState != PoseState.Standing)) || (m_ikOverrideProne && (m_poseState == PoseState.Proning)))
m_vrIk.solver.locomotion.weight = 0f;
if(m_ikOverrideFly && MovementSystem.Instance.flying)
m_vrIk.solver.locomotion.weight = 0f;
if(m_detectEmotes && m_emoteActive)
m_vrIk.solver.IKPositionWeight = 0f;

if(PlayerSetup.Instance._inVr)
{
if((m_ikOverrideCrouch && (m_poseState != PoseState.Standing)) || (m_ikOverrideProne && (m_poseState == PoseState.Proning)))
m_vrIk.solver.locomotion.weight = 0f;
if(m_ikOverrideFly && MovementSystem.Instance.flying)
m_vrIk.solver.locomotion.weight = 0f;
}
}

void OnIKPostUpdate()
{
m_vrIk.solver.IKPositionWeight = m_ikWeight;
m_vrIk.solver.locomotion.weight = m_locomotionWeight;
}

Expand Down Expand Up @@ -282,5 +309,9 @@ public void SetIKOverrideFly(bool p_state)
{
m_ikOverrideFly = p_state;
}
public void SetDetectEmotes(bool p_state)
{
m_detectEmotes = p_state;
}
}
}
6 changes: 3 additions & 3 deletions ml_amt/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using System.Reflection;

[assembly: AssemblyTitle("AvatarMotionTweaker")]
[assembly: AssemblyVersion("1.1.1")]
[assembly: AssemblyFileVersion("1.1.1")]
[assembly: AssemblyVersion("1.1.2")]
[assembly: AssemblyFileVersion("1.1.2")]

[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.1.1", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.1.2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
18 changes: 17 additions & 1 deletion ml_amt/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ enum ModSetting
ProneLimit,
PoseTransitions,
AdjustedMovement,
IKOverrideFly
IKOverrideFly,
DetectEmotes
};

static bool ms_ikOverrideCrouch = true;
Expand All @@ -25,6 +26,7 @@ enum ModSetting
static bool ms_poseTransitions = true;
static bool ms_adjustedMovement = true;
static bool ms_ikOverrideFly = true;
static bool ms_detectEmotes = true;

static MelonLoader.MelonPreferences_Category ms_category = null;
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
Expand All @@ -36,6 +38,7 @@ enum ModSetting
static public event Action<bool> PoseTransitionsChange;
static public event Action<bool> AdjustedMovementChange;
static public event Action<bool> IKOverrideFlyChange;
static public event Action<bool> DetectEmotesChange;

public static void Init()
{
Expand All @@ -49,6 +52,7 @@ public static void Init()
ms_entries.Add(ms_category.CreateEntry(ModSetting.PoseTransitions.ToString(), true));
ms_entries.Add(ms_category.CreateEntry(ModSetting.AdjustedMovement.ToString(), true));
ms_entries.Add(ms_category.CreateEntry(ModSetting.IKOverrideFly.ToString(), true));
ms_entries.Add(ms_category.CreateEntry(ModSetting.DetectEmotes.ToString(), true));

Load();

Expand Down Expand Up @@ -86,6 +90,7 @@ static void Load()
ms_poseTransitions = (bool)ms_entries[(int)ModSetting.PoseTransitions].BoxedValue;
ms_adjustedMovement = (bool)ms_entries[(int)ModSetting.AdjustedMovement].BoxedValue;
ms_ikOverrideFly = (bool)ms_entries[(int)ModSetting.IKOverrideFly].BoxedValue;
ms_detectEmotes = (bool)ms_entries[(int)ModSetting.DetectEmotes].BoxedValue;
}

static void OnSliderUpdate(string p_name, string p_value)
Expand Down Expand Up @@ -152,6 +157,13 @@ static void OnToggleUpdate(string p_name, string p_value)
ms_ikOverrideFly = bool.Parse(p_value);
IKOverrideFlyChange?.Invoke(ms_ikOverrideFly);
} break;

case ModSetting.DetectEmotes:
{
ms_detectEmotes = bool.Parse(p_value);
DetectEmotesChange?.Invoke(ms_detectEmotes);
}
break;
}

ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
Expand Down Expand Up @@ -186,5 +198,9 @@ public static bool IKOverrideFly
{
get => ms_ikOverrideFly;
}
public static bool DetectEmotes
{
get => ms_detectEmotes;
}
}
}
7 changes: 7 additions & 0 deletions ml_amt/resources/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,13 @@ function inp_toggle_mod_amt(_obj, _callbackName) {
<div id="AdjustedMovement" class ="inp_toggle no-scroll" data-current="true"></div>
</div>
</div>
<div class ="row-wrapper">
<div class ="option-caption">Detect animations emote tag: </div>
<div class ="option-input">
<div id="DetectEmotes" class ="inp_toggle no-scroll" data-current="true"></div>
</div>
</div>
`;
document.getElementById('settings-implementation').appendChild(l_block);

Expand Down
9 changes: 7 additions & 2 deletions ml_dht/HeadTracked.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
using ABI.CCK.Components;
using ABI_RC.Core.Player;
using System.Reflection;
using UnityEngine;

namespace ml_dht
{
[DisallowMultipleComponent]
class HeadTracked : MonoBehaviour
{
static FieldInfo ms_emotePlaying = typeof(PlayerSetup).GetField("_emotePlaying", BindingFlags.NonPublic | BindingFlags.Instance);

bool m_enabled = false;
float m_smoothing = 0.5f;
bool m_mirrored = false;
Expand Down Expand Up @@ -47,7 +50,9 @@ void OnLookIKPostUpdate()
if(m_enabled && (m_headBone != null))
{
m_lastHeadRotation = Quaternion.Slerp(m_lastHeadRotation, m_avatarDescriptor.transform.rotation * (m_headRotation * m_bindRotation), m_smoothing);
m_headBone.rotation = m_lastHeadRotation;

if(!(bool)ms_emotePlaying.GetValue(PlayerSetup.Instance))
m_headBone.rotation = m_lastHeadRotation;
}
}

Expand All @@ -71,7 +76,7 @@ public void OnFaceTrackingUpdate(CVRFaceTracking p_component)
{
if(m_avatarDescriptor != null)
m_avatarDescriptor.useVisemeLipsync = false;

float l_weight = Mathf.Clamp(Mathf.InverseLerp(0.25f, 1f, Mathf.Abs(m_mouthShapes.y)), 0f, 1f) * 100f;

p_component.BlendShapeValues[(int)ViveSR.anipal.Lip.LipShape_v2.Jaw_Open] = m_mouthShapes.x * 100f;
Expand Down
13 changes: 7 additions & 6 deletions ml_dht/Main.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using ABI.CCK.Components;
using ABI_RC.Core.Player;
using System.Reflection;

namespace ml_dht
{
Expand Down Expand Up @@ -33,22 +34,22 @@ public override void OnApplicationStart()
HarmonyInstance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
null,
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnAvatarClear_Postfix), System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic))
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
HarmonyInstance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.CalibrateAvatar)),
null,
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnCalibrateAvatar_Postfix), System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic))
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnCalibrateAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
HarmonyInstance.Patch(
typeof(CVREyeController).GetMethod("Update", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic),
typeof(CVREyeController).GetMethod("Update", BindingFlags.Instance | BindingFlags.NonPublic),
null,
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnEyeControllerUpdate_Postfix), System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic))
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnEyeControllerUpdate_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
HarmonyInstance.Patch(
typeof(CVRFaceTracking).GetMethod("Update", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic),
typeof(CVRFaceTracking).GetMethod("Update", BindingFlags.Instance | BindingFlags.NonPublic),
null,
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnFaceTrackingUpdate_Postfix), System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic))
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnFaceTrackingUpdate_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);

MelonLoader.MelonCoroutines.Start(WaitForPlayer());
Expand Down
6 changes: 3 additions & 3 deletions ml_dht/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using System.Reflection;

[assembly: AssemblyTitle("DesktopHeadTracking")]
[assembly: AssemblyVersion("1.0.4")]
[assembly: AssemblyFileVersion("1.0.4")]
[assembly: AssemblyVersion("1.0.5")]
[assembly: AssemblyFileVersion("1.0.5")]

[assembly: MelonLoader.MelonInfo(typeof(ml_dht.DesktopHeadTracking), "DesktopHeadTracking", "1.0.4", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonInfo(typeof(ml_dht.DesktopHeadTracking), "DesktopHeadTracking", "1.0.5", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]

0 comments on commit 4dafd9d

Please sign in to comment.