mirror of
https://github.com/hanetzer/sdraw_mods_cvr.git
synced 2025-09-03 10:29:22 +00:00
Merge branch 'master' into experimental
This commit is contained in:
commit
17bc85b6cb
76 changed files with 3390 additions and 1555 deletions
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2024 SDraw
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
23
README.md
23
README.md
|
@ -3,22 +3,23 @@ Merged set of MelonLoader mods for ChilloutVR.
|
|||
**Table for game build 2023r173:**
|
||||
| Full name | Short name | Latest version | Available in [CVRMA](https://github.com/knah/CVRMelonAssistant) |
|
||||
|:---------:|:----------:|:--------------:| :----------------------------------------------------------------|
|
||||
| [Avatar Motion Tweaker](/ml_amt/README.md) | ml_amt | 1.3.6 [:arrow_down:](../../releases/latest/download/ml_amt.dll)| ✔ Yes<br>:hourglass: Update review |
|
||||
| [Avatar Synced Look](/ml_asl/README.md) | ml_asl | 1.0.0 [:arrow_down:](../../releases/latest/download/ml_asl.dll)| ✔ Yes |
|
||||
| [Desktop Head Tracking](/ml_dht/README.md) | ml_dht | 1.2.0 [:arrow_down:](../../releases/latest/download/ml_dht.dll) | ✔ Yes (`Retired` group)<br>:hourglass: Update review |
|
||||
| [Leap Motion Extension](/ml_lme/README.md)| ml_lme | 1.4.5 [:arrow_down:](../../releases/latest/download/ml_lme.dll)| ✔ Yes |
|
||||
| [Pickup Arm Movement](/ml_pam/README.md)| ml_pam | 1.0.9 [:arrow_down:](../../releases/latest/download/ml_pam.dll)| ✔ Yes |
|
||||
| [Player Movement Copycat](/ml_pmc/README.md)| ml_pmc | 1.0.4 [:arrow_down:](../../releases/latest/download/ml_pmc.dll)| ✔ Yes |
|
||||
| [Player Ragdoll Mod](/ml_prm/README.md) | ml_prm | 1.1.2 [:arrow_down:](../../releases/latest/download/ml_prm.dll)| ✔ Yes<br>:hourglass: Update review |
|
||||
| [Players Instance Notifier](/ml_pin/README.md) | ml_pin | 1.0.1 [:arrow_down:](../../releases/latest/download/ml_ml_pin.dll)| ✔ Yes<br>:hourglass: Update review |
|
||||
| [Vive Extended Input](/ml_vei/README.md) | ml_vei | 1.0.0 [:arrow_down:](../../releases/latest/download/ml_vei.dll)| ✔ Yes |
|
||||
| [Avatar Motion Tweaker](/ml_amt/README.md) | ml_amt | 1.3.7 [:arrow_down:](../../releases/latest/download/ml_amt.dll)| Yes |
|
||||
| [Avatar Synced Look](/ml_asl/README.md) | ml_asl | 1.0.1 [:arrow_down:](../../releases/latest/download/ml_asl.dll)| Yes |
|
||||
| [Better Fingers Tracking](/ml_bft/README.md) | ml_bft | 1.0.0 [:arrow_down:](../../releases/latest/download/ml_bft.dll)| Yes<br>Update review |
|
||||
| [Desktop Head Tracking](/ml_dht/README.md) | ml_dht | 1.2.1 [:arrow_down:](../../releases/latest/download/ml_dht.dll) | Yes |
|
||||
| [Leap Motion Extension](/ml_lme/README.md)| ml_lme | 1.4.7 [:arrow_down:](../../releases/latest/download/ml_lme.dll)| Yes<br>Update review |
|
||||
| [Pickup Arm Movement](/ml_pam/README.md)| ml_pam | 1.1.0 [:arrow_down:](../../releases/latest/download/ml_pam.dll)| Yes |
|
||||
| [Player Movement Copycat](/ml_pmc/README.md)| ml_pmc | 1.0.5 [:arrow_down:](../../releases/latest/download/ml_pmc.dll)| Yes |
|
||||
| [Player Ragdoll Mod](/ml_prm/README.md) | ml_prm | 1.1.3 [:arrow_down:](../../releases/latest/download/ml_prm.dll)| Yes |
|
||||
| [Players Instance Notifier](/ml_pin/README.md) | ml_pin | 1.0.2 [:arrow_down:](../../releases/latest/download/ml_ml_pin.dll)| Yes |
|
||||
| [Vive Extended Input](/ml_vei/README.md) | ml_vei | 1.0.1 [:arrow_down:](../../releases/latest/download/ml_vei.dll)| Yes |
|
||||
|
||||
**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 sine 2023r172 update |
|
||||
| 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 sine 2023r172 update |
|
||||
| Game Main Fixes | ml_gmf | In-game feature since 2023r172 update |
|
||||
| Server Connection Info | ml_sci | Superseded by `Extended Game Notifications`
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK;
|
||||
using ABI_RC.Systems.IK.SubSystems;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
|
@ -98,7 +97,7 @@ namespace ml_amt
|
|||
if(m_localTweaker != null)
|
||||
m_localTweaker.OnAvatarReinitialize();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK;
|
||||
using ABI_RC.Systems.IK.SubSystems;
|
||||
using ABI_RC.Systems.Movement;
|
||||
using RootMotion.FinalIK;
|
||||
|
@ -125,6 +124,8 @@ namespace ml_amt
|
|||
|
||||
internal void OnSetupAvatar()
|
||||
{
|
||||
Utils.SetAvatarTPose();
|
||||
|
||||
m_vrIk = PlayerSetup.Instance._avatar.GetComponent<VRIK>();
|
||||
m_locomotionLayer = PlayerSetup.Instance._animator.GetLayerIndex("Locomotion/Emotes");
|
||||
m_avatarScale = Mathf.Abs(PlayerSetup.Instance._avatar.transform.localScale.y);
|
||||
|
@ -179,6 +180,8 @@ namespace ml_amt
|
|||
internal void OnAvatarReinitialize()
|
||||
{
|
||||
// Old VRIK is destroyed by game
|
||||
Utils.SetAvatarTPose();
|
||||
|
||||
m_vrIk = PlayerSetup.Instance._animator.GetComponent<VRIK>();
|
||||
if(m_vrIk != null)
|
||||
{
|
||||
|
@ -242,25 +245,25 @@ namespace ml_amt
|
|||
}
|
||||
|
||||
// Settings
|
||||
internal void SetCrouchLimit(float p_value)
|
||||
void SetCrouchLimit(float p_value)
|
||||
{
|
||||
if(m_ikLimits == null)
|
||||
BetterBetterCharacterController.Instance.avatarCrouchLimit = Mathf.Clamp01(p_value);
|
||||
}
|
||||
internal void SetProneLimit(float p_value)
|
||||
void SetProneLimit(float p_value)
|
||||
{
|
||||
if(m_ikLimits == null)
|
||||
BetterBetterCharacterController.Instance.avatarProneLimit = Mathf.Clamp01(p_value);
|
||||
}
|
||||
internal void SetIKOverrideFly(bool p_state)
|
||||
void SetIKOverrideFly(bool p_state)
|
||||
{
|
||||
m_ikOverrideFly = p_state;
|
||||
}
|
||||
internal void SetIKOverrideJump(bool p_state)
|
||||
void SetIKOverrideJump(bool p_state)
|
||||
{
|
||||
m_ikOverrideJump = p_state;
|
||||
}
|
||||
internal void SetDetectEmotes(bool p_state)
|
||||
void SetDetectEmotes(bool p_state)
|
||||
{
|
||||
m_detectEmotes = p_state;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.3.7-ex", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.3.7", "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)]
|
||||
|
|
|
@ -26,12 +26,12 @@ namespace ml_amt
|
|||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
||||
static public event Action<float> CrouchLimitChange;
|
||||
static public event Action<float> ProneLimitChange;
|
||||
static public event Action<bool> IKOverrideFlyChange;
|
||||
static public event Action<bool> IKOverrideJumpChange;
|
||||
static public event Action<bool> DetectEmotesChange;
|
||||
static public event Action<bool> MassCenterChange;
|
||||
public static event Action<float> CrouchLimitChange;
|
||||
public static event Action<float> ProneLimitChange;
|
||||
public static event Action<bool> IKOverrideFlyChange;
|
||||
public static event Action<bool> IKOverrideJumpChange;
|
||||
public static event Action<bool> DetectEmotesChange;
|
||||
public static event Action<bool> MassCenterChange;
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
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 RootMotion.FinalIK;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
@ -30,7 +32,14 @@ namespace ml_amt
|
|||
return l_result;
|
||||
}
|
||||
|
||||
static public void ExecuteScript(this CohtmlControlledViewWrapper p_instance, string p_script) => ((cohtml.Net.View)ms_view.GetValue(p_instance)).ExecuteScript(p_script);
|
||||
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()
|
||||
{
|
||||
IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose);
|
||||
PlayerSetup.Instance._avatar.transform.localPosition = Vector3.zero;
|
||||
PlayerSetup.Instance._avatar.transform.localRotation = Quaternion.identity;
|
||||
}
|
||||
|
||||
// Engine extensions
|
||||
public static Matrix4x4 GetMatrix(this Transform p_transform, bool p_pos = true, bool p_rot = true, bool p_scl = false)
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DebugType>none</DebugType>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
<DebugType>embedded</DebugType>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ml_asl
|
||||
{
|
||||
public class AvatarSyncedLook : MelonLoader.MelonMod
|
||||
{
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
Settings.Init();
|
||||
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod("UpdatePlayerAvatarMovementData", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(AvatarSyncedLook).GetMethod(nameof(OnPlayerAvatarMovementDataUpdate_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
}
|
||||
|
||||
static void OnPlayerAvatarMovementDataUpdate_Postfix(ref PlayerSetup __instance, PlayerAvatarMovementData ____playerAvatarMovementData)
|
||||
{
|
||||
if(Settings.Enabled && (__instance.EyeMovementController != null))
|
||||
____playerAvatarMovementData.EyeTrackingOverride = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
using ABI_RC.Core.Player;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ml_asl
|
||||
{
|
||||
public class AvatarSyncedLook : MelonLoader.MelonMod
|
||||
{
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
Settings.Init();
|
||||
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod("UpdatePlayerAvatarMovementData", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(AvatarSyncedLook).GetMethod(nameof(OnPlayerAvatarMovementDataUpdate_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
}
|
||||
|
||||
static void OnPlayerAvatarMovementDataUpdate_Postfix(ref PlayerSetup __instance, PlayerAvatarMovementData ____playerAvatarMovementData)
|
||||
{
|
||||
if(Settings.Enabled && (__instance.EyeMovementController != null))
|
||||
____playerAvatarMovementData.EyeTrackingOverride = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_asl.AvatarSyncedLook), "AvatarSyncedLook", "1.0.1-ex", "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)]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_asl.AvatarSyncedLook), "AvatarSyncedLook", "1.0.1", "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)]
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace ml_asl
|
|||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
||||
static public event Action<bool> EnabledChange;
|
||||
public static event Action<bool> EnabledChange;
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
|
|
|
@ -7,6 +7,6 @@ namespace ml_asl
|
|||
{
|
||||
static readonly FieldInfo ms_view = typeof(CohtmlControlledViewWrapper).GetField("_view", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
static public void ExecuteScript(this CohtmlControlledViewWrapper p_instance, string p_script) => ((cohtml.Net.View)ms_view.GetValue(p_instance)).ExecuteScript(p_script);
|
||||
public static void ExecuteScript(this CohtmlControlledViewWrapper p_instance, string p_script) => ((cohtml.Net.View)ms_view.GetValue(p_instance)).ExecuteScript(p_script);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,64 +1,69 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
<PackageId>AvatarSyncedLook</PackageId>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>AvatarSyncedLook</Product>
|
||||
<Version>1.0.1</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="resources\mod_menu.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\0Harmony.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp-firstpass">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="cohtml.Net">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\cohtml.Net.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Cohtml.Runtime">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="MelonLoader">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\MelonLoader.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="..\js\mods_extension.js" Link="resources\mods_extension.js" />
|
||||
<EmbeddedResource Include="resources\mod_menu.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\"" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
<PackageId>AvatarSyncedLook</PackageId>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>AvatarSyncedLook</Product>
|
||||
<Version>1.0.1</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<DebugType>embedded</DebugType>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="resources\mod_menu.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\0Harmony.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp-firstpass">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="cohtml.Net">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\cohtml.Net.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Cohtml.Runtime">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="MelonLoader">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\MelonLoader.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="..\js\mods_extension.js" Link="resources\mods_extension.js" />
|
||||
<EmbeddedResource Include="resources\mod_menu.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\"" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
|
BIN
ml_bft/.github/img_01.png
vendored
Normal file
BIN
ml_bft/.github/img_01.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 306 KiB |
89
ml_bft/AssetsHandler.cs
Normal file
89
ml_bft/AssetsHandler.cs
Normal file
|
@ -0,0 +1,89 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_bft
|
||||
{
|
||||
static class AssetsHandler
|
||||
{
|
||||
static readonly List<string> ms_assets = new List<string>()
|
||||
{
|
||||
"ovr_fingers.asset",
|
||||
"oxr_fingers.asset"
|
||||
};
|
||||
|
||||
static readonly Dictionary<string, AssetBundle> ms_loadedAssets = new Dictionary<string, AssetBundle>();
|
||||
static readonly Dictionary<string, GameObject> ms_loadedObjects = new Dictionary<string, GameObject>();
|
||||
|
||||
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);
|
||||
if(l_assetStream != null)
|
||||
{
|
||||
MemoryStream l_memorySteam = new MemoryStream((int)l_assetStream.Length);
|
||||
l_assetStream.CopyTo(l_memorySteam);
|
||||
AssetBundle l_assetBundle = AssetBundle.LoadFromMemory(l_memorySteam.ToArray(), 0);
|
||||
if(l_assetBundle != null)
|
||||
{
|
||||
l_assetBundle.hideFlags |= HideFlags.DontUnloadUnusedAsset;
|
||||
ms_loadedAssets.Add(l_assetName, l_assetBundle);
|
||||
}
|
||||
else
|
||||
MelonLoader.MelonLogger.Warning("Unable to load bundled '" + l_assetName + "' asset");
|
||||
}
|
||||
else
|
||||
MelonLoader.MelonLogger.Warning("Unable to get bundled '" + l_assetName + "' asset stream");
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Warning("Unable to load bundled '" + l_assetName + "' asset, reason: " + e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static GameObject GetAsset(string p_name)
|
||||
{
|
||||
GameObject l_result = null;
|
||||
if(ms_loadedObjects.ContainsKey(p_name))
|
||||
{
|
||||
l_result = Object.Instantiate(ms_loadedObjects[p_name]);
|
||||
l_result.SetActive(true);
|
||||
l_result.hideFlags |= HideFlags.DontUnloadUnusedAsset;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach(var l_pair in ms_loadedAssets)
|
||||
{
|
||||
if(l_pair.Value.Contains(p_name))
|
||||
{
|
||||
GameObject l_bundledObject = (GameObject)l_pair.Value.LoadAsset(p_name, typeof(GameObject));
|
||||
if(l_bundledObject != null)
|
||||
{
|
||||
ms_loadedObjects.Add(p_name, l_bundledObject);
|
||||
l_result = Object.Instantiate(l_bundledObject);
|
||||
l_result.SetActive(true);
|
||||
l_result.hideFlags |= HideFlags.DontUnloadUnusedAsset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return l_result;
|
||||
}
|
||||
|
||||
public static void Unload()
|
||||
{
|
||||
foreach(var l_pair in ms_loadedAssets)
|
||||
Object.Destroy(l_pair.Value);
|
||||
ms_loadedAssets.Clear();
|
||||
}
|
||||
}
|
||||
}
|
297
ml_bft/FingerSystem.cs
Normal file
297
ml_bft/FingerSystem.cs
Normal file
|
@ -0,0 +1,297 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Savior;
|
||||
using ABI_RC.Systems.IK;
|
||||
using ABI_RC.Systems.InputManagement;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_bft
|
||||
{
|
||||
class FingerSystem
|
||||
{
|
||||
enum PlaneType
|
||||
{
|
||||
OXZ,
|
||||
OYX
|
||||
}
|
||||
|
||||
struct RotationOffset
|
||||
{
|
||||
public Transform m_target;
|
||||
public Transform m_source;
|
||||
public Quaternion m_offset;
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
m_source = null;
|
||||
m_target = null;
|
||||
m_offset = Quaternion.identity;
|
||||
}
|
||||
}
|
||||
|
||||
static readonly HumanBodyBones[] ms_leftFingerBones =
|
||||
{
|
||||
HumanBodyBones.LeftThumbProximal, HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.LeftThumbDistal,
|
||||
HumanBodyBones.LeftIndexProximal, HumanBodyBones.LeftIndexIntermediate, HumanBodyBones.LeftIndexDistal,
|
||||
HumanBodyBones.LeftMiddleProximal, HumanBodyBones.LeftMiddleIntermediate, HumanBodyBones.LeftMiddleDistal,
|
||||
HumanBodyBones.LeftRingProximal, HumanBodyBones.LeftRingIntermediate, HumanBodyBones.LeftRingDistal,
|
||||
HumanBodyBones.LeftLittleProximal, HumanBodyBones.LeftLittleIntermediate, HumanBodyBones.LeftLittleDistal
|
||||
};
|
||||
static readonly HumanBodyBones[] ms_rightFingerBones =
|
||||
{
|
||||
HumanBodyBones.RightThumbProximal, HumanBodyBones.RightThumbIntermediate, HumanBodyBones.RightThumbDistal,
|
||||
HumanBodyBones.RightIndexProximal, HumanBodyBones.RightIndexIntermediate, HumanBodyBones.RightIndexDistal,
|
||||
HumanBodyBones.RightMiddleProximal, HumanBodyBones.RightMiddleIntermediate, HumanBodyBones.RightMiddleDistal,
|
||||
HumanBodyBones.RightRingProximal, HumanBodyBones.RightRingIntermediate, HumanBodyBones.RightRingDistal,
|
||||
HumanBodyBones.RightLittleProximal, HumanBodyBones.RightLittleIntermediate, HumanBodyBones.RightLittleDistal
|
||||
};
|
||||
static readonly (HumanBodyBones, HumanBodyBones, bool)[] ms_rotationFixChains =
|
||||
{
|
||||
(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)
|
||||
};
|
||||
|
||||
public static FingerSystem Instance { get; private set; } = null;
|
||||
|
||||
RotationOffset m_leftHandOffset; // From avatar hand to controller wrist
|
||||
RotationOffset m_rightHandOffset;
|
||||
readonly List<RotationOffset> m_leftFingerOffsets = null; // From controller finger bone to avatar finger bone
|
||||
readonly List<RotationOffset> m_rightFingerOffsets = null;
|
||||
|
||||
public readonly float[] m_lastValues;
|
||||
|
||||
bool m_ready = false;
|
||||
HumanPose m_pose;
|
||||
|
||||
internal FingerSystem()
|
||||
{
|
||||
if(Instance == null)
|
||||
Instance = this;
|
||||
|
||||
m_leftFingerOffsets = new List<RotationOffset>();
|
||||
m_rightFingerOffsets = new List<RotationOffset>();
|
||||
|
||||
m_pose = new HumanPose();
|
||||
m_lastValues = new float[40];
|
||||
}
|
||||
internal void Cleanup()
|
||||
{
|
||||
if(Instance == this)
|
||||
Instance = null;
|
||||
|
||||
m_leftFingerOffsets.Clear();
|
||||
m_rightFingerOffsets.Clear();
|
||||
m_ready = false;
|
||||
}
|
||||
|
||||
internal void OnAvatarSetup()
|
||||
{
|
||||
if(PlayerSetup.Instance._animator.isHuman)
|
||||
{
|
||||
Utils.SetAvatarTPose();
|
||||
InputHandler.Instance.Rebind(PlayerSetup.Instance.transform.rotation);
|
||||
|
||||
// Try to "fix" rotations of fingers
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
// Bind hands
|
||||
m_leftHandOffset.m_source = PlayerSetup.Instance._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_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;
|
||||
|
||||
// Bind fingers
|
||||
foreach(HumanBodyBones p_bone in ms_leftFingerBones)
|
||||
{
|
||||
Transform l_avatarBone = PlayerSetup.Instance._animator.GetBoneTransform(p_bone);
|
||||
Transform l_controllerBone = InputHandler.Instance.GetSourceForBone(p_bone, true);
|
||||
if((l_avatarBone != null) && (l_controllerBone != null))
|
||||
{
|
||||
RotationOffset l_offset = new RotationOffset();
|
||||
l_offset.m_source = l_controllerBone;
|
||||
l_offset.m_target = l_avatarBone;
|
||||
l_offset.m_offset = Quaternion.Inverse(l_controllerBone.rotation) * l_avatarBone.rotation;
|
||||
m_leftFingerOffsets.Add(l_offset);
|
||||
}
|
||||
}
|
||||
foreach(HumanBodyBones p_bone in ms_rightFingerBones)
|
||||
{
|
||||
Transform l_avatarBone = PlayerSetup.Instance._animator.GetBoneTransform(p_bone);
|
||||
Transform l_controllerBone = InputHandler.Instance.GetSourceForBone(p_bone, false);
|
||||
if((l_avatarBone != null) && (l_controllerBone != null))
|
||||
{
|
||||
RotationOffset l_offset = new RotationOffset();
|
||||
l_offset.m_source = l_controllerBone;
|
||||
l_offset.m_target = l_avatarBone;
|
||||
l_offset.m_offset = Quaternion.Inverse(l_controllerBone.rotation) * l_avatarBone.rotation;
|
||||
m_rightFingerOffsets.Add(l_offset);
|
||||
}
|
||||
}
|
||||
|
||||
m_ready = ((m_leftFingerOffsets.Count > 0) || (m_rightFingerOffsets.Count > 0));
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnAvatarClear()
|
||||
{
|
||||
m_ready = false;
|
||||
m_pose = new HumanPose();
|
||||
|
||||
m_leftHandOffset.Reset();
|
||||
m_rightHandOffset.Reset();
|
||||
|
||||
m_leftFingerOffsets.Clear();
|
||||
m_rightFingerOffsets.Clear();
|
||||
}
|
||||
|
||||
internal void OnReinitializeAvatar()
|
||||
{
|
||||
OnAvatarClear();
|
||||
OnAvatarSetup();
|
||||
}
|
||||
|
||||
internal void OnIKSystemLateUpdate(HumanPoseHandler p_handler, Transform p_hips)
|
||||
{
|
||||
if(m_ready && MetaPort.Instance.isUsingVr && (p_handler != null) && Settings.SkeletalInput)
|
||||
{
|
||||
if(CVRInputManager.Instance._leftController != ABI_RC.Systems.InputManagement.XR.eXRControllerType.None)
|
||||
{
|
||||
Quaternion l_turnBack = (m_leftHandOffset.m_source.rotation * m_leftHandOffset.m_offset) * Quaternion.Inverse(m_leftHandOffset.m_target.rotation);
|
||||
foreach(var l_offset in m_leftFingerOffsets)
|
||||
l_offset.m_target.rotation = l_turnBack * (l_offset.m_source.rotation * l_offset.m_offset);
|
||||
}
|
||||
|
||||
if(CVRInputManager.Instance._rightController != ABI_RC.Systems.InputManagement.XR.eXRControllerType.None)
|
||||
{
|
||||
Quaternion l_turnBack = (m_rightHandOffset.m_source.rotation * m_rightHandOffset.m_offset) * Quaternion.Inverse(m_rightHandOffset.m_target.rotation);
|
||||
foreach(var l_offset in m_rightFingerOffsets)
|
||||
l_offset.m_target.rotation = l_turnBack * (l_offset.m_source.rotation * l_offset.m_offset);
|
||||
}
|
||||
|
||||
p_handler.GetHumanPose(ref m_pose);
|
||||
m_lastValues[0] = m_pose.muscles[(int)MuscleIndex.LeftThumb1Stretched];
|
||||
m_lastValues[1] = m_pose.muscles[(int)MuscleIndex.LeftThumb2Stretched];
|
||||
m_lastValues[2] = m_pose.muscles[(int)MuscleIndex.LeftThumb3Stretched];
|
||||
m_lastValues[3] = m_pose.muscles[(int)MuscleIndex.LeftThumbSpread];
|
||||
m_lastValues[4] = m_pose.muscles[(int)MuscleIndex.LeftIndex1Stretched];
|
||||
m_lastValues[5] = m_pose.muscles[(int)MuscleIndex.LeftIndex2Stretched];
|
||||
m_lastValues[6] = m_pose.muscles[(int)MuscleIndex.LeftIndex3Stretched];
|
||||
m_lastValues[7] = m_pose.muscles[(int)MuscleIndex.LeftIndexSpread];
|
||||
m_lastValues[8] = m_pose.muscles[(int)MuscleIndex.LeftMiddle1Stretched];
|
||||
m_lastValues[9] = m_pose.muscles[(int)MuscleIndex.LeftMiddle2Stretched];
|
||||
m_lastValues[10] = m_pose.muscles[(int)MuscleIndex.LeftMiddle3Stretched];
|
||||
m_lastValues[11] = m_pose.muscles[(int)MuscleIndex.LeftMiddleSpread];
|
||||
m_lastValues[12] = m_pose.muscles[(int)MuscleIndex.LeftRing1Stretched];
|
||||
m_lastValues[13] = m_pose.muscles[(int)MuscleIndex.LeftRing2Stretched];
|
||||
m_lastValues[14] = m_pose.muscles[(int)MuscleIndex.LeftRing3Stretched];
|
||||
m_lastValues[15] = m_pose.muscles[(int)MuscleIndex.LeftRingSpread];
|
||||
m_lastValues[16] = m_pose.muscles[(int)MuscleIndex.LeftLittle1Stretched];
|
||||
m_lastValues[17] = m_pose.muscles[(int)MuscleIndex.LeftLittle2Stretched];
|
||||
m_lastValues[18] = m_pose.muscles[(int)MuscleIndex.LeftLittle3Stretched];
|
||||
m_lastValues[19] = m_pose.muscles[(int)MuscleIndex.LeftLittleSpread];
|
||||
m_lastValues[20] = m_pose.muscles[(int)MuscleIndex.RightThumb1Stretched];
|
||||
m_lastValues[21] = m_pose.muscles[(int)MuscleIndex.RightThumb2Stretched];
|
||||
m_lastValues[22] = m_pose.muscles[(int)MuscleIndex.RightThumb3Stretched];
|
||||
m_lastValues[23] = m_pose.muscles[(int)MuscleIndex.RightThumbSpread];
|
||||
m_lastValues[24] = m_pose.muscles[(int)MuscleIndex.RightIndex1Stretched];
|
||||
m_lastValues[25] = m_pose.muscles[(int)MuscleIndex.RightIndex2Stretched];
|
||||
m_lastValues[26] = m_pose.muscles[(int)MuscleIndex.RightIndex3Stretched];
|
||||
m_lastValues[27] = m_pose.muscles[(int)MuscleIndex.RightIndexSpread];
|
||||
m_lastValues[28] = m_pose.muscles[(int)MuscleIndex.RightMiddle1Stretched];
|
||||
m_lastValues[29] = m_pose.muscles[(int)MuscleIndex.RightMiddle2Stretched];
|
||||
m_lastValues[30] = m_pose.muscles[(int)MuscleIndex.RightMiddle3Stretched];
|
||||
m_lastValues[31] = m_pose.muscles[(int)MuscleIndex.RightMiddleSpread];
|
||||
m_lastValues[32] = m_pose.muscles[(int)MuscleIndex.RightRing1Stretched];
|
||||
m_lastValues[33] = m_pose.muscles[(int)MuscleIndex.RightRing2Stretched];
|
||||
m_lastValues[34] = m_pose.muscles[(int)MuscleIndex.RightRing3Stretched];
|
||||
m_lastValues[35] = m_pose.muscles[(int)MuscleIndex.RightRingSpread];
|
||||
m_lastValues[36] = m_pose.muscles[(int)MuscleIndex.RightLittle1Stretched];
|
||||
m_lastValues[37] = m_pose.muscles[(int)MuscleIndex.RightLittle2Stretched];
|
||||
m_lastValues[38] = m_pose.muscles[(int)MuscleIndex.RightLittle3Stretched];
|
||||
m_lastValues[39] = m_pose.muscles[(int)MuscleIndex.RightLittleSpread];
|
||||
|
||||
if(Settings.MechanimFilter && (p_hips != null))
|
||||
{
|
||||
// Yoinked from IKSystem.OnPostSolverUpdateGeneral
|
||||
Vector3 l_pos = p_hips.position;
|
||||
Quaternion l_rot = p_hips.rotation;
|
||||
p_handler.SetHumanPose(ref m_pose);
|
||||
p_hips.SetPositionAndRotation(l_pos, l_rot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReorientateTowards(Transform p_target, Transform p_targetEnd, Transform p_source, Transform p_sourceEnd, PlaneType p_plane)
|
||||
{
|
||||
if((p_target != null) && (p_targetEnd != null) && (p_source != null) && (p_sourceEnd != 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);
|
||||
switch(p_plane)
|
||||
{
|
||||
case PlaneType.OXZ:
|
||||
l_targetDir.y = 0f;
|
||||
l_sourceDir.y = 0f;
|
||||
break;
|
||||
case PlaneType.OYX:
|
||||
l_targetDir.z = 0f;
|
||||
l_sourceDir.z = 0f;
|
||||
break;
|
||||
}
|
||||
l_targetDir = Vector3.Normalize(l_targetDir);
|
||||
l_sourceDir = Vector3.Normalize(l_sourceDir);
|
||||
|
||||
Quaternion l_targetRot = Quaternion.identity;
|
||||
Quaternion l_sourceRot = Quaternion.identity;
|
||||
switch(p_plane)
|
||||
{
|
||||
case PlaneType.OXZ:
|
||||
l_targetRot = Quaternion.LookRotation(l_targetDir, Vector3.up);
|
||||
l_sourceRot = Quaternion.LookRotation(l_sourceDir, Vector3.up);
|
||||
break;
|
||||
case PlaneType.OYX:
|
||||
l_targetRot = Quaternion.LookRotation(l_targetDir, Vector3.forward);
|
||||
l_sourceRot = Quaternion.LookRotation(l_sourceDir, Vector3.forward);
|
||||
break;
|
||||
}
|
||||
|
||||
Quaternion l_diff = Quaternion.Inverse(l_targetRot) * l_sourceRot;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
59
ml_bft/HandHandler.cs
Normal file
59
ml_bft/HandHandler.cs
Normal file
|
@ -0,0 +1,59 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_bft
|
||||
{
|
||||
class HandHandler
|
||||
{
|
||||
protected bool m_left = false;
|
||||
protected List<Transform> m_bones = null;
|
||||
protected List<Quaternion> m_localRotations = null;
|
||||
protected Transform m_prefabRoot = null;
|
||||
protected List<Renderer> m_renderers = null;
|
||||
|
||||
protected HandHandler(bool p_left)
|
||||
{
|
||||
m_left = p_left;
|
||||
m_bones = new List<Transform>();
|
||||
m_localRotations = new List<Quaternion>();
|
||||
m_renderers = new List<Renderer>();
|
||||
|
||||
Settings.ShowHandsChange += this.OnShowHandsChange;
|
||||
}
|
||||
|
||||
public virtual void Cleanup()
|
||||
{
|
||||
if(m_prefabRoot != null)
|
||||
Object.Destroy(m_prefabRoot.gameObject);
|
||||
m_prefabRoot = null;
|
||||
|
||||
m_bones.Clear();
|
||||
m_localRotations.Clear();
|
||||
m_renderers.Clear();
|
||||
|
||||
Settings.ShowHandsChange -= this.OnShowHandsChange;
|
||||
}
|
||||
|
||||
public virtual void Update()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual Transform GetSourceForBone(HumanBodyBones p_bone)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
public virtual void Rebind(Quaternion p_base)
|
||||
{
|
||||
}
|
||||
|
||||
protected void OnShowHandsChange(bool p_state)
|
||||
{
|
||||
foreach(var l_render in m_renderers)
|
||||
{
|
||||
if(l_render != null)
|
||||
l_render.enabled = p_state;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
249
ml_bft/HandHandlerVR.cs
Normal file
249
ml_bft/HandHandlerVR.cs
Normal file
|
@ -0,0 +1,249 @@
|
|||
using UnityEngine;
|
||||
using Valve.VR;
|
||||
|
||||
namespace ml_bft
|
||||
{
|
||||
class HandHandlerVR : HandHandler
|
||||
{
|
||||
// 31 bones in each hand, get index at Valve.VR.SteamVR_Skeleton_JointIndexes or SteamVR_Skeleton_JointIndexEnum
|
||||
const int c_fingerBonesCount = (int)SteamVR_Skeleton_JointIndexEnum.pinkyAux + 1;
|
||||
|
||||
SteamVR_Action_Skeleton m_skeletonAction;
|
||||
|
||||
public HandHandlerVR(Transform p_root, bool p_left) : base(p_left)
|
||||
{
|
||||
for(int i = 0; i < c_fingerBonesCount; i++)
|
||||
{
|
||||
m_bones.Add(null);
|
||||
m_localRotations.Add(Quaternion.identity);
|
||||
}
|
||||
|
||||
// Fill finger transforms
|
||||
m_prefabRoot = AssetsHandler.GetAsset(string.Format("assets/steamvr/models/[openvr] {0}.prefab", m_left ? "left" : "right")).transform;
|
||||
m_prefabRoot.name = "[FingersTracking_VR]";
|
||||
m_prefabRoot.parent = p_root;
|
||||
m_prefabRoot.localPosition = Vector3.zero;
|
||||
m_prefabRoot.localRotation = Quaternion.identity;
|
||||
|
||||
m_prefabRoot.GetComponentsInChildren(true, m_renderers);
|
||||
|
||||
// Ah yes, the stupid code
|
||||
char l_side = (m_left ? 'l' : 'r');
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.root] = m_prefabRoot.Find("Root");
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.wrist] = m_prefabRoot.Find(string.Format("Root/wrist_{0}", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbProximal] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_thumb_0_{0}", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbMiddle] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_thumb_0_{0}/finger_thumb_1_{0}", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbDistal] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_thumb_0_{0}/finger_thumb_1_{0}/finger_thumb_2_{0}", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbTip] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_thumb_0_{0}/finger_thumb_1_{0}/finger_thumb_2_{0}/finger_thumb_{0}_end", l_side));
|
||||
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexMetacarpal] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_index_meta_{0}", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexProximal] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_index_meta_{0}/finger_index_0_{0}", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexMiddle] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_index_meta_{0}/finger_index_0_{0}/finger_index_1_{0}", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexDistal] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_index_meta_{0}/finger_index_0_{0}/finger_index_1_{0}/finger_index_2_{0}", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexTip] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_index_meta_{0}/finger_index_0_{0}/finger_index_1_{0}/finger_index_2_{0}/finger_index_{0}_end", l_side));
|
||||
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleMetacarpal] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_middle_meta_{0}", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleProximal] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_middle_meta_{0}/finger_middle_0_{0}", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleMiddle] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_middle_meta_{0}/finger_middle_0_{0}/finger_middle_1_{0}", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleDistal] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_middle_meta_{0}/finger_middle_0_{0}/finger_middle_1_{0}/finger_middle_2_{0}", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleTip] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_middle_meta_{0}/finger_middle_0_{0}/finger_middle_1_{0}/finger_middle_2_{0}/finger_middle_{0}_end", l_side));
|
||||
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringMetacarpal] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_ring_meta_{0}", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringProximal] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_ring_meta_{0}/finger_ring_0_{0}", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringMiddle] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_ring_meta_{0}/finger_ring_0_{0}/finger_ring_1_{0}", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringDistal] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_ring_meta_{0}/finger_ring_0_{0}/finger_ring_1_{0}/finger_ring_2_{0}", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringTip] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_ring_meta_{0}/finger_ring_0_{0}/finger_ring_1_{0}/finger_ring_2_{0}/finger_ring_{0}_end", l_side));
|
||||
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyMetacarpal] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_pinky_meta_{0}", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyProximal] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_pinky_meta_{0}/finger_pinky_0_{0}", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyMiddle] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_pinky_meta_{0}/finger_pinky_0_{0}/finger_pinky_1_{0}", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyDistal] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_pinky_meta_{0}/finger_pinky_0_{0}/finger_pinky_1_{0}/finger_pinky_2_{0}", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyTip] = m_prefabRoot.Find(string.Format("Root/wrist_{0}/finger_pinky_meta_{0}/finger_pinky_0_{0}/finger_pinky_1_{0}/finger_pinky_2_{0}/finger_pinky_{0}_end", l_side));
|
||||
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbAux] = m_prefabRoot.Find(string.Format("Root/finger_thumb_{0}_aux", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexAux] = m_prefabRoot.Find(string.Format("Root/finger_index_{0}_aux", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleAux] = m_prefabRoot.Find(string.Format("Root/finger_middle_{0}_aux", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringAux] = m_prefabRoot.Find(string.Format("Root/finger_ring_{0}_aux", l_side));
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyAux] = m_prefabRoot.Find(string.Format("Root/finger_pinky_{0}_aux", l_side));
|
||||
|
||||
// Remember local rotations
|
||||
for(int i = 0; i < c_fingerBonesCount; i++)
|
||||
{
|
||||
if(m_bones[i] != null)
|
||||
m_localRotations[i] = m_bones[i].localRotation;
|
||||
}
|
||||
|
||||
m_skeletonAction = SteamVR_Input.GetAction<SteamVR_Action_Skeleton>(p_left ? "SkeletonLeftHand" : "SkeletonRightHand");
|
||||
|
||||
base.OnShowHandsChange(Settings.ShowHands);
|
||||
OnMotionRangeChange(Settings.MotionRange);
|
||||
|
||||
Settings.MotionRangeChange += this.OnMotionRangeChange;
|
||||
}
|
||||
|
||||
public override void Cleanup()
|
||||
{
|
||||
base.Cleanup();
|
||||
|
||||
m_skeletonAction = null;
|
||||
|
||||
Settings.MotionRangeChange -= this.OnMotionRangeChange;
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if(m_skeletonAction != null)
|
||||
{
|
||||
var l_rotations = m_skeletonAction.GetBoneRotations();
|
||||
var l_positions = m_skeletonAction.GetBonePositions();
|
||||
for(int i = 0; i < c_fingerBonesCount; i++)
|
||||
{
|
||||
if(m_bones[i] != null)
|
||||
{
|
||||
m_bones[i].localRotation = l_rotations[i];
|
||||
m_bones[i].localPosition = l_positions[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override Transform GetSourceForBone(HumanBodyBones p_bone)
|
||||
{
|
||||
Transform l_result = null;
|
||||
switch(p_bone)
|
||||
{
|
||||
case HumanBodyBones.LeftHand:
|
||||
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.wrist] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftThumbProximal:
|
||||
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbProximal] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftThumbIntermediate:
|
||||
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbMiddle] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftThumbDistal:
|
||||
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbDistal] : null);
|
||||
break;
|
||||
|
||||
case HumanBodyBones.LeftIndexProximal:
|
||||
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexProximal] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftIndexIntermediate:
|
||||
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexMiddle] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftIndexDistal:
|
||||
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexDistal] : null);
|
||||
break;
|
||||
|
||||
case HumanBodyBones.LeftMiddleProximal:
|
||||
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleProximal] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftMiddleIntermediate:
|
||||
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleMiddle] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftMiddleDistal:
|
||||
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleDistal] : null);
|
||||
break;
|
||||
|
||||
case HumanBodyBones.LeftRingProximal:
|
||||
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringProximal] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftRingIntermediate:
|
||||
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringMiddle] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftRingDistal:
|
||||
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringDistal] : null);
|
||||
break;
|
||||
|
||||
case HumanBodyBones.LeftLittleProximal:
|
||||
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyProximal] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftLittleIntermediate:
|
||||
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyMiddle] : null);
|
||||
break;
|
||||
case HumanBodyBones.LeftLittleDistal:
|
||||
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyDistal] : null);
|
||||
break;
|
||||
|
||||
case HumanBodyBones.RightHand:
|
||||
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.wrist] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightThumbProximal:
|
||||
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbProximal] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightThumbIntermediate:
|
||||
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbMiddle] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightThumbDistal:
|
||||
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbDistal] : null);
|
||||
break;
|
||||
|
||||
case HumanBodyBones.RightIndexProximal:
|
||||
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexProximal] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightIndexIntermediate:
|
||||
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexMiddle] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightIndexDistal:
|
||||
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexDistal] : null);
|
||||
break;
|
||||
|
||||
case HumanBodyBones.RightMiddleProximal:
|
||||
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleProximal] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightMiddleIntermediate:
|
||||
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleMiddle] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightMiddleDistal:
|
||||
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleDistal] : null);
|
||||
break;
|
||||
|
||||
case HumanBodyBones.RightRingProximal:
|
||||
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringProximal] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightRingIntermediate:
|
||||
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringMiddle] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightRingDistal:
|
||||
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringDistal] : null);
|
||||
break;
|
||||
|
||||
case HumanBodyBones.RightLittleProximal:
|
||||
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyProximal] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightLittleIntermediate:
|
||||
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyMiddle] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightLittleDistal:
|
||||
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyDistal] : null);
|
||||
break;
|
||||
}
|
||||
return l_result;
|
||||
}
|
||||
|
||||
public override void Rebind(Quaternion p_base)
|
||||
{
|
||||
for(int i = 0; i < c_fingerBonesCount; i++)
|
||||
{
|
||||
if(m_bones[i] != null)
|
||||
m_bones[i].localRotation = m_localRotations[i];
|
||||
}
|
||||
|
||||
if(m_bones[(int)SteamVR_Skeleton_JointIndexEnum.root] != null)
|
||||
m_bones[(int)SteamVR_Skeleton_JointIndexEnum.root].rotation = p_base * (m_left ? Quaternion.Euler(0f, -90f, -90f) : Quaternion.Euler(0f, 90f, 90f));
|
||||
}
|
||||
|
||||
void OnMotionRangeChange(Settings.MotionRangeType p_mode)
|
||||
{
|
||||
switch(p_mode)
|
||||
{
|
||||
case Settings.MotionRangeType.WithController:
|
||||
m_skeletonAction?.SetRangeOfMotion(EVRSkeletalMotionRange.WithController);
|
||||
break;
|
||||
case Settings.MotionRangeType.WithoutController:
|
||||
m_skeletonAction?.SetRangeOfMotion(EVRSkeletalMotionRange.WithoutController);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
229
ml_bft/HandHandlerXR.cs
Normal file
229
ml_bft/HandHandlerXR.cs
Normal file
|
@ -0,0 +1,229 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.XR.OpenXR;
|
||||
using UnityEngine.XR.Hands;
|
||||
using UnityEngine.XR;
|
||||
|
||||
namespace ml_bft
|
||||
{
|
||||
class HandHandlerXR : HandHandler
|
||||
{
|
||||
// 26 bones, get in XRHandJointID enum
|
||||
const int c_fingerBonesCount = (int)XRHandJointID.EndMarker - 1;
|
||||
|
||||
public HandHandlerXR(Transform p_root, bool p_left) : base(p_left)
|
||||
{
|
||||
for(int i = 0; i < c_fingerBonesCount; i++)
|
||||
{
|
||||
m_bones.Add(null);
|
||||
m_localRotations.Add(Quaternion.identity);
|
||||
}
|
||||
|
||||
m_prefabRoot = AssetsHandler.GetAsset(string.Format("Assets/OpenXR/Models/{0}Hand_IK.prefab", m_left ? "Left" : "Right")).transform;
|
||||
m_prefabRoot.name = "[FingersTracking_XR]";
|
||||
m_prefabRoot.parent = p_root;
|
||||
m_prefabRoot.localPosition = Vector3.zero;
|
||||
m_prefabRoot.localRotation = Quaternion.identity;
|
||||
|
||||
m_prefabRoot.GetComponentsInChildren(true, m_renderers);
|
||||
|
||||
// Ah yes, the stupid code
|
||||
char l_side = (m_left ? 'L' : 'R');
|
||||
m_bones[(int)XRHandJointID.Wrist - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist", l_side));
|
||||
m_bones[(int)XRHandJointID.Palm - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_Palm", l_side));
|
||||
|
||||
m_bones[(int)XRHandJointID.ThumbMetacarpal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_ThumbMetacarpal", l_side));
|
||||
m_bones[(int)XRHandJointID.ThumbProximal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_ThumbMetacarpal/{0}_Wrist/{0}_ThumbProximal", l_side));
|
||||
m_bones[(int)XRHandJointID.ThumbDistal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_ThumbMetacarpal/{0}_Wrist/{0}_ThumbProximal/{0}_ThumbDistal", l_side));
|
||||
m_bones[(int)XRHandJointID.ThumbTip - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_ThumbMetacarpal/{0}_Wrist/{0}_ThumbProximal/{0}_ThumbDistal/{0}_ThumbTip", l_side));
|
||||
m_bones[(int)XRHandJointID.IndexMetacarpal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_IndexMetacarpal", l_side));
|
||||
m_bones[(int)XRHandJointID.IndexProximal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_IndexMetacarpal/{0}_IndexProximal", l_side));
|
||||
m_bones[(int)XRHandJointID.IndexIntermediate - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_IndexMetacarpal/{0}_IndexProximal/{0}_IndexIntermediate", l_side));
|
||||
m_bones[(int)XRHandJointID.IndexDistal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_IndexMetacarpal/{0}_IndexProximal/{0}_IndexIntermediate/{0}_IndexDistal", l_side));
|
||||
m_bones[(int)XRHandJointID.IndexTip - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_IndexMetacarpal/{0}_IndexProximal/{0}_IndexIntermediate/{0}_IndexDistal/{0}_IndexTip", l_side));
|
||||
|
||||
m_bones[(int)XRHandJointID.MiddleMetacarpal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_MiddleMetacarpal", l_side));
|
||||
m_bones[(int)XRHandJointID.MiddleProximal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_MiddleMetacarpal/{0}_MiddleProximal", l_side));
|
||||
m_bones[(int)XRHandJointID.MiddleIntermediate - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_MiddleMetacarpal/{0}_MiddleProximal/{0}_MiddleIntermediate", l_side));
|
||||
m_bones[(int)XRHandJointID.MiddleDistal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_MiddleMetacarpal/{0}_MiddleProximal/{0}_MiddleIntermediate/{0}_MiddleDistal", l_side));
|
||||
m_bones[(int)XRHandJointID.MiddleTip - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_MiddleMetacarpal/{0}_MiddleProximal/{0}_MiddleIntermediate/{0}_MiddleDistal/{0}_MiddleTip", l_side));
|
||||
|
||||
m_bones[(int)XRHandJointID.RingMetacarpal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_RingMetacarpal", l_side));
|
||||
m_bones[(int)XRHandJointID.RingProximal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_RingMetacarpal/{0}_RingProximal", l_side));
|
||||
m_bones[(int)XRHandJointID.RingIntermediate - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_RingMetacarpal/{0}_RingProximal/{0}_RingIntermediate", l_side));
|
||||
m_bones[(int)XRHandJointID.RingDistal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_RingMetacarpal/{0}_RingProximal/{0}_RingIntermediate/{0}_RingDistal", l_side));
|
||||
m_bones[(int)XRHandJointID.RingTip - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_RingMetacarpal/{0}_RingProximal/{0}_RingIntermediate/{0}_RingDistal/{0}_RingTip", l_side));
|
||||
|
||||
m_bones[(int)XRHandJointID.LittleMetacarpal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_LittleMetacarpal", l_side));
|
||||
m_bones[(int)XRHandJointID.LittleProximal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_LittleMetacarpal/{0}_LittleProximal", l_side));
|
||||
m_bones[(int)XRHandJointID.LittleIntermediate - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_LittleMetacarpal/{0}_LittleProximal/{0}_LittleIntermediate", l_side));
|
||||
m_bones[(int)XRHandJointID.LittleDistal - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_LittleMetacarpal/{0}_LittleProximal/{0}_LittleIntermediate/{0}_LittleDistal", l_side));
|
||||
m_bones[(int)XRHandJointID.LittleTip - 1] = m_prefabRoot.Find(string.Format("{0}_Wrist/{0}_LittleMetacarpal/{0}_LittleProximal/{0}_LittleIntermediate/{0}_LittleDistal/{0}_LittleTip", l_side));
|
||||
|
||||
for(int i = 0; i < c_fingerBonesCount; i++)
|
||||
{
|
||||
if(m_bones[i] != null)
|
||||
m_localRotations[i] = m_bones[i].localRotation;
|
||||
}
|
||||
|
||||
base.OnShowHandsChange(Settings.ShowHands);
|
||||
}
|
||||
|
||||
public override Transform GetSourceForBone(HumanBodyBones p_bone)
|
||||
{
|
||||
Transform l_result = null;
|
||||
if(m_left)
|
||||
{
|
||||
switch(p_bone)
|
||||
{
|
||||
case HumanBodyBones.LeftHand:
|
||||
l_result = m_bones[(int)XRHandJointID.Wrist - 1];
|
||||
break;
|
||||
case HumanBodyBones.LeftThumbProximal:
|
||||
l_result = m_bones[(int)XRHandJointID.ThumbMetacarpal - 1];
|
||||
break;
|
||||
case HumanBodyBones.LeftThumbIntermediate:
|
||||
l_result = m_bones[(int)XRHandJointID.ThumbProximal - 1];
|
||||
break;
|
||||
case HumanBodyBones.LeftThumbDistal:
|
||||
l_result = m_bones[(int)XRHandJointID.ThumbDistal - 1];
|
||||
break;
|
||||
|
||||
case HumanBodyBones.LeftIndexProximal:
|
||||
l_result = m_bones[(int)XRHandJointID.IndexProximal - 1];
|
||||
break;
|
||||
case HumanBodyBones.LeftIndexIntermediate:
|
||||
l_result = m_bones[(int)XRHandJointID.IndexIntermediate - 1];
|
||||
break;
|
||||
case HumanBodyBones.LeftIndexDistal:
|
||||
l_result = m_bones[(int)XRHandJointID.IndexDistal - 1];
|
||||
break;
|
||||
|
||||
case HumanBodyBones.LeftMiddleProximal:
|
||||
l_result = m_bones[(int)XRHandJointID.MiddleProximal - 1];
|
||||
break;
|
||||
case HumanBodyBones.LeftMiddleIntermediate:
|
||||
l_result = m_bones[(int)XRHandJointID.MiddleIntermediate - 1];
|
||||
break;
|
||||
case HumanBodyBones.LeftMiddleDistal:
|
||||
l_result = m_bones[(int)XRHandJointID.MiddleDistal - 1];
|
||||
break;
|
||||
|
||||
case HumanBodyBones.LeftRingProximal:
|
||||
l_result = m_bones[(int)XRHandJointID.RingProximal - 1];
|
||||
break;
|
||||
case HumanBodyBones.LeftRingIntermediate:
|
||||
l_result = m_bones[(int)XRHandJointID.RingIntermediate - 1];
|
||||
break;
|
||||
case HumanBodyBones.LeftRingDistal:
|
||||
l_result = m_bones[(int)XRHandJointID.RingDistal - 1];
|
||||
break;
|
||||
|
||||
case HumanBodyBones.LeftLittleProximal:
|
||||
l_result = m_bones[(int)XRHandJointID.LittleProximal - 1];
|
||||
break;
|
||||
case HumanBodyBones.LeftLittleIntermediate:
|
||||
l_result = m_bones[(int)XRHandJointID.LittleIntermediate - 1];
|
||||
break;
|
||||
case HumanBodyBones.LeftLittleDistal:
|
||||
l_result = m_bones[(int)XRHandJointID.LittleDistal - 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(p_bone)
|
||||
{
|
||||
case HumanBodyBones.RightHand:
|
||||
l_result = m_bones[(int)XRHandJointID.Wrist - 1];
|
||||
break;
|
||||
case HumanBodyBones.RightThumbProximal:
|
||||
l_result = m_bones[(int)XRHandJointID.ThumbMetacarpal - 1];
|
||||
break;
|
||||
case HumanBodyBones.RightThumbIntermediate:
|
||||
l_result = m_bones[(int)XRHandJointID.ThumbProximal - 1];
|
||||
break;
|
||||
case HumanBodyBones.RightThumbDistal:
|
||||
l_result = m_bones[(int)XRHandJointID.ThumbDistal - 1];
|
||||
break;
|
||||
|
||||
case HumanBodyBones.RightIndexProximal:
|
||||
l_result = m_bones[(int)XRHandJointID.IndexProximal - 1];
|
||||
break;
|
||||
case HumanBodyBones.RightIndexIntermediate:
|
||||
l_result = m_bones[(int)XRHandJointID.IndexIntermediate - 1];
|
||||
break;
|
||||
case HumanBodyBones.RightIndexDistal:
|
||||
l_result = m_bones[(int)XRHandJointID.IndexDistal - 1];
|
||||
break;
|
||||
|
||||
case HumanBodyBones.RightMiddleProximal:
|
||||
l_result = m_bones[(int)XRHandJointID.MiddleProximal - 1];
|
||||
break;
|
||||
case HumanBodyBones.RightMiddleIntermediate:
|
||||
l_result = m_bones[(int)XRHandJointID.MiddleIntermediate - 1];
|
||||
break;
|
||||
case HumanBodyBones.RightMiddleDistal:
|
||||
l_result = m_bones[(int)XRHandJointID.MiddleDistal - 1];
|
||||
break;
|
||||
|
||||
case HumanBodyBones.RightRingProximal:
|
||||
l_result = m_bones[(int)XRHandJointID.RingProximal - 1];
|
||||
break;
|
||||
case HumanBodyBones.RightRingIntermediate:
|
||||
l_result = m_bones[(int)XRHandJointID.RingIntermediate - 1];
|
||||
break;
|
||||
case HumanBodyBones.RightRingDistal:
|
||||
l_result = m_bones[(int)XRHandJointID.RingDistal - 1];
|
||||
break;
|
||||
|
||||
case HumanBodyBones.RightLittleProximal:
|
||||
l_result = m_bones[(int)XRHandJointID.LittleProximal - 1];
|
||||
break;
|
||||
case HumanBodyBones.RightLittleIntermediate:
|
||||
l_result = m_bones[(int)XRHandJointID.LittleIntermediate - 1];
|
||||
break;
|
||||
case HumanBodyBones.RightLittleDistal:
|
||||
l_result = m_bones[(int)XRHandJointID.LittleDistal - 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return l_result;
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
var l_tracking = OpenXRSettings.Instance.GetFeature<HandTrackingFeature>();
|
||||
var l_device = InputDevices.GetDeviceAtXRNode(m_left ? XRNode.LeftHand : XRNode.RightHand);
|
||||
if((l_device != null) && l_device.TryGetFeatureValue(CommonUsages.deviceRotation, out Quaternion l_deviceRot) && (l_tracking != null))
|
||||
{
|
||||
Quaternion l_handInv = Quaternion.Inverse(l_deviceRot);
|
||||
l_tracking.GetHandJoints(m_left ? HandTrackingFeature.Hand_Index.L : HandTrackingFeature.Hand_Index.R, out var l_positions, out var l_rotations, out _);
|
||||
if(l_positions.Length >= c_fingerBonesCount)
|
||||
{
|
||||
// Joints rotations are in global space, locations are in ... space??? ... wth is wrong with OpenXR?
|
||||
Quaternion l_prefabRot = m_prefabRoot.rotation;
|
||||
for(int i = 0; i < c_fingerBonesCount; i++)
|
||||
{
|
||||
if(m_bones[i] != null)
|
||||
{
|
||||
//m_bones[i].localPosition = l_positions[i];
|
||||
m_bones[i].rotation = l_prefabRot * (l_handInv * l_rotations[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Rebind(Quaternion p_base)
|
||||
{
|
||||
for(int i = 0; i < c_fingerBonesCount; i++)
|
||||
{
|
||||
if(m_bones[i] != null)
|
||||
m_bones[i].localRotation = m_localRotations[i];
|
||||
}
|
||||
|
||||
if(m_bones[(int)XRHandJointID.Wrist - 1] != null)
|
||||
m_bones[(int)XRHandJointID.Wrist - 1].rotation = p_base * (m_left ? Quaternion.Euler(0f, -90f, 0f) : Quaternion.Euler(0f, 90f, 0f));
|
||||
}
|
||||
}
|
||||
}
|
161
ml_bft/InputHandler.cs
Normal file
161
ml_bft/InputHandler.cs
Normal file
|
@ -0,0 +1,161 @@
|
|||
using ABI_RC.Core.Savior;
|
||||
using ABI_RC.Systems.InputManagement;
|
||||
using ABI_RC.Systems.VRModeSwitch;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_bft
|
||||
{
|
||||
// Not an actual module, but can be used as one
|
||||
class InputHandler
|
||||
{
|
||||
public static InputHandler Instance { get; private set; } = null;
|
||||
|
||||
bool m_active = false;
|
||||
|
||||
HandHandler m_leftHandHandler = null;
|
||||
HandHandler m_rightHandHandler = null;
|
||||
|
||||
internal InputHandler()
|
||||
{
|
||||
if(Instance == null)
|
||||
Instance = this;
|
||||
|
||||
m_active = false;
|
||||
|
||||
if(MetaPort.Instance.isUsingVr)
|
||||
SetupHandlers();
|
||||
|
||||
VRModeSwitchEvents.OnInitializeXR.AddListener(this.OnSwitchToVR);
|
||||
VRModeSwitchEvents.OnDeinitializeXR.AddListener(this.OnSwitchToDesktop);
|
||||
|
||||
Settings.SkeletalInputChange += this.OnSkeletalInputChange;
|
||||
}
|
||||
internal void Cleanup()
|
||||
{
|
||||
if(Instance == this)
|
||||
Instance = null;
|
||||
|
||||
RemoveHandlers();
|
||||
}
|
||||
|
||||
void SetupHandlers()
|
||||
{
|
||||
if(!CheckVR.Instance.forceOpenXr)
|
||||
{
|
||||
m_leftHandHandler = new HandHandlerVR(CVRInputManager.Instance.leftHandTransform, true);
|
||||
m_rightHandHandler = new HandHandlerVR(CVRInputManager.Instance.rightHandTransform, false);
|
||||
m_active = true;
|
||||
}
|
||||
}
|
||||
void RemoveHandlers()
|
||||
{
|
||||
m_leftHandHandler?.Cleanup();
|
||||
m_leftHandHandler = null;
|
||||
m_rightHandHandler?.Cleanup();
|
||||
m_rightHandHandler = null;
|
||||
m_active = false;
|
||||
}
|
||||
|
||||
public void Rebind(Quaternion p_base)
|
||||
{
|
||||
if(m_active)
|
||||
{
|
||||
m_leftHandHandler?.Rebind(p_base);
|
||||
m_rightHandHandler?.Rebind(p_base);
|
||||
}
|
||||
}
|
||||
|
||||
public Transform GetSourceForBone(HumanBodyBones p_bone, bool p_left)
|
||||
{
|
||||
Transform l_result;
|
||||
if(p_left)
|
||||
l_result = m_leftHandHandler?.GetSourceForBone(p_bone);
|
||||
else
|
||||
l_result = m_rightHandHandler?.GetSourceForBone(p_bone);
|
||||
return l_result;
|
||||
}
|
||||
|
||||
// Game events
|
||||
internal void OnInputUpdate()
|
||||
{
|
||||
if(m_active && Settings.SkeletalInput)
|
||||
{
|
||||
m_leftHandHandler?.Update();
|
||||
m_rightHandHandler?.Update();
|
||||
|
||||
CVRInputManager.Instance.individualFingerTracking = true;
|
||||
CVRInputManager.Instance.finger1StretchedLeftThumb = FingerSystem.Instance.m_lastValues[0];
|
||||
CVRInputManager.Instance.finger2StretchedLeftThumb = FingerSystem.Instance.m_lastValues[1];
|
||||
CVRInputManager.Instance.finger3StretchedLeftThumb = FingerSystem.Instance.m_lastValues[2];
|
||||
CVRInputManager.Instance.fingerSpreadLeftThumb = FingerSystem.Instance.m_lastValues[3];
|
||||
CVRInputManager.Instance.finger1StretchedLeftIndex = FingerSystem.Instance.m_lastValues[4];
|
||||
CVRInputManager.Instance.finger2StretchedLeftIndex = FingerSystem.Instance.m_lastValues[5];
|
||||
CVRInputManager.Instance.finger3StretchedLeftIndex = FingerSystem.Instance.m_lastValues[6];
|
||||
CVRInputManager.Instance.fingerSpreadLeftIndex = FingerSystem.Instance.m_lastValues[7];
|
||||
CVRInputManager.Instance.finger1StretchedLeftMiddle = FingerSystem.Instance.m_lastValues[8];
|
||||
CVRInputManager.Instance.finger2StretchedLeftMiddle = FingerSystem.Instance.m_lastValues[9];
|
||||
CVRInputManager.Instance.finger3StretchedLeftMiddle = FingerSystem.Instance.m_lastValues[10];
|
||||
CVRInputManager.Instance.fingerSpreadLeftMiddle = FingerSystem.Instance.m_lastValues[11];
|
||||
CVRInputManager.Instance.finger1StretchedLeftRing = FingerSystem.Instance.m_lastValues[12];
|
||||
CVRInputManager.Instance.finger2StretchedLeftRing = FingerSystem.Instance.m_lastValues[13];
|
||||
CVRInputManager.Instance.finger3StretchedLeftRing = FingerSystem.Instance.m_lastValues[14];
|
||||
CVRInputManager.Instance.fingerSpreadLeftRing = FingerSystem.Instance.m_lastValues[15];
|
||||
CVRInputManager.Instance.finger1StretchedLeftPinky = FingerSystem.Instance.m_lastValues[16];
|
||||
CVRInputManager.Instance.finger2StretchedLeftPinky = FingerSystem.Instance.m_lastValues[17];
|
||||
CVRInputManager.Instance.finger3StretchedLeftPinky = FingerSystem.Instance.m_lastValues[18];
|
||||
CVRInputManager.Instance.fingerSpreadLeftPinky = FingerSystem.Instance.m_lastValues[19];
|
||||
CVRInputManager.Instance.finger1StretchedRightThumb = FingerSystem.Instance.m_lastValues[20];
|
||||
CVRInputManager.Instance.finger2StretchedRightThumb = FingerSystem.Instance.m_lastValues[21];
|
||||
CVRInputManager.Instance.finger3StretchedRightThumb = FingerSystem.Instance.m_lastValues[22];
|
||||
CVRInputManager.Instance.fingerSpreadRightThumb = FingerSystem.Instance.m_lastValues[23];
|
||||
CVRInputManager.Instance.finger1StretchedRightIndex = FingerSystem.Instance.m_lastValues[24];
|
||||
CVRInputManager.Instance.finger2StretchedRightIndex = FingerSystem.Instance.m_lastValues[25];
|
||||
CVRInputManager.Instance.finger3StretchedRightIndex = FingerSystem.Instance.m_lastValues[26];
|
||||
CVRInputManager.Instance.fingerSpreadRightIndex = FingerSystem.Instance.m_lastValues[27];
|
||||
CVRInputManager.Instance.finger1StretchedRightMiddle = FingerSystem.Instance.m_lastValues[28];
|
||||
CVRInputManager.Instance.finger2StretchedRightMiddle = FingerSystem.Instance.m_lastValues[29];
|
||||
CVRInputManager.Instance.finger3StretchedRightMiddle = FingerSystem.Instance.m_lastValues[30];
|
||||
CVRInputManager.Instance.fingerSpreadRightMiddle = FingerSystem.Instance.m_lastValues[31];
|
||||
CVRInputManager.Instance.finger1StretchedRightRing = FingerSystem.Instance.m_lastValues[32];
|
||||
CVRInputManager.Instance.finger2StretchedRightRing = FingerSystem.Instance.m_lastValues[33];
|
||||
CVRInputManager.Instance.finger3StretchedRightRing = FingerSystem.Instance.m_lastValues[34];
|
||||
CVRInputManager.Instance.fingerSpreadRightRing = FingerSystem.Instance.m_lastValues[35];
|
||||
CVRInputManager.Instance.finger1StretchedRightPinky = FingerSystem.Instance.m_lastValues[36];
|
||||
CVRInputManager.Instance.finger2StretchedRightPinky = FingerSystem.Instance.m_lastValues[37];
|
||||
CVRInputManager.Instance.finger3StretchedRightPinky = FingerSystem.Instance.m_lastValues[38];
|
||||
CVRInputManager.Instance.fingerSpreadRightPinky = FingerSystem.Instance.m_lastValues[39];
|
||||
}
|
||||
}
|
||||
|
||||
void OnSwitchToVR()
|
||||
{
|
||||
try
|
||||
{
|
||||
SetupHandlers();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
void OnSwitchToDesktop()
|
||||
{
|
||||
try
|
||||
{
|
||||
RemoveHandlers();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Settings
|
||||
void OnSkeletalInputChange(bool p_value)
|
||||
{
|
||||
if(!p_value)
|
||||
CVRInputManager.Instance.individualFingerTracking = Utils.AreKnucklesInUse();
|
||||
}
|
||||
}
|
||||
}
|
141
ml_bft/Main.cs
Normal file
141
ml_bft/Main.cs
Normal file
|
@ -0,0 +1,141 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK;
|
||||
using ABI_RC.Systems.InputManagement;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_bft
|
||||
{
|
||||
public class BetterFingersTracking : MelonLoader.MelonMod
|
||||
{
|
||||
static BetterFingersTracking ms_instance = null;
|
||||
|
||||
InputHandler m_inputHandler = null;
|
||||
FingerSystem m_fingerSystem = null;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
if(ms_instance == null)
|
||||
ms_instance = this;
|
||||
|
||||
Settings.Init();
|
||||
AssetsHandler.Load();
|
||||
|
||||
// Needed patches: avatar initialization and reinitialization on vr switch, after input update, after late iksystem update
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(BetterFingersTracking).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(BetterFingersTracking).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(BetterFingersTracking).GetMethod(nameof(OnReinitializeAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRInputManager).GetMethod("UpdateInput", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(BetterFingersTracking).GetMethod(nameof(OnInputUpdate_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(IKSystem).GetMethod("LateUpdate", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(BetterFingersTracking).GetMethod(nameof(OnIKSystemLateUpdate_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForInstances());
|
||||
}
|
||||
IEnumerator WaitForInstances()
|
||||
{
|
||||
while(CVRInputManager.Instance == null)
|
||||
yield return null;
|
||||
|
||||
m_inputHandler = new InputHandler();
|
||||
m_fingerSystem = new FingerSystem();
|
||||
}
|
||||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
m_inputHandler?.Cleanup();
|
||||
m_inputHandler = null;
|
||||
|
||||
m_fingerSystem?.Cleanup();
|
||||
m_fingerSystem = null;
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar();
|
||||
void OnSetupAvatar()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_fingerSystem?.OnAvatarSetup();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear();
|
||||
void OnAvatarClear()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_fingerSystem?.OnAvatarClear();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnReinitializeAvatar_Postfix() => ms_instance?.OnAvatarReinitialize();
|
||||
void OnAvatarReinitialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_fingerSystem?.OnReinitializeAvatar();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnInputUpdate_Postfix() => ms_instance?.OnInputUpdate();
|
||||
void OnInputUpdate()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_inputHandler?.OnInputUpdate();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnIKSystemLateUpdate_Postfix(HumanPoseHandler ____humanPoseHandler, Transform ____hipTransform) => ms_instance?.OnIKSystemLateUpdate(____humanPoseHandler, ____hipTransform);
|
||||
void OnIKSystemLateUpdate(HumanPoseHandler p_handler, Transform p_hips)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_fingerSystem?.OnIKSystemLateUpdate(p_handler, p_hips);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
4
ml_bft/Properties/AssemblyInfo.cs
Normal file
4
ml_bft/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_bft.BetterFingersTracking), "BetterFingersTracking", "1.0.1", "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)]
|
21
ml_bft/README.md
Normal file
21
ml_bft/README.md
Normal file
|
@ -0,0 +1,21 @@
|
|||
# Better Fingers Tracking
|
||||
Mod that overhauls behaviour of fingers tracking.
|
||||
|
||||
# Installation
|
||||
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
|
||||
* Get [latest release DLL](../../../releases/latest):
|
||||
* Put `ml_bft.dll` in `Mods` folder of game
|
||||
|
||||
# Usage
|
||||
Available mod's settings in `Settings - Input & Key-Bindings - Better Fingers Tracking`:
|
||||
* **Force SteamVR skeletal input:** forced usage of SteamVR skeletal input (works as long as controllers' driver supplies skeletal pose throught OpenVR interfaces); `false` by default
|
||||
* **Motion range:** fingers tracking motion range/mode/type; `With controller` 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.
|
||||
* **Show hands model:** shows transparent hands model (mostly as debug option); `false` by default
|
||||
|
||||
# Notes
|
||||
* Currently supports only SteamVR environment, OpenXR support is planned.
|
||||
* Fingers tracking quality is highly dependant on avatar's hand state in Unity's T-pose, possible solutions are in search.
|
||||
* For Oculus Quest controllers (all versions) be sure that skeleton bindings are properly set up in SteamVR controllers bindings.
|
||||
<kbd></kbd>
|
26
ml_bft/ResourcesHandler.cs
Normal file
26
ml_bft/ResourcesHandler.cs
Normal file
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ml_bft
|
||||
{
|
||||
static class ResourcesHandler
|
||||
{
|
||||
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);
|
||||
StreamReader l_streadReader = new StreamReader(l_libraryStream);
|
||||
l_result = l_streadReader.ReadToEnd();
|
||||
}
|
||||
catch(Exception) { }
|
||||
|
||||
return l_result;
|
||||
}
|
||||
}
|
||||
}
|
127
ml_bft/Settings.cs
Normal file
127
ml_bft/Settings.cs
Normal file
|
@ -0,0 +1,127 @@
|
|||
using ABI_RC.Core.InteractionSystem;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ml_bft
|
||||
{
|
||||
static class Settings
|
||||
{
|
||||
public enum MotionRangeType
|
||||
{
|
||||
WithController = 0,
|
||||
WithoutController
|
||||
}
|
||||
enum ModSetting
|
||||
{
|
||||
SkeletalInput = 0,
|
||||
MotionRange,
|
||||
ShowHands,
|
||||
MechanimFilter
|
||||
}
|
||||
|
||||
public static bool SkeletalInput { get; private set; } = false;
|
||||
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;
|
||||
|
||||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
||||
public static event Action<bool> SkeletalInputChange;
|
||||
public static event Action<MotionRangeType> MotionRangeChange;
|
||||
public static event Action<bool> ShowHandsChange;
|
||||
public static event Action<bool> MechanimFilterChange;
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
ms_category = MelonLoader.MelonPreferences.CreateCategory("BFT", null, true);
|
||||
|
||||
ms_entries = new List<MelonLoader.MelonPreferences_Entry>()
|
||||
{
|
||||
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)
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitMainMenuUi());
|
||||
}
|
||||
|
||||
static System.Collections.IEnumerator WaitMainMenuUi()
|
||||
{
|
||||
while(ViewManager.Instance == null)
|
||||
yield return null;
|
||||
while(ViewManager.Instance.gameMenuView == null)
|
||||
yield return null;
|
||||
while(ViewManager.Instance.gameMenuView.Listener == null)
|
||||
yield return null;
|
||||
|
||||
ViewManager.Instance.gameMenuView.Listener.ReadyForBindings += () =>
|
||||
{
|
||||
ViewManager.Instance.gameMenuView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate));
|
||||
ViewManager.Instance.gameMenuView.View.BindCall("OnDropdownUpdate_" + ms_category.Identifier, new Action<string, string>(OnDropdownUpdate));
|
||||
};
|
||||
ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) =>
|
||||
{
|
||||
ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mods_extension.js"));
|
||||
ViewManager.Instance.gameMenuView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mod_menu.js"));
|
||||
foreach(var l_entry in ms_entries)
|
||||
ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString());
|
||||
};
|
||||
}
|
||||
|
||||
static void OnToggleUpdate(string p_name, string p_value)
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
switch(l_setting)
|
||||
{
|
||||
case ModSetting.SkeletalInput:
|
||||
{
|
||||
SkeletalInput = bool.Parse(p_value);
|
||||
SkeletalInputChange?.Invoke(SkeletalInput);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.ShowHands:
|
||||
{
|
||||
ShowHands = bool.Parse(p_value);
|
||||
ShowHandsChange?.Invoke(ShowHands);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.MechanimFilter:
|
||||
{
|
||||
MechanimFilter = bool.Parse(p_value);
|
||||
MechanimFilterChange?.Invoke(MechanimFilter);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnDropdownUpdate(string p_name, string p_value)
|
||||
{
|
||||
if(Enum.TryParse(p_name, out ModSetting l_setting))
|
||||
{
|
||||
switch(l_setting)
|
||||
{
|
||||
case ModSetting.MotionRange:
|
||||
{
|
||||
MotionRange = (MotionRangeType)int.Parse(p_value);
|
||||
MotionRangeChange?.Invoke(MotionRange);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
25
ml_bft/Utils.cs
Normal file
25
ml_bft/Utils.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.UI;
|
||||
using ABI_RC.Systems.IK;
|
||||
using ABI_RC.Systems.InputManagement;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_bft
|
||||
{
|
||||
static class Utils
|
||||
{
|
||||
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);
|
||||
|
||||
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()
|
||||
{
|
||||
IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose);
|
||||
PlayerSetup.Instance._avatar.transform.localPosition = Vector3.zero;
|
||||
PlayerSetup.Instance._avatar.transform.localRotation = Quaternion.identity;
|
||||
}
|
||||
}
|
||||
}
|
100
ml_bft/ml_bft.csproj
Normal file
100
ml_bft/ml_bft.csproj
Normal file
|
@ -0,0 +1,100 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
<PackageId>BetterFingersTracking</PackageId>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>BetterFingersTracking</Product>
|
||||
<Version>1.0.1</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<DebugType>embedded</DebugType>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="resources\mod_menu.js" />
|
||||
<EmbeddedResource Include="resources\ovr_fingers.asset" />
|
||||
<EmbeddedResource Include="resources\oxr_fingers.asset" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="..\js\mods_extension.js" Link="resources\mods_extension.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\0Harmony.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="cohtml.Net">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\cohtml.Net.dll</HintPath>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Cohtml.Runtime">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll</HintPath>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="MelonLoader">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\MelonLoader.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="SteamVR">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\SteamVR.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Unity.XR.Hands">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Unity.XR.Hands.dll</HintPath>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Unity.XR.OpenVR">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Unity.XR.OpenVR.dll</HintPath>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Unity.XR.OpenXR">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Unity.XR.OpenXR.dll</HintPath>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.AnimationModule">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll</HintPath>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.AssetBundleModule">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AssetBundleModule.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>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.XRModule">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.XRModule.dll</HintPath>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\"" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
46
ml_bft/resources/mod_menu.js
Normal file
46
ml_bft/resources/mod_menu.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
let l_block = document.createElement('div');
|
||||
l_block.innerHTML = `
|
||||
<div class ="settings-subcategory">
|
||||
<div class ="subcategory-name">Better Fingers Tracking</div>
|
||||
<div class ="subcategory-description"></div>
|
||||
</div>
|
||||
|
||||
<div class ="row-wrapper">
|
||||
<div class ="option-caption">Force SteamVR skeletal input: </div>
|
||||
<div class ="option-input">
|
||||
<div id="SkeletalInput" class ="inp_toggle no-scroll" data-current="false"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class ="row-wrapper">
|
||||
<div class ="option-caption">Motion range: </div>
|
||||
<div class ="option-input">
|
||||
<div id="MotionRange" class ="inp_dropdown no-scroll" data-options="0:With controller,1:Without controller" data-current="0"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class ="row-wrapper">
|
||||
<div class ="option-caption">Filter humanoid limits: </div>
|
||||
<div class ="option-input">
|
||||
<div id="MechanimFilter" class ="inp_toggle no-scroll" data-current="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class ="row-wrapper">
|
||||
<div class ="option-caption">Show hands model: </div>
|
||||
<div class ="option-input">
|
||||
<div id="ShowHands" class ="inp_toggle no-scroll" data-current="false"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
document.getElementById('settings-input').appendChild(l_block);
|
||||
|
||||
// Toggles
|
||||
for (let l_toggle of l_block.querySelectorAll('.inp_toggle'))
|
||||
modsExtension.addSetting('BFT', l_toggle.id, modsExtension.createToggle(l_toggle, 'OnToggleUpdate_BFT'));
|
||||
|
||||
// Dropdowns
|
||||
for (let l_dropdown of l_block.querySelectorAll('.inp_dropdown'))
|
||||
modsExtension.addSetting('BFT', l_dropdown.id, modsExtension.createDropdown(l_dropdown, 'OnDropdownUpdate_BFT'));
|
||||
}
|
BIN
ml_bft/resources/ovr_fingers.asset
Normal file
BIN
ml_bft/resources/ovr_fingers.asset
Normal file
Binary file not shown.
BIN
ml_bft/resources/oxr_fingers.asset
Normal file
BIN
ml_bft/resources/oxr_fingers.asset
Normal file
Binary file not shown.
|
@ -1,29 +1,29 @@
|
|||
namespace ml_dht
|
||||
{
|
||||
class DataParser
|
||||
{
|
||||
MemoryMapReader m_mapReader = null;
|
||||
byte[] m_buffer = null;
|
||||
TrackingData m_trackingData;
|
||||
|
||||
public DataParser()
|
||||
{
|
||||
m_buffer = new byte[1024];
|
||||
m_mapReader = new MemoryMapReader();
|
||||
m_mapReader.Open("head/data");
|
||||
}
|
||||
~DataParser()
|
||||
{
|
||||
m_mapReader.Close();
|
||||
m_mapReader = null;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if(m_mapReader.Read(ref m_buffer))
|
||||
m_trackingData = TrackingData.ToObject(m_buffer);
|
||||
}
|
||||
|
||||
public ref TrackingData GetLatestTrackingData() => ref m_trackingData;
|
||||
}
|
||||
}
|
||||
namespace ml_dht
|
||||
{
|
||||
class DataParser
|
||||
{
|
||||
MemoryMapReader m_mapReader = null;
|
||||
byte[] m_buffer = null;
|
||||
TrackingData m_trackingData;
|
||||
|
||||
public DataParser()
|
||||
{
|
||||
m_buffer = new byte[1024];
|
||||
m_mapReader = new MemoryMapReader();
|
||||
m_mapReader.Open("head/data");
|
||||
}
|
||||
~DataParser()
|
||||
{
|
||||
m_mapReader.Close();
|
||||
m_mapReader = null;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if(m_mapReader.Read(ref m_buffer))
|
||||
m_trackingData = TrackingData.ToObject(m_buffer);
|
||||
}
|
||||
|
||||
public ref TrackingData GetLatestTrackingData() => ref m_trackingData;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,197 +1,198 @@
|
|||
using ABI.CCK.Components;
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
CVRAvatar m_avatarDescriptor = null;
|
||||
Transform m_camera = null;
|
||||
LookAtIK m_lookIK = null;
|
||||
Transform m_headBone = null;
|
||||
|
||||
Vector3 m_headPosition;
|
||||
Quaternion m_headRotation;
|
||||
Vector2 m_gazeDirection;
|
||||
float m_blinkProgress = 0f;
|
||||
LipData_v2 m_lipData;
|
||||
bool m_lipDataSent = false;
|
||||
|
||||
Quaternion m_bindRotation;
|
||||
Quaternion m_lastHeadRotation;
|
||||
|
||||
internal HeadTracked()
|
||||
{
|
||||
m_lipData = new LipData_v2();
|
||||
m_lipData.frame = 0;
|
||||
m_lipData.time = 0;
|
||||
m_lipData.image = IntPtr.Zero;
|
||||
m_lipData.prediction_data = new PredictionData_v2();
|
||||
m_lipData.prediction_data.blend_shape_weight = new float[(int)LipShape_v2.Max];
|
||||
}
|
||||
|
||||
// Unity events
|
||||
void Start()
|
||||
{
|
||||
SetEnabled(Settings.Enabled);
|
||||
SetHeadTracking(Settings.HeadTracking);
|
||||
SetSmoothing(Settings.Smoothing);
|
||||
|
||||
Settings.EnabledChange += this.SetEnabled;
|
||||
Settings.HeadTrackingChange += this.SetHeadTracking;
|
||||
Settings.SmoothingChange += this.SetSmoothing;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
Settings.EnabledChange -= this.SetEnabled;
|
||||
Settings.HeadTrackingChange -= this.SetHeadTracking;
|
||||
Settings.SmoothingChange -= this.SetSmoothing;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if(m_lipDataSent)
|
||||
m_lipDataSent = false;
|
||||
}
|
||||
|
||||
// Tracking updates
|
||||
public void UpdateTrackingData(ref TrackingData p_data)
|
||||
{
|
||||
m_headPosition.Set(p_data.m_headPositionX * (Settings.Mirrored ? -1f : 1f), p_data.m_headPositionY, p_data.m_headPositionZ);
|
||||
m_headRotation.Set(p_data.m_headRotationX, p_data.m_headRotationY * (Settings.Mirrored ? -1f : 1f), p_data.m_headRotationZ * (Settings.Mirrored ? -1f : 1f), p_data.m_headRotationW);
|
||||
m_gazeDirection.Set(Settings.Mirrored ? (1f - p_data.m_gazeX) : p_data.m_gazeX, p_data.m_gazeY);
|
||||
m_blinkProgress = p_data.m_blink;
|
||||
|
||||
float l_weight = Mathf.Clamp01(Mathf.InverseLerp(0.25f, 1f, Mathf.Abs(p_data.m_mouthShape)));
|
||||
m_lipData.prediction_data.blend_shape_weight[(int)LipShape_v2.Jaw_Open] = p_data.m_mouthOpen;
|
||||
m_lipData.prediction_data.blend_shape_weight[(int)LipShape_v2.Mouth_Pout] = ((p_data.m_mouthShape > 0f) ? l_weight : 0f);
|
||||
m_lipData.prediction_data.blend_shape_weight[(int)LipShape_v2.Mouth_Smile_Left] = ((p_data.m_mouthShape < 0f) ? l_weight : 0f);
|
||||
m_lipData.prediction_data.blend_shape_weight[(int)LipShape_v2.Mouth_Smile_Right] = ((p_data.m_mouthShape < 0f) ? l_weight : 0f);
|
||||
}
|
||||
|
||||
void OnLookIKPostUpdate()
|
||||
{
|
||||
if(m_enabled && m_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))
|
||||
m_headBone.rotation = m_lastHeadRotation;
|
||||
}
|
||||
}
|
||||
|
||||
// Game events
|
||||
internal void OnSetupAvatar()
|
||||
{
|
||||
m_camera = PlayerSetup.Instance.GetActiveCamera().transform;
|
||||
m_avatarDescriptor = PlayerSetup.Instance._avatar.GetComponent<CVRAvatar>();
|
||||
m_headBone = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Head);
|
||||
m_lookIK = PlayerSetup.Instance._avatar.GetComponent<LookAtIK>();
|
||||
|
||||
if(m_headBone != null)
|
||||
m_bindRotation = (m_avatarDescriptor.transform.GetMatrix().inverse * m_headBone.GetMatrix()).rotation;
|
||||
|
||||
if(m_lookIK != null)
|
||||
m_lookIK.onPostSolverUpdate.AddListener(this.OnLookIKPostUpdate);
|
||||
|
||||
}
|
||||
internal void OnAvatarClear()
|
||||
{
|
||||
m_avatarDescriptor = null;
|
||||
m_lookIK = null;
|
||||
m_headBone = null;
|
||||
m_lastHeadRotation = Quaternion.identity;
|
||||
m_bindRotation = Quaternion.identity;
|
||||
}
|
||||
internal void OnAvatarReinitialize()
|
||||
{
|
||||
m_camera = PlayerSetup.Instance.GetActiveCamera().transform;
|
||||
m_lookIK = PlayerSetup.Instance._avatar.GetComponent<LookAtIK>();
|
||||
if(m_lookIK != null)
|
||||
m_lookIK.onPostSolverUpdate.AddListener(this.OnLookIKPostUpdate);
|
||||
}
|
||||
|
||||
internal void OnEyeControllerUpdate(EyeMovementController p_component)
|
||||
{
|
||||
if(m_enabled)
|
||||
{
|
||||
// Gaze
|
||||
if(Settings.EyeTracking && (m_camera != null))
|
||||
{
|
||||
p_component.manualViewTarget = true;
|
||||
p_component.targetViewPosition = m_camera.position + m_camera.rotation * new Vector3((m_gazeDirection.x - 0.5f) * 2f, (m_gazeDirection.y - 0.5f) * 2f, 1f);
|
||||
}
|
||||
|
||||
// Blink
|
||||
if(Settings.Blinking)
|
||||
{
|
||||
p_component.manualBlinking = true;
|
||||
p_component.blinkProgress = m_blinkProgress;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal bool UpdateFaceTracking(CVRFaceTracking p_component)
|
||||
{
|
||||
bool l_result = false;
|
||||
if(m_enabled && Settings.FaceTracking)
|
||||
{
|
||||
if(!m_lipDataSent)
|
||||
{
|
||||
FaceTrackingManager.Instance.SubmitNewFacialData(m_lipData);
|
||||
m_lipDataSent = true;
|
||||
}
|
||||
p_component.LipSyncWasUpdated = true;
|
||||
p_component.UpdateShapesLocal_Private();
|
||||
|
||||
l_result = true;
|
||||
}
|
||||
return l_result;
|
||||
}
|
||||
|
||||
// Settings
|
||||
void SetEnabled(bool p_state)
|
||||
{
|
||||
if(m_enabled != p_state)
|
||||
{
|
||||
m_enabled = p_state;
|
||||
TryRestoreHeadRotation();
|
||||
}
|
||||
}
|
||||
void SetHeadTracking(bool p_state)
|
||||
{
|
||||
if(m_headTracking != p_state)
|
||||
{
|
||||
m_headTracking = p_state;
|
||||
TryRestoreHeadRotation();
|
||||
}
|
||||
}
|
||||
void SetSmoothing(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Player.EyeMovement;
|
||||
using ABI_RC.Systems.FaceTracking;
|
||||
using RootMotion.FinalIK;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using ViveSR.anipal.Lip;
|
||||
|
||||
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;
|
||||
|
||||
CVRAvatar m_avatarDescriptor = null;
|
||||
Transform m_camera = null;
|
||||
LookAtIK m_lookIK = null;
|
||||
Transform m_headBone = null;
|
||||
|
||||
Vector3 m_headPosition;
|
||||
Quaternion m_headRotation;
|
||||
Vector2 m_gazeDirection;
|
||||
float m_blinkProgress = 0f;
|
||||
LipData_v2 m_lipData;
|
||||
bool m_lipDataSent = false;
|
||||
|
||||
Quaternion m_bindRotation;
|
||||
Quaternion m_lastHeadRotation;
|
||||
|
||||
internal HeadTracked()
|
||||
{
|
||||
m_lipData = new LipData_v2();
|
||||
m_lipData.frame = 0;
|
||||
m_lipData.time = 0;
|
||||
m_lipData.image = IntPtr.Zero;
|
||||
m_lipData.prediction_data = new PredictionData_v2();
|
||||
m_lipData.prediction_data.blend_shape_weight = new float[(int)LipShape_v2.Max];
|
||||
}
|
||||
|
||||
// Unity events
|
||||
void Start()
|
||||
{
|
||||
SetEnabled(Settings.Enabled);
|
||||
SetHeadTracking(Settings.HeadTracking);
|
||||
SetSmoothing(Settings.Smoothing);
|
||||
|
||||
Settings.EnabledChange += this.SetEnabled;
|
||||
Settings.HeadTrackingChange += this.SetHeadTracking;
|
||||
Settings.SmoothingChange += this.SetSmoothing;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
Settings.EnabledChange -= this.SetEnabled;
|
||||
Settings.HeadTrackingChange -= this.SetHeadTracking;
|
||||
Settings.SmoothingChange -= this.SetSmoothing;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if(m_lipDataSent)
|
||||
m_lipDataSent = false;
|
||||
}
|
||||
|
||||
// Tracking updates
|
||||
public void UpdateTrackingData(ref TrackingData p_data)
|
||||
{
|
||||
m_headPosition.Set(p_data.m_headPositionX * (Settings.Mirrored ? -1f : 1f), p_data.m_headPositionY, p_data.m_headPositionZ);
|
||||
m_headRotation.Set(p_data.m_headRotationX, p_data.m_headRotationY * (Settings.Mirrored ? -1f : 1f), p_data.m_headRotationZ * (Settings.Mirrored ? -1f : 1f), p_data.m_headRotationW);
|
||||
m_gazeDirection.Set(Settings.Mirrored ? (1f - p_data.m_gazeX) : p_data.m_gazeX, p_data.m_gazeY);
|
||||
m_blinkProgress = p_data.m_blink;
|
||||
|
||||
float l_weight = Mathf.Clamp01(Mathf.InverseLerp(0.25f, 1f, Mathf.Abs(p_data.m_mouthShape)));
|
||||
m_lipData.prediction_data.blend_shape_weight[(int)LipShape_v2.Jaw_Open] = p_data.m_mouthOpen;
|
||||
m_lipData.prediction_data.blend_shape_weight[(int)LipShape_v2.Mouth_Pout] = ((p_data.m_mouthShape > 0f) ? l_weight : 0f);
|
||||
m_lipData.prediction_data.blend_shape_weight[(int)LipShape_v2.Mouth_Smile_Left] = ((p_data.m_mouthShape < 0f) ? l_weight : 0f);
|
||||
m_lipData.prediction_data.blend_shape_weight[(int)LipShape_v2.Mouth_Smile_Right] = ((p_data.m_mouthShape < 0f) ? l_weight : 0f);
|
||||
}
|
||||
|
||||
void OnLookIKPostUpdate()
|
||||
{
|
||||
if(m_enabled && m_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))
|
||||
m_headBone.rotation = m_lastHeadRotation;
|
||||
}
|
||||
}
|
||||
|
||||
// Game events
|
||||
internal void OnSetupAvatar()
|
||||
{
|
||||
Utils.SetAvatarTPose();
|
||||
|
||||
m_camera = PlayerSetup.Instance.GetActiveCamera().transform;
|
||||
m_avatarDescriptor = PlayerSetup.Instance._avatar.GetComponent<CVRAvatar>();
|
||||
m_headBone = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Head);
|
||||
m_lookIK = PlayerSetup.Instance._avatar.GetComponent<LookAtIK>();
|
||||
|
||||
if(m_headBone != null)
|
||||
m_bindRotation = Quaternion.Inverse(m_avatarDescriptor.transform.rotation) * m_headBone.rotation;
|
||||
|
||||
if(m_lookIK != null)
|
||||
m_lookIK.onPostSolverUpdate.AddListener(this.OnLookIKPostUpdate);
|
||||
|
||||
}
|
||||
internal void OnAvatarClear()
|
||||
{
|
||||
m_avatarDescriptor = null;
|
||||
m_lookIK = null;
|
||||
m_headBone = null;
|
||||
m_lastHeadRotation = Quaternion.identity;
|
||||
m_bindRotation = Quaternion.identity;
|
||||
}
|
||||
internal void OnAvatarReinitialize()
|
||||
{
|
||||
m_camera = PlayerSetup.Instance.GetActiveCamera().transform;
|
||||
m_lookIK = PlayerSetup.Instance._avatar.GetComponent<LookAtIK>();
|
||||
if(m_lookIK != null)
|
||||
m_lookIK.onPostSolverUpdate.AddListener(this.OnLookIKPostUpdate);
|
||||
}
|
||||
|
||||
internal void OnEyeControllerUpdate(EyeMovementController p_component)
|
||||
{
|
||||
if(m_enabled)
|
||||
{
|
||||
// Gaze
|
||||
if(Settings.EyeTracking && (m_camera != null))
|
||||
{
|
||||
p_component.manualViewTarget = true;
|
||||
p_component.targetViewPosition = m_camera.position + m_camera.rotation * new Vector3((m_gazeDirection.x - 0.5f) * 2f, (m_gazeDirection.y - 0.5f) * 2f, 1f);
|
||||
}
|
||||
|
||||
// Blink
|
||||
if(Settings.Blinking)
|
||||
{
|
||||
p_component.manualBlinking = true;
|
||||
p_component.blinkProgress = m_blinkProgress;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal bool UpdateFaceTracking(CVRFaceTracking p_component)
|
||||
{
|
||||
bool l_result = false;
|
||||
if(m_enabled && Settings.FaceTracking)
|
||||
{
|
||||
if(!m_lipDataSent)
|
||||
{
|
||||
FaceTrackingManager.Instance.SubmitNewFacialData(m_lipData);
|
||||
m_lipDataSent = true;
|
||||
}
|
||||
p_component.LipSyncWasUpdated = true;
|
||||
p_component.UpdateShapesLocal_Private();
|
||||
|
||||
l_result = true;
|
||||
}
|
||||
return l_result;
|
||||
}
|
||||
|
||||
// Settings
|
||||
void SetEnabled(bool p_state)
|
||||
{
|
||||
if(m_enabled != p_state)
|
||||
{
|
||||
m_enabled = p_state;
|
||||
TryRestoreHeadRotation();
|
||||
}
|
||||
}
|
||||
void SetHeadTracking(bool p_state)
|
||||
{
|
||||
if(m_headTracking != p_state)
|
||||
{
|
||||
m_headTracking = p_state;
|
||||
TryRestoreHeadRotation();
|
||||
}
|
||||
}
|
||||
void SetSmoothing(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
308
ml_dht/Main.cs
308
ml_dht/Main.cs
|
@ -1,155 +1,155 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Player.EyeMovement;
|
||||
using ABI_RC.Core.Savior;
|
||||
using ABI_RC.Systems.IK;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ml_dht
|
||||
{
|
||||
public class DesktopHeadTracking : MelonLoader.MelonMod
|
||||
{
|
||||
static DesktopHeadTracking ms_instance = null;
|
||||
|
||||
DataParser m_dataParser = null;
|
||||
HeadTracked m_localTracked = null;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
if(ms_instance == null)
|
||||
ms_instance = this;
|
||||
|
||||
Settings.Init();
|
||||
|
||||
// Patches
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForInstances());
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator WaitForInstances()
|
||||
{
|
||||
while(MetaPort.Instance == null)
|
||||
yield return null;
|
||||
|
||||
while(PlayerSetup.Instance == null)
|
||||
yield return null;
|
||||
|
||||
m_dataParser = new DataParser();
|
||||
m_localTracked = PlayerSetup.Instance.gameObject.AddComponent<HeadTracked>();
|
||||
|
||||
// If you think it's a joke to put patch here, go on, try to put it in OnInitializeMelon, you melon :>
|
||||
HarmonyInstance.Patch(
|
||||
typeof(EyeMovementController).GetMethod("Update", BindingFlags.Instance | BindingFlags.NonPublic),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnEyeControllerUpdate_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRFaceTracking).GetMethod("UpdateLocalData", BindingFlags.Instance | BindingFlags.NonPublic),
|
||||
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnFaceTrackingLocalUpdate_Prefix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
}
|
||||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar();
|
||||
void OnSetupAvatar()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localTracked != null)
|
||||
m_localTracked.OnSetupAvatar();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear();
|
||||
void OnAvatarClear()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localTracked != null)
|
||||
m_localTracked.OnAvatarClear();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarReinitialize_Postfix() => ms_instance?.OnAvatarReinitialize();
|
||||
void OnAvatarReinitialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localTracked != null)
|
||||
m_localTracked.OnAvatarReinitialize();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnEyeControllerUpdate_Postfix(ref EyeMovementController __instance) => ms_instance?.OnEyeControllerUpdate(__instance);
|
||||
void OnEyeControllerUpdate(EyeMovementController p_component)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(p_component.IsLocal && (m_localTracked != null))
|
||||
m_localTracked.OnEyeControllerUpdate(p_component);
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static bool OnFaceTrackingLocalUpdate_Prefix(ref CVRFaceTracking __instance)
|
||||
{
|
||||
bool? l_result = ms_instance?.OnFaceTrackingLocalUpdate(__instance);
|
||||
return l_result.GetValueOrDefault(true);
|
||||
}
|
||||
bool OnFaceTrackingLocalUpdate(CVRFaceTracking p_component)
|
||||
{
|
||||
bool l_result = true;
|
||||
if(p_component.UseFacialTracking && (m_localTracked != null))
|
||||
l_result = !m_localTracked.UpdateFaceTracking(p_component);
|
||||
return l_result;
|
||||
}
|
||||
}
|
||||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Player.EyeMovement;
|
||||
using ABI_RC.Core.Savior;
|
||||
using ABI_RC.Systems.IK;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ml_dht
|
||||
{
|
||||
public class DesktopHeadTracking : MelonLoader.MelonMod
|
||||
{
|
||||
static DesktopHeadTracking ms_instance = null;
|
||||
|
||||
DataParser m_dataParser = null;
|
||||
HeadTracked m_localTracked = null;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
if(ms_instance == null)
|
||||
ms_instance = this;
|
||||
|
||||
Settings.Init();
|
||||
|
||||
// Patches
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForInstances());
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator WaitForInstances()
|
||||
{
|
||||
while(MetaPort.Instance == null)
|
||||
yield return null;
|
||||
|
||||
while(PlayerSetup.Instance == null)
|
||||
yield return null;
|
||||
|
||||
m_dataParser = new DataParser();
|
||||
m_localTracked = PlayerSetup.Instance.gameObject.AddComponent<HeadTracked>();
|
||||
|
||||
// If you think it's a joke to put patch here, go on, try to put it in OnInitializeMelon, you melon :>
|
||||
HarmonyInstance.Patch(
|
||||
typeof(EyeMovementController).GetMethod("Update", BindingFlags.Instance | BindingFlags.NonPublic),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnEyeControllerUpdate_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRFaceTracking).GetMethod("UpdateLocalData", BindingFlags.Instance | BindingFlags.NonPublic),
|
||||
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnFaceTrackingLocalUpdate_Prefix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
}
|
||||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar();
|
||||
void OnSetupAvatar()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localTracked != null)
|
||||
m_localTracked.OnSetupAvatar();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear();
|
||||
void OnAvatarClear()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localTracked != null)
|
||||
m_localTracked.OnAvatarClear();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarReinitialize_Postfix() => ms_instance?.OnAvatarReinitialize();
|
||||
void OnAvatarReinitialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localTracked != null)
|
||||
m_localTracked.OnAvatarReinitialize();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnEyeControllerUpdate_Postfix(ref EyeMovementController __instance) => ms_instance?.OnEyeControllerUpdate(__instance);
|
||||
void OnEyeControllerUpdate(EyeMovementController p_component)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(p_component.IsLocal && (m_localTracked != null))
|
||||
m_localTracked.OnEyeControllerUpdate(p_component);
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static bool OnFaceTrackingLocalUpdate_Prefix(ref CVRFaceTracking __instance)
|
||||
{
|
||||
bool? l_result = ms_instance?.OnFaceTrackingLocalUpdate(__instance);
|
||||
return l_result.GetValueOrDefault(true);
|
||||
}
|
||||
bool OnFaceTrackingLocalUpdate(CVRFaceTracking p_component)
|
||||
{
|
||||
bool l_result = true;
|
||||
if(p_component.UseFacialTracking && (m_localTracked != null))
|
||||
l_result = !m_localTracked.UpdateFaceTracking(p_component);
|
||||
return l_result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_dht.DesktopHeadTracking), "DesktopHeadTracking", "1.2.1-ex", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_dht.DesktopHeadTracking), "DesktopHeadTracking", "1.2.1", "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)]
|
|
@ -28,14 +28,13 @@ namespace ml_dht
|
|||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
||||
static public event Action<bool> EnabledChange;
|
||||
static public event Action<bool> HeadTrackingChange;
|
||||
static public event Action<bool> EyeTrackingChange;
|
||||
static public event Action<bool> FaceTrackingChange;
|
||||
static public event Action<bool> BlinkingChange;
|
||||
static public event Action<bool> MirroredChange;
|
||||
static public event Action<float> SmoothingChange;
|
||||
|
||||
public static event Action<bool> EnabledChange;
|
||||
public static event Action<bool> HeadTrackingChange;
|
||||
public static event Action<bool> EyeTrackingChange;
|
||||
public static event Action<bool> FaceTrackingChange;
|
||||
public static event Action<bool> BlinkingChange;
|
||||
public static event Action<bool> MirroredChange;
|
||||
public static event Action<float> SmoothingChange;
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
|
|
|
@ -17,7 +17,7 @@ struct TrackingData
|
|||
public float m_mouthShape; // Range - [-1;1], -1 - wide, 1 - narrow
|
||||
public float m_brows; // Range - [-1;1], -1 - up, 1 - down; not used yet
|
||||
|
||||
static public byte[] ToBytes(TrackingData p_faceData)
|
||||
public static byte[] ToBytes(TrackingData p_faceData)
|
||||
{
|
||||
int l_size = Marshal.SizeOf(p_faceData);
|
||||
byte[] l_arr = new byte[l_size];
|
||||
|
@ -29,7 +29,7 @@ struct TrackingData
|
|||
return l_arr;
|
||||
}
|
||||
|
||||
static public TrackingData ToObject(byte[] p_buffer)
|
||||
public static TrackingData ToObject(byte[] p_buffer)
|
||||
{
|
||||
TrackingData l_faceData = new TrackingData();
|
||||
|
||||
|
|
|
@ -1,23 +1,27 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.UI;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_dht
|
||||
{
|
||||
static class Utils
|
||||
{
|
||||
static readonly object[] ms_emptyArray = new object[0];
|
||||
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);
|
||||
|
||||
static public void ExecuteScript(this CohtmlControlledViewWrapper p_instance, string p_script) => ((cohtml.Net.View)ms_view.GetValue(p_instance)).ExecuteScript(p_script);
|
||||
|
||||
static public void UpdateShapesLocal_Private(this CVRFaceTracking p_instance) => ms_updateShapesLocal?.Invoke(p_instance, ms_emptyArray);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.UI;
|
||||
using ABI_RC.Systems.IK;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_dht
|
||||
{
|
||||
static class Utils
|
||||
{
|
||||
static readonly object[] ms_emptyArray = new object[0];
|
||||
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 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);
|
||||
|
||||
public static void SetAvatarTPose()
|
||||
{
|
||||
IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose);
|
||||
PlayerSetup.Instance._avatar.transform.localPosition = Vector3.zero;
|
||||
PlayerSetup.Instance._avatar.transform.localRotation = Quaternion.identity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,84 +1,84 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<PackageId>DesktopHeadTracking</PackageId>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>DesktopHeadTracking</Product>
|
||||
<Version>1.2.1</Version>
|
||||
<Platforms>x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<DebugType>none</DebugType>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="DesktopHeadTracking.json" />
|
||||
<None Remove="resources\mod_menu.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="resources\mod_menu.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="..\js\mods_extension.js" Link="resources\mods_extension.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\0Harmony.dll</HintPath>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp-firstpass">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="cohtml.Net">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\cohtml.Net.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Cohtml.Runtime">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="MelonLoader">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\MelonLoader.dll</HintPath>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.AnimationModule">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\"" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<PackageId>DesktopHeadTracking</PackageId>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>DesktopHeadTracking</Product>
|
||||
<Version>1.2.1</Version>
|
||||
<Platforms>x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<DebugType>embedded</DebugType>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="DesktopHeadTracking.json" />
|
||||
<None Remove="resources\mod_menu.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="resources\mod_menu.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="..\js\mods_extension.js" Link="resources\mods_extension.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\0Harmony.dll</HintPath>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp-firstpass">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="cohtml.Net">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\cohtml.Net.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Cohtml.Runtime">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="MelonLoader">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\MelonLoader.dll</HintPath>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.AnimationModule">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\"" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace ml_lme
|
|||
{
|
||||
class LeapHand
|
||||
{
|
||||
public enum FingerBone
|
||||
enum FingerBone
|
||||
{
|
||||
ThumbMetacarpal = 0,
|
||||
ThumbProximal,
|
||||
|
@ -25,9 +25,12 @@ namespace ml_lme
|
|||
PinkyMetacarpal,
|
||||
PinkyProximal,
|
||||
PinkyIntermediate,
|
||||
PinkyDistal
|
||||
PinkyDistal,
|
||||
|
||||
Count
|
||||
};
|
||||
|
||||
readonly bool m_left = false;
|
||||
readonly Transform m_root = null;
|
||||
readonly Transform m_wrist = null;
|
||||
readonly GameObject m_mesh = null;
|
||||
|
@ -36,14 +39,15 @@ namespace ml_lme
|
|||
|
||||
public LeapHand(Transform p_root, bool p_left)
|
||||
{
|
||||
m_fingersBones = new Transform[20];
|
||||
m_initialRotations = new Quaternion[20];
|
||||
m_left = p_left;
|
||||
m_fingersBones = new Transform[(int)FingerBone.Count];
|
||||
m_initialRotations = new Quaternion[(int)FingerBone.Count];
|
||||
|
||||
m_root = p_root;
|
||||
if(m_root != null)
|
||||
{
|
||||
m_mesh = m_root.Find(p_left ? "GenericHandL" : "GenericHandR")?.gameObject;
|
||||
m_wrist = m_root.Find(p_left ? "LeftHand/Wrist" : "RightHand/Wrist");
|
||||
m_mesh = m_root.Find(m_left ? "GenericHandL" : "GenericHandR")?.gameObject;
|
||||
m_wrist = m_root.Find(m_left ? "LeftHand/Wrist" : "RightHand/Wrist");
|
||||
if(m_wrist != null)
|
||||
{
|
||||
m_fingersBones[0] = null; // Actual thumb-meta, look at Leap Motion docs, dummy, it's zero point
|
||||
|
@ -91,7 +95,7 @@ namespace ml_lme
|
|||
{
|
||||
if(m_fingersBones[i] != null)
|
||||
{
|
||||
//m_fingers[i].position = p_data.m_fingerPosition[i];
|
||||
//m_fingersBones[i].position = p_data.m_fingerPosition[i];
|
||||
m_fingersBones[i].rotation = p_data.m_fingerRotation[i];
|
||||
}
|
||||
}
|
||||
|
@ -101,12 +105,14 @@ namespace ml_lme
|
|||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
public void Rebind(Quaternion p_base)
|
||||
{
|
||||
if(m_wrist != null)
|
||||
{
|
||||
m_wrist.localPosition = Vector3.zero;
|
||||
m_wrist.localRotation = Quaternion.identity;
|
||||
|
||||
m_wrist.rotation = p_base * Quaternion.Euler(0f, m_left ? -90f : 90f, 0f);
|
||||
}
|
||||
|
||||
for(int i = 0; i < 20; i++)
|
||||
|
@ -117,8 +123,111 @@ namespace ml_lme
|
|||
}
|
||||
|
||||
public Transform GetRoot() => m_root;
|
||||
public Transform GetWrist() => m_wrist;
|
||||
public Transform GetFingersBone(FingerBone p_bone) => m_fingersBones[(int)p_bone];
|
||||
public Transform GetBone(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);
|
||||
break;
|
||||
|
||||
case HumanBodyBones.RightHand:
|
||||
l_result = (!m_left ? m_wrist : null);
|
||||
break;
|
||||
case HumanBodyBones.RightThumbProximal:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.ThumbProximal] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightThumbIntermediate:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.ThumbIntermediate] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightThumbDistal:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.ThumbDistal] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightIndexProximal:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.IndexProximal] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightIndexIntermediate:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.IndexIntermediate] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightIndexDistal:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.IndexDistal] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightMiddleProximal:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.MiddleProximal] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightMiddleIntermediate:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.MiddleIntermediate] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightMiddleDistal:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.MiddleDistal] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightRingProximal:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.RingProximal] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightRingIntermediate:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.RingIntermediate] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightRingDistal:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.RingDistal] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightLittleProximal:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.PinkyProximal] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightLittleIntermediate:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.PinkyIntermediate] : null);
|
||||
break;
|
||||
case HumanBodyBones.RightLittleDistal:
|
||||
l_result = (!m_left ? m_fingersBones[(int)FingerBone.PinkyDistal] : null);
|
||||
break;
|
||||
}
|
||||
return l_result;
|
||||
}
|
||||
|
||||
public void SetMeshActive(bool p_state)
|
||||
{
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace ml_lme
|
|||
m_handRayLeft.hand = true;
|
||||
m_handRayLeft.generalMask = -269;
|
||||
m_handRayLeft.isInteractionRay = true;
|
||||
m_handRayLeft.triggerGazeEvents = false;
|
||||
//m_handRayLeft.triggerGazeEvents = false;
|
||||
m_handRayLeft.holderRoot = m_handRayLeft.gameObject;
|
||||
m_handRayLeft.attachmentDistance = 0f;
|
||||
m_handRayLeft.uiMask = 32;
|
||||
|
@ -60,7 +60,7 @@ namespace ml_lme
|
|||
m_handRayRight.hand = false;
|
||||
m_handRayRight.generalMask = -269;
|
||||
m_handRayRight.isInteractionRay = true;
|
||||
m_handRayRight.triggerGazeEvents = false;
|
||||
//m_handRayRight.triggerGazeEvents = false;
|
||||
m_handRayRight.holderRoot = m_handRayRight.gameObject;
|
||||
m_handRayRight.attachmentDistance = 0f;
|
||||
m_handRayRight.uiMask = 32;
|
||||
|
@ -538,29 +538,29 @@ namespace ml_lme
|
|||
{
|
||||
if(p_left)
|
||||
{
|
||||
base._inputManager.finger1StretchedLeftThumb = -0.5f;
|
||||
base._inputManager.finger2StretchedLeftThumb = 0.7f;
|
||||
base._inputManager.finger3StretchedLeftThumb = 0.7f;
|
||||
base._inputManager.finger1StretchedLeftThumb = 0f;
|
||||
base._inputManager.finger2StretchedLeftThumb = 0f;
|
||||
base._inputManager.finger3StretchedLeftThumb = 0f;
|
||||
base._inputManager.fingerSpreadLeftThumb = 0f;
|
||||
|
||||
base._inputManager.finger1StretchedLeftIndex = 0.5f;
|
||||
base._inputManager.finger2StretchedLeftIndex = 0.7f;
|
||||
base._inputManager.finger3StretchedLeftIndex = 0.7f;
|
||||
base._inputManager.finger1StretchedLeftIndex = 0f;
|
||||
base._inputManager.finger2StretchedLeftIndex =0f;
|
||||
base._inputManager.finger3StretchedLeftIndex = 0f;
|
||||
base._inputManager.fingerSpreadLeftIndex = 0f;
|
||||
|
||||
base._inputManager.finger1StretchedLeftMiddle = 0.5f;
|
||||
base._inputManager.finger2StretchedLeftMiddle = 0.7f;
|
||||
base._inputManager.finger3StretchedLeftMiddle = 0.7f;
|
||||
base._inputManager.finger1StretchedLeftMiddle = 0f;
|
||||
base._inputManager.finger2StretchedLeftMiddle = 0f;
|
||||
base._inputManager.finger3StretchedLeftMiddle = 0f;
|
||||
base._inputManager.fingerSpreadLeftMiddle = 0f;
|
||||
|
||||
base._inputManager.finger1StretchedLeftRing = 0.5f;
|
||||
base._inputManager.finger2StretchedLeftRing = 0.7f;
|
||||
base._inputManager.finger3StretchedLeftRing = 0.7f;
|
||||
base._inputManager.finger1StretchedLeftRing = 0f;
|
||||
base._inputManager.finger2StretchedLeftRing = 0f;
|
||||
base._inputManager.finger3StretchedLeftRing = 0f;
|
||||
base._inputManager.fingerSpreadLeftRing = 0f;
|
||||
|
||||
base._inputManager.finger1StretchedLeftPinky = 0.5f;
|
||||
base._inputManager.finger2StretchedLeftPinky = 0.7f;
|
||||
base._inputManager.finger3StretchedLeftPinky = 0.7f;
|
||||
base._inputManager.finger1StretchedLeftPinky = 0f;
|
||||
base._inputManager.finger2StretchedLeftPinky = 0f;
|
||||
base._inputManager.finger3StretchedLeftPinky = 0f;
|
||||
base._inputManager.fingerSpreadLeftPinky = 0f;
|
||||
|
||||
base._inputManager.fingerFullCurlNormalizedLeftThumb = 0f;
|
||||
|
@ -571,29 +571,29 @@ namespace ml_lme
|
|||
}
|
||||
else
|
||||
{
|
||||
base._inputManager.finger1StretchedRightThumb = -0.5f;
|
||||
base._inputManager.finger2StretchedRightThumb = 0.7f;
|
||||
base._inputManager.finger3StretchedRightThumb = 0.7f;
|
||||
base._inputManager.finger1StretchedRightThumb = 0f;
|
||||
base._inputManager.finger2StretchedRightThumb = 0f;
|
||||
base._inputManager.finger3StretchedRightThumb = 0f;
|
||||
base._inputManager.fingerSpreadRightThumb = 0f;
|
||||
|
||||
base._inputManager.finger1StretchedRightIndex = 0.5f;
|
||||
base._inputManager.finger2StretchedRightIndex = 0.7f;
|
||||
base._inputManager.finger3StretchedRightIndex = 0.7f;
|
||||
base._inputManager.finger1StretchedRightIndex = 0f;
|
||||
base._inputManager.finger2StretchedRightIndex = 0f;
|
||||
base._inputManager.finger3StretchedRightIndex = 0f;
|
||||
base._inputManager.fingerSpreadRightIndex = 0f;
|
||||
|
||||
base._inputManager.finger1StretchedRightMiddle = 0.5f;
|
||||
base._inputManager.finger2StretchedRightMiddle = 0.7f;
|
||||
base._inputManager.finger3StretchedRightMiddle = 0.7f;
|
||||
base._inputManager.finger1StretchedRightMiddle = 0f;
|
||||
base._inputManager.finger2StretchedRightMiddle = 0f;
|
||||
base._inputManager.finger3StretchedRightMiddle = 0f;
|
||||
base._inputManager.fingerSpreadRightMiddle = 0f;
|
||||
|
||||
base._inputManager.finger1StretchedRightRing = 0.5f;
|
||||
base._inputManager.finger2StretchedRightRing = 0.7f;
|
||||
base._inputManager.finger3StretchedRightRing = 0.7f;
|
||||
base._inputManager.finger1StretchedRightRing = 0f;
|
||||
base._inputManager.finger2StretchedRightRing = 0f;
|
||||
base._inputManager.finger3StretchedRightRing = 0f;
|
||||
base._inputManager.fingerSpreadRightRing = 0f;
|
||||
|
||||
base._inputManager.finger1StretchedRightPinky = 0.5f;
|
||||
base._inputManager.finger2StretchedRightPinky = 0.7f;
|
||||
base._inputManager.finger3StretchedRightPinky = 0.7f;
|
||||
base._inputManager.finger1StretchedRightPinky = 0f;
|
||||
base._inputManager.finger2StretchedRightPinky = 0f;
|
||||
base._inputManager.finger3StretchedRightPinky = 0f;
|
||||
base._inputManager.fingerSpreadRightPinky = 0f;
|
||||
|
||||
base._inputManager.fingerFullCurlNormalizedRightThumb = 0f;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK;
|
||||
using RootMotion.FinalIK;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
@ -11,6 +10,12 @@ namespace ml_lme
|
|||
[DefaultExecutionOrder(999999)]
|
||||
class LeapTracked : MonoBehaviour
|
||||
{
|
||||
enum PlaneType
|
||||
{
|
||||
OXZ,
|
||||
OYX
|
||||
}
|
||||
|
||||
struct IKInfo
|
||||
{
|
||||
public Vector4 m_armsWeights;
|
||||
|
@ -21,50 +26,69 @@ namespace ml_lme
|
|||
public Transform m_rightElbowTarget;
|
||||
}
|
||||
|
||||
struct FingerBoneInfo
|
||||
struct RotationOffset
|
||||
{
|
||||
public LeapHand.FingerBone m_bone;
|
||||
public Transform m_targetBone;
|
||||
public Transform m_sourceBone;
|
||||
public Transform m_target;
|
||||
public Transform m_source;
|
||||
public Quaternion m_offset;
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
m_source = null;
|
||||
m_target = null;
|
||||
m_offset = Quaternion.identity;
|
||||
}
|
||||
}
|
||||
|
||||
static readonly Quaternion ms_offsetLeft = Quaternion.Euler(0f, 90f, 0f);
|
||||
static readonly Quaternion ms_offsetRight = Quaternion.Euler(0f, 270f, 0f);
|
||||
|
||||
static readonly (HumanBodyBones, LeapHand.FingerBone, bool)[] ms_fingerBonesLinks =
|
||||
static readonly (HumanBodyBones, bool)[] ms_fingers =
|
||||
{
|
||||
(HumanBodyBones.LeftThumbProximal, LeapHand.FingerBone.ThumbProximal, true),
|
||||
(HumanBodyBones.LeftThumbIntermediate, LeapHand.FingerBone.ThumbIntermediate, true),
|
||||
(HumanBodyBones.LeftThumbDistal, LeapHand.FingerBone.ThumbDistal, true),
|
||||
(HumanBodyBones.LeftIndexProximal, LeapHand.FingerBone.IndexProximal, true),
|
||||
(HumanBodyBones.LeftIndexIntermediate, LeapHand.FingerBone.IndexIntermediate, true),
|
||||
(HumanBodyBones.LeftIndexDistal, LeapHand.FingerBone.IndexDistal, true),
|
||||
(HumanBodyBones.LeftMiddleProximal, LeapHand.FingerBone.MiddleProximal, true),
|
||||
(HumanBodyBones.LeftMiddleIntermediate, LeapHand.FingerBone.MiddleIntermediate, true),
|
||||
(HumanBodyBones.LeftMiddleDistal, LeapHand.FingerBone.MiddleDistal, true),
|
||||
(HumanBodyBones.LeftRingProximal, LeapHand.FingerBone.RingProximal, true),
|
||||
(HumanBodyBones.LeftRingIntermediate, LeapHand.FingerBone.RingIntermediate, true),
|
||||
(HumanBodyBones.LeftRingDistal, LeapHand.FingerBone.RingDistal, true),
|
||||
(HumanBodyBones.LeftLittleProximal, LeapHand.FingerBone.PinkyProximal, true),
|
||||
(HumanBodyBones.LeftLittleIntermediate, LeapHand.FingerBone.PinkyIntermediate, true),
|
||||
(HumanBodyBones.LeftLittleDistal, LeapHand.FingerBone.PinkyDistal, true),
|
||||
(HumanBodyBones.LeftThumbProximal, true),
|
||||
(HumanBodyBones.LeftThumbIntermediate, true),
|
||||
(HumanBodyBones.LeftThumbDistal, true),
|
||||
(HumanBodyBones.LeftIndexProximal, true),
|
||||
(HumanBodyBones.LeftIndexIntermediate, true),
|
||||
(HumanBodyBones.LeftIndexDistal, true),
|
||||
(HumanBodyBones.LeftMiddleProximal, true),
|
||||
(HumanBodyBones.LeftMiddleIntermediate, true),
|
||||
(HumanBodyBones.LeftMiddleDistal, true),
|
||||
(HumanBodyBones.LeftRingProximal, true),
|
||||
(HumanBodyBones.LeftRingIntermediate, true),
|
||||
(HumanBodyBones.LeftRingDistal, true),
|
||||
(HumanBodyBones.LeftLittleProximal, true),
|
||||
(HumanBodyBones.LeftLittleIntermediate, true),
|
||||
(HumanBodyBones.LeftLittleDistal, true),
|
||||
|
||||
(HumanBodyBones.RightThumbProximal, LeapHand.FingerBone.ThumbProximal, false),
|
||||
(HumanBodyBones.RightThumbIntermediate, LeapHand.FingerBone.ThumbIntermediate, false),
|
||||
(HumanBodyBones.RightThumbDistal, LeapHand.FingerBone.ThumbDistal, false),
|
||||
(HumanBodyBones.RightIndexProximal, LeapHand.FingerBone.IndexProximal, false),
|
||||
(HumanBodyBones.RightIndexIntermediate, LeapHand.FingerBone.IndexIntermediate, false),
|
||||
(HumanBodyBones.RightIndexDistal, LeapHand.FingerBone.IndexDistal, false),
|
||||
(HumanBodyBones.RightMiddleProximal, LeapHand.FingerBone.MiddleProximal, false),
|
||||
(HumanBodyBones.RightMiddleIntermediate, LeapHand.FingerBone.MiddleIntermediate, false),
|
||||
(HumanBodyBones.RightMiddleDistal, LeapHand.FingerBone.MiddleDistal, false),
|
||||
(HumanBodyBones.RightRingProximal, LeapHand.FingerBone.RingProximal, false),
|
||||
(HumanBodyBones.RightRingIntermediate, LeapHand.FingerBone.RingIntermediate, false),
|
||||
(HumanBodyBones.RightRingDistal, LeapHand.FingerBone.RingDistal, false),
|
||||
(HumanBodyBones.RightLittleProximal, LeapHand.FingerBone.PinkyProximal, false),
|
||||
(HumanBodyBones.RightLittleIntermediate, LeapHand.FingerBone.PinkyIntermediate, false),
|
||||
(HumanBodyBones.RightLittleDistal, LeapHand.FingerBone.PinkyDistal, false),
|
||||
(HumanBodyBones.RightThumbProximal, false),
|
||||
(HumanBodyBones.RightThumbIntermediate, false),
|
||||
(HumanBodyBones.RightThumbDistal, false),
|
||||
(HumanBodyBones.RightIndexProximal, false),
|
||||
(HumanBodyBones.RightIndexIntermediate, false),
|
||||
(HumanBodyBones.RightIndexDistal, false),
|
||||
(HumanBodyBones.RightMiddleProximal, false),
|
||||
(HumanBodyBones.RightMiddleIntermediate, false),
|
||||
(HumanBodyBones.RightMiddleDistal, false),
|
||||
(HumanBodyBones.RightRingProximal, false),
|
||||
(HumanBodyBones.RightRingIntermediate, false),
|
||||
(HumanBodyBones.RightRingDistal, false),
|
||||
(HumanBodyBones.RightLittleProximal, false),
|
||||
(HumanBodyBones.RightLittleIntermediate, false),
|
||||
(HumanBodyBones.RightLittleDistal, false),
|
||||
};
|
||||
static readonly (HumanBodyBones, HumanBodyBones, bool)[] ms_rotationFixChains =
|
||||
{
|
||||
(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)
|
||||
};
|
||||
|
||||
public static readonly float[] ms_lastLeftFingerBones = new float[20];
|
||||
|
@ -72,13 +96,12 @@ namespace ml_lme
|
|||
|
||||
bool m_inVR = false;
|
||||
VRIK m_vrIK = null;
|
||||
Transform m_hips = null;
|
||||
|
||||
bool m_enabled = true;
|
||||
bool m_fingersOnly = false;
|
||||
bool m_trackElbows = true;
|
||||
|
||||
Transform m_leftHand = null;
|
||||
Transform m_rightHand = null;
|
||||
IKInfo m_vrIKInfo;
|
||||
ArmIK m_leftArmIK = null;
|
||||
ArmIK m_rightArmIK = null;
|
||||
|
@ -89,16 +112,15 @@ namespace ml_lme
|
|||
bool m_leftTargetActive = false; // VRIK only
|
||||
bool m_rightTargetActive = false; // VRIK only
|
||||
|
||||
readonly List<FingerBoneInfo> m_leftFingerBones = null;
|
||||
readonly List<FingerBoneInfo> m_rightFingerBones = null;
|
||||
|
||||
Quaternion m_leftWristOffset;
|
||||
Quaternion m_rightWristOffset;
|
||||
RotationOffset m_leftHandOffset; // From avatar hand to Leap wrist
|
||||
RotationOffset m_rightHandOffset;
|
||||
readonly List<RotationOffset> m_leftFingerOffsets = null; // From Leap finger bone to avatar finger bone
|
||||
readonly List<RotationOffset> m_rightFingerOffsets = null;
|
||||
|
||||
internal LeapTracked()
|
||||
{
|
||||
m_leftFingerBones = new List<FingerBoneInfo>();
|
||||
m_rightFingerBones = new List<FingerBoneInfo>();
|
||||
m_leftFingerOffsets = new List<RotationOffset>();
|
||||
m_rightFingerOffsets = new List<RotationOffset>();
|
||||
}
|
||||
|
||||
// Unity events
|
||||
|
@ -181,42 +203,44 @@ namespace ml_lme
|
|||
LeapParser.LeapData l_data = LeapManager.Instance.GetLatestData();
|
||||
if(l_data.m_leftHand.m_present)
|
||||
{
|
||||
Transform l_leapWrist = LeapTracking.Instance.GetLeftHand().GetWrist();
|
||||
Quaternion l_turnBack = (m_leftHand.rotation * m_leftWristOffset) * Quaternion.Inverse(l_leapWrist.rotation);
|
||||
foreach(var l_info in m_leftFingerBones)
|
||||
l_info.m_targetBone.rotation = l_turnBack * (l_info.m_sourceBone.rotation * l_info.m_offset);
|
||||
Quaternion l_turnBack = (m_leftHandOffset.m_source.rotation * m_leftHandOffset.m_offset) * Quaternion.Inverse(m_leftHandOffset.m_target.rotation);
|
||||
foreach(var l_info in m_leftFingerOffsets)
|
||||
l_info.m_target.rotation = l_turnBack * (l_info.m_source.rotation * l_info.m_offset);
|
||||
}
|
||||
if(l_data.m_rightHand.m_present)
|
||||
{
|
||||
Transform l_leapWrist = LeapTracking.Instance.GetRightHand().GetWrist();
|
||||
Quaternion l_turnBack = (m_rightHand.rotation * m_rightWristOffset) * Quaternion.Inverse(l_leapWrist.rotation);
|
||||
foreach(var l_info in m_rightFingerBones)
|
||||
l_info.m_targetBone.rotation = l_turnBack * (l_info.m_sourceBone.rotation * l_info.m_offset);
|
||||
Quaternion l_turnBack = (m_rightHandOffset.m_source.rotation * m_rightHandOffset.m_offset) * Quaternion.Inverse(m_rightHandOffset.m_target.rotation);
|
||||
foreach(var l_info in m_rightFingerOffsets)
|
||||
l_info.m_target.rotation = l_turnBack * (l_info.m_source.rotation * l_info.m_offset);
|
||||
}
|
||||
|
||||
m_poseHandler.GetHumanPose(ref m_pose);
|
||||
if(l_data.m_leftHand.m_present)
|
||||
if(l_data.m_leftHand.m_present || l_data.m_rightHand.m_present)
|
||||
{
|
||||
for(int i = 0; i < 5; i++)
|
||||
{
|
||||
int l_offset = i * 4;
|
||||
|
||||
ms_lastLeftFingerBones[l_offset] = m_pose.muscles[(int)MuscleIndex.LeftThumb1Stretched + l_offset];
|
||||
ms_lastLeftFingerBones[l_offset + 1] = m_pose.muscles[(int)MuscleIndex.LeftThumb2Stretched + l_offset];
|
||||
ms_lastLeftFingerBones[l_offset + 2] = m_pose.muscles[(int)MuscleIndex.LeftThumb3Stretched + l_offset];
|
||||
ms_lastLeftFingerBones[l_offset + 3] = m_pose.muscles[(int)MuscleIndex.LeftThumbSpread + l_offset];
|
||||
}
|
||||
}
|
||||
if(l_data.m_rightHand.m_present)
|
||||
{
|
||||
for(int i = 0; i < 5; i++)
|
||||
{
|
||||
int l_offset = i * 4;
|
||||
|
||||
ms_lastRightFingerBones[l_offset] = m_pose.muscles[(int)MuscleIndex.RightThumb1Stretched + l_offset];
|
||||
ms_lastRightFingerBones[l_offset + 1] = m_pose.muscles[(int)MuscleIndex.RightThumb2Stretched + l_offset];
|
||||
ms_lastRightFingerBones[l_offset + 2] = m_pose.muscles[(int)MuscleIndex.RightThumb3Stretched + l_offset];
|
||||
ms_lastRightFingerBones[l_offset + 3] = m_pose.muscles[(int)MuscleIndex.RightThumbSpread + l_offset];
|
||||
}
|
||||
}
|
||||
|
||||
if(Settings.MechanimFilter && (m_hips != null))
|
||||
{
|
||||
// Yoinked from IKSystem.OnPostSolverUpdateGeneral
|
||||
Vector3 l_pos = m_hips.position;
|
||||
Quaternion l_rot = m_hips.rotation;
|
||||
m_poseHandler.SetHumanPose(ref m_pose);
|
||||
m_hips.SetPositionAndRotation(l_pos, l_rot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,6 +248,7 @@ namespace ml_lme
|
|||
internal void OnAvatarClear()
|
||||
{
|
||||
m_vrIK = null;
|
||||
m_hips = null;
|
||||
m_leftArmIK = null;
|
||||
m_rightArmIK = null;
|
||||
m_leftTargetActive = false;
|
||||
|
@ -237,41 +262,35 @@ namespace ml_lme
|
|||
m_rightHandTarget.localPosition = Vector3.zero;
|
||||
m_rightHandTarget.localRotation = Quaternion.identity;
|
||||
|
||||
m_leftFingerBones.Clear();
|
||||
m_rightFingerBones.Clear();
|
||||
m_leftHandOffset.Reset();
|
||||
m_rightHandOffset.Reset();
|
||||
|
||||
m_leftHand = null;
|
||||
m_rightHand = null;
|
||||
m_leftWristOffset = Quaternion.identity;
|
||||
m_rightWristOffset = Quaternion.identity;
|
||||
m_leftFingerOffsets.Clear();
|
||||
m_rightFingerOffsets.Clear();
|
||||
}
|
||||
|
||||
internal void OnAvatarSetup()
|
||||
{
|
||||
m_inVR = Utils.IsInVR();
|
||||
m_vrIK = PlayerSetup.Instance._animator.GetComponent<VRIK>();
|
||||
|
||||
if(PlayerSetup.Instance._animator.isHuman)
|
||||
{
|
||||
Utils.SetAvatarTPose();
|
||||
|
||||
m_poseHandler = new HumanPoseHandler(PlayerSetup.Instance._animator.avatar, PlayerSetup.Instance._animator.transform);
|
||||
m_poseHandler.GetHumanPose(ref m_pose);
|
||||
|
||||
if(m_inVR)
|
||||
{
|
||||
PlayerSetup.Instance._avatar.transform.localPosition = Vector3.zero;
|
||||
PlayerSetup.Instance._avatar.transform.localRotation = Quaternion.identity;
|
||||
}
|
||||
else
|
||||
PoseHelper.ForceTPose(PlayerSetup.Instance._animator);
|
||||
m_hips = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Hips);
|
||||
|
||||
m_leftHand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand);
|
||||
m_leftHandTarget.localRotation = ms_offsetLeft * (Quaternion.Inverse(PlayerSetup.Instance._avatar.transform.rotation) * m_leftHand.rotation);
|
||||
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_rightHand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand);
|
||||
m_rightHandTarget.localRotation = ms_offsetRight * (Quaternion.Inverse(PlayerSetup.Instance._avatar.transform.rotation) * m_rightHand.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);
|
||||
|
||||
ParseFingersBones();
|
||||
|
||||
m_vrIK = PlayerSetup.Instance._animator.GetComponent<VRIK>();
|
||||
if(m_vrIK != null)
|
||||
{
|
||||
m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreUpdate);
|
||||
|
@ -298,7 +317,7 @@ namespace ml_lme
|
|||
}
|
||||
else
|
||||
{
|
||||
PoseHelper.ForceTPose(PlayerSetup.Instance._animator);
|
||||
Utils.SetAvatarTPose();
|
||||
SetupArmIK();
|
||||
}
|
||||
}
|
||||
|
@ -453,31 +472,96 @@ namespace ml_lme
|
|||
|
||||
void ParseFingersBones()
|
||||
{
|
||||
LeapTracking.Instance.GetLeftHand().Reset();
|
||||
LeapTracking.Instance.GetLeftHand().GetWrist().rotation = PlayerSetup.Instance.transform.rotation * ms_offsetRight; // Weird, but that's how it works
|
||||
m_leftWristOffset = Quaternion.Inverse(m_leftHand.rotation) * LeapTracking.Instance.GetLeftHand().GetWrist().rotation;
|
||||
LeapTracking.Instance.Rebind(PlayerSetup.Instance.transform.rotation);
|
||||
|
||||
LeapTracking.Instance.GetRightHand().Reset();
|
||||
LeapTracking.Instance.GetRightHand().GetWrist().rotation = PlayerSetup.Instance.transform.rotation * ms_offsetLeft; // Weird, but that's how it works
|
||||
m_rightWristOffset = Quaternion.Inverse(m_rightHand.rotation) * LeapTracking.Instance.GetRightHand().GetWrist().rotation;
|
||||
// Try to "fix" rotations, slightly inaccurate after 0YX plane rotation
|
||||
foreach(var l_tuple in ms_rotationFixChains)
|
||||
{
|
||||
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),
|
||||
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),
|
||||
PlaneType.OYX
|
||||
);
|
||||
}
|
||||
|
||||
foreach(var l_link in ms_fingerBonesLinks)
|
||||
// Bind
|
||||
m_leftHandOffset.m_target = LeapTracking.Instance.GetLeftHand().GetBone(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);
|
||||
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);
|
||||
if(l_transform != null)
|
||||
{
|
||||
FingerBoneInfo l_info = new FingerBoneInfo();
|
||||
l_info.m_bone = l_link.Item2;
|
||||
l_info.m_targetBone = l_transform;
|
||||
l_info.m_sourceBone = (l_link.Item3 ? LeapTracking.Instance.GetLeftHand().GetFingersBone(l_link.Item2) : LeapTracking.Instance.GetRightHand().GetFingersBone(l_link.Item2));
|
||||
l_info.m_offset = Quaternion.Inverse(l_info.m_sourceBone.rotation) * l_info.m_targetBone.rotation;
|
||||
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_offset = Quaternion.Inverse(l_offset.m_source.rotation) * l_offset.m_target.rotation;
|
||||
|
||||
if(l_link.Item3)
|
||||
m_leftFingerBones.Add(l_info);
|
||||
if(l_link.Item2)
|
||||
m_leftFingerOffsets.Add(l_offset);
|
||||
else
|
||||
m_rightFingerBones.Add(l_info);
|
||||
m_rightFingerOffsets.Add(l_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReorientateTowards(Transform p_target, Transform p_targetEnd, Transform p_source, Transform p_sourceEnd, PlaneType p_plane)
|
||||
{
|
||||
if((p_target != null) && (p_targetEnd != null) && (p_source != null) && (p_sourceEnd != 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);
|
||||
switch(p_plane)
|
||||
{
|
||||
case PlaneType.OXZ:
|
||||
l_targetDir.y = 0f;
|
||||
l_sourceDir.y = 0f;
|
||||
break;
|
||||
case PlaneType.OYX:
|
||||
l_targetDir.z = 0f;
|
||||
l_sourceDir.z = 0f;
|
||||
break;
|
||||
}
|
||||
l_targetDir = Vector3.Normalize(l_targetDir);
|
||||
l_sourceDir = Vector3.Normalize(l_sourceDir);
|
||||
|
||||
Quaternion l_targetRot = Quaternion.identity;
|
||||
Quaternion l_sourceRot = Quaternion.identity;
|
||||
switch(p_plane)
|
||||
{
|
||||
case PlaneType.OXZ:
|
||||
l_targetRot = Quaternion.LookRotation(l_targetDir, Vector3.up);
|
||||
l_sourceRot = Quaternion.LookRotation(l_sourceDir, Vector3.up);
|
||||
break;
|
||||
case PlaneType.OYX:
|
||||
l_targetRot = Quaternion.LookRotation(l_targetDir, Vector3.forward);
|
||||
l_sourceRot = Quaternion.LookRotation(l_sourceDir, Vector3.forward);
|
||||
break;
|
||||
}
|
||||
|
||||
Quaternion l_diff = Quaternion.Inverse(l_targetRot) * l_sourceRot;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@ namespace ml_lme
|
|||
GameObject m_leapHands = null;
|
||||
LeapHand m_leapHandLeft = null;
|
||||
LeapHand m_leapHandRight = null;
|
||||
GameObject m_leapElbowLeft = null;
|
||||
GameObject m_leapElbowRight = null;
|
||||
Transform m_leapElbowLeft = null;
|
||||
Transform m_leapElbowRight = null;
|
||||
GameObject m_leapControllerModel = null;
|
||||
|
||||
float m_scaleRelation = 1f;
|
||||
|
@ -31,15 +31,15 @@ namespace ml_lme
|
|||
|
||||
m_inVR = Utils.IsInVR();
|
||||
|
||||
m_leapElbowLeft = new GameObject("LeapElbowLeft");
|
||||
m_leapElbowLeft.transform.parent = this.transform;
|
||||
m_leapElbowLeft.transform.localPosition = Vector3.zero;
|
||||
m_leapElbowLeft.transform.localRotation = Quaternion.identity;
|
||||
m_leapElbowLeft = new GameObject("LeapElbowLeft").transform;
|
||||
m_leapElbowLeft.parent = this.transform;
|
||||
m_leapElbowLeft.localPosition = Vector3.zero;
|
||||
m_leapElbowLeft.localRotation = Quaternion.identity;
|
||||
|
||||
m_leapElbowRight = new GameObject("LeapElbowRight");
|
||||
m_leapElbowRight.transform.parent = this.transform;
|
||||
m_leapElbowRight.transform.localPosition = Vector3.zero;
|
||||
m_leapElbowRight.transform.localRotation = Quaternion.identity;
|
||||
m_leapElbowRight = new GameObject("LeapElbowRight").transform;
|
||||
m_leapElbowRight.parent = this.transform;
|
||||
m_leapElbowRight.localPosition = Vector3.zero;
|
||||
m_leapElbowRight.localRotation = Quaternion.identity;
|
||||
|
||||
m_leapControllerModel = AssetsHandler.GetAsset("assets/models/leapmotion/leap_motion_1_0.obj");
|
||||
if(m_leapControllerModel != null)
|
||||
|
@ -101,11 +101,11 @@ namespace ml_lme
|
|||
m_leapHandRight = null;
|
||||
|
||||
if(m_leapElbowLeft != null)
|
||||
Object.Destroy(m_leapElbowLeft);
|
||||
Object.Destroy(m_leapElbowLeft.gameObject);
|
||||
m_leapElbowLeft = null;
|
||||
|
||||
if(m_leapElbowRight != null)
|
||||
Object.Destroy(m_leapElbowRight);
|
||||
Object.Destroy(m_leapElbowRight.gameObject);
|
||||
m_leapElbowRight = null;
|
||||
|
||||
if(m_leapControllerModel != null)
|
||||
|
@ -140,7 +140,7 @@ namespace ml_lme
|
|||
m_leapHandLeft.GetRoot().localRotation = l_data.m_leftHand.m_rotation;
|
||||
|
||||
OrientationAdjustment(ref l_data.m_leftHand.m_elbowPosition, ref ms_dummyRotation, Settings.TrackingMode);
|
||||
m_leapElbowLeft.transform.localPosition = l_data.m_leftHand.m_elbowPosition;
|
||||
m_leapElbowLeft.localPosition = l_data.m_leftHand.m_elbowPosition;
|
||||
|
||||
m_leapHandLeft?.Update(l_data.m_leftHand);
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ namespace ml_lme
|
|||
m_leapHandRight.GetRoot().localRotation = l_data.m_rightHand.m_rotation;
|
||||
|
||||
OrientationAdjustment(ref l_data.m_rightHand.m_elbowPosition, ref ms_dummyRotation, Settings.TrackingMode);
|
||||
m_leapElbowRight.transform.localPosition = l_data.m_rightHand.m_elbowPosition;
|
||||
m_leapElbowRight.localPosition = l_data.m_rightHand.m_elbowPosition;
|
||||
|
||||
m_leapHandRight?.Update(l_data.m_rightHand);
|
||||
}
|
||||
|
@ -164,8 +164,13 @@ namespace ml_lme
|
|||
|
||||
public LeapHand GetLeftHand() => m_leapHandLeft;
|
||||
public LeapHand GetRightHand() => m_leapHandRight;
|
||||
public Transform GetLeftElbow() => m_leapElbowLeft.transform;
|
||||
public Transform GetRightElbow() => m_leapElbowRight.transform;
|
||||
public Transform GetLeftElbow() => m_leapElbowLeft;
|
||||
public Transform GetRightElbow() => m_leapElbowRight;
|
||||
public void Rebind(Quaternion p_base)
|
||||
{
|
||||
m_leapHandLeft?.Rebind(p_base);
|
||||
m_leapHandRight?.Rebind(p_base);
|
||||
}
|
||||
|
||||
// Settings
|
||||
void OnDesktopOffsetChange(Vector3 p_offset)
|
||||
|
|
332
ml_lme/Main.cs
332
ml_lme/Main.cs
|
@ -1,166 +1,166 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_lme
|
||||
{
|
||||
|
||||
public class LeapMotionExtension : MelonLoader.MelonMod
|
||||
{
|
||||
static LeapMotionExtension ms_instance = null;
|
||||
|
||||
LeapManager m_leapManager = null;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
if(ms_instance == null)
|
||||
ms_instance = this;
|
||||
|
||||
DependenciesHandler.ExtractDependencies();
|
||||
Settings.Init();
|
||||
AssetsHandler.Load();
|
||||
|
||||
// Patches
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetControllerRayScale)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnRayScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod("SetPlaySpaceScale", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnPlayspaceScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
|
||||
typeof(CVRPickupObject).GetMethod(nameof(CVRPickupObject.Grab), BindingFlags.Public | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnPickupGrab_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
ModSupporter.Init();
|
||||
MelonLoader.MelonCoroutines.Start(WaitForRootLogic());
|
||||
}
|
||||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
if(m_leapManager != null)
|
||||
Object.Destroy(m_leapManager);
|
||||
m_leapManager = null;
|
||||
}
|
||||
|
||||
IEnumerator WaitForRootLogic()
|
||||
{
|
||||
while(ABI_RC.Core.RootLogic.Instance == null)
|
||||
yield return null;
|
||||
|
||||
m_leapManager = new GameObject("LeapMotionManager").AddComponent<LeapManager>();
|
||||
}
|
||||
|
||||
// Patches
|
||||
static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear();
|
||||
void OnAvatarClear()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_leapManager != null)
|
||||
m_leapManager.OnAvatarClear();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar();
|
||||
void OnSetupAvatar()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_leapManager != null)
|
||||
m_leapManager.OnAvatarSetup();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarReinitialize_Postfix() => ms_instance?.OnAvatarReinitialize();
|
||||
void OnAvatarReinitialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_leapManager != null)
|
||||
m_leapManager.OnAvatarReinitialize();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnRayScale_Postfix(float __0) => ms_instance?.OnRayScale(__0);
|
||||
void OnRayScale(float p_scale)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_leapManager != null)
|
||||
m_leapManager.OnRayScale(p_scale);
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnPlayspaceScale_Postfix(float ____avatarScaleRelation) => ms_instance?.OnPlayspaceScale(____avatarScaleRelation);
|
||||
void OnPlayspaceScale(float p_relation)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_leapManager != null)
|
||||
m_leapManager.OnPlayspaceScale(p_relation);
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnPickupGrab_Postfix(ref CVRPickupObject __instance) => ms_instance?.OnPickupGrab(__instance);
|
||||
void OnPickupGrab(CVRPickupObject p_pickup)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_leapManager != null)
|
||||
m_leapManager.OnPickupGrab(p_pickup);
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_lme
|
||||
{
|
||||
|
||||
public class LeapMotionExtension : MelonLoader.MelonMod
|
||||
{
|
||||
static LeapMotionExtension ms_instance = null;
|
||||
|
||||
LeapManager m_leapManager = null;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
if(ms_instance == null)
|
||||
ms_instance = this;
|
||||
|
||||
DependenciesHandler.ExtractDependencies();
|
||||
Settings.Init();
|
||||
AssetsHandler.Load();
|
||||
|
||||
// Patches
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetControllerRayScale)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnRayScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod("SetPlaySpaceScale", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnPlayspaceScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
|
||||
typeof(CVRPickupObject).GetMethod(nameof(CVRPickupObject.Grab), BindingFlags.Public | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(LeapMotionExtension).GetMethod(nameof(OnPickupGrab_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
ModSupporter.Init();
|
||||
MelonLoader.MelonCoroutines.Start(WaitForRootLogic());
|
||||
}
|
||||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
if(m_leapManager != null)
|
||||
Object.Destroy(m_leapManager);
|
||||
m_leapManager = null;
|
||||
}
|
||||
|
||||
IEnumerator WaitForRootLogic()
|
||||
{
|
||||
while(ABI_RC.Core.RootLogic.Instance == null)
|
||||
yield return null;
|
||||
|
||||
m_leapManager = new GameObject("LeapMotionManager").AddComponent<LeapManager>();
|
||||
}
|
||||
|
||||
// Patches
|
||||
static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear();
|
||||
void OnAvatarClear()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_leapManager != null)
|
||||
m_leapManager.OnAvatarClear();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar();
|
||||
void OnSetupAvatar()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_leapManager != null)
|
||||
m_leapManager.OnAvatarSetup();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarReinitialize_Postfix() => ms_instance?.OnAvatarReinitialize();
|
||||
void OnAvatarReinitialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_leapManager != null)
|
||||
m_leapManager.OnAvatarReinitialize();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnRayScale_Postfix(float __0) => ms_instance?.OnRayScale(__0);
|
||||
void OnRayScale(float p_scale)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_leapManager != null)
|
||||
m_leapManager.OnRayScale(p_scale);
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnPlayspaceScale_Postfix(float ____avatarScaleRelation) => ms_instance?.OnPlayspaceScale(____avatarScaleRelation);
|
||||
void OnPlayspaceScale(float p_relation)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_leapManager != null)
|
||||
m_leapManager.OnPlayspaceScale(p_relation);
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnPickupGrab_Postfix(ref CVRPickupObject __instance) => ms_instance?.OnPickupGrab(__instance);
|
||||
void OnPickupGrab(CVRPickupObject p_pickup)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_leapManager != null)
|
||||
m_leapManager.OnPickupGrab(p_pickup);
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
using UnityEngine;
|
||||
using ABI_RC.Systems.IK;
|
||||
|
||||
namespace ml_lme
|
||||
{
|
||||
static class PoseHelper
|
||||
{
|
||||
public static void ForceTPose(Animator p_animator)
|
||||
{
|
||||
if(p_animator.isHuman)
|
||||
{
|
||||
HumanPoseHandler l_handler = new HumanPoseHandler(p_animator.avatar, p_animator.transform);
|
||||
HumanPose l_pose = new HumanPose();
|
||||
l_handler.GetHumanPose(ref l_pose);
|
||||
|
||||
for(int i=0, j = Mathf.Min(l_pose.muscles.Length,MusclePoses.TPoseMuscles.Length); i < j; i++)
|
||||
l_pose.muscles[i] = MusclePoses.TPoseMuscles[i];
|
||||
|
||||
l_pose.bodyPosition = Vector3.up;
|
||||
l_pose.bodyRotation = Quaternion.identity;
|
||||
l_handler.SetHumanPose(ref l_pose);
|
||||
l_handler.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.4.6-ex", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.4.7", "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)]
|
||||
|
|
|
@ -25,3 +25,5 @@ Available mod's settings in `Settings - Implementation - Leap Motion Tracking`:
|
|||
* **Recognize gestures:** sets avatar gestures (fist, gun, rock'n'roll and etc.) based on current fingers pose; `false` by default.
|
||||
* **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.
|
||||
|
|
|
@ -35,7 +35,8 @@ namespace ml_lme
|
|||
Gestures,
|
||||
InteractThreadhold,
|
||||
GripThreadhold,
|
||||
VisualHands
|
||||
VisualHands,
|
||||
MechanimFilter
|
||||
};
|
||||
|
||||
public static bool Enabled { get; private set; } = false;
|
||||
|
@ -52,24 +53,26 @@ namespace ml_lme
|
|||
public static float InteractThreadhold { get; private set; } = 0.8f;
|
||||
public static float GripThreadhold { get; private set; } = 0.4f;
|
||||
public static bool VisualHands { get; private set; } = false;
|
||||
public static bool MechanimFilter { get; private set; } = true;
|
||||
|
||||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
||||
static public event Action<bool> EnabledChange;
|
||||
static public event Action<Vector3> DesktopOffsetChange;
|
||||
static public event Action<bool> FingersOnlyChange;
|
||||
static public event Action<bool> ModelVisibilityChange;
|
||||
static public event Action<LeapTrackingMode> TrackingModeChange;
|
||||
static public event Action<Vector3> RootAngleChange;
|
||||
static public event Action<bool> HeadAttachChange;
|
||||
static public event Action<Vector3> HeadOffsetChange;
|
||||
static public event Action<bool> TrackElbowsChange;
|
||||
static public event Action<bool> InteractionChange;
|
||||
static public event Action<bool> GesturesChange;
|
||||
static public event Action<float> InteractThreadholdChange;
|
||||
static public event Action<float> GripThreadholdChange;
|
||||
static public event Action<bool> VisualHandsChange;
|
||||
public static event Action<bool> EnabledChange;
|
||||
public static event Action<Vector3> DesktopOffsetChange;
|
||||
public static event Action<bool> FingersOnlyChange;
|
||||
public static event Action<bool> ModelVisibilityChange;
|
||||
public static event Action<LeapTrackingMode> TrackingModeChange;
|
||||
public static event Action<Vector3> RootAngleChange;
|
||||
public static event Action<bool> HeadAttachChange;
|
||||
public static event Action<Vector3> HeadOffsetChange;
|
||||
public static event Action<bool> TrackElbowsChange;
|
||||
public static event Action<bool> InteractionChange;
|
||||
public static event Action<bool> GesturesChange;
|
||||
public static event Action<float> InteractThreadholdChange;
|
||||
public static event Action<float> GripThreadholdChange;
|
||||
public static event Action<bool> VisualHandsChange;
|
||||
public static event Action<bool> MechanimFilterChange;
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
|
@ -96,7 +99,8 @@ namespace ml_lme
|
|||
ms_category.CreateEntry(ModSetting.Gestures.ToString(), Gestures),
|
||||
ms_category.CreateEntry(ModSetting.InteractThreadhold.ToString(), (int)(InteractThreadhold * 100f)),
|
||||
ms_category.CreateEntry(ModSetting.GripThreadhold.ToString(), (int)(GripThreadhold * 100f)),
|
||||
ms_category.CreateEntry(ModSetting.VisualHands.ToString(), VisualHands)
|
||||
ms_category.CreateEntry(ModSetting.VisualHands.ToString(), VisualHands),
|
||||
ms_category.CreateEntry(ModSetting.MechanimFilter.ToString(), MechanimFilter)
|
||||
};
|
||||
|
||||
Load();
|
||||
|
@ -156,6 +160,7 @@ namespace ml_lme
|
|||
InteractThreadhold = (int)ms_entries[(int)ModSetting.InteractThreadhold].BoxedValue * 0.01f;
|
||||
GripThreadhold = (int)ms_entries[(int)ModSetting.GripThreadhold].BoxedValue * 0.01f;
|
||||
VisualHands = (bool)ms_entries[(int)ModSetting.VisualHands].BoxedValue;
|
||||
MechanimFilter = (bool)ms_entries[(int)ModSetting.MechanimFilter].BoxedValue;
|
||||
}
|
||||
|
||||
static void OnToggleUpdate(string p_name, string p_value)
|
||||
|
@ -219,6 +224,13 @@ namespace ml_lme
|
|||
VisualHandsChange?.Invoke(VisualHands);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModSetting.MechanimFilter:
|
||||
{
|
||||
MechanimFilter = bool.Parse(p_value);
|
||||
MechanimFilterChange?.Invoke(MechanimFilter);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using ABI_RC.Core.InteractionSystem;
|
||||
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;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
@ -49,7 +51,14 @@ namespace ml_lme
|
|||
}
|
||||
}
|
||||
|
||||
static public void ExecuteScript(this CohtmlControlledViewWrapper p_instance, string p_script) => ((cohtml.Net.View)ms_view.GetValue(p_instance)).ExecuteScript(p_script);
|
||||
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()
|
||||
{
|
||||
IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose);
|
||||
PlayerSetup.Instance._avatar.transform.localPosition = Vector3.zero;
|
||||
PlayerSetup.Instance._avatar.transform.localRotation = Quaternion.identity;
|
||||
}
|
||||
|
||||
public static void Swap<T>(ref T lhs, ref T rhs)
|
||||
{
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
<PackageId>LeapMotionExtension</PackageId>
|
||||
<Version>1.4.6</Version>
|
||||
<Version>1.4.7</Version>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>LeapMotionExtension</Product>
|
||||
|
|
|
@ -145,6 +145,13 @@
|
|||
<div id="GripThreadhold" class ="inp_slider no-scroll" data-min="0" data-max="100" data-current="40"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class ="row-wrapper">
|
||||
<div class ="option-caption">Filter humanoid limits: </div>
|
||||
<div class ="option-input">
|
||||
<div id="MechanimFilter" class ="inp_toggle no-scroll" data-current="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
document.getElementById('settings-implementation').appendChild(l_block);
|
||||
|
||||
|
|
|
@ -24,6 +24,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_pin", "ml_pin\ml_pin.csp
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_dht", "ml_dht\ml_dht.csproj", "{31987392-989C-40C1-A48B-7F6099816EBE}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_bft", "ml_bft\ml_bft.csproj", "{331C995D-9648-44AD-8B02-D5F3A89FDC1F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
|
@ -60,6 +62,9 @@ Global
|
|||
{31987392-989C-40C1-A48B-7F6099816EBE}.Debug|x64.Build.0 = Debug|x64
|
||||
{31987392-989C-40C1-A48B-7F6099816EBE}.Release|x64.ActiveCfg = Release|x64
|
||||
{31987392-989C-40C1-A48B-7F6099816EBE}.Release|x64.Build.0 = Release|x64
|
||||
{331C995D-9648-44AD-8B02-D5F3A89FDC1F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{331C995D-9648-44AD-8B02-D5F3A89FDC1F}.Release|x64.ActiveCfg = Release|x64
|
||||
{331C995D-9648-44AD-8B02-D5F3A89FDC1F}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -332,8 +332,7 @@ namespace ml_pam
|
|||
|
||||
if(PlayerSetup.Instance._animator.isHuman)
|
||||
{
|
||||
if(!m_inVR)
|
||||
PoseHelper.ForceTPose(PlayerSetup.Instance._animator);
|
||||
Utils.SetAvatarTPose();
|
||||
|
||||
Transform l_leftHand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand);
|
||||
if(l_leftHand != null)
|
||||
|
|
320
ml_pam/Main.cs
320
ml_pam/Main.cs
|
@ -1,160 +1,160 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.InteractionSystem;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_pam
|
||||
{
|
||||
public class PickupArmMovement : MelonLoader.MelonMod
|
||||
{
|
||||
static PickupArmMovement ms_instance = null;
|
||||
|
||||
ArmMover m_localMover = null;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
if(ms_instance == null)
|
||||
ms_instance = this;
|
||||
|
||||
Settings.Init();
|
||||
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRPickupObject).GetMethod(nameof(CVRPickupObject.Grab)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnCVRPickupObjectGrab_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRPickupObject).GetMethod(nameof(CVRPickupObject.Drop)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnCVRPickupObjectDrop_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod("SetPlaySpaceScale", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnPlayspaceScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator WaitForLocalPlayer()
|
||||
{
|
||||
while(PlayerSetup.Instance == null)
|
||||
yield return null;
|
||||
|
||||
m_localMover = PlayerSetup.Instance.gameObject.AddComponent<ArmMover>();
|
||||
}
|
||||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
if(m_localMover != null)
|
||||
UnityEngine.Object.Destroy(m_localMover);
|
||||
m_localMover = null;
|
||||
}
|
||||
|
||||
static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear();
|
||||
void OnAvatarClear()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localMover != null)
|
||||
m_localMover.OnAvatarClear();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar();
|
||||
void OnSetupAvatar()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localMover != null)
|
||||
m_localMover.OnAvatarSetup();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarReinitialize_Postfix() => ms_instance?.OnAvatarReinitialize();
|
||||
void OnAvatarReinitialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localMover != null)
|
||||
m_localMover.OnAvatarReinitialize();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCVRPickupObjectGrab_Postfix(ref CVRPickupObject __instance, ControllerRay __1, Vector3 __2) => ms_instance?.OnCVRPickupObjectGrab(__instance, __1, __2);
|
||||
void OnCVRPickupObjectGrab(CVRPickupObject p_pickup, ControllerRay p_ray, Vector3 p_hit)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(p_pickup.IsGrabbedByMe() && (m_localMover != null))
|
||||
m_localMover.OnPickupGrab(p_pickup, p_ray, p_hit);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCVRPickupObjectDrop_Postfix(ref CVRPickupObject __instance) => ms_instance?.OnCVRPickupObjectDrop(__instance);
|
||||
void OnCVRPickupObjectDrop(CVRPickupObject p_pickup)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localMover != null)
|
||||
m_localMover.OnPickupDrop(p_pickup);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnPlayspaceScale_Postfix(float ____avatarScaleRelation) => ms_instance?.OnPlayspaceScale(____avatarScaleRelation);
|
||||
void OnPlayspaceScale(float p_relation)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localMover != null)
|
||||
m_localMover.OnPlayspaceScale(p_relation);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.InteractionSystem;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Systems.IK;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_pam
|
||||
{
|
||||
public class PickupArmMovement : MelonLoader.MelonMod
|
||||
{
|
||||
static PickupArmMovement ms_instance = null;
|
||||
|
||||
ArmMover m_localMover = null;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
if(ms_instance == null)
|
||||
ms_instance = this;
|
||||
|
||||
Settings.Init();
|
||||
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnAvatarClear_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnSetupAvatar_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(IKSystem).GetMethod(nameof(IKSystem.ReinitializeAvatar), BindingFlags.Instance | BindingFlags.Public),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnAvatarReinitialize_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRPickupObject).GetMethod(nameof(CVRPickupObject.Grab)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnCVRPickupObjectGrab_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRPickupObject).GetMethod(nameof(CVRPickupObject.Drop)),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnCVRPickupObjectDrop_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod("SetPlaySpaceScale", BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
null,
|
||||
new HarmonyLib.HarmonyMethod(typeof(PickupArmMovement).GetMethod(nameof(OnPlayspaceScale_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
|
||||
);
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator WaitForLocalPlayer()
|
||||
{
|
||||
while(PlayerSetup.Instance == null)
|
||||
yield return null;
|
||||
|
||||
m_localMover = PlayerSetup.Instance.gameObject.AddComponent<ArmMover>();
|
||||
}
|
||||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
if(ms_instance == this)
|
||||
ms_instance = null;
|
||||
|
||||
if(m_localMover != null)
|
||||
UnityEngine.Object.Destroy(m_localMover);
|
||||
m_localMover = null;
|
||||
}
|
||||
|
||||
static void OnAvatarClear_Postfix() => ms_instance?.OnAvatarClear();
|
||||
void OnAvatarClear()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localMover != null)
|
||||
m_localMover.OnAvatarClear();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSetupAvatar_Postfix() => ms_instance?.OnSetupAvatar();
|
||||
void OnSetupAvatar()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localMover != null)
|
||||
m_localMover.OnAvatarSetup();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnAvatarReinitialize_Postfix() => ms_instance?.OnAvatarReinitialize();
|
||||
void OnAvatarReinitialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localMover != null)
|
||||
m_localMover.OnAvatarReinitialize();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCVRPickupObjectGrab_Postfix(ref CVRPickupObject __instance, ControllerRay __1, Vector3 __2) => ms_instance?.OnCVRPickupObjectGrab(__instance, __1, __2);
|
||||
void OnCVRPickupObjectGrab(CVRPickupObject p_pickup, ControllerRay p_ray, Vector3 p_hit)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(p_pickup.IsGrabbedByMe() && (m_localMover != null))
|
||||
m_localMover.OnPickupGrab(p_pickup, p_ray, p_hit);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCVRPickupObjectDrop_Postfix(ref CVRPickupObject __instance) => ms_instance?.OnCVRPickupObjectDrop(__instance);
|
||||
void OnCVRPickupObjectDrop(CVRPickupObject p_pickup)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localMover != null)
|
||||
m_localMover.OnPickupDrop(p_pickup);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnPlayspaceScale_Postfix(float ____avatarScaleRelation) => ms_instance?.OnPlayspaceScale(____avatarScaleRelation);
|
||||
void OnPlayspaceScale(float p_relation)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(m_localMover != null)
|
||||
m_localMover.OnPlayspaceScale(p_relation);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
using UnityEngine;
|
||||
using ABI_RC.Systems.IK;
|
||||
|
||||
namespace ml_pam
|
||||
{
|
||||
static class PoseHelper
|
||||
{
|
||||
public static void ForceTPose(Animator p_animator)
|
||||
{
|
||||
if(p_animator.isHuman)
|
||||
{
|
||||
HumanPoseHandler l_handler = new HumanPoseHandler(p_animator.avatar, p_animator.transform);
|
||||
HumanPose l_pose = new HumanPose();
|
||||
l_handler.GetHumanPose(ref l_pose);
|
||||
|
||||
for(int i = 0, j = Mathf.Min(l_pose.muscles.Length, MusclePoses.TPoseMuscles.Length); i < j; i++)
|
||||
l_pose.muscles[i] = MusclePoses.TPoseMuscles[i];
|
||||
|
||||
l_pose.bodyPosition = Vector3.up;
|
||||
l_pose.bodyRotation = Quaternion.identity;
|
||||
l_handler.SetHumanPose(ref l_pose);
|
||||
l_handler.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_pam.PickupArmMovement), "PickupArmMovement", "1.1.0-ex", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_pam.PickupArmMovement), "PickupArmMovement", "1.1.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)]
|
||||
|
|
|
@ -28,10 +28,10 @@ namespace ml_pam
|
|||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
||||
static public event Action<bool> EnabledChange;
|
||||
static public event Action<float> GrabOffsetChange;
|
||||
static public event Action<LeadHand> LeadingHandChange;
|
||||
static public event Action<bool> HandsExtensionChange;
|
||||
public static event Action<bool> EnabledChange;
|
||||
public static event Action<float> GrabOffsetChange;
|
||||
public static event Action<LeadHand> LeadingHandChange;
|
||||
public static event Action<bool> HandsExtensionChange;
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
|
|
|
@ -1,22 +1,31 @@
|
|||
using ABI_RC.Core.Savior;
|
||||
using ABI_RC.Core.UI;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_pam
|
||||
{
|
||||
static class Utils
|
||||
{
|
||||
static readonly FieldInfo ms_view = typeof(CohtmlControlledViewWrapper).GetField("_view", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
public static bool IsInVR() => ((MetaPort.Instance != null) && MetaPort.Instance.isUsingVr);
|
||||
|
||||
static public 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Savior;
|
||||
using ABI_RC.Core.UI;
|
||||
using ABI_RC.Systems.IK;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ml_pam
|
||||
{
|
||||
static class Utils
|
||||
{
|
||||
static readonly FieldInfo ms_view = typeof(CohtmlControlledViewWrapper).GetField("_view", 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 SetAvatarTPose()
|
||||
{
|
||||
IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose);
|
||||
PlayerSetup.Instance._avatar.transform.localPosition = Vector3.zero;
|
||||
PlayerSetup.Instance._avatar.transform.localRotation = Quaternion.identity;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<DebugType>none</DebugType>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
<DebugType>embedded</DebugType>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
226
ml_pin/Main.cs
226
ml_pin/Main.cs
|
@ -1,113 +1,113 @@
|
|||
using ABI_RC.Core.AudioEffects;
|
||||
using ABI_RC.Core.Networking.IO.Social;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Savior;
|
||||
using ABI_RC.Systems.GameEventSystem;
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace ml_pin
|
||||
{
|
||||
public class PlayersInstanceNotifier : MelonLoader.MelonMod
|
||||
{
|
||||
SoundManager m_soundManager = null;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
Settings.Init();
|
||||
ResourcesHandler.ExtractAudioResources();
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForInstances());
|
||||
}
|
||||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
m_soundManager = null;
|
||||
}
|
||||
|
||||
IEnumerator WaitForInstances()
|
||||
{
|
||||
if(InterfaceAudio.Instance == null)
|
||||
yield return null;
|
||||
|
||||
m_soundManager = new SoundManager();
|
||||
m_soundManager.LoadSounds();
|
||||
|
||||
CVRGameEventSystem.Player.OnJoin.AddListener(OnPlayerJoin);
|
||||
CVRGameEventSystem.Player.OnLeave.AddListener(OnPlayerLeave);
|
||||
}
|
||||
|
||||
void OnPlayerJoin(PlayerDescriptor p_player)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(p_player != null) // This happens sometimes, no idea why
|
||||
{
|
||||
bool l_isFriend = Friends.FriendsWith(p_player.ownerId);
|
||||
bool l_notify = false;
|
||||
|
||||
switch(Settings.NotifyType)
|
||||
{
|
||||
case Settings.NotificationType.None:
|
||||
l_notify = false;
|
||||
break;
|
||||
case Settings.NotificationType.Friends:
|
||||
l_notify = (l_isFriend && ShouldNotifyInCurrentInstance());
|
||||
break;
|
||||
case Settings.NotificationType.All:
|
||||
l_notify = ShouldNotifyInCurrentInstance();
|
||||
break;
|
||||
}
|
||||
l_notify |= (l_isFriend && Settings.FriendsAlways);
|
||||
|
||||
if(l_notify)
|
||||
m_soundManager?.PlaySound(l_isFriend ? SoundManager.SoundType.FriendJoin : SoundManager.SoundType.PlayerJoin);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Warning(e);
|
||||
}
|
||||
}
|
||||
void OnPlayerLeave(PlayerDescriptor p_player)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(p_player != null) // This happens sometimes, no idea why
|
||||
{
|
||||
bool l_isFriend = Friends.FriendsWith(p_player.ownerId);
|
||||
bool l_notify = false;
|
||||
|
||||
switch(Settings.NotifyType)
|
||||
{
|
||||
case Settings.NotificationType.None:
|
||||
l_notify = false;
|
||||
break;
|
||||
case Settings.NotificationType.Friends:
|
||||
l_notify = (l_isFriend && ShouldNotifyInCurrentInstance());
|
||||
break;
|
||||
case Settings.NotificationType.All:
|
||||
l_notify = ShouldNotifyInCurrentInstance();
|
||||
break;
|
||||
}
|
||||
l_notify |= (l_isFriend && Settings.FriendsAlways);
|
||||
|
||||
if(l_notify)
|
||||
m_soundManager?.PlaySound(l_isFriend ? SoundManager.SoundType.FriendLeave : SoundManager.SoundType.PlayerLeave);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Warning(e);
|
||||
}
|
||||
}
|
||||
|
||||
bool ShouldNotifyInCurrentInstance()
|
||||
{
|
||||
bool l_isInPublic = (MetaPort.Instance.CurrentInstancePrivacy.Contains("Public") && Settings.NotifyInPublic);
|
||||
bool l_isInFriends = (MetaPort.Instance.CurrentInstancePrivacy.Contains("Friends") && Settings.NotifyInFriends);
|
||||
bool l_isInPrivate = (MetaPort.Instance.CurrentInstancePrivacy.Contains("invite") && Settings.NotifyInPrivate);
|
||||
return (l_isInPublic || l_isInFriends || l_isInPrivate);
|
||||
}
|
||||
}
|
||||
}
|
||||
using ABI_RC.Core.AudioEffects;
|
||||
using ABI_RC.Core.Networking.IO.Social;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Savior;
|
||||
using ABI_RC.Systems.GameEventSystem;
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace ml_pin
|
||||
{
|
||||
public class PlayersInstanceNotifier : MelonLoader.MelonMod
|
||||
{
|
||||
SoundManager m_soundManager = null;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
Settings.Init();
|
||||
ResourcesHandler.ExtractAudioResources();
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForInstances());
|
||||
}
|
||||
|
||||
public override void OnDeinitializeMelon()
|
||||
{
|
||||
m_soundManager = null;
|
||||
}
|
||||
|
||||
IEnumerator WaitForInstances()
|
||||
{
|
||||
if(InterfaceAudio.Instance == null)
|
||||
yield return null;
|
||||
|
||||
m_soundManager = new SoundManager();
|
||||
m_soundManager.LoadSounds();
|
||||
|
||||
CVRGameEventSystem.Player.OnJoin.AddListener(OnPlayerJoin);
|
||||
CVRGameEventSystem.Player.OnLeave.AddListener(OnPlayerLeave);
|
||||
}
|
||||
|
||||
void OnPlayerJoin(PlayerDescriptor p_player)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(p_player != null) // This happens sometimes, no idea why
|
||||
{
|
||||
bool l_isFriend = Friends.FriendsWith(p_player.ownerId);
|
||||
bool l_notify = false;
|
||||
|
||||
switch(Settings.NotifyType)
|
||||
{
|
||||
case Settings.NotificationType.None:
|
||||
l_notify = false;
|
||||
break;
|
||||
case Settings.NotificationType.Friends:
|
||||
l_notify = (l_isFriend && ShouldNotifyInCurrentInstance());
|
||||
break;
|
||||
case Settings.NotificationType.All:
|
||||
l_notify = ShouldNotifyInCurrentInstance();
|
||||
break;
|
||||
}
|
||||
l_notify |= (l_isFriend && Settings.FriendsAlways);
|
||||
|
||||
if(l_notify)
|
||||
m_soundManager?.PlaySound(l_isFriend ? SoundManager.SoundType.FriendJoin : SoundManager.SoundType.PlayerJoin);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Warning(e);
|
||||
}
|
||||
}
|
||||
void OnPlayerLeave(PlayerDescriptor p_player)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(p_player != null) // This happens sometimes, no idea why
|
||||
{
|
||||
bool l_isFriend = Friends.FriendsWith(p_player.ownerId);
|
||||
bool l_notify = false;
|
||||
|
||||
switch(Settings.NotifyType)
|
||||
{
|
||||
case Settings.NotificationType.None:
|
||||
l_notify = false;
|
||||
break;
|
||||
case Settings.NotificationType.Friends:
|
||||
l_notify = (l_isFriend && ShouldNotifyInCurrentInstance());
|
||||
break;
|
||||
case Settings.NotificationType.All:
|
||||
l_notify = ShouldNotifyInCurrentInstance();
|
||||
break;
|
||||
}
|
||||
l_notify |= (l_isFriend && Settings.FriendsAlways);
|
||||
|
||||
if(l_notify)
|
||||
m_soundManager?.PlaySound(l_isFriend ? SoundManager.SoundType.FriendLeave : SoundManager.SoundType.PlayerLeave);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Warning(e);
|
||||
}
|
||||
}
|
||||
|
||||
bool ShouldNotifyInCurrentInstance()
|
||||
{
|
||||
bool l_isInPublic = (MetaPort.Instance.CurrentInstancePrivacy.Contains("Public") && Settings.NotifyInPublic);
|
||||
bool l_isInFriends = (MetaPort.Instance.CurrentInstancePrivacy.Contains("Friends") && Settings.NotifyInFriends);
|
||||
bool l_isInPrivate = (MetaPort.Instance.CurrentInstancePrivacy.Contains("invite") && Settings.NotifyInPrivate);
|
||||
return (l_isInPublic || l_isInFriends || l_isInPrivate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_pin.PlayersInstanceNotifier), "PlayersInstanceNotifier", "1.0.2-ex", "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)]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_pin.PlayersInstanceNotifier), "PlayersInstanceNotifier", "1.0.2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
||||
|
|
|
@ -33,12 +33,12 @@ namespace ml_pin
|
|||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
||||
static public event Action<NotificationType> NotifyTypeChange;
|
||||
static public event Action<float> VolumeChange;
|
||||
static public event Action<bool> NotifyInPublicChange;
|
||||
static public event Action<bool> NotifyInFriendsChange;
|
||||
static public event Action<bool> NotifyInPrivateChange;
|
||||
static public event Action<bool> FriendsAlwaysChange;
|
||||
public static event Action<NotificationType> NotifyTypeChange;
|
||||
public static event Action<float> VolumeChange;
|
||||
public static event Action<bool> NotifyInPublicChange;
|
||||
public static event Action<bool> NotifyInFriendsChange;
|
||||
public static event Action<bool> NotifyInPrivateChange;
|
||||
public static event Action<bool> FriendsAlwaysChange;
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
|
|
|
@ -7,6 +7,6 @@ namespace ml_pin
|
|||
{
|
||||
static readonly FieldInfo ms_view = typeof(CohtmlControlledViewWrapper).GetField("_view", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
static public void ExecuteScript(this CohtmlControlledViewWrapper p_instance, string p_script) => ((cohtml.Net.View)ms_view.GetValue(p_instance)).ExecuteScript(p_script);
|
||||
public static void ExecuteScript(this CohtmlControlledViewWrapper p_instance, string p_script) => ((cohtml.Net.View)ms_view.GetValue(p_instance)).ExecuteScript(p_script);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,86 +1,91 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
<PackageId>PlayersInstanceNotifier</PackageId>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>PlayersInstanceNotifier</Product>
|
||||
<Version>1.0.2</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="resources\Chime.wav" />
|
||||
<None Remove="resources\DoorClose.wav" />
|
||||
<None Remove="resources\mod_menu.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="resources\Chime.wav" />
|
||||
<EmbeddedResource Include="resources\DoorClose.wav" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="..\js\mods_extension.js" Link="resources\mods_extension.js" />
|
||||
<EmbeddedResource Include="resources\mod_menu.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\0Harmony.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="cohtml.Net">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\cohtml.Net.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Cohtml.Runtime">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="MelonLoader">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\MelonLoader.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>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.AudioModule">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AudioModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UnityWebRequestAudioModule">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.UnityWebRequestAudioModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UnityWebRequestModule">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.UnityWebRequestModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\"" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
<PackageId>PlayersInstanceNotifier</PackageId>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>PlayersInstanceNotifier</Product>
|
||||
<Version>1.0.2</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<DebugType>embedded</DebugType>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="resources\Chime.wav" />
|
||||
<None Remove="resources\DoorClose.wav" />
|
||||
<None Remove="resources\mod_menu.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="resources\Chime.wav" />
|
||||
<EmbeddedResource Include="resources\DoorClose.wav" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="..\js\mods_extension.js" Link="resources\mods_extension.js" />
|
||||
<EmbeddedResource Include="resources\mod_menu.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\0Harmony.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="cohtml.Net">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\cohtml.Net.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Cohtml.Runtime">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="MelonLoader">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\MelonLoader.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>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.AudioModule">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AudioModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UnityWebRequestAudioModule">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.UnityWebRequestAudioModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UnityWebRequestModule">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.UnityWebRequestModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\"" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -3,7 +3,6 @@ using ABI_RC.Systems.IK;
|
|||
using ABI_RC.Systems.IK.SubSystems;
|
||||
using ABI_RC.Systems.InputManagement;
|
||||
using ABI_RC.Systems.Movement;
|
||||
using ABI_RC.Systems.VRModeSwitch;
|
||||
using RootMotion.FinalIK;
|
||||
using UnityEngine;
|
||||
|
||||
|
@ -14,8 +13,8 @@ namespace ml_pmc
|
|||
{
|
||||
static readonly Vector4 ms_pointVector = new Vector4(0f, 0f, 0f, 1f);
|
||||
|
||||
static public PoseCopycat Instance { get; private set; } = null;
|
||||
static internal System.Action<bool> OnActivityChange;
|
||||
public static PoseCopycat Instance { get; private set; } = null;
|
||||
internal static System.Action<bool> OnActivityChange;
|
||||
|
||||
Animator m_animator = null;
|
||||
VRIK m_vrIk = null;
|
||||
|
@ -372,29 +371,29 @@ namespace ml_pmc
|
|||
if(!CVRInputManager.Instance.individualFingerTracking)
|
||||
{
|
||||
// Left hand
|
||||
CVRInputManager.Instance.finger1StretchedLeftThumb = -0.5f;
|
||||
CVRInputManager.Instance.finger2StretchedLeftThumb = 0.7f;
|
||||
CVRInputManager.Instance.finger3StretchedLeftThumb = 0.7f;
|
||||
CVRInputManager.Instance.finger1StretchedLeftThumb = -0f;
|
||||
CVRInputManager.Instance.finger2StretchedLeftThumb = 0f;
|
||||
CVRInputManager.Instance.finger3StretchedLeftThumb = 0f;
|
||||
CVRInputManager.Instance.fingerSpreadLeftThumb = 0f;
|
||||
|
||||
CVRInputManager.Instance.finger1StretchedLeftIndex = 0.5f;
|
||||
CVRInputManager.Instance.finger2StretchedLeftIndex = 0.7f;
|
||||
CVRInputManager.Instance.finger3StretchedLeftIndex = 0.7f;
|
||||
CVRInputManager.Instance.finger1StretchedLeftIndex = 0f;
|
||||
CVRInputManager.Instance.finger2StretchedLeftIndex = 0f;
|
||||
CVRInputManager.Instance.finger3StretchedLeftIndex = 0f;
|
||||
CVRInputManager.Instance.fingerSpreadLeftIndex = 0f;
|
||||
|
||||
CVRInputManager.Instance.finger1StretchedLeftMiddle = 0.5f;
|
||||
CVRInputManager.Instance.finger2StretchedLeftMiddle = 0.7f;
|
||||
CVRInputManager.Instance.finger3StretchedLeftMiddle = 0.7f;
|
||||
CVRInputManager.Instance.finger1StretchedLeftMiddle = 0;
|
||||
CVRInputManager.Instance.finger2StretchedLeftMiddle = 0f;
|
||||
CVRInputManager.Instance.finger3StretchedLeftMiddle = 0f;
|
||||
CVRInputManager.Instance.fingerSpreadLeftMiddle = 0f;
|
||||
|
||||
CVRInputManager.Instance.finger1StretchedLeftRing = 0.5f;
|
||||
CVRInputManager.Instance.finger2StretchedLeftRing = 0.7f;
|
||||
CVRInputManager.Instance.finger3StretchedLeftRing = 0.7f;
|
||||
CVRInputManager.Instance.finger1StretchedLeftRing = 0f;
|
||||
CVRInputManager.Instance.finger2StretchedLeftRing = 0f;
|
||||
CVRInputManager.Instance.finger3StretchedLeftRing = 0f;
|
||||
CVRInputManager.Instance.fingerSpreadLeftRing = 0f;
|
||||
|
||||
CVRInputManager.Instance.finger1StretchedLeftPinky = 0.5f;
|
||||
CVRInputManager.Instance.finger2StretchedLeftPinky = 0.7f;
|
||||
CVRInputManager.Instance.finger3StretchedLeftPinky = 0.7f;
|
||||
CVRInputManager.Instance.finger1StretchedLeftPinky = 0f;
|
||||
CVRInputManager.Instance.finger2StretchedLeftPinky = 0f;
|
||||
CVRInputManager.Instance.finger3StretchedLeftPinky = 0f;
|
||||
CVRInputManager.Instance.fingerSpreadLeftPinky = 0f;
|
||||
|
||||
CVRInputManager.Instance.fingerFullCurlNormalizedLeftThumb = 0f;
|
||||
|
@ -404,29 +403,29 @@ namespace ml_pmc
|
|||
CVRInputManager.Instance.fingerFullCurlNormalizedLeftPinky = 0f;
|
||||
|
||||
// Right hand
|
||||
CVRInputManager.Instance.finger1StretchedRightThumb = -0.5f;
|
||||
CVRInputManager.Instance.finger2StretchedRightThumb = 0.7f;
|
||||
CVRInputManager.Instance.finger3StretchedRightThumb = 0.7f;
|
||||
CVRInputManager.Instance.finger1StretchedRightThumb = 0f;
|
||||
CVRInputManager.Instance.finger2StretchedRightThumb = 0f;
|
||||
CVRInputManager.Instance.finger3StretchedRightThumb = 0f;
|
||||
CVRInputManager.Instance.fingerSpreadRightThumb = 0f;
|
||||
|
||||
CVRInputManager.Instance.finger1StretchedRightIndex = 0.5f;
|
||||
CVRInputManager.Instance.finger2StretchedRightIndex = 0.7f;
|
||||
CVRInputManager.Instance.finger3StretchedRightIndex = 0.7f;
|
||||
CVRInputManager.Instance.finger1StretchedRightIndex = 0f;
|
||||
CVRInputManager.Instance.finger2StretchedRightIndex = 0f;
|
||||
CVRInputManager.Instance.finger3StretchedRightIndex = 0f;
|
||||
CVRInputManager.Instance.fingerSpreadRightIndex = 0f;
|
||||
|
||||
CVRInputManager.Instance.finger1StretchedRightMiddle = 0.5f;
|
||||
CVRInputManager.Instance.finger2StretchedRightMiddle = 0.7f;
|
||||
CVRInputManager.Instance.finger3StretchedRightMiddle = 0.7f;
|
||||
CVRInputManager.Instance.finger1StretchedRightMiddle = 0f;
|
||||
CVRInputManager.Instance.finger2StretchedRightMiddle = 0f;
|
||||
CVRInputManager.Instance.finger3StretchedRightMiddle = 0f;
|
||||
CVRInputManager.Instance.fingerSpreadRightMiddle = 0f;
|
||||
|
||||
CVRInputManager.Instance.finger1StretchedRightRing = 0.5f;
|
||||
CVRInputManager.Instance.finger2StretchedRightRing = 0.7f;
|
||||
CVRInputManager.Instance.finger3StretchedRightRing = 0.7f;
|
||||
CVRInputManager.Instance.finger1StretchedRightRing = 0f;
|
||||
CVRInputManager.Instance.finger2StretchedRightRing = 0f;
|
||||
CVRInputManager.Instance.finger3StretchedRightRing = 0f;
|
||||
CVRInputManager.Instance.fingerSpreadRightRing = 0f;
|
||||
|
||||
CVRInputManager.Instance.finger1StretchedRightPinky = 0.5f;
|
||||
CVRInputManager.Instance.finger2StretchedRightPinky = 0.7f;
|
||||
CVRInputManager.Instance.finger3StretchedRightPinky = 0.7f;
|
||||
CVRInputManager.Instance.finger1StretchedRightPinky = 0f;
|
||||
CVRInputManager.Instance.finger2StretchedRightPinky = 0f;
|
||||
CVRInputManager.Instance.finger3StretchedRightPinky = 0f;
|
||||
CVRInputManager.Instance.fingerSpreadRightPinky = 0f;
|
||||
|
||||
CVRInputManager.Instance.fingerFullCurlNormalizedRightThumb = 0f;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_pmc.PlayerMovementCopycat), "PlayerMovementCopycat", "1.0.5-ex", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_pmc.PlayerMovementCopycat), "PlayerMovementCopycat", "1.0.5", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||
[assembly: MelonLoader.MelonPriority(3)]
|
||||
[assembly: MelonLoader.MelonAdditionalDependencies("BTKUILib")]
|
||||
|
|
|
@ -10,6 +10,11 @@
|
|||
<Version>1.0.5</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<DebugType>embedded</DebugType>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\"" />
|
||||
</Target>
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace ml_prm
|
|||
FallLimit
|
||||
}
|
||||
|
||||
static public event Action SwitchChange;
|
||||
public static event Action SwitchChange;
|
||||
|
||||
static List<object> ms_uiElements = null;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.1.3-ex", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.1.3", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||
[assembly: MelonLoader.MelonPriority(2)]
|
||||
[assembly: MelonLoader.MelonOptionalDependencies("BTKUILib")]
|
||||
|
|
|
@ -288,6 +288,8 @@ namespace ml_prm
|
|||
|
||||
if(PlayerSetup.Instance._animator.isHuman)
|
||||
{
|
||||
Utils.SetAvatarTPose();
|
||||
|
||||
BipedRagdollReferences l_avatarReferences = BipedRagdollReferences.FromAvatar(PlayerSetup.Instance._animator);
|
||||
|
||||
m_puppet = new GameObject("Root").transform;
|
||||
|
|
|
@ -47,24 +47,24 @@ namespace ml_prm
|
|||
public static bool FallDamage { get; private set; } = true;
|
||||
public static float FallLimit { get; private set; } = 5f;
|
||||
|
||||
static public event Action<bool> HotkeyChange;
|
||||
static public event Action<KeyCode> HotkeyKeyChange;
|
||||
static public event Action<float> VelocityMultiplierChange;
|
||||
static public event Action<float> MovementDragChange;
|
||||
static public event Action<float> AngularDragChange;
|
||||
static public event Action<bool> GravityChange;
|
||||
static public event Action<bool> PointersReactionChange;
|
||||
static public event Action<bool> IgnoreLocalChange;
|
||||
static public event Action<bool> CombatReactionChange;
|
||||
static public event Action<bool> AutoRecoverChange;
|
||||
static public event Action<float> RecoverDelayChange;
|
||||
static public event Action<bool> SlipperinessChange;
|
||||
static public event Action<bool> BouncinessChange;
|
||||
static public event Action<bool> ViewVelocityChange;
|
||||
static public event Action<bool> JumpRecoverChange;
|
||||
static public event Action<bool> BuoyancyChange;
|
||||
static public event Action<bool> FallDamageChange;
|
||||
static public event Action<float> FallLimitChange;
|
||||
public static event Action<bool> HotkeyChange;
|
||||
public static event Action<KeyCode> HotkeyKeyChange;
|
||||
public static event Action<float> VelocityMultiplierChange;
|
||||
public static event Action<float> MovementDragChange;
|
||||
public static event Action<float> AngularDragChange;
|
||||
public static event Action<bool> GravityChange;
|
||||
public static event Action<bool> PointersReactionChange;
|
||||
public static event Action<bool> IgnoreLocalChange;
|
||||
public static event Action<bool> CombatReactionChange;
|
||||
public static event Action<bool> AutoRecoverChange;
|
||||
public static event Action<float> RecoverDelayChange;
|
||||
public static event Action<bool> SlipperinessChange;
|
||||
public static event Action<bool> BouncinessChange;
|
||||
public static event Action<bool> ViewVelocityChange;
|
||||
public static event Action<bool> JumpRecoverChange;
|
||||
public static event Action<bool> BuoyancyChange;
|
||||
public static event Action<bool> FallDamageChange;
|
||||
public static event Action<float> FallLimitChange;
|
||||
|
||||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Savior;
|
||||
using ABI_RC.Systems.IK;
|
||||
using ABI_RC.Systems.Movement;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
@ -46,5 +48,12 @@ namespace ml_prm
|
|||
(ms_influencerTouchingVolumes.GetValue(p_instance) as List<FluidVolume>)?.Clear();
|
||||
(ms_influencerSubmergedColliders.GetValue(p_instance) as Dictionary<FluidVolume, int>)?.Clear();
|
||||
}
|
||||
|
||||
public static void SetAvatarTPose()
|
||||
{
|
||||
IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose);
|
||||
PlayerSetup.Instance._avatar.transform.localPosition = Vector3.zero;
|
||||
PlayerSetup.Instance._avatar.transform.localRotation = Quaternion.identity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,11 @@
|
|||
<Product>PlayerRagdollMod</Product>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<DebugType>embedded</DebugType>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="PlayerRagdollMod.json" />
|
||||
<None Remove="resources\person.png" />
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[assembly: MelonLoader.MelonInfo(typeof(ml_vei.ViveExtendedInput), "ViveExtendedInput", "1.0.1-ex", "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)]
|
||||
[assembly: MelonLoader.MelonInfo(typeof(ml_vei.ViveExtendedInput), "ViveExtendedInput", "1.0.1", "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)]
|
||||
|
|
|
@ -26,9 +26,9 @@ namespace ml_vei
|
|||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||
|
||||
static public event Action<bool> GesturesChange;
|
||||
static public event Action<bool> GripTriggerChange;
|
||||
static public event Action<PriorityAxis> AxisPriorityChange;
|
||||
public static event Action<bool> GesturesChange;
|
||||
public static event Action<bool> GripTriggerChange;
|
||||
public static event Action<PriorityAxis> AxisPriorityChange;
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
|
|
|
@ -7,6 +7,6 @@ namespace ml_vei
|
|||
{
|
||||
static readonly FieldInfo ms_view = typeof(CohtmlControlledViewWrapper).GetField("_view", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
static public void ExecuteScript(this CohtmlControlledViewWrapper p_instance, string p_script) => ((cohtml.Net.View)ms_view.GetValue(p_instance)).ExecuteScript(p_script);
|
||||
public static void ExecuteScript(this CohtmlControlledViewWrapper p_instance, string p_script) => ((cohtml.Net.View)ms_view.GetValue(p_instance)).ExecuteScript(p_script);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,78 +1,83 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
<PackageId>ViveExtendedInput</PackageId>
|
||||
<Version>1.0.1</Version>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>ViveExtendedInput</Product>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="PlayerRagdollMod.json" />
|
||||
<None Remove="resources\mod_menu.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\0Harmony.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="cohtml.Net">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\cohtml.Net.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Cohtml.Runtime">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="MelonLoader">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\MelonLoader.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Unity.Postprocessing.Runtime">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Unity.Postprocessing.Runtime.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>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.AnimationModule">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="resources\mod_menu.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="..\js\mods_extension.js" Link="resources\mods_extension.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\"" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
<PackageId>ViveExtendedInput</PackageId>
|
||||
<Version>1.0.1</Version>
|
||||
<Authors>SDraw</Authors>
|
||||
<Company>None</Company>
|
||||
<Product>ViveExtendedInput</Product>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<DebugType>embedded</DebugType>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="PlayerRagdollMod.json" />
|
||||
<None Remove="resources\mod_menu.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\0Harmony.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="cohtml.Net">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\cohtml.Net.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Cohtml.Runtime">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="MelonLoader">
|
||||
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\MelonLoader.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Unity.Postprocessing.Runtime">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Unity.Postprocessing.Runtime.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>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.AnimationModule">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
<SpecificVersion>false</SpecificVersion>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="resources\mod_menu.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="..\js\mods_extension.js" Link="resources\mods_extension.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="copy /y "$(TargetPath)" "D:\Games\Steam\steamapps\common\ChilloutVR\Mods\"" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue