mirror of
https://github.com/hanetzer/sdraw_mods_cvr.git
synced 2025-09-03 10:29:22 +00:00
Too many changes
This commit is contained in:
parent
45557943c4
commit
a22e5992d0
72 changed files with 1064 additions and 927 deletions
36
README.md
36
README.md
|
@ -1,25 +1,15 @@
|
|||
Merged set of MelonLoader mods for ChilloutVR.
|
||||
|
||||
**Table for game build 2023r175:**
|
||||
| Full name | Short name | Latest version |
|
||||
|:---------:|:----------:|:--------------:|
|
||||
| [Avatar Motion Tweaker](/ml_amt/README.md) | ml_amt | 1.4.1 [:arrow_down:](../../releases/latest/download/ml_amt.dll)|
|
||||
| [Avatar Synced Look](/ml_asl/README.md) | ml_asl | 1.0.4 [:arrow_down:](../../releases/latest/download/ml_asl.dll)|
|
||||
| [Better Fingers Tracking](/ml_bft/README.md) | ml_bft | 1.0.4 [:arrow_down:](../../releases/latest/download/ml_bft.dll)|
|
||||
| [Desktop Head Tracking](/ml_dht/README.md) | ml_dht | 1.2.5 [:arrow_down:](../../releases/latest/download/ml_dht.dll)|
|
||||
| [Leap Motion Extension](/ml_lme/README.md)| ml_lme | 1.5.2 [:arrow_down:](../../releases/latest/download/ml_lme.dll)|
|
||||
| [Pickup Arm Movement](/ml_pam/README.md)| ml_pam | 1.1.4 [:arrow_down:](../../releases/latest/download/ml_pam.dll)|
|
||||
| [Player Movement Copycat](/ml_pmc/README.md)| ml_pmc | 1.0.8 [:arrow_down:](../../releases/latest/download/ml_pmc.dll)|
|
||||
| [Player Ragdoll Mod](/ml_prm/README.md) | ml_prm | 1.1.9 [:arrow_down:](../../releases/latest/download/ml_prm.dll)|
|
||||
| [Players Instance Notifier](/ml_pin/README.md) | ml_pin | 1.0.8 [:arrow_down:](../../releases/latest/download/ml_ml_pin.dll)|
|
||||
| [Vive Extended Input](/ml_vei/README.md) | ml_vei | 1.0.4 [:arrow_down:](../../releases/latest/download/ml_vei.dll)|
|
||||
|
||||
**Archived mods:**
|
||||
| Full name | Short name | Notes |
|
||||
|:---------:|:----------:|-------|
|
||||
| Avatar Change Info | ml_aci | Superseded by `Extended Game Notifications` |
|
||||
| Desktop Reticle Switch | ml_drs | Boring functionality |
|
||||
| Extended Game Notifications | ml_egn | In-game feature since 2023r172 update |
|
||||
| Four Point Tracking | ml_fpt | In-game feature since 2022r170 update |
|
||||
| Game Main Fixes | ml_gmf | In-game feature since 2023r172 update |
|
||||
| Server Connection Info | ml_sci | Superseded by `Extended Game Notifications`
|
||||
**Table for game build 2023r177:**
|
||||
| Full name | Latest version |
|
||||
|:---------:|:--------------:|
|
||||
|[Avatar Motion Tweaker](/ml_amt/README.md)|1.5.0 [:arrow_down:](../../releases/latest/download/ml_amt.dll)|
|
||||
|[Avatar Synced Look](/ml_asl/README.md)|1.1.0 [:arrow_down:](../../releases/latest/download/ml_asl.dll)|
|
||||
|[Better Fingers Tracking](/ml_bft/README.md)|1.1.0 [:arrow_down:](../../releases/latest/download/ml_bft.dll)|
|
||||
|[Desktop Head Tracking](/ml_dht/README.md)|1.3.0 [:arrow_down:](../../releases/latest/download/ml_dht.dll)|
|
||||
|[Leap Motion Extension](/ml_lme/README.md)| 1.6.0 [:arrow_down:](../../releases/latest/download/ml_lme.dll)|
|
||||
|[Pickup Arm Movement](/ml_pam/README.md)|1.2.0 [:arrow_down:](../../releases/latest/download/ml_pam.dll)|
|
||||
|[Player Movement Copycat](/ml_pmc/README.md)|1.1.0 [:arrow_down:](../../releases/latest/download/ml_pmc.dll)|
|
||||
|[Player Ragdoll Mod](/ml_prm/README.md)|1.2.0 [:arrow_down:](../../releases/latest/download/ml_prm.dll)|
|
||||
|[Players Instance Notifier](/ml_pin/README.md)|1.1.0 [:arrow_down:](../../releases/latest/download/ml_ml_pin.dll)|
|
||||
|[Vive Extended Input](/ml_vei/README.md)|1.1.0 [:arrow_down:](../../releases/latest/download/ml_vei.dll)|
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace ml_amt
|
|||
[DisallowMultipleComponent]
|
||||
class MotionTweaker : MonoBehaviour
|
||||
{
|
||||
struct IKState
|
||||
struct IKInfo
|
||||
{
|
||||
public float m_weight;
|
||||
public float m_locomotionWeight;
|
||||
|
@ -20,7 +20,9 @@ namespace ml_amt
|
|||
public bool m_bendNormalRight;
|
||||
}
|
||||
|
||||
IKState m_ikState;
|
||||
static MotionTweaker ms_instance = null;
|
||||
|
||||
IKInfo m_ikInfo;
|
||||
VRIK m_vrIk = null;
|
||||
float m_avatarScale = 1f;
|
||||
Vector3 m_locomotionOffset = Vector3.zero; // Original locomotion offset
|
||||
|
@ -37,10 +39,19 @@ namespace ml_amt
|
|||
}
|
||||
|
||||
// Unity events
|
||||
void Awake()
|
||||
{
|
||||
if(ms_instance != null)
|
||||
{
|
||||
DestroyImmediate(this);
|
||||
return;
|
||||
}
|
||||
|
||||
ms_instance = this;
|
||||
DontDestroyOnLoad(this);
|
||||
}
|
||||
void Start()
|
||||
{
|
||||
DontDestroyOnLoad(this);
|
||||
|
||||
OnCrouchLimitChanged(Settings.CrouchLimit);
|
||||
OnProneLimitChanged(Settings.ProneLimit);
|
||||
|
||||
|
@ -56,6 +67,9 @@ namespace ml_amt
|
|||
|
||||
void OnDestroy()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
m_vrIk = null;
|
||||
m_ikLimits = null;
|
||||
m_parameters.Clear();
|
||||
|
@ -170,11 +184,11 @@ namespace ml_amt
|
|||
// IK events
|
||||
void OnIKPreSolverUpdate()
|
||||
{
|
||||
m_ikState.m_weight = m_vrIk.solver.IKPositionWeight;
|
||||
m_ikState.m_locomotionWeight = m_vrIk.solver.locomotion.weight;
|
||||
m_ikState.m_plantFeet = m_vrIk.solver.plantFeet;
|
||||
m_ikState.m_bendNormalLeft = m_vrIk.solver.leftLeg.useAnimatedBendNormal;
|
||||
m_ikState.m_bendNormalRight = m_vrIk.solver.rightLeg.useAnimatedBendNormal;
|
||||
m_ikInfo.m_weight = m_vrIk.solver.IKPositionWeight;
|
||||
m_ikInfo.m_locomotionWeight = m_vrIk.solver.locomotion.weight;
|
||||
m_ikInfo.m_plantFeet = m_vrIk.solver.plantFeet;
|
||||
m_ikInfo.m_bendNormalLeft = m_vrIk.solver.leftLeg.useAnimatedBendNormal;
|
||||
m_ikInfo.m_bendNormalRight = m_vrIk.solver.rightLeg.useAnimatedBendNormal;
|
||||
|
||||
if(!BodySystem.isCalibratedAsFullBody)
|
||||
{
|
||||
|
@ -200,11 +214,11 @@ namespace ml_amt
|
|||
|
||||
void OnIKPostSolverUpdate()
|
||||
{
|
||||
m_vrIk.solver.IKPositionWeight = m_ikState.m_weight;
|
||||
m_vrIk.solver.locomotion.weight = m_ikState.m_locomotionWeight;
|
||||
m_vrIk.solver.plantFeet = m_ikState.m_plantFeet;
|
||||
m_vrIk.solver.leftLeg.useAnimatedBendNormal = m_ikState.m_bendNormalLeft;
|
||||
m_vrIk.solver.rightLeg.useAnimatedBendNormal = m_ikState.m_bendNormalRight;
|
||||
m_vrIk.solver.IKPositionWeight = m_ikInfo.m_weight;
|
||||
m_vrIk.solver.locomotion.weight = m_ikInfo.m_locomotionWeight;
|
||||
m_vrIk.solver.plantFeet = m_ikInfo.m_plantFeet;
|
||||
m_vrIk.solver.leftLeg.useAnimatedBendNormal = m_ikInfo.m_bendNormalLeft;
|
||||
m_vrIk.solver.rightLeg.useAnimatedBendNormal = m_ikInfo.m_bendNormalRight;
|
||||
}
|
||||
|
||||
// Settings
|
||||
|
|
|
@ -6,15 +6,16 @@ namespace ml_amt
|
|||
{
|
||||
static class ResourcesHandler
|
||||
{
|
||||
readonly static string ms_namespace = typeof(ResourcesHandler).Namespace;
|
||||
|
||||
public static string GetEmbeddedResource(string p_name)
|
||||
{
|
||||
string l_result = "";
|
||||
Assembly l_assembly = Assembly.GetExecutingAssembly();
|
||||
string l_assemblyName = l_assembly.GetName().Name;
|
||||
|
||||
try
|
||||
{
|
||||
Stream l_libraryStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name);
|
||||
Stream l_libraryStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + p_name);
|
||||
StreamReader l_streadReader = new StreamReader(l_libraryStream);
|
||||
l_result = l_streadReader.ReadToEnd();
|
||||
}
|
||||
|
|
|
@ -18,20 +18,6 @@ namespace ml_amt
|
|||
|
||||
public static bool HasToes(this IKSolverVR p_instance) => (bool)ms_hasToes.GetValue(p_instance);
|
||||
|
||||
public static bool IsWorldSafe() => ((CVRWorld.Instance != null) && CVRWorld.Instance.allowFlying);
|
||||
public static float GetWorldMovementLimit()
|
||||
{
|
||||
float l_result = 1f;
|
||||
if(CVRWorld.Instance != null)
|
||||
{
|
||||
l_result = CVRWorld.Instance.baseMovementSpeed;
|
||||
l_result *= CVRWorld.Instance.sprintMultiplier;
|
||||
l_result *= CVRWorld.Instance.inAirMovementMultiplier;
|
||||
l_result *= CVRWorld.Instance.flyMultiplier;
|
||||
}
|
||||
return l_result;
|
||||
}
|
||||
|
||||
public static void ExecuteScript(this CohtmlControlledViewWrapper p_instance, string p_script) => ((cohtml.Net.View)ms_view.GetValue(p_instance)).ExecuteScript(p_script);
|
||||
|
||||
public static void SetAvatarTPose()
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<Company>SDraw</Company>
|
||||
<Product>AvatarMotionTweaker</Product>
|
||||
<PackageId>AvatarMotionTweaker</PackageId>
|
||||
<Version>1.4.2</Version>
|
||||
<Version>1.5.0</Version>
|
||||
<Platforms>x64</Platforms>
|
||||
<AssemblyName>AvatarMotionTweaker</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_asl
|
||||
{
|
||||
public class AvatarSyncedLook : MelonLoader.MelonMod
|
||||
{
|
||||
readonly static Matrix4x4 ms_back = Matrix4x4.Translate(Vector3.back);
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
Settings.Init();
|
||||
|
@ -19,7 +22,14 @@ namespace ml_asl
|
|||
static void OnPlayerAvatarMovementDataUpdate_Postfix(ref PlayerSetup __instance, PlayerAvatarMovementData ____playerAvatarMovementData)
|
||||
{
|
||||
if(Settings.Enabled && (__instance.EyeMovementController != null))
|
||||
{
|
||||
____playerAvatarMovementData.EyeTrackingOverride = true;
|
||||
|
||||
if(__instance.EyeMovementController.CurrentTarget != null)
|
||||
____playerAvatarMovementData.EyeTrackingPosition = __instance.EyeMovementController.CurrentTarget.GetPosition();
|
||||
else
|
||||
____playerAvatarMovementData.EyeTrackingPosition = (__instance.transform.GetMatrix() * ms_back).GetPosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_asl.AvatarSyncedLook), "AvatarSyncedLook", "1.0.4", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_asl.AvatarSyncedLook), "AvatarSyncedLook", "1.1.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
# Avatar Synced Look
|
||||
This mod Forces local player's eyes look direction to be synced for remote players.
|
||||
This mod forces local player's eyes look direction to be synced for remote players.
|
||||
|
||||
# Installation
|
||||
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
|
||||
* Get [latest release DLL](../../../releases/latest):
|
||||
* Put `ml_asl.dll` in `Mods` folder of game
|
||||
* Put `AvatarSyncedLook.dll` in `Mods` folder of game
|
||||
|
||||
# Usage
|
||||
Available mod's settings in `Settings - Interactions - Avatar Synced Look`:
|
||||
* **Enabled:** sets eyes look direction to be synced or locally generated on remote users side; `true` by default.
|
||||
|
||||
# Notes
|
||||
* Remote users with [EyeMovementFix](https://github.com/kafeijao/Kafe_CVR_Mods/tree/master/EyeMovementFix) installed can't see synced look direction.
|
||||
|
|
|
@ -6,15 +6,16 @@ namespace ml_asl
|
|||
{
|
||||
static class ResourcesHandler
|
||||
{
|
||||
readonly static string ms_namespace = typeof(ResourcesHandler).Namespace;
|
||||
|
||||
public static string GetEmbeddedResource(string p_name)
|
||||
{
|
||||
string l_result = "";
|
||||
Assembly l_assembly = Assembly.GetExecutingAssembly();
|
||||
string l_assemblyName = l_assembly.GetName().Name;
|
||||
|
||||
try
|
||||
{
|
||||
Stream l_libraryStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name);
|
||||
Stream l_libraryStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + p_name);
|
||||
StreamReader l_streadReader = new StreamReader(l_libraryStream);
|
||||
l_result = l_streadReader.ReadToEnd();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using ABI_RC.Core.UI;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_asl
|
||||
{
|
||||
|
@ -8,5 +9,11 @@ namespace ml_asl
|
|||
static readonly FieldInfo ms_view = typeof(CohtmlControlledViewWrapper).GetField("_view", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
public static void ExecuteScript(this CohtmlControlledViewWrapper p_instance, string p_script) => ((cohtml.Net.View)ms_view.GetValue(p_instance)).ExecuteScript(p_script);
|
||||
|
||||
// Extensions
|
||||
public static Matrix4x4 GetMatrix(this Transform p_transform, bool p_pos = true, bool p_rot = true, bool p_scl = false)
|
||||
{
|
||||
return Matrix4x4.TRS(p_pos ? p_transform.position : Vector3.zero, p_rot ? p_transform.rotation : Quaternion.identity, p_scl ? p_transform.localScale : Vector3.one);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,10 @@
|
|||
<Platforms>x64</Platforms>
|
||||
<PackageId>AvatarSyncedLook</PackageId>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Company>SDraw</Company>
|
||||
<Product>AvatarSyncedLook</Product>
|
||||
<Version>1.0.4</Version>
|
||||
<Version>1.1.0</Version>
|
||||
<AssemblyName>AvatarSyncedLook</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
@ -50,6 +51,11 @@
|
|||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.dll</HintPath>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
|
|
|
@ -7,10 +7,11 @@ namespace ml_bft
|
|||
{
|
||||
static class AssetsHandler
|
||||
{
|
||||
readonly static string ms_namespace = typeof(AssetsHandler).Namespace;
|
||||
|
||||
static readonly List<string> ms_assets = new List<string>()
|
||||
{
|
||||
"ovr_fingers.asset",
|
||||
"oxr_fingers.asset"
|
||||
"ovr_fingers.asset"
|
||||
};
|
||||
|
||||
static readonly Dictionary<string, AssetBundle> ms_loadedAssets = new Dictionary<string, AssetBundle>();
|
||||
|
@ -19,13 +20,12 @@ namespace ml_bft
|
|||
public static void Load()
|
||||
{
|
||||
Assembly l_assembly = Assembly.GetExecutingAssembly();
|
||||
string l_assemblyName = l_assembly.GetName().Name;
|
||||
|
||||
foreach(string l_assetName in ms_assets)
|
||||
{
|
||||
try
|
||||
{
|
||||
Stream l_assetStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + l_assetName);
|
||||
Stream l_assetStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + l_assetName);
|
||||
if(l_assetStream != null)
|
||||
{
|
||||
MemoryStream l_memorySteam = new MemoryStream((int)l_assetStream.Length);
|
||||
|
|
|
@ -45,18 +45,28 @@ namespace ml_bft
|
|||
HumanBodyBones.RightRingProximal, HumanBodyBones.RightRingIntermediate, HumanBodyBones.RightRingDistal,
|
||||
HumanBodyBones.RightLittleProximal, HumanBodyBones.RightLittleIntermediate, HumanBodyBones.RightLittleDistal
|
||||
};
|
||||
static readonly (HumanBodyBones, HumanBodyBones, bool)[] ms_rotationFixChains =
|
||||
static readonly (HumanBodyBones, HumanBodyBones, bool)[] ms_fingersChains =
|
||||
{
|
||||
(HumanBodyBones.LeftThumbProximal,HumanBodyBones.LeftThumbIntermediate,true), (HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.LeftThumbDistal,true),
|
||||
(HumanBodyBones.LeftIndexProximal,HumanBodyBones.LeftIndexIntermediate,true), (HumanBodyBones.LeftIndexIntermediate, HumanBodyBones.LeftIndexDistal,true),
|
||||
(HumanBodyBones.LeftMiddleProximal,HumanBodyBones.LeftMiddleIntermediate,true), (HumanBodyBones.LeftMiddleIntermediate, HumanBodyBones.LeftMiddleDistal,true),
|
||||
(HumanBodyBones.LeftRingProximal,HumanBodyBones.LeftRingIntermediate,true), (HumanBodyBones.LeftRingIntermediate, HumanBodyBones.LeftRingDistal,true),
|
||||
(HumanBodyBones.LeftLittleProximal,HumanBodyBones.LeftLittleIntermediate,true), (HumanBodyBones.LeftLittleIntermediate, HumanBodyBones.LeftLittleDistal,true),
|
||||
(HumanBodyBones.RightThumbProximal,HumanBodyBones.RightThumbIntermediate,false), (HumanBodyBones.RightThumbIntermediate, HumanBodyBones.RightThumbDistal,false),
|
||||
(HumanBodyBones.RightIndexProximal,HumanBodyBones.RightIndexIntermediate,false), (HumanBodyBones.RightIndexIntermediate, HumanBodyBones.RightIndexDistal,false),
|
||||
(HumanBodyBones.RightMiddleProximal,HumanBodyBones.RightMiddleIntermediate,false), (HumanBodyBones.RightMiddleIntermediate, HumanBodyBones.RightMiddleDistal,false),
|
||||
(HumanBodyBones.RightRingProximal,HumanBodyBones.RightRingIntermediate,false), (HumanBodyBones.RightRingIntermediate, HumanBodyBones.RightRingDistal,false),
|
||||
(HumanBodyBones.RightLittleProximal,HumanBodyBones.RightLittleIntermediate,false), (HumanBodyBones.RightLittleIntermediate, HumanBodyBones.RightLittleDistal,false)
|
||||
(HumanBodyBones.LeftThumbProximal,HumanBodyBones.LeftThumbIntermediate,true), (HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.LeftThumbDistal,true), (HumanBodyBones.LeftThumbDistal,HumanBodyBones.LastBone,true),
|
||||
(HumanBodyBones.LeftIndexProximal,HumanBodyBones.LeftIndexIntermediate,true), (HumanBodyBones.LeftIndexIntermediate, HumanBodyBones.LeftIndexDistal,true), (HumanBodyBones.LeftIndexDistal,HumanBodyBones.LastBone,true),
|
||||
(HumanBodyBones.LeftMiddleProximal,HumanBodyBones.LeftMiddleIntermediate,true), (HumanBodyBones.LeftMiddleIntermediate, HumanBodyBones.LeftMiddleDistal,true), (HumanBodyBones.LeftMiddleDistal,HumanBodyBones.LastBone,true),
|
||||
(HumanBodyBones.LeftRingProximal,HumanBodyBones.LeftRingIntermediate,true), (HumanBodyBones.LeftRingIntermediate, HumanBodyBones.LeftRingDistal,true), (HumanBodyBones.LeftRingDistal,HumanBodyBones.LastBone,true),
|
||||
(HumanBodyBones.LeftLittleProximal,HumanBodyBones.LeftLittleIntermediate,true), (HumanBodyBones.LeftLittleIntermediate, HumanBodyBones.LeftLittleDistal,true), (HumanBodyBones.LeftLittleDistal,HumanBodyBones.LastBone,true),
|
||||
(HumanBodyBones.RightThumbProximal,HumanBodyBones.RightThumbIntermediate,false), (HumanBodyBones.RightThumbIntermediate, HumanBodyBones.RightThumbDistal,false), (HumanBodyBones.RightThumbDistal,HumanBodyBones.LastBone,false),
|
||||
(HumanBodyBones.RightIndexProximal,HumanBodyBones.RightIndexIntermediate,false), (HumanBodyBones.RightIndexIntermediate, HumanBodyBones.RightIndexDistal,false), (HumanBodyBones.RightIndexDistal,HumanBodyBones.LastBone,false),
|
||||
(HumanBodyBones.RightMiddleProximal,HumanBodyBones.RightMiddleIntermediate,false), (HumanBodyBones.RightMiddleIntermediate, HumanBodyBones.RightMiddleDistal,false), (HumanBodyBones.RightMiddleDistal,HumanBodyBones.LastBone,false),
|
||||
(HumanBodyBones.RightRingProximal,HumanBodyBones.RightRingIntermediate,false), (HumanBodyBones.RightRingIntermediate, HumanBodyBones.RightRingDistal,false), (HumanBodyBones.RightRingDistal,HumanBodyBones.LastBone,false),
|
||||
(HumanBodyBones.RightLittleProximal,HumanBodyBones.RightLittleIntermediate,false), (HumanBodyBones.RightLittleIntermediate, HumanBodyBones.RightLittleDistal,false),(HumanBodyBones.RightLittleDistal,HumanBodyBones.LastBone,false),
|
||||
};
|
||||
|
||||
static readonly Vector3[] ms_directions =
|
||||
{
|
||||
Vector3.forward,
|
||||
Vector3.back,
|
||||
Vector3.left,
|
||||
Vector3.right,
|
||||
Vector3.up,
|
||||
Vector3.down,
|
||||
};
|
||||
|
||||
public static FingerSystem Instance { get; private set; } = null;
|
||||
|
@ -104,39 +114,39 @@ namespace ml_bft
|
|||
|
||||
internal void OnAvatarSetup()
|
||||
{
|
||||
if(PlayerSetup.Instance._animator.isHuman)
|
||||
Animator l_animator = PlayerSetup.Instance._animator;
|
||||
if(l_animator.isHuman)
|
||||
{
|
||||
Utils.SetAvatarTPose();
|
||||
InputHandler.Instance.Rebind(PlayerSetup.Instance.transform.rotation);
|
||||
|
||||
if(Settings.FixFingers)
|
||||
foreach(var l_tuple in ms_fingersChains)
|
||||
{
|
||||
foreach(var l_tuple in ms_rotationFixChains)
|
||||
{
|
||||
ReorientateTowards(
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item1),
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item2),
|
||||
InputHandler.Instance.GetSourceForBone(l_tuple.Item1, l_tuple.Item3),
|
||||
InputHandler.Instance.GetSourceForBone(l_tuple.Item2, l_tuple.Item3),
|
||||
PlaneType.OXZ
|
||||
);
|
||||
ReorientateTowards(
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item1),
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item2),
|
||||
InputHandler.Instance.GetSourceForBone(l_tuple.Item1, l_tuple.Item3),
|
||||
InputHandler.Instance.GetSourceForBone(l_tuple.Item2, l_tuple.Item3),
|
||||
PlaneType.OYX
|
||||
);
|
||||
}
|
||||
ReorientateTowards(
|
||||
PlayerSetup.Instance.transform,
|
||||
l_animator.GetBoneTransform(l_tuple.Item1),
|
||||
(l_tuple.Item2 != HumanBodyBones.LastBone) ? l_animator.GetBoneTransform(l_tuple.Item2) : null,
|
||||
InputHandler.Instance.GetSourceForBone(l_tuple.Item1, l_tuple.Item3),
|
||||
InputHandler.Instance.GetSourceForBone(l_tuple.Item2, l_tuple.Item3),
|
||||
PlaneType.OXZ
|
||||
);
|
||||
ReorientateTowards(
|
||||
PlayerSetup.Instance.transform,
|
||||
l_animator.GetBoneTransform(l_tuple.Item1),
|
||||
(l_tuple.Item2 != HumanBodyBones.LastBone) ? l_animator.GetBoneTransform(l_tuple.Item2) : null,
|
||||
InputHandler.Instance.GetSourceForBone(l_tuple.Item1, l_tuple.Item3),
|
||||
InputHandler.Instance.GetSourceForBone(l_tuple.Item2, l_tuple.Item3),
|
||||
PlaneType.OYX
|
||||
);
|
||||
}
|
||||
|
||||
// Bind hands
|
||||
m_leftHandOffset.m_source = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand);
|
||||
m_leftHandOffset.m_source = l_animator.GetBoneTransform(HumanBodyBones.LeftHand);
|
||||
m_leftHandOffset.m_target = InputHandler.Instance.GetSourceForBone(HumanBodyBones.LeftHand, true);
|
||||
if((m_leftHandOffset.m_source != null) && (m_leftHandOffset.m_target != null))
|
||||
m_leftHandOffset.m_offset = Quaternion.Inverse(m_leftHandOffset.m_source.rotation) * m_leftHandOffset.m_target.rotation;
|
||||
|
||||
m_rightHandOffset.m_source = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand);
|
||||
m_rightHandOffset.m_source = l_animator.GetBoneTransform(HumanBodyBones.RightHand);
|
||||
m_rightHandOffset.m_target = InputHandler.Instance.GetSourceForBone(HumanBodyBones.RightHand, false);
|
||||
if((m_rightHandOffset.m_source != null) && (m_rightHandOffset.m_target != null))
|
||||
m_rightHandOffset.m_offset = Quaternion.Inverse(m_rightHandOffset.m_source.rotation) * m_rightHandOffset.m_target.rotation;
|
||||
|
@ -144,7 +154,7 @@ namespace ml_bft
|
|||
// Bind fingers
|
||||
foreach(HumanBodyBones p_bone in ms_leftFingerBones)
|
||||
{
|
||||
Transform l_avatarBone = PlayerSetup.Instance._animator.GetBoneTransform(p_bone);
|
||||
Transform l_avatarBone = l_animator.GetBoneTransform(p_bone);
|
||||
Transform l_controllerBone = InputHandler.Instance.GetSourceForBone(p_bone, true);
|
||||
if((l_avatarBone != null) && (l_controllerBone != null))
|
||||
{
|
||||
|
@ -157,7 +167,7 @@ namespace ml_bft
|
|||
}
|
||||
foreach(HumanBodyBones p_bone in ms_rightFingerBones)
|
||||
{
|
||||
Transform l_avatarBone = PlayerSetup.Instance._animator.GetBoneTransform(p_bone);
|
||||
Transform l_avatarBone = l_animator.GetBoneTransform(p_bone);
|
||||
Transform l_controllerBone = InputHandler.Instance.GetSourceForBone(p_bone, false);
|
||||
if((l_avatarBone != null) && (l_controllerBone != null))
|
||||
{
|
||||
|
@ -262,13 +272,13 @@ namespace ml_bft
|
|||
}
|
||||
}
|
||||
|
||||
void ReorientateTowards(Transform p_target, Transform p_targetEnd, Transform p_source, Transform p_sourceEnd, PlaneType p_plane)
|
||||
static void ReorientateTowards(Transform root, Transform p_source, Transform p_sourceEnd, Transform p_target, Transform p_targetEnd, PlaneType p_plane)
|
||||
{
|
||||
if((p_target != null) && (p_targetEnd != null) && (p_source != null) && (p_sourceEnd != null))
|
||||
if((root != null) && (p_target != null) && (p_source != null))
|
||||
{
|
||||
Quaternion l_playerInv = Quaternion.Inverse(PlayerSetup.Instance.transform.rotation);
|
||||
Vector3 l_targetDir = l_playerInv * (p_targetEnd.position - p_target.position);
|
||||
Vector3 l_sourceDir = l_playerInv * (p_sourceEnd.position - p_source.position);
|
||||
Quaternion l_rootInv = Quaternion.Inverse(root.rotation);
|
||||
Vector3 l_targetDir = l_rootInv * (((p_targetEnd != null) ? p_targetEnd.position : GuessEnd(p_target)) - p_target.position);
|
||||
Vector3 l_sourceDir = l_rootInv * (((p_sourceEnd != null) ? p_sourceEnd.position : GuessEnd(p_source)) - p_source.position);
|
||||
switch(p_plane)
|
||||
{
|
||||
case PlaneType.OXZ:
|
||||
|
@ -301,9 +311,30 @@ namespace ml_bft
|
|||
if(p_plane == PlaneType.OYX)
|
||||
l_diff = Quaternion.Euler(0f, 0f, l_diff.eulerAngles.y);
|
||||
|
||||
Quaternion l_adjusted = l_diff * (l_playerInv * p_target.rotation);
|
||||
p_target.rotation = PlayerSetup.Instance.transform.rotation * l_adjusted;
|
||||
Quaternion l_adjusted = l_diff * (l_rootInv * p_target.rotation);
|
||||
p_target.rotation = root.rotation * l_adjusted;
|
||||
}
|
||||
}
|
||||
|
||||
static Vector3 GuessEnd(Transform p_target)
|
||||
{
|
||||
Vector3 l_result = p_target.position;
|
||||
if(p_target.parent != null)
|
||||
{
|
||||
float l_dot = -1f;
|
||||
Vector3 l_axisDir = p_target.position - p_target.parent.position;
|
||||
foreach(Vector3 l_dir in ms_directions)
|
||||
{
|
||||
Vector3 l_rotDir = p_target.rotation * l_dir;
|
||||
float l_stepDot = Vector3.Dot(l_rotDir, l_axisDir);
|
||||
if(l_stepDot >= l_dot)
|
||||
{
|
||||
l_dot = l_stepDot;
|
||||
l_result = p_target.position + l_rotDir;
|
||||
}
|
||||
}
|
||||
}
|
||||
return l_result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,6 +90,7 @@ namespace ml_bft
|
|||
OnShowHandsChanged(Settings.ShowHands);
|
||||
OnMotionRangeChanged(Settings.MotionRange);
|
||||
|
||||
Settings.OnSkeletalInputChanged.AddListener(this.OnSkeletalInputChanged);
|
||||
Settings.OnShowHandsChanged.AddListener(this.OnShowHandsChanged);
|
||||
Settings.OnMotionRangeChanged.AddListener(this.OnMotionRangeChanged);
|
||||
}
|
||||
|
@ -106,6 +107,7 @@ namespace ml_bft
|
|||
|
||||
m_skeletonAction = null;
|
||||
|
||||
Settings.OnSkeletalInputChanged.RemoveListener(this.OnSkeletalInputChanged);
|
||||
Settings.OnShowHandsChanged.RemoveListener(this.OnShowHandsChanged);
|
||||
Settings.OnMotionRangeChanged.RemoveListener(this.OnMotionRangeChanged);
|
||||
}
|
||||
|
@ -254,12 +256,17 @@ namespace ml_bft
|
|||
}
|
||||
|
||||
// Settings
|
||||
void OnSkeletalInputChanged(bool p_state)
|
||||
{
|
||||
OnShowHandsChanged(Settings.ShowHands);
|
||||
}
|
||||
|
||||
void OnShowHandsChanged(bool p_state)
|
||||
{
|
||||
foreach(var l_render in m_renderers)
|
||||
{
|
||||
if(l_render != null)
|
||||
l_render.enabled = p_state;
|
||||
l_render.enabled = (Settings.SkeletalInput && p_state);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,8 +25,7 @@ namespace ml_bft
|
|||
if(MetaPort.Instance.isUsingVr)
|
||||
SetupHandlers();
|
||||
|
||||
VRModeSwitchEvents.OnInitializeXR.AddListener(this.OnSwitchToVR);
|
||||
VRModeSwitchEvents.OnDeinitializeXR.AddListener(this.OnSwitchToDesktop);
|
||||
VRModeSwitchEvents.OnCompletedVRModeSwitch.AddListener(this.OnVRModeSwitch);
|
||||
|
||||
Settings.OnSkeletalInputChanged.AddListener(this.OnSkeletalInputChanged);
|
||||
|
||||
|
@ -39,6 +38,8 @@ namespace ml_bft
|
|||
|
||||
RemoveHandlers();
|
||||
|
||||
VRModeSwitchEvents.OnCompletedVRModeSwitch.RemoveListener(this.OnVRModeSwitch);
|
||||
|
||||
Settings.OnSkeletalInputChanged.RemoveListener(this.OnSkeletalInputChanged);
|
||||
|
||||
GameEvents.OnInputUpdate.RemoveListener(this.OnInputUpdate);
|
||||
|
@ -133,23 +134,14 @@ namespace ml_bft
|
|||
}
|
||||
}
|
||||
|
||||
void OnSwitchToVR()
|
||||
void OnVRModeSwitch(bool p_state)
|
||||
{
|
||||
try
|
||||
{
|
||||
SetupHandlers();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
void OnSwitchToDesktop()
|
||||
{
|
||||
try
|
||||
{
|
||||
RemoveHandlers();
|
||||
if(Utils.IsInVR())
|
||||
SetupHandlers();
|
||||
else
|
||||
RemoveHandlers();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_bft.BetterFingersTracking), "BetterFingersTracking", "1.0.5", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_bft.BetterFingersTracking), "BetterFingersTracking", "1.1.0", "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)]
|
||||
|
|
|
@ -13,7 +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
|
||||
* 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
|
||||
* **Change fingers direction at bind:** tries to allign avatar's fingers for more accurate poses
|
||||
* **Change fingers direction at bind:** tries to allign avatar's fingers for more accurate poses; `true` by default
|
||||
|
||||
# Notes
|
||||
* Currently supports only SteamVR environment, OpenXR support is planned.
|
||||
|
|
|
@ -6,15 +6,16 @@ namespace ml_bft
|
|||
{
|
||||
static class ResourcesHandler
|
||||
{
|
||||
readonly static string ms_namespace = typeof(ResourcesHandler).Namespace;
|
||||
|
||||
public static string GetEmbeddedResource(string p_name)
|
||||
{
|
||||
string l_result = "";
|
||||
Assembly l_assembly = Assembly.GetExecutingAssembly();
|
||||
string l_assemblyName = l_assembly.GetName().Name;
|
||||
|
||||
try
|
||||
{
|
||||
Stream l_libraryStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name);
|
||||
Stream l_libraryStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + p_name);
|
||||
StreamReader l_streadReader = new StreamReader(l_libraryStream);
|
||||
l_result = l_streadReader.ReadToEnd();
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@ namespace ml_bft
|
|||
public static MotionRangeType MotionRange { get; private set; } = MotionRangeType.WithController;
|
||||
public static bool ShowHands { get; private set; } = false;
|
||||
public static bool MechanimFilter { get; private set; } = true;
|
||||
public static bool FixFingers { get; private set; } = true;
|
||||
|
||||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
@ -41,7 +40,6 @@ namespace ml_bft
|
|||
public static readonly SettingEvent<MotionRangeType> OnMotionRangeChanged = new SettingEvent<MotionRangeType>();
|
||||
public static readonly SettingEvent<bool> OnShowHandsChanged = 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()
|
||||
{
|
||||
|
@ -52,14 +50,12 @@ namespace ml_bft
|
|||
ms_category.CreateEntry(ModSetting.SkeletalInput.ToString(), SkeletalInput),
|
||||
ms_category.CreateEntry(ModSetting.MotionRange.ToString(), (int)MotionRange),
|
||||
ms_category.CreateEntry(ModSetting.ShowHands.ToString(), ShowHands),
|
||||
ms_category.CreateEntry(ModSetting.MechanimFilter.ToString(), MechanimFilter),
|
||||
ms_category.CreateEntry(ModSetting.FixFingers.ToString(), FixFingers)
|
||||
ms_category.CreateEntry(ModSetting.MechanimFilter.ToString(), MechanimFilter)
|
||||
};
|
||||
|
||||
SkeletalInput = (bool)ms_entries[(int)ModSetting.SkeletalInput].BoxedValue;
|
||||
MotionRange = (MotionRangeType)(int)ms_entries[(int)ModSetting.MotionRange].BoxedValue;
|
||||
ShowHands = (bool)ms_entries[(int)ModSetting.ShowHands].BoxedValue;
|
||||
FixFingers = (bool)ms_entries[(int)ModSetting.FixFingers].BoxedValue;
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitMainMenuUi());
|
||||
}
|
||||
|
@ -115,13 +111,6 @@ namespace ml_bft
|
|||
OnMechanimFilterChanged.Invoke(MechanimFilter);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.FixFingers:
|
||||
{
|
||||
FixFingers = l_value;
|
||||
OnFixFingersChanged.Invoke(FixFingers);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ms_entries[(int)l_setting].BoxedValue = l_value;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Savior;
|
||||
using ABI_RC.Core.UI;
|
||||
using ABI_RC.Systems.IK;
|
||||
using ABI_RC.Systems.InputManagement;
|
||||
|
@ -13,6 +14,8 @@ namespace ml_bft
|
|||
|
||||
public static void ExecuteScript(this CohtmlControlledViewWrapper p_instance, string p_script) => ((cohtml.Net.View)ms_view.GetValue(p_instance)).ExecuteScript(p_script);
|
||||
|
||||
public static bool IsInVR() => ((MetaPort.Instance != null) && MetaPort.Instance.isUsingVr);
|
||||
|
||||
public static bool AreKnucklesInUse() => ((CVRInputManager.Instance._leftController == ABI_RC.Systems.InputManagement.XR.eXRControllerType.Index) || (CVRInputManager.Instance._rightController == ABI_RC.Systems.InputManagement.XR.eXRControllerType.Index));
|
||||
|
||||
public static void SetAvatarTPose()
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<Authors>SDraw</Authors>
|
||||
<Company>SDraw</Company>
|
||||
<Product>BetterFingersTracking</Product>
|
||||
<Version>1.0.5</Version>
|
||||
<Version>1.1.0</Version>
|
||||
<AssemblyName>BetterFingersTracking</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
|
|
|
@ -20,13 +20,6 @@
|
|||
</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 ="option-caption">Filter humanoid limits: </div>
|
||||
<div class ="option-input">
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Player.EyeMovement;
|
||||
using ABI_RC.Systems.FaceTracking;
|
||||
using ABI_RC.Systems.VRModeSwitch;
|
||||
using RootMotion.FinalIK;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using ViveSR.anipal.Lip;
|
||||
|
||||
|
@ -13,11 +13,7 @@ namespace ml_dht
|
|||
[DisallowMultipleComponent]
|
||||
class HeadTracked : MonoBehaviour
|
||||
{
|
||||
static FieldInfo ms_emotePlaying = typeof(PlayerSetup).GetField("_emotePlaying", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
bool m_enabled = false;
|
||||
bool m_headTracking = true;
|
||||
float m_smoothing = 0.5f;
|
||||
static HeadTracked ms_instance = null;
|
||||
|
||||
CVRAvatar m_avatarDescriptor = null;
|
||||
Transform m_camera = null;
|
||||
|
@ -34,6 +30,9 @@ namespace ml_dht
|
|||
Quaternion m_bindRotation;
|
||||
Quaternion m_lastHeadRotation;
|
||||
|
||||
DataParser m_dataParser = null;
|
||||
float m_smoothing = 0.5f;
|
||||
|
||||
internal HeadTracked()
|
||||
{
|
||||
m_lipData = new LipData_v2();
|
||||
|
@ -45,14 +44,28 @@ namespace ml_dht
|
|||
}
|
||||
|
||||
// Unity events
|
||||
void Awake()
|
||||
{
|
||||
if(ms_instance != null)
|
||||
{
|
||||
DestroyImmediate(this);
|
||||
return;
|
||||
}
|
||||
|
||||
DontDestroyOnLoad(this);
|
||||
|
||||
ms_instance = this;
|
||||
m_dataParser = new DataParser();
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
OnEnabledChanged(Settings.Enabled);
|
||||
OnHeadTrackingChanged(Settings.HeadTracking);
|
||||
OnSmoothingChanged(Settings.Smoothing);
|
||||
|
||||
Settings.OnEnabledChanged.AddListener(this.OnEnabledChanged);
|
||||
Settings.OnHeadTrackingChanged.AddListener(this.OnHeadTrackingChanged);
|
||||
OnVRModeSwitch(true);
|
||||
|
||||
Settings.OnEnabledChanged.AddListener(this.OnEnabledOrHeadTrackingChanged);
|
||||
Settings.OnHeadTrackingChanged.AddListener(this.OnEnabledOrHeadTrackingChanged);
|
||||
Settings.OnSmoothingChanged.AddListener(this.OnSmoothingChanged);
|
||||
|
||||
GameEvents.OnAvatarClear.AddListener(this.OnAvatarClear);
|
||||
|
@ -60,12 +73,19 @@ namespace ml_dht
|
|||
GameEvents.OnAvatarReuse.AddListener(this.OnAvatarReuse);
|
||||
GameEvents.OnEyeControllerUpdate.AddListener(this.OnEyeControllerUpdate);
|
||||
GameEvents.OnFaceTrackingUpdate.AddListener(this.UpdateFaceTracking);
|
||||
|
||||
VRModeSwitchEvents.OnCompletedVRModeSwitch.AddListener(this.OnVRModeSwitch);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
Settings.OnEnabledChanged.RemoveListener(this.OnEnabledChanged);
|
||||
Settings.OnHeadTrackingChanged.RemoveListener(this.OnHeadTrackingChanged);
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
m_dataParser = null;
|
||||
|
||||
Settings.OnEnabledChanged.RemoveListener(this.OnEnabledOrHeadTrackingChanged);
|
||||
Settings.OnHeadTrackingChanged.RemoveListener(this.OnEnabledOrHeadTrackingChanged);
|
||||
Settings.OnSmoothingChanged.RemoveListener(this.OnSmoothingChanged);
|
||||
|
||||
GameEvents.OnAvatarClear.RemoveListener(this.OnAvatarClear);
|
||||
|
@ -73,12 +93,20 @@ namespace ml_dht
|
|||
GameEvents.OnAvatarReuse.RemoveListener(this.OnAvatarReuse);
|
||||
GameEvents.OnEyeControllerUpdate.RemoveListener(this.OnEyeControllerUpdate);
|
||||
GameEvents.OnFaceTrackingUpdate.RemoveListener(this.UpdateFaceTracking);
|
||||
|
||||
VRModeSwitchEvents.OnCompletedVRModeSwitch.RemoveListener(this.OnVRModeSwitch);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if(m_lipDataSent)
|
||||
m_lipDataSent = false;
|
||||
|
||||
if(Settings.Enabled && (m_dataParser != null))
|
||||
{
|
||||
m_dataParser.Update();
|
||||
UpdateTrackingData(ref m_dataParser.GetLatestTrackingData());
|
||||
}
|
||||
}
|
||||
|
||||
// Tracking updates
|
||||
|
@ -98,11 +126,11 @@ namespace ml_dht
|
|||
|
||||
void OnLookIKPostUpdate()
|
||||
{
|
||||
if(m_enabled && m_headTracking && (m_headBone != null))
|
||||
if(Settings.Enabled && Settings.HeadTracking && (m_headBone != null))
|
||||
{
|
||||
m_lastHeadRotation = Quaternion.Slerp(m_lastHeadRotation, m_avatarDescriptor.transform.rotation * (m_headRotation * m_bindRotation), m_smoothing);
|
||||
|
||||
if(!(bool)ms_emotePlaying.GetValue(PlayerSetup.Instance))
|
||||
if(!PlayerSetup.Instance.IsEmotePlaying())
|
||||
m_headBone.rotation = m_lastHeadRotation;
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +170,7 @@ namespace ml_dht
|
|||
|
||||
void OnEyeControllerUpdate(EyeMovementController p_component)
|
||||
{
|
||||
if(m_enabled)
|
||||
if(this.enabled && Settings.Enabled)
|
||||
{
|
||||
// Gaze
|
||||
if(Settings.EyeTracking && (m_camera != null))
|
||||
|
@ -162,7 +190,7 @@ namespace ml_dht
|
|||
|
||||
void UpdateFaceTracking(CVRFaceTracking p_component, GameEvents.EventResult p_result)
|
||||
{
|
||||
if(p_component.isLocal && p_component.UseFacialTracking && m_enabled && Settings.FaceTracking)
|
||||
if(this.enabled && Settings.Enabled && Settings.FaceTracking && p_component.isLocal && p_component.UseFacialTracking )
|
||||
{
|
||||
if(!m_lipDataSent)
|
||||
{
|
||||
|
@ -176,33 +204,27 @@ namespace ml_dht
|
|||
}
|
||||
}
|
||||
|
||||
// Settings
|
||||
void OnEnabledChanged(bool p_state)
|
||||
void OnVRModeSwitch(bool p_state)
|
||||
{
|
||||
if(m_enabled != p_state)
|
||||
try
|
||||
{
|
||||
m_enabled = p_state;
|
||||
TryRestoreHeadRotation();
|
||||
this.enabled = !Utils.IsInVR();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
void OnHeadTrackingChanged(bool p_state)
|
||||
|
||||
// Settings
|
||||
void OnEnabledOrHeadTrackingChanged(bool p_state)
|
||||
{
|
||||
if(m_headTracking != p_state)
|
||||
{
|
||||
m_headTracking = p_state;
|
||||
TryRestoreHeadRotation();
|
||||
}
|
||||
if(Settings.Enabled && Settings.HeadTracking)
|
||||
m_lastHeadRotation = ((m_headBone != null) ? m_headBone.rotation : m_bindRotation);
|
||||
}
|
||||
void OnSmoothingChanged(float p_value)
|
||||
{
|
||||
m_smoothing = 1f - Mathf.Clamp(p_value, 0f, 0.99f);
|
||||
}
|
||||
|
||||
// Arbitrary
|
||||
void TryRestoreHeadRotation()
|
||||
{
|
||||
if(m_enabled && m_headTracking)
|
||||
m_lastHeadRotation = ((m_headBone != null) ? m_headBone.rotation : m_bindRotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Savior;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_dht
|
||||
{
|
||||
public class DesktopHeadTracking : MelonLoader.MelonMod
|
||||
{
|
||||
DataParser m_dataParser = null;
|
||||
HeadTracked m_localTracked = null;
|
||||
|
||||
HeadTracked m_tracked = null;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
|
@ -26,24 +27,14 @@ namespace ml_dht
|
|||
|
||||
GameEvents.InitB(HarmonyInstance);
|
||||
|
||||
m_dataParser = new DataParser();
|
||||
m_localTracked = PlayerSetup.Instance.gameObject.AddComponent<HeadTracked>();
|
||||
m_tracked = new GameObject("[DesktopHeadTracking]").AddComponent<HeadTracked>();
|
||||
}
|
||||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
m_dataParser = null;
|
||||
m_localTracked = null;
|
||||
}
|
||||
|
||||
public override void OnUpdate()
|
||||
{
|
||||
if(Settings.Enabled && (m_dataParser != null))
|
||||
{
|
||||
m_dataParser.Update();
|
||||
if(m_localTracked != null)
|
||||
m_localTracked.UpdateTrackingData(ref m_dataParser.GetLatestTrackingData());
|
||||
}
|
||||
if(m_tracked != null)
|
||||
Object.Destroy(m_tracked.gameObject);
|
||||
m_tracked = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_dht.DesktopHeadTracking), "DesktopHeadTracking", "1.2.5", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_dht.DesktopHeadTracking), "DesktopHeadTracking", "1.3.0", "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)]
|
|
@ -13,7 +13,7 @@ Refer to `TrackingData.cs` for reference in case of implementing own software.
|
|||
# Installation
|
||||
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
|
||||
* Get [latest release DLL](../../../releases/latest):
|
||||
* Put `ml_dht.dll` in `Mods` folder of game
|
||||
* Put `DesktopHeadTracking.dll` in `Mods` folder of game
|
||||
|
||||
# Usage
|
||||
Available mod's settings in `Settings - Implementation - Desktop Head Tracking`:
|
||||
|
|
|
@ -6,15 +6,16 @@ namespace ml_dht
|
|||
{
|
||||
static class ResourcesHandler
|
||||
{
|
||||
readonly static string ms_namespace = typeof(ResourcesHandler).Namespace;
|
||||
|
||||
public static string GetEmbeddedResource(string p_name)
|
||||
{
|
||||
string l_result = "";
|
||||
Assembly l_assembly = Assembly.GetExecutingAssembly();
|
||||
string l_assemblyName = l_assembly.GetName().Name;
|
||||
|
||||
try
|
||||
{
|
||||
Stream l_libraryStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name);
|
||||
Stream l_libraryStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + p_name);
|
||||
StreamReader l_streadReader = new StreamReader(l_libraryStream);
|
||||
l_result = l_streadReader.ReadToEnd();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Savior;
|
||||
using ABI_RC.Core.UI;
|
||||
using ABI_RC.Systems.IK;
|
||||
using System.Reflection;
|
||||
|
@ -13,6 +14,8 @@ namespace ml_dht
|
|||
static readonly FieldInfo ms_view = typeof(CohtmlControlledViewWrapper).GetField("_view", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
static readonly MethodInfo ms_updateShapesLocal = typeof(CVRFaceTracking).GetMethod("UpdateShapesLocal", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
public static bool IsInVR() => ((MetaPort.Instance != null) && MetaPort.Instance.isUsingVr);
|
||||
|
||||
public static void ExecuteScript(this CohtmlControlledViewWrapper p_instance, string p_script) => ((cohtml.Net.View)ms_view.GetValue(p_instance)).ExecuteScript(p_script);
|
||||
|
||||
public static void UpdateShapesLocal_Private(this CVRFaceTracking p_instance) => ms_updateShapesLocal?.Invoke(p_instance, ms_emptyArray);
|
||||
|
|
|
@ -4,10 +4,11 @@
|
|||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<PackageId>DesktopHeadTracking</PackageId>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Company>SDraw</Company>
|
||||
<Product>DesktopHeadTracking</Product>
|
||||
<Version>1.2.5</Version>
|
||||
<Version>1.3.0</Version>
|
||||
<Platforms>x64</Platforms>
|
||||
<AssemblyName>DesktopHeadTracking</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
|
|
@ -7,6 +7,8 @@ namespace ml_lme
|
|||
{
|
||||
static class AssetsHandler
|
||||
{
|
||||
readonly static string ms_namespace = typeof(AssetsHandler).Namespace;
|
||||
|
||||
static readonly List<string> ms_assets = new List<string>()
|
||||
{
|
||||
"leapmotion_controller.asset",
|
||||
|
@ -19,13 +21,12 @@ namespace ml_lme
|
|||
public static void Load()
|
||||
{
|
||||
Assembly l_assembly = Assembly.GetExecutingAssembly();
|
||||
string l_assemblyName = l_assembly.GetName().Name;
|
||||
|
||||
foreach(string l_assetName in ms_assets)
|
||||
{
|
||||
try
|
||||
{
|
||||
Stream l_assetStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + l_assetName);
|
||||
Stream l_assetStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + l_assetName);
|
||||
if(l_assetStream != null)
|
||||
{
|
||||
MemoryStream l_memorySteam = new MemoryStream((int)l_assetStream.Length);
|
||||
|
|
|
@ -8,6 +8,8 @@ namespace ml_lme
|
|||
{
|
||||
static class DependenciesHandler
|
||||
{
|
||||
readonly static string ms_namespace = typeof(DependenciesHandler).Namespace;
|
||||
|
||||
static readonly List<string> ms_libraries = new List<string>()
|
||||
{
|
||||
"LeapC.dll"
|
||||
|
@ -16,11 +18,10 @@ namespace ml_lme
|
|||
public static void ExtractDependencies()
|
||||
{
|
||||
Assembly l_assembly = Assembly.GetExecutingAssembly();
|
||||
string l_assemblyName = l_assembly.GetName().Name;
|
||||
|
||||
foreach(string l_library in ms_libraries)
|
||||
{
|
||||
Stream l_libraryStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + l_library);
|
||||
Stream l_libraryStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + l_library);
|
||||
|
||||
if(!File.Exists(l_library))
|
||||
{
|
||||
|
|
|
@ -123,107 +123,89 @@ namespace ml_lme
|
|||
}
|
||||
|
||||
public Transform GetRoot() => m_root;
|
||||
public Transform GetBone(HumanBodyBones p_bone)
|
||||
public Transform GetLinkedBone(HumanBodyBones p_bone)
|
||||
{
|
||||
Transform l_result = null;
|
||||
switch(p_bone)
|
||||
{
|
||||
case HumanBodyBones.LeftHand:
|
||||
l_result = (m_left ? m_wrist : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftThumbProximal:
|
||||
l_result = (m_left ? m_fingersBones[(int)FingerBone.ThumbProximal] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftThumbIntermediate:
|
||||
l_result = (m_left ? m_fingersBones[(int)FingerBone.ThumbIntermediate] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftThumbDistal:
|
||||
l_result = (m_left ? m_fingersBones[(int)FingerBone.ThumbDistal] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftIndexProximal:
|
||||
l_result = (m_left ? m_fingersBones[(int)FingerBone.IndexProximal] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftIndexIntermediate:
|
||||
l_result = (m_left ? m_fingersBones[(int)FingerBone.IndexIntermediate] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftIndexDistal:
|
||||
l_result = (m_left ? m_fingersBones[(int)FingerBone.IndexDistal] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftMiddleProximal:
|
||||
l_result = (m_left ? m_fingersBones[(int)FingerBone.MiddleProximal] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftMiddleIntermediate:
|
||||
l_result = (m_left ? m_fingersBones[(int)FingerBone.MiddleIntermediate] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftMiddleDistal:
|
||||
l_result = (m_left ? m_fingersBones[(int)FingerBone.MiddleDistal] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftRingProximal:
|
||||
l_result = (m_left ? m_fingersBones[(int)FingerBone.RingProximal] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftRingIntermediate:
|
||||
l_result = (m_left ? m_fingersBones[(int)FingerBone.RingIntermediate] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftRingDistal:
|
||||
l_result = (m_left ? m_fingersBones[(int)FingerBone.RingDistal] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftLittleProximal:
|
||||
l_result = (m_left ? m_fingersBones[(int)FingerBone.PinkyProximal] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftLittleIntermediate:
|
||||
l_result = (m_left ? m_fingersBones[(int)FingerBone.PinkyIntermediate] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftLittleDistal:
|
||||
l_result = (m_left ? m_fingersBones[(int)FingerBone.PinkyDistal] : null);
|
||||
case HumanBodyBones.RightHand:
|
||||
l_result = m_wrist;
|
||||
break;
|
||||
|
||||
case HumanBodyBones.RightHand:
|
||||
l_result = (!m_left ? m_wrist : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftThumbProximal:
|
||||
case HumanBodyBones.RightThumbProximal:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.ThumbProximal] : null);
|
||||
l_result = m_fingersBones[(int)FingerBone.ThumbProximal];
|
||||
break;
|
||||
|
||||
case HumanBodyBones.LeftThumbIntermediate:
|
||||
case HumanBodyBones.RightThumbIntermediate:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.ThumbIntermediate] : null);
|
||||
l_result = m_fingersBones[(int)FingerBone.ThumbIntermediate];
|
||||
break;
|
||||
|
||||
case HumanBodyBones.LeftThumbDistal:
|
||||
case HumanBodyBones.RightThumbDistal:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.ThumbDistal] : null);
|
||||
l_result = m_fingersBones[(int)FingerBone.ThumbDistal];
|
||||
break;
|
||||
|
||||
case HumanBodyBones.LeftIndexProximal:
|
||||
case HumanBodyBones.RightIndexProximal:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.IndexProximal] : null);
|
||||
l_result = m_fingersBones[(int)FingerBone.IndexProximal];
|
||||
break;
|
||||
|
||||
case HumanBodyBones.LeftIndexIntermediate:
|
||||
case HumanBodyBones.RightIndexIntermediate:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.IndexIntermediate] : null);
|
||||
l_result = m_fingersBones[(int)FingerBone.IndexIntermediate];
|
||||
break;
|
||||
|
||||
case HumanBodyBones.LeftIndexDistal:
|
||||
case HumanBodyBones.RightIndexDistal:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.IndexDistal] : null);
|
||||
l_result = m_fingersBones[(int)FingerBone.IndexDistal];
|
||||
break;
|
||||
|
||||
case HumanBodyBones.LeftMiddleProximal:
|
||||
case HumanBodyBones.RightMiddleProximal:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.MiddleProximal] : null);
|
||||
l_result = m_fingersBones[(int)FingerBone.MiddleProximal];
|
||||
break;
|
||||
|
||||
case HumanBodyBones.LeftMiddleIntermediate:
|
||||
case HumanBodyBones.RightMiddleIntermediate:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.MiddleIntermediate] : null);
|
||||
l_result = m_fingersBones[(int)FingerBone.MiddleIntermediate];
|
||||
break;
|
||||
|
||||
case HumanBodyBones.LeftMiddleDistal:
|
||||
case HumanBodyBones.RightMiddleDistal:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.MiddleDistal] : null);
|
||||
l_result = m_fingersBones[(int)FingerBone.MiddleDistal];
|
||||
break;
|
||||
|
||||
case HumanBodyBones.LeftRingProximal:
|
||||
case HumanBodyBones.RightRingProximal:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.RingProximal] : null);
|
||||
l_result = m_fingersBones[(int)FingerBone.RingProximal];
|
||||
break;
|
||||
|
||||
case HumanBodyBones.LeftRingIntermediate:
|
||||
case HumanBodyBones.RightRingIntermediate:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.RingIntermediate] : null);
|
||||
l_result = m_fingersBones[(int)FingerBone.RingIntermediate];
|
||||
break;
|
||||
|
||||
case HumanBodyBones.LeftRingDistal:
|
||||
case HumanBodyBones.RightRingDistal:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.RingDistal] : null);
|
||||
l_result = m_fingersBones[(int)FingerBone.RingDistal];
|
||||
break;
|
||||
|
||||
case HumanBodyBones.LeftLittleProximal:
|
||||
case HumanBodyBones.RightLittleProximal:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.PinkyProximal] : null);
|
||||
l_result = m_fingersBones[(int)FingerBone.PinkyProximal];
|
||||
break;
|
||||
|
||||
case HumanBodyBones.LeftLittleIntermediate:
|
||||
case HumanBodyBones.RightLittleIntermediate:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.PinkyIntermediate] : null);
|
||||
l_result = m_fingersBones[(int)FingerBone.PinkyIntermediate];
|
||||
break;
|
||||
|
||||
case HumanBodyBones.LeftLittleDistal:
|
||||
case HumanBodyBones.RightLittleDistal:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.PinkyDistal] : null);
|
||||
l_result = m_fingersBones[(int)FingerBone.PinkyDistal];
|
||||
break;
|
||||
}
|
||||
return l_result;
|
||||
|
@ -234,5 +216,7 @@ namespace ml_lme
|
|||
if(m_mesh != null)
|
||||
m_mesh.SetActive(p_state);
|
||||
}
|
||||
|
||||
public bool IsLeft() => m_left;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,8 +89,7 @@ namespace ml_lme
|
|||
MelonLoader.MelonCoroutines.Start(WaitForSettings());
|
||||
MelonLoader.MelonCoroutines.Start(WaitForMaterial());
|
||||
|
||||
VRModeSwitchEvents.OnInitializeXR.AddListener(OnModeSwitch);
|
||||
VRModeSwitchEvents.OnDeinitializeXR.AddListener(OnModeSwitch);
|
||||
VRModeSwitchEvents.OnCompletedVRModeSwitch.AddListener(OnVRModeSwitch);
|
||||
|
||||
Settings.OnEnabledChanged.AddListener(this.OnEnableChanged);
|
||||
Settings.OnInteractionChanged.AddListener(this.OnInteractionChanged);
|
||||
|
@ -153,8 +152,7 @@ namespace ml_lme
|
|||
m_lineRight = null;
|
||||
|
||||
MetaPort.Instance.settings.settingBoolChanged.RemoveListener(this.OnGameSettingBoolChange);
|
||||
VRModeSwitchEvents.OnInitializeXR.RemoveListener(OnModeSwitch);
|
||||
VRModeSwitchEvents.OnDeinitializeXR.RemoveListener(OnModeSwitch);
|
||||
VRModeSwitchEvents.OnCompletedVRModeSwitch.RemoveListener(OnVRModeSwitch);
|
||||
|
||||
Settings.OnEnabledChanged.RemoveListener(this.OnEnableChanged);
|
||||
Settings.OnInteractionChanged.RemoveListener(this.OnInteractionChanged);
|
||||
|
@ -291,7 +289,7 @@ namespace ml_lme
|
|||
m_handVisibleRight = false;
|
||||
}
|
||||
|
||||
if(!ModSupporter.SkipFingersOverride() && (!m_inVR || !Utils.AreKnucklesInUse()))
|
||||
if(!m_inVR || !Utils.AreKnucklesInUse())
|
||||
SetGameFingersTracking(m_handVisibleRight || m_handVisibleLeft);
|
||||
|
||||
base.UpdateInput();
|
||||
|
@ -384,7 +382,7 @@ namespace ml_lme
|
|||
ResetGestures(false);
|
||||
}
|
||||
|
||||
// Reset to default, FreedomFingers can go brrr, player should press funny controller button two times
|
||||
// Reset to default
|
||||
SetGameFingersTracking(m_inVR && Utils.AreKnucklesInUse() && !CVRInputManager._moduleXR.GestureToggleValue);
|
||||
}
|
||||
|
||||
|
@ -450,23 +448,30 @@ namespace ml_lme
|
|||
}
|
||||
}
|
||||
|
||||
void OnModeSwitch()
|
||||
void OnVRModeSwitch(bool p_state)
|
||||
{
|
||||
m_inVR = Utils.IsInVR();
|
||||
base._inputManager.SetModuleAsLast(this);
|
||||
|
||||
if(m_handRayLeft != null)
|
||||
try
|
||||
{
|
||||
m_handRayLeft.isDesktopRay = !m_inVR;
|
||||
m_handRayLeft.SetVRActive(m_inVR);
|
||||
}
|
||||
if(m_handRayRight != null)
|
||||
{
|
||||
m_handRayRight.isDesktopRay = !m_inVR;
|
||||
m_handRayRight.SetVRActive(m_inVR);
|
||||
}
|
||||
m_inVR = Utils.IsInVR();
|
||||
base._inputManager.SetModuleAsLast(this);
|
||||
|
||||
OnEnableChanged(Settings.Enabled);
|
||||
if(m_handRayLeft != null)
|
||||
{
|
||||
m_handRayLeft.isDesktopRay = !m_inVR;
|
||||
m_handRayLeft.SetVRActive(m_inVR);
|
||||
}
|
||||
if(m_handRayRight != null)
|
||||
{
|
||||
m_handRayRight.isDesktopRay = !m_inVR;
|
||||
m_handRayRight.SetVRActive(m_inVR);
|
||||
}
|
||||
|
||||
OnEnableChanged(Settings.Enabled);
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Arbitrary
|
||||
|
|
|
@ -19,9 +19,9 @@ namespace ml_lme
|
|||
|
||||
void Awake()
|
||||
{
|
||||
if((Instance != null) && (Instance != this))
|
||||
if(Instance != null)
|
||||
{
|
||||
Object.DestroyImmediate(this);
|
||||
DestroyImmediate(this);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -44,8 +44,7 @@ namespace ml_lme
|
|||
Settings.OnEnabledChanged.AddListener(this.OnEnableChanged);
|
||||
Settings.OnTrackingModeChanged.AddListener(this.OnTrackingModeChanged);
|
||||
|
||||
m_leapTracking = new GameObject("[LeapTrackingRoot]").AddComponent<LeapTracking>();
|
||||
m_leapTracking.transform.parent = this.transform;
|
||||
m_leapTracking = this.gameObject.AddComponent<LeapTracking>();
|
||||
|
||||
OnEnableChanged(Settings.Enabled);
|
||||
OnTrackingModeChanged(Settings.TrackingMode);
|
||||
|
@ -102,7 +101,7 @@ namespace ml_lme
|
|||
m_leapInput = new LeapInput();
|
||||
CVRInputManager.Instance.AddInputModule(m_leapInput);
|
||||
|
||||
m_leapTracked = PlayerSetup.Instance.gameObject.AddComponent<LeapTracked>();
|
||||
m_leapTracked = this.gameObject.AddComponent<LeapTracked>();
|
||||
}
|
||||
|
||||
void Update()
|
||||
|
|
|
@ -77,18 +77,28 @@ namespace ml_lme
|
|||
(HumanBodyBones.RightLittleIntermediate, false),
|
||||
(HumanBodyBones.RightLittleDistal, false),
|
||||
};
|
||||
static readonly (HumanBodyBones, HumanBodyBones, bool)[] ms_rotationFixChains =
|
||||
static readonly (HumanBodyBones, HumanBodyBones, bool)[] ms_fingersChains =
|
||||
{
|
||||
(HumanBodyBones.LeftThumbProximal,HumanBodyBones.LeftThumbIntermediate,true), (HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.LeftThumbDistal,true),
|
||||
(HumanBodyBones.LeftIndexProximal,HumanBodyBones.LeftIndexIntermediate,true), (HumanBodyBones.LeftIndexIntermediate, HumanBodyBones.LeftIndexDistal,true),
|
||||
(HumanBodyBones.LeftMiddleProximal,HumanBodyBones.LeftMiddleIntermediate,true), (HumanBodyBones.LeftMiddleIntermediate, HumanBodyBones.LeftMiddleDistal,true),
|
||||
(HumanBodyBones.LeftRingProximal,HumanBodyBones.LeftRingIntermediate,true), (HumanBodyBones.LeftRingIntermediate, HumanBodyBones.LeftRingDistal,true),
|
||||
(HumanBodyBones.LeftLittleProximal,HumanBodyBones.LeftLittleIntermediate,true), (HumanBodyBones.LeftLittleIntermediate, HumanBodyBones.LeftLittleDistal,true),
|
||||
(HumanBodyBones.RightThumbProximal,HumanBodyBones.RightThumbIntermediate,false), (HumanBodyBones.RightThumbIntermediate, HumanBodyBones.RightThumbDistal,false),
|
||||
(HumanBodyBones.RightIndexProximal,HumanBodyBones.RightIndexIntermediate,false), (HumanBodyBones.RightIndexIntermediate, HumanBodyBones.RightIndexDistal,false),
|
||||
(HumanBodyBones.RightMiddleProximal,HumanBodyBones.RightMiddleIntermediate,false), (HumanBodyBones.RightMiddleIntermediate, HumanBodyBones.RightMiddleDistal,false),
|
||||
(HumanBodyBones.RightRingProximal,HumanBodyBones.RightRingIntermediate,false), (HumanBodyBones.RightRingIntermediate, HumanBodyBones.RightRingDistal,false),
|
||||
(HumanBodyBones.RightLittleProximal,HumanBodyBones.RightLittleIntermediate,false), (HumanBodyBones.RightLittleIntermediate, HumanBodyBones.RightLittleDistal,false)
|
||||
(HumanBodyBones.LeftThumbProximal,HumanBodyBones.LeftThumbIntermediate,true), (HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.LeftThumbDistal,true), (HumanBodyBones.LeftThumbDistal,HumanBodyBones.LastBone,true),
|
||||
(HumanBodyBones.LeftIndexProximal,HumanBodyBones.LeftIndexIntermediate,true), (HumanBodyBones.LeftIndexIntermediate, HumanBodyBones.LeftIndexDistal,true), (HumanBodyBones.LeftIndexDistal,HumanBodyBones.LastBone,true),
|
||||
(HumanBodyBones.LeftMiddleProximal,HumanBodyBones.LeftMiddleIntermediate,true), (HumanBodyBones.LeftMiddleIntermediate, HumanBodyBones.LeftMiddleDistal,true), (HumanBodyBones.LeftMiddleDistal,HumanBodyBones.LastBone,true),
|
||||
(HumanBodyBones.LeftRingProximal,HumanBodyBones.LeftRingIntermediate,true), (HumanBodyBones.LeftRingIntermediate, HumanBodyBones.LeftRingDistal,true), (HumanBodyBones.LeftRingDistal,HumanBodyBones.LastBone,true),
|
||||
(HumanBodyBones.LeftLittleProximal,HumanBodyBones.LeftLittleIntermediate,true), (HumanBodyBones.LeftLittleIntermediate, HumanBodyBones.LeftLittleDistal,true), (HumanBodyBones.LeftLittleDistal,HumanBodyBones.LastBone,true),
|
||||
(HumanBodyBones.RightThumbProximal,HumanBodyBones.RightThumbIntermediate,false), (HumanBodyBones.RightThumbIntermediate, HumanBodyBones.RightThumbDistal,false), (HumanBodyBones.RightThumbDistal,HumanBodyBones.LastBone,false),
|
||||
(HumanBodyBones.RightIndexProximal,HumanBodyBones.RightIndexIntermediate,false), (HumanBodyBones.RightIndexIntermediate, HumanBodyBones.RightIndexDistal,false), (HumanBodyBones.RightIndexDistal,HumanBodyBones.LastBone,false),
|
||||
(HumanBodyBones.RightMiddleProximal,HumanBodyBones.RightMiddleIntermediate,false), (HumanBodyBones.RightMiddleIntermediate, HumanBodyBones.RightMiddleDistal,false), (HumanBodyBones.RightMiddleDistal,HumanBodyBones.LastBone,false),
|
||||
(HumanBodyBones.RightRingProximal,HumanBodyBones.RightRingIntermediate,false), (HumanBodyBones.RightRingIntermediate, HumanBodyBones.RightRingDistal,false), (HumanBodyBones.RightRingDistal,HumanBodyBones.LastBone,false),
|
||||
(HumanBodyBones.RightLittleProximal,HumanBodyBones.RightLittleIntermediate,false), (HumanBodyBones.RightLittleIntermediate, HumanBodyBones.RightLittleDistal,false),(HumanBodyBones.RightLittleDistal,HumanBodyBones.LastBone,false),
|
||||
};
|
||||
|
||||
static readonly Vector3[] ms_directions =
|
||||
{
|
||||
Vector3.forward,
|
||||
Vector3.back,
|
||||
Vector3.left,
|
||||
Vector3.right,
|
||||
Vector3.up,
|
||||
Vector3.down,
|
||||
};
|
||||
|
||||
public static readonly float[] ms_lastLeftFingerBones = new float[20];
|
||||
|
@ -97,10 +107,6 @@ namespace ml_lme
|
|||
VRIK m_vrIK = null;
|
||||
Transform m_hips = null;
|
||||
|
||||
bool m_enabled = true;
|
||||
bool m_fingersOnly = false;
|
||||
bool m_trackElbows = true;
|
||||
|
||||
IKInfo m_vrIKInfo;
|
||||
ArmIK m_leftArmIK = null;
|
||||
ArmIK m_rightArmIK = null;
|
||||
|
@ -135,12 +141,11 @@ namespace ml_lme
|
|||
m_rightHandTarget.localPosition = Vector3.zero;
|
||||
m_rightHandTarget.localRotation = Quaternion.identity;
|
||||
|
||||
OnEnabledChanged(Settings.Enabled);
|
||||
OnFingersOnlyChanged(Settings.FingersOnly);
|
||||
OnEnabledOrFingersOnlyChanged(Settings.Enabled || Settings.FingersOnly);
|
||||
OnTrackElbowsChanged(Settings.TrackElbows);
|
||||
|
||||
Settings.OnEnabledChanged.AddListener(this.OnEnabledChanged);
|
||||
Settings.OnFingersOnlyChanged.AddListener(this.OnFingersOnlyChanged);
|
||||
Settings.OnEnabledChanged.AddListener(this.OnEnabledOrFingersOnlyChanged);
|
||||
Settings.OnFingersOnlyChanged.AddListener(this.OnEnabledOrFingersOnlyChanged);
|
||||
Settings.OnTrackElbowsChanged.AddListener(this.OnTrackElbowsChanged);
|
||||
|
||||
GameEvents.OnAvatarClear.AddListener(this.OnAvatarClear);
|
||||
|
@ -165,8 +170,8 @@ namespace ml_lme
|
|||
|
||||
m_vrIK = null;
|
||||
|
||||
Settings.OnEnabledChanged.RemoveListener(this.OnEnabledChanged);
|
||||
Settings.OnFingersOnlyChanged.RemoveListener(this.OnFingersOnlyChanged);
|
||||
Settings.OnEnabledChanged.RemoveListener(this.OnEnabledOrFingersOnlyChanged);
|
||||
Settings.OnFingersOnlyChanged.RemoveListener(this.OnEnabledOrFingersOnlyChanged);
|
||||
Settings.OnTrackElbowsChanged.RemoveListener(this.OnTrackElbowsChanged);
|
||||
|
||||
GameEvents.OnAvatarClear.RemoveListener(this.OnAvatarClear);
|
||||
|
@ -176,24 +181,24 @@ namespace ml_lme
|
|||
|
||||
void Update()
|
||||
{
|
||||
if(m_enabled)
|
||||
if(Settings.Enabled)
|
||||
{
|
||||
LeapParser.LeapData l_data = LeapManager.Instance.GetLatestData();
|
||||
|
||||
if((m_leftArmIK != null) && (m_rightArmIK != null))
|
||||
{
|
||||
m_leftArmIK.solver.IKPositionWeight = Mathf.Lerp(m_leftArmIK.solver.IKPositionWeight, (l_data.m_leftHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f);
|
||||
m_leftArmIK.solver.IKRotationWeight = Mathf.Lerp(m_leftArmIK.solver.IKRotationWeight, (l_data.m_leftHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f);
|
||||
if(m_trackElbows)
|
||||
m_leftArmIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_leftArmIK.solver.arm.bendGoalWeight, (l_data.m_leftHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f);
|
||||
m_leftArmIK.solver.IKPositionWeight = Mathf.Lerp(m_leftArmIK.solver.IKPositionWeight, (l_data.m_leftHand.m_present && !Settings.FingersOnly) ? 1f : 0f, 0.25f);
|
||||
m_leftArmIK.solver.IKRotationWeight = Mathf.Lerp(m_leftArmIK.solver.IKRotationWeight, (l_data.m_leftHand.m_present && !Settings.FingersOnly) ? 1f : 0f, 0.25f);
|
||||
if(Settings.TrackElbows)
|
||||
m_leftArmIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_leftArmIK.solver.arm.bendGoalWeight, (l_data.m_leftHand.m_present && !Settings.FingersOnly) ? 1f : 0f, 0.25f);
|
||||
|
||||
m_rightArmIK.solver.IKPositionWeight = Mathf.Lerp(m_rightArmIK.solver.IKPositionWeight, (l_data.m_rightHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f);
|
||||
m_rightArmIK.solver.IKRotationWeight = Mathf.Lerp(m_rightArmIK.solver.IKRotationWeight, (l_data.m_rightHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f);
|
||||
if(m_trackElbows)
|
||||
m_rightArmIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_rightArmIK.solver.arm.bendGoalWeight, (l_data.m_rightHand.m_present && !m_fingersOnly) ? 1f : 0f, 0.25f);
|
||||
m_rightArmIK.solver.IKPositionWeight = Mathf.Lerp(m_rightArmIK.solver.IKPositionWeight, (l_data.m_rightHand.m_present && !Settings.FingersOnly) ? 1f : 0f, 0.25f);
|
||||
m_rightArmIK.solver.IKRotationWeight = Mathf.Lerp(m_rightArmIK.solver.IKRotationWeight, (l_data.m_rightHand.m_present && !Settings.FingersOnly) ? 1f : 0f, 0.25f);
|
||||
if(Settings.TrackElbows)
|
||||
m_rightArmIK.solver.arm.bendGoalWeight = Mathf.Lerp(m_rightArmIK.solver.arm.bendGoalWeight, (l_data.m_rightHand.m_present && !Settings.FingersOnly) ? 1f : 0f, 0.25f);
|
||||
}
|
||||
|
||||
if((m_vrIK != null) && !m_fingersOnly)
|
||||
if((m_vrIK != null) && !Settings.FingersOnly)
|
||||
{
|
||||
m_leftTargetActive = l_data.m_leftHand.m_present;
|
||||
m_rightTargetActive = l_data.m_rightHand.m_present;
|
||||
|
@ -203,7 +208,7 @@ namespace ml_lme
|
|||
|
||||
void LateUpdate()
|
||||
{
|
||||
if(m_enabled && (m_poseHandler != null))
|
||||
if(Settings.Enabled && (m_poseHandler != null))
|
||||
{
|
||||
LeapParser.LeapData l_data = LeapManager.Instance.GetLatestData();
|
||||
if(l_data.m_leftHand.m_present)
|
||||
|
@ -276,24 +281,25 @@ namespace ml_lme
|
|||
|
||||
void OnAvatarSetup()
|
||||
{
|
||||
if(PlayerSetup.Instance._animator.isHuman)
|
||||
Animator l_animator = PlayerSetup.Instance._animator;
|
||||
if(l_animator.isHuman)
|
||||
{
|
||||
Utils.SetAvatarTPose();
|
||||
|
||||
m_poseHandler = new HumanPoseHandler(PlayerSetup.Instance._animator.avatar, PlayerSetup.Instance._animator.transform);
|
||||
m_poseHandler = new HumanPoseHandler(l_animator.avatar, l_animator.transform);
|
||||
m_poseHandler.GetHumanPose(ref m_pose);
|
||||
|
||||
m_hips = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Hips);
|
||||
m_hips = l_animator.GetBoneTransform(HumanBodyBones.Hips);
|
||||
|
||||
m_leftHandOffset.m_source = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand);
|
||||
m_leftHandTarget.localRotation = ms_offsetLeft * (Quaternion.Inverse(PlayerSetup.Instance._avatar.transform.rotation) * m_leftHandOffset.m_source.rotation);
|
||||
m_leftHandOffset.m_source = l_animator.GetBoneTransform(HumanBodyBones.LeftHand);
|
||||
m_leftHandTarget.localRotation = ms_offsetLeft * (Quaternion.Inverse(l_animator.transform.rotation) * m_leftHandOffset.m_source.rotation);
|
||||
|
||||
m_rightHandOffset.m_source = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand);
|
||||
m_rightHandTarget.localRotation = ms_offsetRight * (Quaternion.Inverse(PlayerSetup.Instance._avatar.transform.rotation) * m_rightHandOffset.m_source.rotation);
|
||||
m_rightHandOffset.m_source = l_animator.GetBoneTransform(HumanBodyBones.RightHand);
|
||||
m_rightHandTarget.localRotation = ms_offsetRight * (Quaternion.Inverse(l_animator.transform.rotation) * m_rightHandOffset.m_source.rotation);
|
||||
|
||||
ParseFingersBones();
|
||||
|
||||
m_vrIK = PlayerSetup.Instance._animator.GetComponent<VRIK>();
|
||||
m_vrIK = l_animator.GetComponent<VRIK>();
|
||||
if(m_vrIK != null)
|
||||
{
|
||||
m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreSolverUpdate);
|
||||
|
@ -339,7 +345,7 @@ namespace ml_lme
|
|||
m_vrIK.solver.leftArm.positionWeight = 1f;
|
||||
m_vrIK.solver.leftArm.rotationWeight = 1f;
|
||||
m_vrIK.solver.leftArm.bendGoal = LeapTracking.Instance.GetLeftElbow();
|
||||
m_vrIK.solver.leftArm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
|
||||
m_vrIK.solver.leftArm.bendGoalWeight = (Settings.TrackElbows ? 1f : 0f);
|
||||
}
|
||||
if(m_rightTargetActive)
|
||||
{
|
||||
|
@ -353,7 +359,7 @@ namespace ml_lme
|
|||
m_vrIK.solver.rightArm.positionWeight = 1f;
|
||||
m_vrIK.solver.rightArm.rotationWeight = 1f;
|
||||
m_vrIK.solver.rightArm.bendGoal = LeapTracking.Instance.GetRightElbow();
|
||||
m_vrIK.solver.rightArm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
|
||||
m_vrIK.solver.rightArm.bendGoalWeight = (Settings.TrackElbows ? 1f : 0f);
|
||||
}
|
||||
}
|
||||
void OnIKPostSolverUpdate()
|
||||
|
@ -377,30 +383,18 @@ namespace ml_lme
|
|||
}
|
||||
|
||||
// Settings
|
||||
void OnEnabledChanged(bool p_state)
|
||||
void OnEnabledOrFingersOnlyChanged(bool p_state)
|
||||
{
|
||||
m_enabled = p_state;
|
||||
|
||||
RefreshArmIK();
|
||||
ResetTargetsStates();
|
||||
}
|
||||
|
||||
void OnFingersOnlyChanged(bool p_state)
|
||||
{
|
||||
m_fingersOnly = p_state;
|
||||
|
||||
RefreshArmIK();
|
||||
ResetTargetsStates();
|
||||
}
|
||||
|
||||
void OnTrackElbowsChanged(bool p_state)
|
||||
{
|
||||
m_trackElbows = p_state;
|
||||
|
||||
if((m_leftArmIK != null) && (m_rightArmIK != null))
|
||||
{
|
||||
m_leftArmIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
|
||||
m_rightArmIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
|
||||
m_leftArmIK.solver.arm.bendGoalWeight = (p_state ? 1f : 0f);
|
||||
m_rightArmIK.solver.arm.bendGoalWeight = (p_state ? 1f : 0f);
|
||||
}
|
||||
|
||||
ResetTargetsStates();
|
||||
|
@ -415,41 +409,42 @@ namespace ml_lme
|
|||
|
||||
void SetupArmIK()
|
||||
{
|
||||
Transform l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.UpperChest);
|
||||
Animator l_animator = PlayerSetup.Instance._animator;
|
||||
Transform l_chest = l_animator.GetBoneTransform(HumanBodyBones.UpperChest);
|
||||
if(l_chest == null)
|
||||
l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Chest);
|
||||
l_chest = l_animator.GetBoneTransform(HumanBodyBones.Chest);
|
||||
if(l_chest == null)
|
||||
l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Spine);
|
||||
l_chest = l_animator.GetBoneTransform(HumanBodyBones.Spine);
|
||||
|
||||
m_leftArmIK = PlayerSetup.Instance._avatar.AddComponent<ArmIK>();
|
||||
m_leftArmIK = l_animator.gameObject.AddComponent<ArmIK>();
|
||||
m_leftArmIK.solver.isLeft = true;
|
||||
m_leftArmIK.solver.SetChain(
|
||||
l_chest,
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftShoulder),
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftUpperArm),
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftLowerArm),
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand),
|
||||
PlayerSetup.Instance._animator.transform
|
||||
l_animator.GetBoneTransform(HumanBodyBones.LeftShoulder),
|
||||
l_animator.GetBoneTransform(HumanBodyBones.LeftUpperArm),
|
||||
l_animator.GetBoneTransform(HumanBodyBones.LeftLowerArm),
|
||||
l_animator.GetBoneTransform(HumanBodyBones.LeftHand),
|
||||
l_animator.transform
|
||||
);
|
||||
m_leftArmIK.solver.arm.target = m_leftHandTarget;
|
||||
m_leftArmIK.solver.arm.bendGoal = LeapTracking.Instance.GetLeftElbow();
|
||||
m_leftArmIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
|
||||
m_leftArmIK.enabled = (m_enabled && !m_fingersOnly);
|
||||
m_leftArmIK.solver.arm.bendGoalWeight = (Settings.TrackElbows ? 1f : 0f);
|
||||
m_leftArmIK.enabled = (Settings.Enabled && !Settings.FingersOnly);
|
||||
|
||||
m_rightArmIK = PlayerSetup.Instance._avatar.AddComponent<ArmIK>();
|
||||
m_rightArmIK = l_animator.gameObject.AddComponent<ArmIK>();
|
||||
m_rightArmIK.solver.isLeft = false;
|
||||
m_rightArmIK.solver.SetChain(
|
||||
l_chest,
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightShoulder),
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightUpperArm),
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightLowerArm),
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand),
|
||||
PlayerSetup.Instance._animator.transform
|
||||
l_animator.GetBoneTransform(HumanBodyBones.RightShoulder),
|
||||
l_animator.GetBoneTransform(HumanBodyBones.RightUpperArm),
|
||||
l_animator.GetBoneTransform(HumanBodyBones.RightLowerArm),
|
||||
l_animator.GetBoneTransform(HumanBodyBones.RightHand),
|
||||
l_animator.transform
|
||||
);
|
||||
m_rightArmIK.solver.arm.target = m_rightHandTarget;
|
||||
m_rightArmIK.solver.arm.bendGoal = LeapTracking.Instance.GetRightElbow();
|
||||
m_rightArmIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f);
|
||||
m_rightArmIK.enabled = (m_enabled && !m_fingersOnly);
|
||||
m_rightArmIK.solver.arm.bendGoalWeight = (Settings.TrackElbows ? 1f : 0f);
|
||||
m_rightArmIK.enabled = (Settings.Enabled && !Settings.FingersOnly);
|
||||
}
|
||||
|
||||
void RemoveArmIK()
|
||||
|
@ -467,8 +462,8 @@ namespace ml_lme
|
|||
{
|
||||
if((m_leftArmIK != null) && (m_rightArmIK != null))
|
||||
{
|
||||
m_leftArmIK.enabled = (m_enabled && !m_fingersOnly);
|
||||
m_rightArmIK.enabled = (m_enabled && !m_fingersOnly);
|
||||
m_leftArmIK.enabled = (Settings.Enabled && !Settings.FingersOnly);
|
||||
m_rightArmIK.enabled = (Settings.Enabled && !Settings.FingersOnly);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -476,42 +471,48 @@ namespace ml_lme
|
|||
{
|
||||
LeapTracking.Instance.Rebind(PlayerSetup.Instance.transform.rotation);
|
||||
|
||||
// Align rotations of leap fingers to avatar fingers
|
||||
Animator l_animator = PlayerSetup.Instance._animator;
|
||||
LeapHand l_leapLeft = LeapTracking.Instance.GetLeftHand();
|
||||
LeapHand l_leapRight = LeapTracking.Instance.GetRightHand();
|
||||
// Try to "fix" rotations, slightly inaccurate after 0YX plane rotation
|
||||
foreach(var l_tuple in ms_rotationFixChains)
|
||||
foreach(var l_tuple in ms_fingersChains)
|
||||
{
|
||||
ReorientateTowards(
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item1),
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item2),
|
||||
l_tuple.Item3 ? LeapTracking.Instance.GetLeftHand().GetBone(l_tuple.Item1) : LeapTracking.Instance.GetRightHand().GetBone(l_tuple.Item1),
|
||||
l_tuple.Item3 ? LeapTracking.Instance.GetLeftHand().GetBone(l_tuple.Item2) : LeapTracking.Instance.GetRightHand().GetBone(l_tuple.Item2),
|
||||
PlayerSetup.Instance.transform,
|
||||
l_animator.GetBoneTransform(l_tuple.Item1),
|
||||
(l_tuple.Item2 != HumanBodyBones.LastBone) ? l_animator.GetBoneTransform(l_tuple.Item2) : null,
|
||||
l_tuple.Item3 ? l_leapLeft.GetLinkedBone(l_tuple.Item1) : l_leapRight.GetLinkedBone(l_tuple.Item1),
|
||||
l_tuple.Item3 ? l_leapLeft.GetLinkedBone(l_tuple.Item2) : l_leapRight.GetLinkedBone(l_tuple.Item2),
|
||||
PlaneType.OXZ
|
||||
);
|
||||
ReorientateTowards(
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item1),
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item2),
|
||||
l_tuple.Item3 ? LeapTracking.Instance.GetLeftHand().GetBone(l_tuple.Item1) : LeapTracking.Instance.GetRightHand().GetBone(l_tuple.Item1),
|
||||
l_tuple.Item3 ? LeapTracking.Instance.GetLeftHand().GetBone(l_tuple.Item2) : LeapTracking.Instance.GetRightHand().GetBone(l_tuple.Item2),
|
||||
PlayerSetup.Instance.transform,
|
||||
l_animator.GetBoneTransform(l_tuple.Item1),
|
||||
(l_tuple.Item2 != HumanBodyBones.LastBone) ? l_animator.GetBoneTransform(l_tuple.Item2) : null,
|
||||
l_tuple.Item3 ? l_leapLeft.GetLinkedBone(l_tuple.Item1) : l_leapRight.GetLinkedBone(l_tuple.Item1),
|
||||
l_tuple.Item3 ? l_leapLeft.GetLinkedBone(l_tuple.Item2) : l_leapRight.GetLinkedBone(l_tuple.Item2),
|
||||
PlaneType.OYX
|
||||
);
|
||||
}
|
||||
|
||||
// Bind
|
||||
m_leftHandOffset.m_target = LeapTracking.Instance.GetLeftHand().GetBone(HumanBodyBones.LeftHand);
|
||||
m_leftHandOffset.m_target = l_leapLeft.GetLinkedBone(HumanBodyBones.LeftHand);
|
||||
if((m_leftHandOffset.m_source != null) && (m_leftHandOffset.m_target != null))
|
||||
m_leftHandOffset.m_offset = Quaternion.Inverse(m_leftHandOffset.m_source.rotation) * m_leftHandOffset.m_target.rotation;
|
||||
|
||||
m_rightHandOffset.m_target = LeapTracking.Instance.GetRightHand().GetBone(HumanBodyBones.RightHand);
|
||||
m_rightHandOffset.m_target = l_leapRight.GetLinkedBone(HumanBodyBones.RightHand);
|
||||
if((m_rightHandOffset.m_source != null) && (m_rightHandOffset.m_target != null))
|
||||
m_rightHandOffset.m_offset = Quaternion.Inverse(m_rightHandOffset.m_source.rotation) * m_rightHandOffset.m_target.rotation;
|
||||
|
||||
foreach(var l_link in ms_fingers)
|
||||
{
|
||||
Transform l_transform = PlayerSetup.Instance._animator.GetBoneTransform(l_link.Item1);
|
||||
Transform l_transform = l_animator.GetBoneTransform(l_link.Item1);
|
||||
if(l_transform != null)
|
||||
{
|
||||
RotationOffset l_offset = new RotationOffset();
|
||||
l_offset.m_target = l_transform;
|
||||
l_offset.m_source = (l_link.Item2 ? LeapTracking.Instance.GetLeftHand().GetBone(l_link.Item1) : LeapTracking.Instance.GetRightHand().GetBone(l_link.Item1));
|
||||
l_offset.m_source = (l_link.Item2 ? l_leapLeft.GetLinkedBone(l_link.Item1) : l_leapRight.GetLinkedBone(l_link.Item1));
|
||||
l_offset.m_offset = Quaternion.Inverse(l_offset.m_source.rotation) * l_offset.m_target.rotation;
|
||||
|
||||
if(l_link.Item2)
|
||||
|
@ -522,13 +523,13 @@ namespace ml_lme
|
|||
}
|
||||
}
|
||||
|
||||
void ReorientateTowards(Transform p_target, Transform p_targetEnd, Transform p_source, Transform p_sourceEnd, PlaneType p_plane)
|
||||
static void ReorientateTowards(Transform root, Transform p_source, Transform p_sourceEnd, Transform p_target, Transform p_targetEnd, PlaneType p_plane)
|
||||
{
|
||||
if((p_target != null) && (p_targetEnd != null) && (p_source != null) && (p_sourceEnd != null))
|
||||
if((root != null) && (p_target != null) && (p_source != null))
|
||||
{
|
||||
Quaternion l_playerInv = Quaternion.Inverse(PlayerSetup.Instance.transform.rotation);
|
||||
Vector3 l_targetDir = l_playerInv * (p_targetEnd.position - p_target.position);
|
||||
Vector3 l_sourceDir = l_playerInv * (p_sourceEnd.position - p_source.position);
|
||||
Quaternion l_rootInv = Quaternion.Inverse(root.rotation);
|
||||
Vector3 l_targetDir = l_rootInv * (((p_targetEnd != null) ? p_targetEnd.position : GuessEnd(p_target)) - p_target.position);
|
||||
Vector3 l_sourceDir = l_rootInv * (((p_sourceEnd != null) ? p_sourceEnd.position : GuessEnd(p_source)) - p_source.position);
|
||||
switch(p_plane)
|
||||
{
|
||||
case PlaneType.OXZ:
|
||||
|
@ -561,9 +562,30 @@ namespace ml_lme
|
|||
if(p_plane == PlaneType.OYX)
|
||||
l_diff = Quaternion.Euler(0f, 0f, l_diff.eulerAngles.y);
|
||||
|
||||
Quaternion l_adjusted = l_diff * (l_playerInv * p_target.rotation);
|
||||
p_target.rotation = PlayerSetup.Instance.transform.rotation * l_adjusted;
|
||||
Quaternion l_adjusted = l_diff * (l_rootInv * p_target.rotation);
|
||||
p_target.rotation = root.rotation * l_adjusted;
|
||||
}
|
||||
}
|
||||
|
||||
static Vector3 GuessEnd(Transform p_target)
|
||||
{
|
||||
Vector3 l_result = p_target.position;
|
||||
if(p_target.parent != null)
|
||||
{
|
||||
float l_dot = -1f;
|
||||
Vector3 l_axisDir = p_target.position - p_target.parent.position;
|
||||
foreach(Vector3 l_dir in ms_directions)
|
||||
{
|
||||
Vector3 l_rotDir = p_target.rotation * l_dir;
|
||||
float l_stepDot = Vector3.Dot(l_rotDir, l_axisDir);
|
||||
if(l_stepDot >= l_dot)
|
||||
{
|
||||
l_dot = l_stepDot;
|
||||
l_result = p_target.position + l_rotDir;
|
||||
}
|
||||
}
|
||||
}
|
||||
return l_result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.VRModeSwitch;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_lme
|
||||
|
@ -13,8 +11,8 @@ namespace ml_lme
|
|||
static readonly Quaternion ms_hmdRotation = new Quaternion(0f, 0.7071068f, 0.7071068f, 0f);
|
||||
static readonly Quaternion ms_screentopRotation = new Quaternion(0f, 0f, -1f, 0f);
|
||||
|
||||
bool m_inVR = false;
|
||||
|
||||
Transform m_root = null;
|
||||
Transform m_offsetPoint = null;
|
||||
GameObject m_leapHands = null;
|
||||
LeapHand m_leapHandLeft = null;
|
||||
LeapHand m_leapHandRight = null;
|
||||
|
@ -22,26 +20,33 @@ namespace ml_lme
|
|||
Transform m_leapElbowRight = null;
|
||||
GameObject m_leapControllerModel = null;
|
||||
|
||||
float m_scaleRelation = 1f;
|
||||
|
||||
void Start()
|
||||
{
|
||||
if((Instance != null) && (Instance != this))
|
||||
if(Instance != null)
|
||||
{
|
||||
Object.DestroyImmediate(this);
|
||||
return;
|
||||
}
|
||||
|
||||
Instance = this;
|
||||
m_inVR = Utils.IsInVR();
|
||||
|
||||
m_root = new GameObject("Root").transform;
|
||||
m_root.parent = this.transform;
|
||||
m_root.localPosition = Vector3.zero;
|
||||
m_root.localRotation = Quaternion.identity;
|
||||
|
||||
m_offsetPoint = new GameObject("OffsetPoint").transform;
|
||||
m_offsetPoint.parent = m_root;
|
||||
m_offsetPoint.localPosition = Vector3.zero;
|
||||
m_offsetPoint.localRotation = Quaternion.identity;
|
||||
|
||||
m_leapElbowLeft = new GameObject("LeapElbowLeft").transform;
|
||||
m_leapElbowLeft.parent = this.transform;
|
||||
m_leapElbowLeft.parent = m_offsetPoint;
|
||||
m_leapElbowLeft.localPosition = Vector3.zero;
|
||||
m_leapElbowLeft.localRotation = Quaternion.identity;
|
||||
|
||||
m_leapElbowRight = new GameObject("LeapElbowRight").transform;
|
||||
m_leapElbowRight.parent = this.transform;
|
||||
m_leapElbowRight.parent = m_offsetPoint;
|
||||
m_leapElbowRight.localPosition = Vector3.zero;
|
||||
m_leapElbowRight.localRotation = Quaternion.identity;
|
||||
|
||||
|
@ -49,7 +54,7 @@ namespace ml_lme
|
|||
if(m_leapControllerModel != null)
|
||||
{
|
||||
m_leapControllerModel.name = "LeapModel";
|
||||
m_leapControllerModel.transform.parent = this.transform;
|
||||
m_leapControllerModel.transform.parent = m_offsetPoint;
|
||||
m_leapControllerModel.transform.localPosition = Vector3.zero;
|
||||
m_leapControllerModel.transform.localRotation = Quaternion.identity;
|
||||
}
|
||||
|
@ -58,7 +63,7 @@ namespace ml_lme
|
|||
if(m_leapHands != null)
|
||||
{
|
||||
m_leapHands.name = "LeapHands";
|
||||
m_leapHands.transform.parent = this.transform;
|
||||
m_leapHands.transform.parent = m_offsetPoint;
|
||||
m_leapHands.transform.localPosition = Vector3.zero;
|
||||
m_leapHands.transform.localRotation = Quaternion.identity;
|
||||
|
||||
|
@ -69,34 +74,21 @@ namespace ml_lme
|
|||
OnModelVisibilityChanged(Settings.ModelVisibility);
|
||||
OnVisualHandsChanged(Settings.VisualHands);
|
||||
OnTrackingModeChanged(Settings.TrackingMode);
|
||||
OnHeadAttachChanged(Settings.HeadAttach);
|
||||
OnRootAngleChanged(Settings.RootAngle);
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
|
||||
|
||||
VRModeSwitchEvents.OnInitializeXR.AddListener(this.OnAvatarSetup);
|
||||
VRModeSwitchEvents.OnDeinitializeXR.AddListener(this.OnAvatarSetup);
|
||||
|
||||
Settings.OnDesktopOffsetChanged.AddListener(this.OnDesktopOffsetChanged);
|
||||
Settings.OnEnabledChanged.AddListener(this.OnEnabledChanged);
|
||||
Settings.OnModelVisibilityChanged.AddListener(this.OnModelVisibilityChanged);
|
||||
Settings.OnVisualHandsChanged.AddListener(this.OnVisualHandsChanged);
|
||||
Settings.OnTrackingModeChanged.AddListener(this.OnTrackingModeChanged);
|
||||
Settings.OnRootAngleChanged.AddListener(this.OnRootAngleChanged);
|
||||
Settings.OnHeadAttachChanged.AddListener(this.OnHeadAttachChanged);
|
||||
Settings.OnHeadOffsetChanged.AddListener(this.OnHeadOffsetChanged);
|
||||
Settings.OnDesktopOffsetChanged.AddListener(this.OnDesktopOffsetChanged);
|
||||
Settings.OnRootAngleChanged.AddListener(this.OnRootAngleChanged);
|
||||
|
||||
GameEvents.OnAvatarClear.AddListener(this.OnAvatarClear);
|
||||
GameEvents.OnAvatarSetup.AddListener(this.OnAvatarSetup);
|
||||
GameEvents.OnPlayspaceScale.AddListener(this.OnPlayspaceScale);
|
||||
}
|
||||
|
||||
IEnumerator WaitForLocalPlayer()
|
||||
{
|
||||
while(PlayerSetup.Instance == null)
|
||||
yield return null;
|
||||
|
||||
OnHeadAttachChanged(Settings.HeadAttach);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if(Instance == this)
|
||||
|
@ -120,19 +112,23 @@ namespace ml_lme
|
|||
Object.Destroy(m_leapControllerModel);
|
||||
m_leapControllerModel = null;
|
||||
|
||||
VRModeSwitchEvents.OnInitializeXR.RemoveListener(this.OnAvatarSetup);
|
||||
VRModeSwitchEvents.OnDeinitializeXR.RemoveListener(this.OnAvatarSetup);
|
||||
if(m_offsetPoint != null)
|
||||
Destroy(m_offsetPoint.gameObject);
|
||||
m_offsetPoint = null;
|
||||
|
||||
Settings.OnDesktopOffsetChanged.RemoveListener(this.OnDesktopOffsetChanged);
|
||||
if(m_root != null)
|
||||
Destroy(m_root.gameObject);
|
||||
m_root = null;
|
||||
|
||||
Settings.OnEnabledChanged.RemoveListener(this.OnEnabledChanged);
|
||||
Settings.OnModelVisibilityChanged.RemoveListener(this.OnModelVisibilityChanged);
|
||||
Settings.OnVisualHandsChanged.RemoveListener(this.OnVisualHandsChanged);
|
||||
Settings.OnTrackingModeChanged.RemoveListener(this.OnTrackingModeChanged);
|
||||
Settings.OnRootAngleChanged.RemoveListener(this.OnRootAngleChanged);
|
||||
Settings.OnHeadAttachChanged.RemoveListener(this.OnHeadAttachChanged);
|
||||
Settings.OnHeadOffsetChanged.RemoveListener(this.OnHeadOffsetChanged);
|
||||
Settings.OnDesktopOffsetChanged.RemoveListener(this.OnDesktopOffsetChanged);
|
||||
Settings.OnRootAngleChanged.RemoveListener(this.OnRootAngleChanged);
|
||||
|
||||
GameEvents.OnAvatarClear.RemoveListener(this.OnAvatarClear);
|
||||
GameEvents.OnAvatarSetup.RemoveListener(this.OnAvatarSetup);
|
||||
GameEvents.OnPlayspaceScale.RemoveListener(this.OnPlayspaceScale);
|
||||
}
|
||||
|
||||
|
@ -140,6 +136,10 @@ namespace ml_lme
|
|||
{
|
||||
if(Settings.Enabled)
|
||||
{
|
||||
Transform l_camera = PlayerSetup.Instance.GetActiveCamera().transform;
|
||||
m_root.position = l_camera.position;
|
||||
m_root.rotation = (Settings.HeadAttach ? l_camera.rotation : PlayerSetup.Instance.GetPlayerRotation());
|
||||
|
||||
LeapParser.LeapData l_data = LeapManager.Instance.GetLatestData();
|
||||
|
||||
if(l_data.m_leftHand.m_present)
|
||||
|
@ -185,21 +185,22 @@ namespace ml_lme
|
|||
}
|
||||
|
||||
// Settings
|
||||
void OnDesktopOffsetChanged(Vector3 p_offset)
|
||||
void OnEnabledChanged(bool p_state)
|
||||
{
|
||||
if(!Settings.HeadAttach)
|
||||
this.transform.localPosition = p_offset * (!m_inVR ? m_scaleRelation : 1f);
|
||||
OnModelVisibilityChanged(Settings.ModelVisibility);
|
||||
OnVisualHandsChanged(Settings.VisualHands);
|
||||
}
|
||||
|
||||
void OnModelVisibilityChanged(bool p_state)
|
||||
{
|
||||
m_leapControllerModel.SetActive(p_state);
|
||||
if(m_leapControllerModel != null)
|
||||
m_leapControllerModel.SetActive(Settings.Enabled && p_state);
|
||||
}
|
||||
|
||||
void OnVisualHandsChanged(bool p_state)
|
||||
{
|
||||
m_leapHandLeft?.SetMeshActive(p_state);
|
||||
m_leapHandRight?.SetMeshActive(p_state);
|
||||
m_leapHandLeft?.SetMeshActive(Settings.Enabled && p_state);
|
||||
m_leapHandRight?.SetMeshActive(Settings.Enabled && p_state);
|
||||
}
|
||||
|
||||
void OnTrackingModeChanged(Settings.LeapTrackingMode p_mode)
|
||||
|
@ -218,51 +219,42 @@ namespace ml_lme
|
|||
}
|
||||
}
|
||||
|
||||
void OnRootAngleChanged(Vector3 p_angle)
|
||||
{
|
||||
this.transform.localRotation = Quaternion.Euler(p_angle);
|
||||
}
|
||||
|
||||
void OnHeadAttachChanged(bool p_state)
|
||||
{
|
||||
if(!m_inVR)
|
||||
{
|
||||
this.transform.parent = (p_state ? PlayerSetup.Instance.desktopCamera.transform : PlayerSetup.Instance.desktopCameraRig.transform);
|
||||
this.transform.localPosition = (p_state ? Settings.HeadOffset : Settings.DesktopOffset) * m_scaleRelation;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.transform.parent = (p_state ? PlayerSetup.Instance.vrCamera.transform : PlayerSetup.Instance.vrCameraRig.transform);
|
||||
this.transform.localPosition = (p_state ? Settings.HeadOffset : Settings.DesktopOffset);
|
||||
}
|
||||
|
||||
this.transform.localScale = Vector3.one * (!m_inVR ? m_scaleRelation : 1f);
|
||||
this.transform.localRotation = Quaternion.Euler(Settings.RootAngle);
|
||||
if(m_offsetPoint != null)
|
||||
m_offsetPoint.localPosition = (p_state ? Settings.HeadOffset : Settings.DesktopOffset);
|
||||
}
|
||||
|
||||
void OnHeadOffsetChanged(Vector3 p_offset)
|
||||
{
|
||||
if(Settings.HeadAttach)
|
||||
this.transform.localPosition = p_offset * (!m_inVR ? m_scaleRelation : 1f);
|
||||
if(Settings.HeadAttach && (m_offsetPoint != null))
|
||||
m_offsetPoint.localPosition = p_offset;
|
||||
}
|
||||
|
||||
void OnDesktopOffsetChanged(Vector3 p_offset)
|
||||
{
|
||||
if(!Settings.HeadAttach && (m_offsetPoint != null))
|
||||
m_offsetPoint.localPosition = p_offset;
|
||||
}
|
||||
|
||||
void OnRootAngleChanged(Vector3 p_angle)
|
||||
{
|
||||
if(m_offsetPoint != null)
|
||||
m_offsetPoint.localRotation = Quaternion.Euler(p_angle);
|
||||
}
|
||||
|
||||
// Game events
|
||||
void OnAvatarClear()
|
||||
{
|
||||
m_scaleRelation = 1f;
|
||||
OnHeadAttachChanged(Settings.HeadAttach);
|
||||
}
|
||||
|
||||
void OnAvatarSetup()
|
||||
{
|
||||
m_inVR = Utils.IsInVR();
|
||||
OnHeadAttachChanged(Settings.HeadAttach);
|
||||
}
|
||||
|
||||
void OnPlayspaceScale(float p_relation)
|
||||
{
|
||||
m_scaleRelation = p_relation;
|
||||
OnHeadAttachChanged(Settings.HeadAttach);
|
||||
try
|
||||
{
|
||||
if(m_root != null)
|
||||
m_root.localScale = Vector3.one * p_relation;
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Utils
|
||||
|
|
|
@ -14,7 +14,6 @@ namespace ml_lme
|
|||
Settings.Init();
|
||||
AssetsHandler.Load();
|
||||
GameEvents.Init(HarmonyInstance);
|
||||
ModSupporter.Init();
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForRootLogic());
|
||||
}
|
||||
|
@ -31,7 +30,7 @@ namespace ml_lme
|
|||
while(ABI_RC.Core.RootLogic.Instance == null)
|
||||
yield return null;
|
||||
|
||||
m_leapManager = new GameObject("LeapMotionManager").AddComponent<LeapManager>();
|
||||
m_leapManager = new GameObject("[LeapMotionExtension]").AddComponent<LeapManager>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
using System.Collections;
|
||||
using System.Linq;
|
||||
|
||||
namespace ml_lme
|
||||
{
|
||||
static class ModSupporter
|
||||
{
|
||||
static bool ms_copycatMod = false;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
if(MelonLoader.MelonMod.RegisteredMelons.FirstOrDefault(m => m.Info.Name == "PlayerMovementCopycat") != null)
|
||||
MelonLoader.MelonCoroutines.Start(WaitForCopycatInstance());
|
||||
}
|
||||
|
||||
// PlayerMovementCopycat support
|
||||
static IEnumerator WaitForCopycatInstance()
|
||||
{
|
||||
while(ml_pmc.PoseCopycat.Instance == null)
|
||||
yield return null;
|
||||
|
||||
ms_copycatMod = true;
|
||||
}
|
||||
static bool IsCopycating() => (ml_pmc.PoseCopycat.Instance.IsActive() && ml_pmc.PoseCopycat.Instance.IsFingerTrackingActive());
|
||||
|
||||
public static bool SkipFingersOverride()
|
||||
{
|
||||
bool l_result = false;
|
||||
l_result |= (ms_copycatMod && IsCopycating());
|
||||
return l_result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.5.2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.6.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||
[assembly: MelonLoader.MelonOptionalDependencies("ml_pmc")]
|
||||
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
# Leap Motion Extension
|
||||
This mod allows you to use your Leap Motion controller for hands and fingers tracking.
|
||||
|
||||
[](https://youtu.be/nak1C8uibgc)
|
||||

|
||||
|
||||
# Installation
|
||||
* Install [latest Ultraleap Gemini tracking software](https://developer.leapmotion.com/tracking-software-download)
|
||||
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
|
||||
* Get [latest release DLL](../../../releases/latest):
|
||||
* Put `ml_lme.dll` in `Mods` folder of game
|
||||
* Put `LeapMotionExtension.dll` in `Mods` folder of game
|
||||
|
||||
# Usage
|
||||
## Settings
|
||||
|
@ -26,4 +26,4 @@ Available mod's settings in `Settings - Implementation - Leap Motion Tracking`:
|
|||
* **Interact gesture threadhold:** activation limit for interaction based on hand gesture; 80 by default.
|
||||
* **Grip gesture threadhold:** activation limit for grip based on hand gesture; 40 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 some cases.
|
||||
|
|
|
@ -6,15 +6,16 @@ namespace ml_lme
|
|||
{
|
||||
static class ResourcesHandler
|
||||
{
|
||||
readonly static string ms_namespace = typeof(ResourcesHandler).Namespace;
|
||||
|
||||
public static string GetEmbeddedResource(string p_name)
|
||||
{
|
||||
string l_result = "";
|
||||
Assembly l_assembly = Assembly.GetExecutingAssembly();
|
||||
string l_assemblyName = l_assembly.GetName().Name;
|
||||
|
||||
try
|
||||
{
|
||||
Stream l_libraryStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name);
|
||||
Stream l_libraryStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + p_name);
|
||||
StreamReader l_streadReader = new StreamReader(l_libraryStream);
|
||||
l_result = l_streadReader.ReadToEnd();
|
||||
}
|
||||
|
|
|
@ -31,9 +31,9 @@ namespace ml_lme
|
|||
if(CohtmlHud.Instance != null)
|
||||
{
|
||||
if(p_immediate)
|
||||
CohtmlHud.Instance.ViewDropTextImmediate(p_title, p_message, p_small);
|
||||
CohtmlHud.Instance.ViewDropTextImmediate(p_title, p_message, p_small, "", false);
|
||||
else
|
||||
CohtmlHud.Instance.ViewDropText(p_title, p_message, p_small);
|
||||
CohtmlHud.Instance.ViewDropText(p_title, p_message, p_small, "", false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,10 +4,11 @@
|
|||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
<PackageId>LeapMotionExtension</PackageId>
|
||||
<Version>1.5.2</Version>
|
||||
<Version>1.6.0</Version>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Company>SDraw</Company>
|
||||
<Product>LeapMotionExtension</Product>
|
||||
<AssemblyName>LeapMotionExtension</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
@ -68,11 +69,6 @@
|
|||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="ml_pmc">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\Mods\ml_pmc.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.InteractionSystem;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.VRModeSwitch;
|
||||
using RootMotion.FinalIK;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_pam
|
||||
|
@ -22,61 +24,79 @@ namespace ml_pam
|
|||
public Transform m_rightHandTarget;
|
||||
}
|
||||
|
||||
const float c_offsetLimit = 0.5f;
|
||||
const KeyCode c_leftKey = KeyCode.Q;
|
||||
const KeyCode c_rightKey = KeyCode.E;
|
||||
|
||||
static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f);
|
||||
static ArmMover ms_instance = null;
|
||||
|
||||
static readonly Quaternion ms_offsetLeft = Quaternion.Euler(270f, 90f, 0f);
|
||||
static readonly Quaternion ms_offsetRight = Quaternion.Euler(270f, 270f, 0f);
|
||||
|
||||
bool m_inVR = false;
|
||||
VRIK m_vrIK = null;
|
||||
float m_armLength = 0f;
|
||||
float m_playspaceScale = 1f;
|
||||
Vector4 m_armsLength; // x,y - from upper arm to hand; z,w - from center to upper arm
|
||||
Transform m_camera = null;
|
||||
IKInfo m_ikInfo;
|
||||
|
||||
bool m_enabled = true;
|
||||
IKInfo m_vrIKInfo;
|
||||
Transform m_rootLeft = null;
|
||||
Transform m_rootRight = null;
|
||||
Transform m_root = null;
|
||||
Transform m_leftTarget = null;
|
||||
Transform m_rightTarget = null;
|
||||
Transform m_leftRotationTarget = null;
|
||||
Transform m_rightRotationTarget = null;
|
||||
ArmIK m_armIKLeft = null;
|
||||
ArmIK m_armIKRight = null;
|
||||
CVRPickupObject m_pickup = null;
|
||||
Matrix4x4 m_offset;
|
||||
|
||||
HandState m_leftHandState = HandState.Empty;
|
||||
HandState m_rightHandState = HandState.Empty;
|
||||
Vector2 m_handsWeights;
|
||||
|
||||
AvatarBoolParameter m_leftHandParameter = null;
|
||||
AvatarBoolParameter m_rightHandParameter = null;
|
||||
|
||||
Coroutine m_disableTask = null;
|
||||
|
||||
// Unity events
|
||||
void Awake()
|
||||
{
|
||||
if(ms_instance != null)
|
||||
{
|
||||
DestroyImmediate(this);
|
||||
return;
|
||||
}
|
||||
|
||||
ms_instance = this;
|
||||
DontDestroyOnLoad(this);
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
m_inVR = Utils.IsInVR();
|
||||
m_camera = PlayerSetup.Instance.GetActiveCamera().transform;
|
||||
|
||||
m_rootLeft = new GameObject("[ArmPickupLeft]").transform;
|
||||
m_rootLeft.parent = PlayerSetup.Instance.GetActiveCamera().transform;
|
||||
m_rootLeft.localPosition = Vector3.zero;
|
||||
m_rootLeft.localRotation = Quaternion.identity;
|
||||
m_root = new GameObject("Root").transform;
|
||||
m_root.parent = this.transform;
|
||||
m_root.localPosition = Vector3.zero;
|
||||
m_root.localRotation = Quaternion.identity;
|
||||
|
||||
m_leftTarget = new GameObject("Target").transform;
|
||||
m_leftTarget.parent = m_rootLeft;
|
||||
m_leftTarget.localPosition = new Vector3(c_offsetLimit * -Settings.GrabOffset, 0f, 0f);
|
||||
m_leftTarget = new GameObject("TargetLeft").transform;
|
||||
m_leftTarget.parent = m_root;
|
||||
m_leftTarget.localPosition = Vector3.zero;
|
||||
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_leftRotationTarget = new GameObject("RotationTarget").transform;
|
||||
m_leftRotationTarget.parent = m_leftTarget;
|
||||
m_leftRotationTarget.localPosition = Vector3.zero;
|
||||
m_leftRotationTarget.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 = new GameObject("TargetRight").transform;
|
||||
m_rightTarget.parent = m_root;
|
||||
m_rightTarget.localPosition = Vector3.zero;
|
||||
m_rightTarget.localRotation = Quaternion.identity;
|
||||
|
||||
m_enabled = Settings.Enabled;
|
||||
m_rightRotationTarget = new GameObject("RotationTarget").transform;
|
||||
m_rightRotationTarget.parent = m_rightTarget;
|
||||
m_rightRotationTarget.localPosition = Vector3.zero;
|
||||
m_rightRotationTarget.localRotation = Quaternion.identity;
|
||||
|
||||
Settings.OnEnabledChanged.AddListener(this.OnEnabledChanged);
|
||||
Settings.OnGrabOffsetChanged.AddListener(this.OnGrabOffsetChanged);
|
||||
|
@ -86,25 +106,44 @@ namespace ml_pam
|
|||
GameEvents.OnAvatarClear.AddListener(this.OnAvatarClear);
|
||||
GameEvents.OnAvatarSetup.AddListener(this.OnAvatarSetup);
|
||||
GameEvents.OnAvatarReuse.AddListener(this.OnAvatarReuse);
|
||||
GameEvents.OnPlayspaceScale.AddListener(this.OnPlayspaceScale);
|
||||
GameEvents.OnIKScaling.AddListener(this.OnIKScaling);
|
||||
GameEvents.OnPickupGrab.AddListener(this.OnPickupGrab);
|
||||
GameEvents.OnPickupDrop.AddListener(this.OnPickupDrop);
|
||||
|
||||
VRModeSwitchEvents.OnCompletedVRModeSwitch.AddListener(this.OnVRModeSwitch);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
if(m_disableTask != null)
|
||||
StopCoroutine(m_disableTask);
|
||||
m_disableTask = null;
|
||||
|
||||
RemoveArmIK();
|
||||
|
||||
if(m_rootLeft != null)
|
||||
Destroy(m_rootLeft);
|
||||
m_rootLeft = null;
|
||||
if(m_leftRotationTarget != null)
|
||||
Destroy(m_leftRotationTarget.gameObject);
|
||||
m_leftRotationTarget = null;
|
||||
|
||||
if(m_leftTarget != null)
|
||||
Destroy(m_leftTarget.gameObject);
|
||||
m_leftTarget = null;
|
||||
|
||||
if(m_rootRight != null)
|
||||
Destroy(m_rootRight);
|
||||
m_rootRight = null;
|
||||
if(m_rightRotationTarget != null)
|
||||
Destroy(m_rightRotationTarget.gameObject);
|
||||
m_rightRotationTarget = null;
|
||||
|
||||
if(m_rightTarget != null)
|
||||
Destroy(m_rightTarget.gameObject);
|
||||
m_rightTarget = null;
|
||||
|
||||
if(m_root != null)
|
||||
Destroy(m_root.gameObject);
|
||||
m_root = null;
|
||||
|
||||
m_pickup = null;
|
||||
m_vrIK = null;
|
||||
|
||||
|
@ -116,13 +155,21 @@ namespace ml_pam
|
|||
GameEvents.OnAvatarClear.RemoveListener(this.OnAvatarClear);
|
||||
GameEvents.OnAvatarSetup.RemoveListener(this.OnAvatarSetup);
|
||||
GameEvents.OnAvatarReuse.RemoveListener(this.OnAvatarReuse);
|
||||
GameEvents.OnPlayspaceScale.RemoveListener(this.OnPlayspaceScale);
|
||||
GameEvents.OnIKScaling.AddListener(this.OnIKScaling);
|
||||
GameEvents.OnPickupGrab.RemoveListener(this.OnPickupGrab);
|
||||
GameEvents.OnPickupDrop.RemoveListener(this.OnPickupDrop);
|
||||
|
||||
VRModeSwitchEvents.OnCompletedVRModeSwitch.RemoveListener(this.OnVRModeSwitch);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if((m_root != null) && (m_camera != null))
|
||||
{
|
||||
m_root.position = m_camera.position;
|
||||
m_root.rotation = m_camera.rotation;
|
||||
}
|
||||
|
||||
if(!ReferenceEquals(m_pickup, null) && (m_pickup == null))
|
||||
OnPickupDrop(m_pickup);
|
||||
|
||||
|
@ -130,205 +177,170 @@ namespace ml_pam
|
|||
{
|
||||
case HandState.Empty:
|
||||
{
|
||||
if(Settings.HandsExtension && Input.GetKeyDown(c_leftKey))
|
||||
{
|
||||
if(Settings.Enabled && Settings.HandsExtension && Input.GetKey(c_leftKey) && !ViewManager.Instance.IsAnyMenuOpen)
|
||||
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))
|
||||
{
|
||||
if(!Input.GetKey(c_leftKey))
|
||||
m_leftHandState = HandState.Empty;
|
||||
SetArmActive(Settings.LeadHand.Left, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HandState.Pickup:
|
||||
{
|
||||
if(m_pickup != null)
|
||||
{
|
||||
Matrix4x4 l_result = m_pickup.transform.GetMatrix() * m_offset;
|
||||
m_rootLeft.position = l_result * ms_pointVector;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch(m_rightHandState)
|
||||
{
|
||||
case HandState.Empty:
|
||||
{
|
||||
if(Settings.HandsExtension && Input.GetKeyDown(c_rightKey))
|
||||
{
|
||||
if(Settings.Enabled && Settings.HandsExtension && Input.GetKey(c_rightKey) && !ViewManager.Instance.IsAnyMenuOpen)
|
||||
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))
|
||||
{
|
||||
if(!Input.GetKey(c_rightKey))
|
||||
m_rightHandState = HandState.Empty;
|
||||
SetArmActive(Settings.LeadHand.Right, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HandState.Pickup:
|
||||
}
|
||||
|
||||
m_handsWeights.x = Mathf.Clamp01(m_handsWeights.x + ((m_leftHandState != HandState.Empty) ? 1f : -1f) * Time.unscaledDeltaTime * Settings.ExtensionSpeed);
|
||||
m_handsWeights.y = Mathf.Clamp01(m_handsWeights.y + ((m_rightHandState != HandState.Empty) ? 1f : -1f) * Time.unscaledDeltaTime * Settings.ExtensionSpeed);
|
||||
|
||||
UpdateArmIK(m_armIKLeft, m_handsWeights.x);
|
||||
UpdateArmIK(m_armIKRight, m_handsWeights.y);
|
||||
|
||||
m_leftHandParameter?.SetValue(m_leftHandState != HandState.Empty);
|
||||
m_rightHandParameter?.SetValue(m_rightHandState != HandState.Empty);
|
||||
|
||||
if(m_leftHandState != HandState.Empty)
|
||||
{
|
||||
if(m_pickup != null)
|
||||
{
|
||||
if(m_pickup != null)
|
||||
{
|
||||
Matrix4x4 l_result = m_pickup.transform.GetMatrix() * m_offset;
|
||||
m_rootRight.position = l_result * ms_pointVector;
|
||||
}
|
||||
Matrix4x4 l_result = m_pickup.transform.GetMatrix() * m_offset;
|
||||
m_leftTarget.position = l_result.GetPosition();
|
||||
m_leftTarget.rotation = l_result.rotation;
|
||||
m_leftTarget.localPosition = Vector3.ClampMagnitude(m_leftTarget.localPosition, m_armsLength.x);
|
||||
}
|
||||
break;
|
||||
else
|
||||
{
|
||||
m_leftTarget.localPosition = new Vector3(0f, 0f, m_armsLength.x);
|
||||
m_leftTarget.localRotation = Quaternion.identity;
|
||||
}
|
||||
}
|
||||
if(m_rightHandState != HandState.Empty)
|
||||
{
|
||||
if(m_pickup != null)
|
||||
{
|
||||
Matrix4x4 l_result = m_pickup.transform.GetMatrix() * m_offset;
|
||||
m_rightTarget.position = l_result.GetPosition();
|
||||
m_rightTarget.rotation = l_result.rotation;
|
||||
m_rightTarget.localPosition = Vector3.ClampMagnitude(m_rightTarget.localPosition, m_armsLength.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_rightTarget.localPosition = new Vector3(0f, 0f, m_armsLength.y);
|
||||
m_rightTarget.localRotation = Quaternion.identity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
if((m_root != null) && (m_camera != null))
|
||||
{
|
||||
m_root.position = m_camera.position;
|
||||
m_root.rotation = m_camera.rotation;
|
||||
}
|
||||
}
|
||||
|
||||
// VRIK updates
|
||||
void OnIKPreUpdate()
|
||||
{
|
||||
if(m_enabled)
|
||||
if(!Mathf.Approximately(m_handsWeights.x, 0f))
|
||||
{
|
||||
if(m_leftHandState != HandState.Empty)
|
||||
{
|
||||
m_vrIKInfo.m_leftHandTarget = m_vrIK.solver.leftArm.target;
|
||||
m_vrIKInfo.m_armsWeights.x = m_vrIK.solver.leftArm.positionWeight;
|
||||
m_vrIKInfo.m_armsWeights.y = m_vrIK.solver.leftArm.rotationWeight;
|
||||
m_ikInfo.m_leftHandTarget = m_vrIK.solver.leftArm.target;
|
||||
m_ikInfo.m_armsWeights.x = m_vrIK.solver.leftArm.positionWeight;
|
||||
m_ikInfo.m_armsWeights.y = m_vrIK.solver.leftArm.rotationWeight;
|
||||
|
||||
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_vrIKInfo.m_rightHandTarget = m_vrIK.solver.rightArm.target;
|
||||
m_vrIKInfo.m_armsWeights.z = m_vrIK.solver.rightArm.positionWeight;
|
||||
m_vrIKInfo.m_armsWeights.w = m_vrIK.solver.rightArm.rotationWeight;
|
||||
m_vrIK.solver.leftArm.positionWeight = m_handsWeights.x;
|
||||
m_vrIK.solver.leftArm.rotationWeight = m_handsWeights.x;
|
||||
m_vrIK.solver.leftArm.target = m_leftRotationTarget;
|
||||
}
|
||||
if(!Mathf.Approximately(m_handsWeights.y, 0f))
|
||||
{
|
||||
m_ikInfo.m_rightHandTarget = m_vrIK.solver.rightArm.target;
|
||||
m_ikInfo.m_armsWeights.z = m_vrIK.solver.rightArm.positionWeight;
|
||||
m_ikInfo.m_armsWeights.w = m_vrIK.solver.rightArm.rotationWeight;
|
||||
|
||||
m_vrIK.solver.rightArm.positionWeight = 1f;
|
||||
m_vrIK.solver.rightArm.rotationWeight = 1f;
|
||||
m_vrIK.solver.rightArm.target = m_rightTarget;
|
||||
}
|
||||
m_vrIK.solver.rightArm.positionWeight = m_handsWeights.y;
|
||||
m_vrIK.solver.rightArm.rotationWeight = m_handsWeights.y;
|
||||
m_vrIK.solver.rightArm.target = m_rightRotationTarget;
|
||||
}
|
||||
}
|
||||
void OnIKPostUpdate()
|
||||
{
|
||||
if(m_enabled)
|
||||
if(!Mathf.Approximately(m_handsWeights.x, 0f))
|
||||
{
|
||||
if(m_leftHandState != HandState.Empty)
|
||||
{
|
||||
m_vrIK.solver.leftArm.target = m_vrIKInfo.m_leftHandTarget;
|
||||
m_vrIK.solver.leftArm.positionWeight = m_vrIKInfo.m_armsWeights.x;
|
||||
m_vrIK.solver.leftArm.rotationWeight = m_vrIKInfo.m_armsWeights.y;
|
||||
}
|
||||
if(m_rightHandState != HandState.Empty)
|
||||
{
|
||||
m_vrIK.solver.rightArm.target = m_vrIKInfo.m_rightHandTarget;
|
||||
m_vrIK.solver.rightArm.positionWeight = m_vrIKInfo.m_armsWeights.z;
|
||||
m_vrIK.solver.rightArm.rotationWeight = m_vrIKInfo.m_armsWeights.w;
|
||||
}
|
||||
m_vrIK.solver.leftArm.target = m_ikInfo.m_leftHandTarget;
|
||||
m_vrIK.solver.leftArm.positionWeight = m_ikInfo.m_armsWeights.x;
|
||||
m_vrIK.solver.leftArm.rotationWeight = m_ikInfo.m_armsWeights.y;
|
||||
}
|
||||
if(!Mathf.Approximately(m_handsWeights.y, 0f))
|
||||
{
|
||||
m_vrIK.solver.rightArm.target = m_ikInfo.m_rightHandTarget;
|
||||
m_vrIK.solver.rightArm.positionWeight = m_ikInfo.m_armsWeights.z;
|
||||
m_vrIK.solver.rightArm.rotationWeight = m_ikInfo.m_armsWeights.w;
|
||||
}
|
||||
}
|
||||
|
||||
// Settings
|
||||
void OnEnabledChanged(bool p_state)
|
||||
{
|
||||
m_enabled = p_state;
|
||||
|
||||
if(p_state)
|
||||
{
|
||||
if(m_leftHandState != HandState.Empty)
|
||||
SetArmActive(Settings.LeadHand.Left, true);
|
||||
if(m_rightHandState != HandState.Empty)
|
||||
SetArmActive(Settings.LeadHand.Right, true);
|
||||
if(this.enabled)
|
||||
{
|
||||
if(m_disableTask != null)
|
||||
{
|
||||
StopCoroutine(m_disableTask);
|
||||
m_disableTask = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
this.enabled = true;
|
||||
|
||||
OnHandsExtensionChanged(Settings.HandsExtension);
|
||||
OnLeadingHandChanged(Settings.LeadingHand);
|
||||
}
|
||||
else
|
||||
SetArmActive(Settings.LeadHand.Both, false, true);
|
||||
{
|
||||
m_leftHandState = HandState.Empty;
|
||||
m_rightHandState = HandState.Empty;
|
||||
|
||||
m_disableTask = StartCoroutine(WaitToDisable());
|
||||
}
|
||||
}
|
||||
|
||||
void OnGrabOffsetChanged(float p_value)
|
||||
{
|
||||
if(m_leftTarget != null)
|
||||
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);
|
||||
if(m_leftRotationTarget != null)
|
||||
m_leftRotationTarget.localPosition = new Vector3(-m_armsLength.z * p_value * 2f, 0f, 0f);
|
||||
if(m_rightRotationTarget != null)
|
||||
m_rightRotationTarget.localPosition = new Vector3(m_armsLength.w * p_value * 2f, 0f, 0f);
|
||||
}
|
||||
|
||||
void OnLeadingHandChanged(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);
|
||||
}
|
||||
SetLeadingHandState((m_pickup != null) ? HandState.Pickup : HandState.Empty);
|
||||
SetUnleadingHandState(HandState.Empty);
|
||||
}
|
||||
|
||||
void OnHandsExtensionChanged(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(m_leftHandState == HandState.Extended)
|
||||
m_leftHandState = HandState.Empty;
|
||||
if(m_rightHandState == HandState.Extended)
|
||||
m_rightHandState = HandState.Empty;
|
||||
}
|
||||
|
||||
// Game events
|
||||
|
@ -337,65 +349,81 @@ namespace ml_pam
|
|||
m_vrIK = null;
|
||||
m_armIKLeft = null;
|
||||
m_armIKRight = null;
|
||||
m_armLength = 0f;
|
||||
m_armsLength.Set(0f, 0f, 0f, 0f);
|
||||
m_leftHandParameter = null;
|
||||
m_rightHandParameter = null;
|
||||
}
|
||||
|
||||
void OnAvatarSetup()
|
||||
{
|
||||
m_inVR = Utils.IsInVR();
|
||||
m_vrIK = PlayerSetup.Instance._animator.GetComponent<VRIK>();
|
||||
|
||||
ReparentRoots();
|
||||
m_camera = PlayerSetup.Instance.GetActiveCamera().transform;
|
||||
|
||||
if(PlayerSetup.Instance._animator.isHuman)
|
||||
{
|
||||
m_vrIK = PlayerSetup.Instance._animator.GetComponent<VRIK>();
|
||||
Utils.SetAvatarTPose();
|
||||
|
||||
Transform l_leftHand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand);
|
||||
if(l_leftHand != null)
|
||||
m_leftTarget.localRotation = ms_offsetLeft * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_leftHand.GetMatrix()).rotation;
|
||||
Transform l_rightHand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand);
|
||||
if(l_rightHand != null)
|
||||
m_rightTarget.localRotation = ms_offsetRight * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_rightHand.GetMatrix()).rotation;
|
||||
Animator l_animator = PlayerSetup.Instance._animator;
|
||||
Matrix4x4 l_avatarMatrixInv = l_animator.transform.GetMatrix().inverse; // Animator and avatar are on same game object
|
||||
|
||||
if(m_vrIK != null)
|
||||
Transform l_leftHand = l_animator.GetBoneTransform(HumanBodyBones.LeftHand);
|
||||
if(l_leftHand != null)
|
||||
m_leftRotationTarget.localRotation = ms_offsetLeft * (l_avatarMatrixInv * l_leftHand.GetMatrix()).rotation;
|
||||
Transform l_rightHand = l_animator.GetBoneTransform(HumanBodyBones.RightHand);
|
||||
if(l_rightHand != null)
|
||||
m_rightRotationTarget.localRotation = ms_offsetRight * (l_avatarMatrixInv * l_rightHand.GetMatrix()).rotation;
|
||||
|
||||
m_armsLength.x = GetChainLength(new Transform[]{
|
||||
l_animator.GetBoneTransform(HumanBodyBones.LeftUpperArm),
|
||||
l_animator.GetBoneTransform(HumanBodyBones.LeftLowerArm),
|
||||
l_animator.GetBoneTransform(HumanBodyBones.LeftHand)
|
||||
});
|
||||
m_armsLength.y = GetChainLength(new Transform[]{
|
||||
l_animator.GetBoneTransform(HumanBodyBones.RightUpperArm),
|
||||
l_animator.GetBoneTransform(HumanBodyBones.RightLowerArm),
|
||||
l_animator.GetBoneTransform(HumanBodyBones.RightHand)
|
||||
});
|
||||
m_armsLength.z = Mathf.Abs((l_avatarMatrixInv * l_animator.GetBoneTransform(HumanBodyBones.LeftUpperArm).GetMatrix()).GetPosition().x);
|
||||
m_armsLength.w = Mathf.Abs((l_avatarMatrixInv * l_animator.GetBoneTransform(HumanBodyBones.RightUpperArm).GetMatrix()).GetPosition().x);
|
||||
|
||||
if(!Utils.IsInVR())
|
||||
{
|
||||
m_armLength = m_vrIK.solver.leftArm.mag * 1.25f;
|
||||
m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreUpdate);
|
||||
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate);
|
||||
if(m_vrIK != null)
|
||||
{
|
||||
m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreUpdate);
|
||||
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate);
|
||||
}
|
||||
else
|
||||
SetupArmIK();
|
||||
}
|
||||
else if(!m_inVR)
|
||||
SetupArmIK();
|
||||
}
|
||||
|
||||
m_leftHandParameter = new AvatarBoolParameter("LeftHandExtended", PlayerSetup.Instance.animatorManager);
|
||||
m_rightHandParameter = new AvatarBoolParameter("RightHandExtended", PlayerSetup.Instance.animatorManager);
|
||||
|
||||
OnEnabledChanged(m_enabled);
|
||||
OnEnabledChanged(Settings.Enabled);
|
||||
OnGrabOffsetChanged(Settings.GrabOffset);
|
||||
}
|
||||
|
||||
void OnAvatarReuse()
|
||||
{
|
||||
// Old VRIK is destroyed by game
|
||||
m_inVR = Utils.IsInVR();
|
||||
m_vrIK = PlayerSetup.Instance._animator.GetComponent<VRIK>();
|
||||
|
||||
ReparentRoots();
|
||||
|
||||
if(m_inVR)
|
||||
if(Utils.IsInVR())
|
||||
RemoveArmIK();
|
||||
|
||||
if(m_vrIK != null)
|
||||
else
|
||||
{
|
||||
m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreUpdate);
|
||||
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate);
|
||||
if(m_vrIK != null)
|
||||
{
|
||||
m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreUpdate);
|
||||
m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate);
|
||||
}
|
||||
else
|
||||
SetupArmIK();
|
||||
}
|
||||
else if(!m_inVR)
|
||||
SetupArmIK();
|
||||
|
||||
OnEnabledChanged(m_enabled);
|
||||
OnEnabledChanged(Settings.Enabled);
|
||||
}
|
||||
|
||||
void OnPickupGrab(CVRPickupObject p_pickup, Vector3 p_hit)
|
||||
|
@ -416,97 +444,82 @@ namespace ml_pam
|
|||
}
|
||||
}
|
||||
else
|
||||
m_offset = m_pickup.transform.GetMatrix().inverse * Matrix4x4.Translate(p_hit);
|
||||
m_offset = m_pickup.transform.GetMatrix().inverse * Matrix4x4.TRS(p_hit, m_camera.rotation, Vector3.one);
|
||||
|
||||
switch(Settings.LeadingHand)
|
||||
{
|
||||
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(Settings.LeadingHand, true);
|
||||
if(Settings.Enabled)
|
||||
OnLeadingHandChanged(Settings.LeadingHand);
|
||||
}
|
||||
}
|
||||
|
||||
void OnPickupDrop(CVRPickupObject p_pickup)
|
||||
{
|
||||
if(m_pickup == p_pickup)
|
||||
if(ReferenceEquals(m_pickup, p_pickup) || (m_pickup == p_pickup))
|
||||
{
|
||||
m_pickup = null;
|
||||
switch(Settings.LeadingHand)
|
||||
{
|
||||
case Settings.LeadHand.Left:
|
||||
m_leftHandState = HandState.Empty;
|
||||
break;
|
||||
case Settings.LeadHand.Right:
|
||||
m_rightHandState = HandState.Empty;
|
||||
break;
|
||||
case Settings.LeadHand.Both:
|
||||
{
|
||||
m_leftHandState = HandState.Empty;
|
||||
m_rightHandState = HandState.Empty;
|
||||
}
|
||||
break;
|
||||
}
|
||||
SetArmActive(Settings.LeadingHand, false);
|
||||
|
||||
if(Settings.Enabled)
|
||||
SetLeadingHandState(HandState.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
void OnPlayspaceScale(float p_relation)
|
||||
void OnIKScaling(float p_relation)
|
||||
{
|
||||
m_playspaceScale = p_relation;
|
||||
OnGrabOffsetChanged(Settings.GrabOffset);
|
||||
if(m_root != null)
|
||||
m_root.localScale = Vector3.one * p_relation;
|
||||
}
|
||||
|
||||
void OnVRModeSwitch(bool p_state)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_camera = PlayerSetup.Instance.GetActiveCamera().transform;
|
||||
this.enabled = !Utils.IsInVR();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Arbitrary
|
||||
void SetupArmIK()
|
||||
{
|
||||
Transform l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.UpperChest);
|
||||
Animator l_animator = PlayerSetup.Instance._animator;
|
||||
|
||||
Transform l_chest = l_animator.GetBoneTransform(HumanBodyBones.UpperChest);
|
||||
if(l_chest == null)
|
||||
l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Chest);
|
||||
l_chest = l_animator.GetBoneTransform(HumanBodyBones.Chest);
|
||||
if(l_chest == null)
|
||||
l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Spine);
|
||||
l_chest = l_animator.GetBoneTransform(HumanBodyBones.Spine);
|
||||
|
||||
m_armIKLeft = PlayerSetup.Instance._avatar.AddComponent<ArmIK>();
|
||||
m_armIKLeft.solver.isLeft = true;
|
||||
m_armIKLeft.solver.SetChain(
|
||||
l_chest,
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftShoulder),
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftUpperArm),
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftLowerArm),
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand),
|
||||
PlayerSetup.Instance._animator.transform
|
||||
l_animator.GetBoneTransform(HumanBodyBones.LeftShoulder),
|
||||
l_animator.GetBoneTransform(HumanBodyBones.LeftUpperArm),
|
||||
l_animator.GetBoneTransform(HumanBodyBones.LeftLowerArm),
|
||||
l_animator.GetBoneTransform(HumanBodyBones.LeftHand),
|
||||
l_animator.transform
|
||||
);
|
||||
m_armIKLeft.solver.arm.target = m_leftTarget;
|
||||
m_armIKLeft.solver.arm.target = m_leftRotationTarget;
|
||||
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,
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightShoulder),
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightUpperArm),
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightLowerArm),
|
||||
PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand),
|
||||
PlayerSetup.Instance._animator.transform
|
||||
l_animator.GetBoneTransform(HumanBodyBones.RightShoulder),
|
||||
l_animator.GetBoneTransform(HumanBodyBones.RightUpperArm),
|
||||
l_animator.GetBoneTransform(HumanBodyBones.RightLowerArm),
|
||||
l_animator.GetBoneTransform(HumanBodyBones.RightHand),
|
||||
l_animator.transform
|
||||
);
|
||||
m_armIKRight.solver.arm.target = m_rightTarget;
|
||||
m_armIKRight.solver.arm.target = m_rightRotationTarget;
|
||||
m_armIKRight.solver.arm.positionWeight = 1f;
|
||||
m_armIKRight.solver.arm.rotationWeight = 1f;
|
||||
m_armIKRight.solver.IKPositionWeight = 0f;
|
||||
|
@ -525,39 +538,66 @@ namespace ml_pam
|
|||
m_armIKRight = null;
|
||||
}
|
||||
|
||||
void SetArmActive(Settings.LeadHand p_hand, bool p_state, bool p_forced = false)
|
||||
void UpdateArmIK(ArmIK p_ik, float p_weight)
|
||||
{
|
||||
if(m_enabled || p_forced)
|
||||
if(p_ik != null)
|
||||
{
|
||||
if(((p_hand == Settings.LeadHand.Left) || (p_hand == Settings.LeadHand.Both)) && (m_armIKLeft != null))
|
||||
{
|
||||
m_armIKLeft.enabled = m_enabled;
|
||||
m_armIKLeft.solver.IKPositionWeight = (p_state ? 1f : 0f);
|
||||
m_armIKLeft.solver.IKRotationWeight = (p_state ? 1f : 0f);
|
||||
}
|
||||
if(((p_hand == Settings.LeadHand.Right) || (p_hand == Settings.LeadHand.Both)) && (m_armIKRight != null))
|
||||
{
|
||||
m_armIKRight.enabled = m_enabled;
|
||||
m_armIKRight.solver.IKPositionWeight = (p_state ? 1f : 0f);
|
||||
m_armIKRight.solver.IKRotationWeight = (p_state ? 1f : 0f);
|
||||
}
|
||||
|
||||
if((p_hand == Settings.LeadHand.Left) || (p_hand == Settings.LeadHand.Both))
|
||||
m_leftHandParameter?.SetValue(p_state);
|
||||
if((p_hand == Settings.LeadHand.Right) || (p_hand == Settings.LeadHand.Both))
|
||||
m_rightHandParameter?.SetValue(p_state);
|
||||
bool l_state = !Mathf.Approximately(p_weight, 0f);
|
||||
p_ik.solver.IKPositionWeight = p_weight;
|
||||
p_ik.solver.IKRotationWeight = p_weight;
|
||||
p_ik.enabled = l_state;
|
||||
}
|
||||
}
|
||||
|
||||
void ReparentRoots()
|
||||
void SetLeadingHandState(HandState p_state)
|
||||
{
|
||||
m_rootLeft.parent = PlayerSetup.Instance.GetActiveCamera().transform;
|
||||
m_rootLeft.localPosition = Vector3.zero;
|
||||
m_rootLeft.localRotation = Quaternion.identity;
|
||||
switch(Settings.LeadingHand)
|
||||
{
|
||||
case Settings.LeadHand.Left:
|
||||
m_leftHandState = p_state;
|
||||
break;
|
||||
case Settings.LeadHand.Right:
|
||||
m_rightHandState = p_state;
|
||||
break;
|
||||
case Settings.LeadHand.Both:
|
||||
{
|
||||
m_leftHandState = p_state;
|
||||
m_rightHandState = p_state;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
void SetUnleadingHandState(HandState p_state)
|
||||
{
|
||||
switch(Settings.LeadingHand)
|
||||
{
|
||||
case Settings.LeadHand.Left:
|
||||
m_rightHandState = p_state;
|
||||
break;
|
||||
case Settings.LeadHand.Right:
|
||||
m_leftHandState = p_state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_rootRight.parent = PlayerSetup.Instance.GetActiveCamera().transform;
|
||||
m_rootRight.localPosition = Vector3.zero;
|
||||
m_rootRight.localRotation = Quaternion.identity;
|
||||
IEnumerator WaitToDisable()
|
||||
{
|
||||
while(!Mathf.Approximately(m_handsWeights.x + m_handsWeights.y, 0f))
|
||||
yield return null;
|
||||
|
||||
this.enabled = false;
|
||||
m_disableTask = null;
|
||||
}
|
||||
|
||||
static float GetChainLength(Transform[] p_chain)
|
||||
{
|
||||
float l_result = 0f;
|
||||
for(int i = 0, j = p_chain.Length - 1; i < j; i++)
|
||||
{
|
||||
if((p_chain[i] != null) && (p_chain[i + 1] != null))
|
||||
l_result += Vector3.Distance(p_chain[i].position, p_chain[i + 1].position);
|
||||
}
|
||||
return l_result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace ml_pam
|
|||
public static readonly GameEvent OnAvatarSetup = new GameEvent();
|
||||
public static readonly GameEvent OnAvatarClear = new GameEvent();
|
||||
public static readonly GameEvent OnAvatarReuse = new GameEvent();
|
||||
public static readonly GameEvent<float> OnPlayspaceScale = new GameEvent<float>();
|
||||
public static readonly GameEvent<float> OnIKScaling = new GameEvent<float>();
|
||||
public static readonly GameEvent<CVRPickupObject, Vector3> OnPickupGrab = new GameEvent<CVRPickupObject, Vector3>();
|
||||
public static readonly GameEvent<CVRPickupObject> OnPickupDrop = new GameEvent<CVRPickupObject>();
|
||||
|
||||
|
@ -61,9 +61,9 @@ namespace ml_pam
|
|||
);
|
||||
|
||||
p_instance.Patch(
|
||||
typeof(PlayerSetup).GetMethod("SetPlaySpaceScale", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
typeof(PlayerSetup).GetMethod("SetupIKScaling", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnPlayspaceScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
new HarmonyLib.HarmonyMethod(typeof(GameEvents).GetMethod(nameof(OnSetupIKScaling_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
p_instance.Patch(
|
||||
|
@ -120,11 +120,11 @@ namespace ml_pam
|
|||
}
|
||||
}
|
||||
|
||||
static void OnPlayspaceScale_Postfix(float ____avatarScaleRelation)
|
||||
static void OnSetupIKScaling_Postfix(ref UnityEngine.Vector3 ___scaleDifference)
|
||||
{
|
||||
try
|
||||
{
|
||||
OnPlayspaceScale.Invoke(____avatarScaleRelation);
|
||||
OnIKScaling.Invoke(1f + ___scaleDifference.y);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
|
|
|
@ -1,32 +1,34 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_pam
|
||||
{
|
||||
public class PickupArmMovement : MelonLoader.MelonMod
|
||||
{
|
||||
ArmMover m_localMover = null;
|
||||
ArmMover m_mover = null;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
Settings.Init();
|
||||
GameEvents.Init(HarmonyInstance);
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
|
||||
MelonLoader.MelonCoroutines.Start(WaitForRootLogic());
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator WaitForLocalPlayer()
|
||||
System.Collections.IEnumerator WaitForRootLogic()
|
||||
{
|
||||
while(PlayerSetup.Instance == null)
|
||||
while(ABI_RC.Core.RootLogic.Instance == null)
|
||||
yield return null;
|
||||
while(ABI_RC.Core.Player.PlayerSetup.Instance == null)
|
||||
yield return null;
|
||||
|
||||
m_localMover = PlayerSetup.Instance.gameObject.AddComponent<ArmMover>();
|
||||
m_mover = new GameObject("[PickupArmMovement]").AddComponent<ArmMover>();
|
||||
}
|
||||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
if(m_localMover != null)
|
||||
UnityEngine.Object.Destroy(m_localMover);
|
||||
m_localMover = null;
|
||||
if(m_mover != null)
|
||||
Object.Destroy(m_mover.gameObject);
|
||||
m_mover = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_pam.PickupArmMovement), "PickupArmMovement", "1.1.4", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_pam.PickupArmMovement), "PickupArmMovement", "1.2.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||
[assembly: MelonLoader.MelonPriority(1)]
|
||||
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||
|
|
|
@ -4,14 +4,15 @@ This mod adds arm tracking upon holding pickup in desktop mode.
|
|||
# Installation
|
||||
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
|
||||
* Get [latest release DLL](../../../releases/latest):
|
||||
* Put `ml_pam.dll` in `Mods` folder of game
|
||||
* Put `PickupArmMovement.dll` in `Mods` folder of game
|
||||
|
||||
# Usage
|
||||
Available mod's settings in `Settings - Interactions - Pickup Arm Movement`:
|
||||
Available mod's settings in `Settings - Input & Key-Bindings - Pickup Arm Movement`:
|
||||
* **Enable hand movement:** enables/disables arm tracking; default value - `true`.
|
||||
* **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`.
|
||||
* **Hand extension speed::** smoothing speed multiplier between extended and animated hands; default value - `25`.
|
||||
|
||||
Available animator boolean parameters:
|
||||
* **LeftHandExtended:`` indicates if left hand is extended.
|
||||
|
|
|
@ -6,15 +6,16 @@ namespace ml_pam
|
|||
{
|
||||
static class ResourcesHandler
|
||||
{
|
||||
readonly static string ms_namespace = typeof(ResourcesHandler).Namespace;
|
||||
|
||||
public static string GetEmbeddedResources(string p_name)
|
||||
{
|
||||
string l_result = "";
|
||||
Assembly l_assembly = Assembly.GetExecutingAssembly();
|
||||
string l_assemblyName = l_assembly.GetName().Name;
|
||||
|
||||
try
|
||||
{
|
||||
Stream l_libraryStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name);
|
||||
Stream l_libraryStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + p_name);
|
||||
StreamReader l_streadReader = new StreamReader(l_libraryStream);
|
||||
l_result = l_streadReader.ReadToEnd();
|
||||
}
|
||||
|
|
|
@ -19,7 +19,8 @@ namespace ml_pam
|
|||
Enabled = 0,
|
||||
GrabOffset,
|
||||
LeadHand,
|
||||
HandsExtension
|
||||
HandsExtension,
|
||||
ExtensionSpeed
|
||||
}
|
||||
public enum LeadHand
|
||||
{
|
||||
|
@ -29,9 +30,10 @@ namespace ml_pam
|
|||
}
|
||||
|
||||
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.5f;
|
||||
public static LeadHand LeadingHand { get; private set; } = LeadHand.Right;
|
||||
public static bool HandsExtension { get; private set; } = true;
|
||||
public static float ExtensionSpeed { get; private set; } = 10f;
|
||||
|
||||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
@ -40,6 +42,7 @@ namespace ml_pam
|
|||
public static readonly SettingEvent<float> OnGrabOffsetChanged = new SettingEvent<float>();
|
||||
public static readonly SettingEvent<LeadHand> OnLeadingHandChanged = new SettingEvent<LeadHand>();
|
||||
public static readonly SettingEvent<bool> OnHandsExtensionChanged = new SettingEvent<bool>();
|
||||
public static readonly SettingEvent<float> OnExtensionSpeedChanged = new SettingEvent<float>();
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
|
@ -51,12 +54,14 @@ namespace ml_pam
|
|||
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),
|
||||
ms_category.CreateEntry(ModSetting.ExtensionSpeed.ToString(), (int)ExtensionSpeed),
|
||||
};
|
||||
|
||||
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;
|
||||
ExtensionSpeed = Math.Clamp((int)ms_entries[(int)ModSetting.ExtensionSpeed].BoxedValue, 1f, 50f);
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitMainMenuUi());
|
||||
}
|
||||
|
@ -72,6 +77,7 @@ namespace ml_pam
|
|||
|
||||
ViewManager.Instance.gameMenuView.Listener.ReadyForBindings += () =>
|
||||
{
|
||||
|
||||
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("OnDropdownUpdate_" + ms_category.Identifier, new Action<string, string>(OnDropdownUpdate));
|
||||
|
@ -131,6 +137,13 @@ namespace ml_pam
|
|||
OnGrabOffsetChanged.Invoke(GrabOffset);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.ExtensionSpeed:
|
||||
{
|
||||
ExtensionSpeed = l_value;
|
||||
OnExtensionSpeedChanged.Invoke(ExtensionSpeed);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ms_entries[(int)l_setting].BoxedValue = l_value;
|
||||
|
|
|
@ -4,10 +4,11 @@
|
|||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
<PackageId>PickupArmMovement</PackageId>
|
||||
<Version>1.1.4</Version>
|
||||
<Version>1.2.0</Version>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Company>SDraw</Company>
|
||||
<Product>PickupArmMovement</Product>
|
||||
<AssemblyName>PickupArmMovement</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<div class ="row-wrapper">
|
||||
<div class ="option-caption">Grab offset: </div>
|
||||
<div class ="option-input">
|
||||
<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="50"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -33,8 +33,15 @@
|
|||
<div id="HandsExtension" class ="inp_toggle no-scroll" data-current="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class ="row-wrapper">
|
||||
<div class ="option-caption">Hand extension speed: </div>
|
||||
<div class ="option-input">
|
||||
<div id="ExtensionSpeed" class ="inp_slider no-scroll" data-min="1" data-max="50" data-current="10"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
document.getElementById('settings-interaction').appendChild(l_block);
|
||||
document.getElementById('settings-input').appendChild(l_block);
|
||||
|
||||
// Toggles
|
||||
for (let l_toggle of l_block.querySelectorAll('.inp_toggle'))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_pin.PlayersInstanceNotifier), "PlayersInstanceNotifier", "1.0.9", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_pin.PlayersInstanceNotifier), "PlayersInstanceNotifier", "1.1.0", "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)]
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace ml_pin
|
|||
static class ResourcesHandler
|
||||
{
|
||||
const string c_modName = "PlayersInstanceNotifier";
|
||||
readonly static string ms_namespace = typeof(ResourcesHandler).Namespace;
|
||||
|
||||
static readonly List<string> ms_audioResources = new List<string>()
|
||||
{
|
||||
|
@ -45,11 +46,10 @@ namespace ml_pin
|
|||
static void ExtractAudioFile(string p_name, string p_path)
|
||||
{
|
||||
Assembly l_assembly = Assembly.GetExecutingAssembly();
|
||||
string l_assemblyName = l_assembly.GetName().Name;
|
||||
|
||||
try
|
||||
{
|
||||
Stream l_resourceStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name);
|
||||
Stream l_resourceStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + p_name);
|
||||
Stream l_fileStream = File.Create(p_path);
|
||||
l_resourceStream.CopyTo(l_fileStream);
|
||||
l_fileStream.Flush();
|
||||
|
@ -66,11 +66,10 @@ namespace ml_pin
|
|||
{
|
||||
string l_result = "";
|
||||
Assembly l_assembly = Assembly.GetExecutingAssembly();
|
||||
string l_assemblyName = l_assembly.GetName().Name;
|
||||
|
||||
try
|
||||
{
|
||||
Stream l_libraryStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name);
|
||||
Stream l_libraryStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + p_name);
|
||||
StreamReader l_streadReader = new StreamReader(l_libraryStream);
|
||||
l_result = l_streadReader.ReadToEnd();
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
<Platforms>x64</Platforms>
|
||||
<PackageId>PlayersInstanceNotifier</PackageId>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Company>SDraw</Company>
|
||||
<Product>PlayersInstanceNotifier</Product>
|
||||
<Version>1.0.9</Version>
|
||||
<Version>1.1.0</Version>
|
||||
<AssemblyName>PlayersInstanceNotifier</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_pmc
|
||||
{
|
||||
public class PlayerMovementCopycat : MelonLoader.MelonMod
|
||||
{
|
||||
PoseCopycat m_localCopycat = null;
|
||||
PoseCopycat m_poseCopycat = null;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
|
@ -17,9 +18,9 @@ namespace ml_pmc
|
|||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
if(m_localCopycat != null)
|
||||
UnityEngine.Object.Destroy(m_localCopycat);
|
||||
m_localCopycat = null;
|
||||
if(m_poseCopycat != null)
|
||||
Object.Destroy(m_poseCopycat.gameObject);
|
||||
m_poseCopycat = null;
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator WaitForLocalPlayer()
|
||||
|
@ -27,7 +28,7 @@ namespace ml_pmc
|
|||
while(PlayerSetup.Instance == null)
|
||||
yield return null;
|
||||
|
||||
m_localCopycat = PlayerSetup.Instance.gameObject.AddComponent<PoseCopycat>();
|
||||
m_poseCopycat = new GameObject("[PlayerMovementCopycat]").AddComponent<PoseCopycat>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ using UnityEngine;
|
|||
namespace ml_pmc
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public class PoseCopycat : MonoBehaviour
|
||||
class PoseCopycat : MonoBehaviour
|
||||
{
|
||||
public class CopycatEvent<T1>
|
||||
{
|
||||
|
@ -22,7 +22,7 @@ namespace ml_pmc
|
|||
|
||||
static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f);
|
||||
|
||||
public static PoseCopycat Instance { get; private set; } = null;
|
||||
static PoseCopycat ms_instance = null;
|
||||
internal static readonly CopycatEvent<bool> OnCopycatChanged = new CopycatEvent<bool>();
|
||||
|
||||
Animator m_animator = null;
|
||||
|
@ -43,10 +43,14 @@ namespace ml_pmc
|
|||
|
||||
void Awake()
|
||||
{
|
||||
if((Instance != null) && (Instance != this))
|
||||
Object.Destroy(this);
|
||||
else
|
||||
Instance = this;
|
||||
if(ms_instance != null)
|
||||
{
|
||||
DestroyImmediate(this);
|
||||
return;
|
||||
}
|
||||
|
||||
ms_instance = this;
|
||||
DontDestroyOnLoad(this);
|
||||
}
|
||||
|
||||
void Start()
|
||||
|
@ -60,8 +64,8 @@ namespace ml_pmc
|
|||
}
|
||||
void OnDestroy()
|
||||
{
|
||||
if(Instance == this)
|
||||
Instance = null;
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
m_poseHandler?.Dispose();
|
||||
m_poseHandler = null;
|
||||
|
@ -201,7 +205,7 @@ namespace ml_pmc
|
|||
PlayerSetup.Instance.transform.rotation = l_result.rotation;
|
||||
}
|
||||
|
||||
if(Vector3.Distance(this.transform.position, m_puppetParser.transform.position) > m_distanceLimit)
|
||||
if(Vector3.Distance(PlayerSetup.Instance.GetPlayerPosition(), m_puppetParser.transform.position) > m_distanceLimit)
|
||||
SetTarget(null);
|
||||
}
|
||||
else
|
||||
|
@ -364,7 +368,7 @@ namespace ml_pmc
|
|||
}
|
||||
|
||||
// Arbitrary
|
||||
public void SetTarget(PuppetMaster p_target)
|
||||
void SetTarget(PuppetMaster p_target)
|
||||
{
|
||||
if(m_animator != null)
|
||||
{
|
||||
|
@ -405,9 +409,6 @@ namespace ml_pmc
|
|||
}
|
||||
}
|
||||
|
||||
public bool IsActive() => m_active;
|
||||
public bool IsFingerTrackingActive() => m_fingerTracking;
|
||||
|
||||
void OverrideIK()
|
||||
{
|
||||
if(!BodySystem.isCalibrating)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_pmc.PlayerMovementCopycat), "PlayerMovementCopycat", "1.0.8", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_pmc.PlayerMovementCopycat), "PlayerMovementCopycat", "1.1.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||
[assembly: MelonLoader.MelonPriority(3)]
|
||||
[assembly: MelonLoader.MelonAdditionalDependencies("BTKUILib")]
|
||||
|
|
|
@ -5,7 +5,7 @@ Allows to copy pose, gestures and movement of your friends.
|
|||
* Install [BTKUILib](https://github.com/BTK-Development/BTKUILib)
|
||||
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
|
||||
* Get [latest release DLL](../../../releases/latest):
|
||||
* Put `ml_pmc.dll` in `Mods` folder of game
|
||||
* Put `PlayerMovementCopycat.dll` in `Mods` folder of game
|
||||
|
||||
# Usage
|
||||
Available options in BTKUILib players list upon player selection:
|
||||
|
|
|
@ -5,9 +5,10 @@
|
|||
<Platforms>x64</Platforms>
|
||||
<PackageId>PlayerMovementCopycat</PackageId>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Company>SDraw</Company>
|
||||
<Product>PlayerMovementCopycat</Product>
|
||||
<Version>1.0.8</Version>
|
||||
<Version>1.1.0</Version>
|
||||
<AssemblyName>PlayerMovementCopycat</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
|
|
@ -248,6 +248,5 @@ namespace ml_prm
|
|||
}
|
||||
return !ms_result.m_result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,14 +42,9 @@ namespace ml_prm
|
|||
System.Collections.IEnumerator WaitForWhitelist()
|
||||
{
|
||||
// Whitelist the toggle script
|
||||
FieldInfo l_field = typeof(SharedFilter).GetField("_localComponentWhitelist", BindingFlags.NonPublic | BindingFlags.Static);
|
||||
HashSet<Type> l_hashSet = l_field?.GetValue(null) as HashSet<Type>;
|
||||
while(l_hashSet == null)
|
||||
{
|
||||
l_hashSet = l_field?.GetValue(null) as HashSet<Type>;
|
||||
while(SharedFilter.LocalComponentWhitelist == null)
|
||||
yield return null;
|
||||
}
|
||||
l_hashSet.Add(typeof(RagdollToggle));
|
||||
SharedFilter.LocalComponentWhitelist.Add(typeof(RagdollToggle));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ namespace ml_prm
|
|||
const string c_ragdollKeyTooltip = "Switch ragdoll mode with '{0}' key";
|
||||
const string c_fallLimitTooltip = "Fall limit based on impact velocity<p>Current value corresponds to drop from {0} units with default gravity</p>";
|
||||
|
||||
readonly static string ms_namespace = typeof(ModUi).Namespace;
|
||||
internal static readonly UiEvent OnSwitchChanged = new UiEvent();
|
||||
|
||||
static Page ms_page = null;
|
||||
|
@ -345,7 +346,7 @@ namespace ml_prm
|
|||
{
|
||||
Assembly l_assembly = Assembly.GetExecutingAssembly();
|
||||
string l_assemblyName = l_assembly.GetName().Name;
|
||||
return l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name);
|
||||
return l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + p_name);
|
||||
}
|
||||
|
||||
static float GetDropHeight(float p_speed, float p_gravity = 9.8f)
|
||||
|
|
|
@ -65,7 +65,7 @@ Now you can animate both parameters available:
|
|||

|
||||
Note: In order to work the game object needs to be active and the component enabled.
|
||||
|
||||
# Mods Integration
|
||||
# Mods integration
|
||||
You can use this mod's functions within your mod. To do this you need:
|
||||
* Add mod's dll as reference in your project
|
||||
* Access ragdoll controller with `ml_prm.RagdollController.Instance`
|
||||
|
@ -75,9 +75,3 @@ Available methods:
|
|||
* ```void SwitchRagdoll()```
|
||||
* ```void Ragdoll()```
|
||||
* ```void Unragdoll()```
|
||||
|
||||
# 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):
|
||||
* Renaming avatar emote animations to not have default name or containing `Emote` substring.
|
||||
* Holding any movement key right after activating ragdoll state.
|
||||
* Add transition from `Any state` to state with A-pose/T-pose animation and condition with `Ragdolled` parameter on main avatar's animator layer.
|
||||
|
|
|
@ -26,8 +26,10 @@ namespace ml_prm
|
|||
bool m_applyHipsPosition = false;
|
||||
bool m_applyHipsRotation = false;
|
||||
|
||||
bool m_avatarReady = false;
|
||||
bool m_ragdolled = false;
|
||||
bool m_forcedSwitch = false;
|
||||
Coroutine m_initTask = null;
|
||||
|
||||
Transform m_puppet = null;
|
||||
Transform m_puppetRoot = null;
|
||||
|
@ -36,10 +38,6 @@ namespace ml_prm
|
|||
readonly List<System.Tuple<Transform, Transform>> m_boneLinks = null;
|
||||
readonly List<System.Tuple<CharacterJoint, Vector3>> m_jointAnchors = null;
|
||||
|
||||
bool m_avatarReady = false;
|
||||
Coroutine m_initCoroutine = null;
|
||||
Vector3 m_ragdollLastPos = Vector3.zero;
|
||||
|
||||
RagdollToggle m_avatarRagdollToggle = null; // Custom component available for editor
|
||||
AvatarBoolParameter m_ragdolledParameter = null;
|
||||
PhysicMaterial m_physicsMaterial = null;
|
||||
|
@ -49,6 +47,11 @@ namespace ml_prm
|
|||
float m_groundedTime = 0f;
|
||||
float m_downTime = float.MinValue;
|
||||
|
||||
Vector3 m_lastRagdollPosition;
|
||||
Vector3 m_lastSeatPositon;
|
||||
Vector3 m_seatVelocity;
|
||||
Plane m_playerPlane;
|
||||
|
||||
internal RagdollController()
|
||||
{
|
||||
m_ragdollBodyHandlers = new List<RagdollBodypartHandler>();
|
||||
|
@ -59,10 +62,14 @@ namespace ml_prm
|
|||
// Unity events
|
||||
void Awake()
|
||||
{
|
||||
if((Instance != null) && (Instance != this))
|
||||
Object.Destroy(this);
|
||||
else
|
||||
Instance = this;
|
||||
if(Instance != null)
|
||||
{
|
||||
DestroyImmediate(this);
|
||||
return;
|
||||
}
|
||||
|
||||
Instance = this;
|
||||
DontDestroyOnLoad(this);
|
||||
}
|
||||
|
||||
void Start()
|
||||
|
@ -112,9 +119,9 @@ namespace ml_prm
|
|||
if(Instance == this)
|
||||
Instance = null;
|
||||
|
||||
if(m_initCoroutine != null)
|
||||
StopCoroutine(m_initCoroutine);
|
||||
m_initCoroutine = null;
|
||||
if(m_initTask != null)
|
||||
StopCoroutine(m_initTask);
|
||||
m_initTask = null;
|
||||
|
||||
if(m_puppet != null)
|
||||
Object.Destroy(m_puppet);
|
||||
|
@ -160,7 +167,7 @@ namespace ml_prm
|
|||
{
|
||||
if(m_avatarReady)
|
||||
{
|
||||
if(!m_ragdolled && Settings.FallDamage && !BetterBetterCharacterController.Instance.IsFlying())
|
||||
if(!m_ragdolled && Settings.FallDamage && !BetterBetterCharacterController.Instance.IsFlying() && !BetterBetterCharacterController.Instance.IsSitting())
|
||||
{
|
||||
bool l_grounded = BetterBetterCharacterController.Instance.IsGrounded();
|
||||
bool l_inWater = BetterBetterCharacterController.Instance.IsInWater();
|
||||
|
@ -170,6 +177,17 @@ namespace ml_prm
|
|||
m_inAir = !(l_grounded || l_inWater);
|
||||
}
|
||||
|
||||
if(!m_ragdolled && BetterBetterCharacterController.Instance.IsSitting()) // Those seats without velocity, smh
|
||||
{
|
||||
CVRSeat l_seat = BetterBetterCharacterController.Instance.GetCurrentSeat();
|
||||
if(l_seat != null)
|
||||
{
|
||||
Vector3 l_pos = l_seat.transform.position;
|
||||
m_seatVelocity = (l_pos - m_lastSeatPositon) / Time.deltaTime;
|
||||
m_lastSeatPositon = l_pos;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_ragdolled)
|
||||
{
|
||||
BodySystem.TrackingPositionWeight = 0f;
|
||||
|
@ -178,7 +196,7 @@ namespace ml_prm
|
|||
PlayerSetup.Instance.animatorManager.CancelEmote = true;
|
||||
}
|
||||
|
||||
if(!m_ragdolled && !m_reachedGround && (BetterBetterCharacterController.Instance.IsOnGround() || BetterBetterCharacterController.Instance.IsInWater()))
|
||||
if(!m_ragdolled && !m_reachedGround && (BetterBetterCharacterController.Instance.IsOnGround() || BetterBetterCharacterController.Instance.IsInWater() || BetterBetterCharacterController.Instance.IsSitting()))
|
||||
{
|
||||
m_groundedTime += Time.unscaledDeltaTime;
|
||||
if(m_groundedTime >= 0.25f)
|
||||
|
@ -210,9 +228,18 @@ namespace ml_prm
|
|||
{
|
||||
if(m_avatarReady && m_ragdolled)
|
||||
{
|
||||
Vector3 l_currentPos = m_puppetReferences.hips.position;
|
||||
PlayerSetup.Instance.transform.position += (l_currentPos - m_ragdollLastPos);
|
||||
m_ragdollLastPos = l_currentPos;
|
||||
Vector3 l_diff = m_puppetReferences.hips.position - m_lastRagdollPosition;
|
||||
m_playerPlane.SetNormalAndPosition(PlayerSetup.Instance.transform.rotation * Vector3.up, PlayerSetup.Instance.transform.position);
|
||||
|
||||
PlayerSetup.Instance.transform.position += l_diff;
|
||||
m_lastRagdollPosition = m_puppetReferences.hips.position;
|
||||
|
||||
// Project on plane and fix our position if we under previous plane
|
||||
if(m_playerPlane.GetDistanceToPoint(m_lastRagdollPosition) < 0f)
|
||||
m_playerPlane.Flip();
|
||||
float l_distance = m_playerPlane.GetDistanceToPoint(PlayerSetup.Instance.transform.position);
|
||||
if(l_distance < 0f)
|
||||
PlayerSetup.Instance.transform.position = m_playerPlane.ClosestPointOnPlane(PlayerSetup.Instance.transform.position);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -242,10 +269,10 @@ namespace ml_prm
|
|||
// Game events
|
||||
void OnAvatarClear()
|
||||
{
|
||||
if(m_initCoroutine != null)
|
||||
if(m_initTask != null)
|
||||
{
|
||||
StopCoroutine(m_initCoroutine);
|
||||
m_initCoroutine = null;
|
||||
StopCoroutine(m_initTask);
|
||||
m_initTask = null;
|
||||
}
|
||||
|
||||
if(m_ragdolled)
|
||||
|
@ -365,7 +392,7 @@ namespace ml_prm
|
|||
m_avatarRagdollToggle = PlayerSetup.Instance._avatar.GetComponentInChildren<RagdollToggle>(true);
|
||||
m_ragdolledParameter = new AvatarBoolParameter("Ragdolled", PlayerSetup.Instance.animatorManager);
|
||||
|
||||
m_initCoroutine = StartCoroutine(WaitForBodyHandlers());
|
||||
m_initTask = StartCoroutine(WaitForBodyHandlers());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -381,7 +408,7 @@ namespace ml_prm
|
|||
}
|
||||
|
||||
m_avatarReady = true;
|
||||
m_initCoroutine = null;
|
||||
m_initTask = null;
|
||||
|
||||
OnMovementDragChanged(Settings.MovementDrag);
|
||||
OnAngularDragChanged(Settings.AngularDrag);
|
||||
|
@ -414,6 +441,8 @@ namespace ml_prm
|
|||
|
||||
void OnSeatPreSit(CVRSeat p_seat)
|
||||
{
|
||||
m_lastSeatPositon = p_seat.transform.position;
|
||||
|
||||
if(!p_seat.occupied)
|
||||
{
|
||||
m_forcedSwitch = true;
|
||||
|
@ -473,9 +502,8 @@ namespace ml_prm
|
|||
|
||||
if(m_avatarReady && m_ragdolled)
|
||||
{
|
||||
Vector3 l_pos = m_hips.position;
|
||||
m_puppetReferences.hips.position = l_pos;
|
||||
m_ragdollLastPos = l_pos;
|
||||
m_puppetReferences.hips.position = m_hips.position;
|
||||
m_lastRagdollPosition = m_puppetReferences.hips.position;
|
||||
}
|
||||
}
|
||||
catch(System.Exception e)
|
||||
|
@ -600,7 +628,7 @@ namespace ml_prm
|
|||
|
||||
void OnGestureGrabChanged(bool p_state)
|
||||
{
|
||||
if(m_avatarReady && m_ragdolled & !p_state)
|
||||
if(m_avatarReady && m_ragdolled && !p_state)
|
||||
{
|
||||
foreach(var l_hanlder in m_ragdollBodyHandlers)
|
||||
l_hanlder.Detach();
|
||||
|
@ -622,13 +650,24 @@ namespace ml_prm
|
|||
{
|
||||
if(m_avatarReady && !m_ragdolled && CanRagdoll())
|
||||
{
|
||||
Vector3 l_velocity = Vector3.ClampMagnitude(BetterBetterCharacterController.Instance.velocity * (WorldManager.IsSafeWorld() ? Settings.VelocityMultiplier : 1f), WorldManager.GetMovementLimit());
|
||||
Vector3 l_velocity = (BetterBetterCharacterController.Instance.IsSitting() ? m_seatVelocity : BetterBetterCharacterController.Instance.velocity);
|
||||
l_velocity *= (WorldManager.IsSafeWorld() ? Settings.VelocityMultiplier : 1f);
|
||||
l_velocity = Vector3.ClampMagnitude(l_velocity, WorldManager.GetMovementLimit());
|
||||
if(Settings.ViewVelocity && WorldManager.IsSafeWorld())
|
||||
{
|
||||
float l_mag = l_velocity.magnitude;
|
||||
l_velocity = PlayerSetup.Instance.GetActiveCamera().transform.forward * l_mag;
|
||||
}
|
||||
|
||||
Vector3 l_playerPos = PlayerSetup.Instance.transform.position;
|
||||
Quaternion l_playerRot = PlayerSetup.Instance.transform.rotation;
|
||||
bool l_wasSitting = BetterBetterCharacterController.Instance.IsSitting();
|
||||
if(BetterBetterCharacterController.Instance.IsSitting())
|
||||
{
|
||||
BetterBetterCharacterController.Instance.SetSitting(false);
|
||||
l_wasSitting = true;
|
||||
}
|
||||
|
||||
if(BetterBetterCharacterController.Instance.IsFlying())
|
||||
BetterBetterCharacterController.Instance.ChangeFlight(false, true);
|
||||
BetterBetterCharacterController.Instance.SetImmobilized(true);
|
||||
|
@ -662,7 +701,12 @@ namespace ml_prm
|
|||
l_handler.SetAngularVelocity(Vector3.zero);
|
||||
}
|
||||
|
||||
m_ragdollLastPos = m_puppetReferences.hips.position;
|
||||
if(l_wasSitting)
|
||||
{
|
||||
PlayerSetup.Instance.transform.position = l_playerPos;
|
||||
PlayerSetup.Instance.transform.rotation = l_playerRot;
|
||||
}
|
||||
m_lastRagdollPosition = m_puppetReferences.hips.position;
|
||||
m_downTime = 0f;
|
||||
|
||||
m_ragdolled = true;
|
||||
|
@ -675,12 +719,6 @@ namespace ml_prm
|
|||
{
|
||||
BetterBetterCharacterController.Instance.TeleportPlayerTo(m_puppetReferences.hips.position, PlayerSetup.Instance.GetPlayerRotation().eulerAngles, false, false);
|
||||
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;
|
||||
|
@ -725,7 +763,6 @@ namespace ml_prm
|
|||
|
||||
bool l_result = m_reachedGround;
|
||||
l_result &= !BodySystem.isCalibrating;
|
||||
l_result &= !BetterBetterCharacterController.Instance.IsSitting();
|
||||
l_result &= ((CombatSystem.Instance == null) || !CombatSystem.Instance.isDown);
|
||||
return (l_result || m_forcedSwitch);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ namespace ml_prm
|
|||
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
|
||||
|
@ -32,6 +33,8 @@ namespace ml_prm
|
|||
public bool m_stateRight = false;
|
||||
}
|
||||
|
||||
static RemoteGesturesManager ms_instance = null;
|
||||
|
||||
readonly List<PlayerEntry> m_entries = null;
|
||||
|
||||
internal RemoteGesturesManager()
|
||||
|
@ -39,10 +42,20 @@ namespace ml_prm
|
|||
m_entries = new List<PlayerEntry>();
|
||||
}
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if(ms_instance != null)
|
||||
{
|
||||
DestroyImmediate(this);
|
||||
return;
|
||||
}
|
||||
|
||||
ms_instance = this;
|
||||
DontDestroyOnLoad(this);
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
DontDestroyOnLoad(this);
|
||||
|
||||
CVRGameEventSystem.Player.OnJoinEntity.AddListener(OnRemotePlayerCreated);
|
||||
CVRGameEventSystem.Player.OnLeaveEntity.AddListener(OnRemotePlayerDestroyed);
|
||||
Settings.OnGestureGrabChanged.AddListener(OnGestureGrabChanged);
|
||||
|
@ -50,6 +63,9 @@ namespace ml_prm
|
|||
|
||||
void OnDestroy()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
m_entries.Clear();
|
||||
|
||||
CVRGameEventSystem.Player.OnJoinEntity.RemoveListener(OnRemotePlayerCreated);
|
||||
|
|
|
@ -8,6 +8,7 @@ using System.Reflection;
|
|||
using UnityEngine;
|
||||
using System.Linq;
|
||||
using ABI_RC.Systems.IK.SubSystems;
|
||||
using ABI_RC.Core.InteractionSystem;
|
||||
|
||||
namespace ml_prm
|
||||
{
|
||||
|
@ -17,6 +18,7 @@ namespace ml_prm
|
|||
static readonly FieldInfo ms_referencePoints = typeof(PhysicsInfluencer).GetField("_referencePoints", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
static readonly FieldInfo ms_influencerTouchingVolumes = typeof(PhysicsInfluencer).GetField("_touchingVolumes", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
static readonly FieldInfo ms_influencerSubmergedColliders = typeof(PhysicsInfluencer).GetField("_submergedColliders", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
static readonly FieldInfo ms_lastCVRSeat = typeof(BetterBetterCharacterController).GetField("_lastCvrSeat", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
public static void ClearFluidVolumes(this BetterBetterCharacterController p_instance) => (ms_touchingVolumes.GetValue(p_instance) as List<FluidVolume>)?.Clear();
|
||||
|
||||
|
@ -58,5 +60,9 @@ namespace ml_prm
|
|||
l_result |= ((FingerSystem.GetCurlNormalized(p_source._playerAvatarMovementDataCurrent.RightMiddle1Stretched) >= 0.5f) && (FingerSystem.GetCurlNormalized(p_source._playerAvatarMovementDataCurrent.RightMiddle2Stretched) >= 0.5f) && (FingerSystem.GetCurlNormalized(p_source._playerAvatarMovementDataCurrent.RightMiddle3Stretched) >= 0.5f));
|
||||
return l_result;
|
||||
}
|
||||
|
||||
public static CVRSeat GetCurrentSeat(this BetterBetterCharacterController p_instance) => (ms_lastCVRSeat?.GetValue(p_instance) as CVRSeat);
|
||||
|
||||
public static bool IsInRange(float p_value, float p_min, float p_max) => ((p_min <= p_value) && (p_value <= p_max));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Systems.GameEventSystem;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_prm
|
||||
|
@ -22,18 +23,25 @@ namespace ml_prm
|
|||
|
||||
static void OnWorldLoad(string p_id)
|
||||
{
|
||||
ms_safeWorld = ((CVRWorld.Instance != null) && CVRWorld.Instance.allowFlying);
|
||||
ms_movementLimit = 1f;
|
||||
|
||||
GameObject l_restrictObj = GameObject.Find("[RagdollRestriction]");
|
||||
ms_restrictedWorld = ((l_restrictObj == null) ? false : (l_restrictObj.scene.name != "DontDestroyOnLoad"));
|
||||
|
||||
if(CVRWorld.Instance != null)
|
||||
try
|
||||
{
|
||||
ms_movementLimit = CVRWorld.Instance.baseMovementSpeed;
|
||||
ms_movementLimit *= CVRWorld.Instance.sprintMultiplier;
|
||||
ms_movementLimit *= CVRWorld.Instance.inAirMovementMultiplier;
|
||||
ms_movementLimit *= CVRWorld.Instance.flyMultiplier;
|
||||
ms_safeWorld = ((CVRWorld.Instance != null) && CVRWorld.Instance.allowFlying);
|
||||
ms_movementLimit = 1f;
|
||||
|
||||
GameObject l_restrictObj = GameObject.Find("[RagdollRestriction]");
|
||||
ms_restrictedWorld = ((l_restrictObj == null) ? false : (l_restrictObj.scene.name != "DontDestroyOnLoad"));
|
||||
|
||||
if(CVRWorld.Instance != null)
|
||||
{
|
||||
ms_movementLimit = CVRWorld.Instance.baseMovementSpeed;
|
||||
ms_movementLimit *= CVRWorld.Instance.sprintMultiplier;
|
||||
ms_movementLimit *= CVRWorld.Instance.inAirMovementMultiplier;
|
||||
ms_movementLimit *= CVRWorld.Instance.flyMultiplier;
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_vei.ViveExtendedInput), "ViveExtendedInput", "1.0.5", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_vei.ViveExtendedInput), "ViveExtendedInput", "1.1.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Vive Extended Input
|
||||
This mod changes input behaviour for Vive controllers.
|
||||
This mod adds few changes of input behaviour for Vive controllers.
|
||||
|
||||
# Installation
|
||||
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
|
||||
|
|
|
@ -6,15 +6,16 @@ namespace ml_vei
|
|||
{
|
||||
static class ResourcesHandler
|
||||
{
|
||||
readonly static string ms_namespace = typeof(ResourcesHandler).Namespace;
|
||||
|
||||
public static string GetEmbeddedResource(string p_name)
|
||||
{
|
||||
string l_result = "";
|
||||
Assembly l_assembly = Assembly.GetExecutingAssembly();
|
||||
string l_assemblyName = l_assembly.GetName().Name;
|
||||
|
||||
try
|
||||
{
|
||||
Stream l_libraryStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name);
|
||||
Stream l_libraryStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + p_name);
|
||||
StreamReader l_streadReader = new StreamReader(l_libraryStream);
|
||||
l_result = l_streadReader.ReadToEnd();
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
<PackageId>ViveExtendedInput</PackageId>
|
||||
<Version>1.0.5</Version>
|
||||
<Version>1.1.0</Version>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>SDraw</Company>
|
||||
<Product>ViveExtendedInput</Product>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue