Emotes custom detection

VRIK component checks for desktop mode
Disable head rotation when emote is active
This commit is contained in:
SDraw 2022-10-08 02:28:22 +03:00
parent 71c0068652
commit 4dafd9dcd7
No known key found for this signature in database
GPG key ID: BB95B4DAB2BB8BB5
9 changed files with 93 additions and 26 deletions

View file

@ -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 |

View file

@ -21,6 +21,7 @@ namespace ml_amt
Settings.PoseTransitionsChange += this.OnPoseTransitonsChange;
Settings.AdjustedMovementChange += this.OnAdjustedMovementChange;
Settings.IKOverrideFlyChange += this.OnIKOverrideFlyChange;
Settings.DetectEmotesChange += this.OnDetectEmotesChange;
HarmonyInstance.Patch(
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
@ -49,6 +50,7 @@ namespace ml_amt
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)
@ -86,6 +88,11 @@ namespace ml_amt
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()

View file

@ -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
{
@ -41,6 +44,8 @@ namespace ml_amt
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
@ -64,6 +69,9 @@ namespace ml_amt
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()
@ -83,7 +91,7 @@ namespace ml_amt
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)
{
@ -115,6 +123,14 @@ namespace ml_amt
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)
@ -129,7 +145,7 @@ namespace ml_amt
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;
}
}
@ -143,7 +159,7 @@ namespace ml_amt
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;
}
}
@ -157,6 +173,7 @@ namespace ml_amt
public void OnAvatarClear()
{
m_vrIk = null;
m_locomotionLayer = -1;
m_avatarReady = false;
m_compatibleAvatar = false;
m_poseState = PoseState.Standing;
@ -165,12 +182,14 @@ namespace ml_amt
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;
@ -227,16 +246,24 @@ namespace ml_amt
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;
}
@ -282,5 +309,9 @@ namespace ml_amt
{
m_ikOverrideFly = p_state;
}
public void SetDetectEmotes(bool p_state)
{
m_detectEmotes = p_state;
}
}
}

View file

@ -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)]

View file

@ -15,7 +15,8 @@ namespace ml_amt
ProneLimit,
PoseTransitions,
AdjustedMovement,
IKOverrideFly
IKOverrideFly,
DetectEmotes
};
static bool ms_ikOverrideCrouch = true;
@ -25,6 +26,7 @@ namespace ml_amt
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;
@ -36,6 +38,7 @@ namespace ml_amt
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()
{
@ -49,6 +52,7 @@ namespace ml_amt
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();
@ -86,6 +90,7 @@ namespace ml_amt
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)
@ -152,6 +157,13 @@ namespace ml_amt
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);
@ -186,5 +198,9 @@ namespace ml_amt
{
get => ms_ikOverrideFly;
}
public static bool DetectEmotes
{
get => ms_detectEmotes;
}
}
}

View file

@ -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);

View file

@ -1,5 +1,6 @@
using ABI.CCK.Components;
using ABI_RC.Core.Player;
using System.Reflection;
using UnityEngine;
namespace ml_dht
@ -7,6 +8,8 @@ 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;
@ -47,7 +50,9 @@ namespace ml_dht
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;
}
}
@ -71,7 +76,7 @@ namespace ml_dht
{
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;

View file

@ -1,5 +1,6 @@
using ABI.CCK.Components;
using ABI_RC.Core.Player;
using System.Reflection;
namespace ml_dht
{
@ -33,22 +34,22 @@ namespace ml_dht
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());

View file

@ -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)]