Moved PlayerRagdollMod and DesktopHeadTracking to archived

Fixed for r173 game build
This commit is contained in:
SDraw 2023-11-10 02:12:12 +03:00
parent a232c2ce13
commit 9886bdc154
No known key found for this signature in database
GPG key ID: BB95B4DAB2BB8BB5
43 changed files with 3490 additions and 3600 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 KiB

View file

@ -1,185 +0,0 @@
using ABI.CCK.Components;
using ABI_RC.Core.Player;
using RootMotion.FinalIK;
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;
bool m_blinking = true;
bool m_eyeTracking = true;
float m_smoothing = 0.5f;
bool m_mirrored = false;
bool m_faceOverride = true;
CVRAvatar m_avatarDescriptor = null;
LookAtIK m_lookIK = null;
Transform m_headBone = null;
Vector3 m_headPosition;
Quaternion m_headRotation;
Vector2 m_gazeDirection;
float m_blinkProgress = 0f;
Vector2 m_mouthShapes;
float m_eyebrowsProgress = 0f;
Quaternion m_bindRotation;
Quaternion m_lastHeadRotation;
// Unity events
void Start()
{
Settings.EnabledChange += this.SetEnabled;
Settings.HeadTrackingChange += this.SetHeadTracking;
Settings.EyeTrackingChange += this.SetEyeTracking;
Settings.BlinkingChange += this.SetBlinking;
Settings.SmoothingChange += this.SetSmoothing;
Settings.MirroredChange += this.SetMirrored;
Settings.FaceOverrideChange += this.SetFaceOverride;
}
void OnDestroy()
{
Settings.EnabledChange -= this.SetEnabled;
Settings.HeadTrackingChange -= this.SetHeadTracking;
Settings.EyeTrackingChange -= this.SetEyeTracking;
Settings.BlinkingChange -= this.SetBlinking;
Settings.SmoothingChange -= this.SetSmoothing;
Settings.MirroredChange -= this.SetMirrored;
Settings.FaceOverrideChange -= this.SetFaceOverride;
}
// Tracking updates
public void UpdateTrackingData(ref TrackingData p_data)
{
m_headPosition.Set(p_data.m_headPositionX * (m_mirrored ? -1f : 1f), p_data.m_headPositionY, p_data.m_headPositionZ);
m_headRotation.Set(p_data.m_headRotationX, p_data.m_headRotationY * (m_mirrored ? -1f : 1f), p_data.m_headRotationZ * (m_mirrored ? -1f : 1f), p_data.m_headRotationW);
m_gazeDirection.Set(m_mirrored ? (1f - p_data.m_gazeX) : p_data.m_gazeX, p_data.m_gazeY);
m_blinkProgress = p_data.m_blink;
m_mouthShapes.Set(p_data.m_mouthOpen, p_data.m_mouthShape);
m_eyebrowsProgress = p_data.m_brows;
}
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 OnEyeControllerUpdate(CVREyeController p_component)
{
if(m_enabled)
{
// Gaze
if(m_eyeTracking)
{
Transform l_camera = PlayerSetup.Instance.GetActiveCamera().transform;
p_component.manualViewTarget = true;
p_component.targetViewPosition = l_camera.position + l_camera.rotation * new Vector3((m_gazeDirection.x - 0.5f) * 2f, (m_gazeDirection.y - 0.5f) * 2f, 1f);
}
// Blink
if(m_blinking)
{
p_component.manualBlinking = true;
p_component.blinkProgress = m_blinkProgress;
}
}
}
internal void OnFaceTrackingUpdate(CVRFaceTracking p_component)
{
if(m_enabled && m_faceOverride)
{
if(m_avatarDescriptor != null)
m_avatarDescriptor.useVisemeLipsync = false;
float l_weight = Mathf.Clamp01(Mathf.InverseLerp(0.25f, 1f, Mathf.Abs(m_mouthShapes.y))) * 100f;
p_component.BlendShapeValues[(int)LipShape_v2.Jaw_Open] = m_mouthShapes.x * 100f;
p_component.BlendShapeValues[(int)LipShape_v2.Mouth_Pout] = ((m_mouthShapes.y > 0f) ? l_weight : 0f);
p_component.BlendShapeValues[(int)LipShape_v2.Mouth_Smile_Left] = ((m_mouthShapes.y < 0f) ? l_weight : 0f);
p_component.BlendShapeValues[(int)LipShape_v2.Mouth_Smile_Right] = ((m_mouthShapes.y < 0f) ? l_weight : 0f);
p_component.LipSyncWasUpdated = true;
p_component.UpdateLipShapes();
}
}
internal void OnSetupAvatar()
{
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.solver.OnPostUpdate += this.OnLookIKPostUpdate;
}
internal void OnAvatarClear()
{
m_avatarDescriptor = null;
m_lookIK = null;
m_headBone = null;
m_lastHeadRotation = Quaternion.identity;
m_bindRotation = Quaternion.identity;
}
// Settings
internal void SetEnabled(bool p_state)
{
if(m_enabled != p_state)
{
m_enabled = p_state;
if(m_enabled && m_headTracking)
m_lastHeadRotation = ((m_headBone != null) ? m_headBone.rotation : m_bindRotation);
}
}
internal void SetHeadTracking(bool p_state)
{
if(m_headTracking != p_state)
{
m_headTracking = p_state;
if(m_enabled && m_headTracking)
m_lastHeadRotation = ((m_headBone != null) ? m_headBone.rotation : m_bindRotation);
}
}
internal void SetEyeTracking(bool p_state)
{
m_eyeTracking = p_state;
}
internal void SetBlinking(bool p_state)
{
m_blinking = p_state;
}
internal void SetSmoothing(float p_value)
{
m_smoothing = 1f - Mathf.Clamp(p_value, 0f, 0.99f);
}
internal void SetMirrored(bool p_state)
{
m_mirrored = p_state;
}
internal void SetFaceOverride(bool p_state)
{
m_faceOverride = p_state;
}
}
}

View file

@ -1,146 +0,0 @@
using ABI.CCK.Components;
using ABI_RC.Core.Player;
using System.Reflection;
namespace ml_dht
{
public class DesktopHeadTracking : MelonLoader.MelonMod
{
static DesktopHeadTracking ms_instance = null;
MemoryMapReader m_mapReader = null;
byte[] m_buffer = null;
TrackingData m_trackingData;
HeadTracked m_localTracked = null;
public override void OnInitializeMelon()
{
if(ms_instance == null)
ms_instance = this;
Settings.Init();
m_mapReader = new MemoryMapReader();
m_buffer = new byte[1024];
m_mapReader.Open("head/data");
// 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(CVREyeController).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("Update", BindingFlags.Instance | BindingFlags.NonPublic),
null,
new HarmonyLib.HarmonyMethod(typeof(DesktopHeadTracking).GetMethod(nameof(OnFaceTrackingUpdate_Postfix), BindingFlags.Static | BindingFlags.NonPublic))
);
MelonLoader.MelonCoroutines.Start(WaitForPlayer());
}
System.Collections.IEnumerator WaitForPlayer()
{
while(PlayerSetup.Instance == null)
yield return null;
m_localTracked = PlayerSetup.Instance.gameObject.AddComponent<HeadTracked>();
m_localTracked.SetEnabled(Settings.Enabled);
m_localTracked.SetHeadTracking(Settings.HeadTracking);
m_localTracked.SetEyeTracking(Settings.EyeTracking);
m_localTracked.SetBlinking(Settings.Blinking);
m_localTracked.SetMirrored(Settings.Mirrored);
m_localTracked.SetSmoothing(Settings.Smoothing);
m_localTracked.SetFaceOverride(Settings.FaceOverride);
}
public override void OnDeinitializeMelon()
{
if(ms_instance == this)
ms_instance = null;
m_mapReader?.Close();
m_mapReader = null;
m_buffer = null;
m_localTracked = null;
}
public override void OnUpdate()
{
if(Settings.Enabled && m_mapReader.Read(ref m_buffer))
{
m_trackingData = TrackingData.ToObject(m_buffer);
if(m_localTracked != null)
m_localTracked.UpdateTrackingData(ref m_trackingData);
}
}
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 OnEyeControllerUpdate_Postfix(ref CVREyeController __instance) => ms_instance?.OnEyeControllerUpdate(__instance);
void OnEyeControllerUpdate(CVREyeController p_component)
{
try
{
if(p_component.isLocal && (m_localTracked != null))
m_localTracked.OnEyeControllerUpdate(p_component);
}
catch(System.Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
static void OnFaceTrackingUpdate_Postfix(ref CVRFaceTracking __instance) => ms_instance?.OnFaceTrackingUpdate(__instance);
void OnFaceTrackingUpdate(CVRFaceTracking p_component)
{
try
{
if(p_component.isLocal && (m_localTracked != null))
m_localTracked.OnFaceTrackingUpdate(p_component);
}
catch(System.Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
}
}

View file

@ -1,55 +0,0 @@
using System.IO;
using System.IO.MemoryMappedFiles;
namespace ml_dht
{
class MemoryMapReader
{
MemoryMappedFile m_file = null;
MemoryMappedViewStream m_stream = null;
int m_dataSize = 0;
public bool Open(string p_path, int p_dataSize = 1024)
{
if(m_file == null)
{
m_dataSize = p_dataSize;
m_file = MemoryMappedFile.CreateOrOpen(p_path, m_dataSize, MemoryMappedFileAccess.ReadWrite);
m_stream = m_file.CreateViewStream(0, m_dataSize, MemoryMappedFileAccess.Read);
}
return (m_file != null);
}
public bool Read(ref byte[] p_data)
{
bool l_result = false;
if((m_stream != null) && m_stream.CanRead)
{
try
{
m_stream.Seek(0, SeekOrigin.Begin);
m_stream.Read(p_data, 0, (p_data.Length > m_dataSize) ? m_dataSize : p_data.Length);
l_result = true;
}
catch(System.Exception) { }
}
return l_result;
}
public void Close()
{
if(m_file != null)
{
m_stream.Close();
m_stream.Dispose();
m_stream = null;
m_file.Dispose();
m_file = null;
m_dataSize = 0;
}
}
}
}

View file

@ -1,4 +0,0 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_dht.DesktopHeadTracking), "DesktopHeadTracking", "1.1.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)]

View file

@ -1,29 +0,0 @@
# Desktop Head Tracking
This mod adds desktop head tracking based on data from memory-mapped file `head/data`.
Refer to `TrackingData.cs` for reference in case of implementing own software.
[![](.github/img_01.png)](https://youtu.be/jgcFhSNi9DM)
# Features
* Head rotation
* Eyes gaze direction
* Blinking
* Basic mouth shapes
# Installation
* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader)
* Get [latest release DLL](../../../releases/latest):
* Put `ml_dht.dll` in `Mods` folder of game
# Usage
Available mod's settings in `Settings - Implementation - Desktop Head Tracking`:
* **Enabled:** enables mod's activity; default value - `false`.
* **Use head tracking:** enables head tracking; default value - `true`.
* **Use eyes tracking:** uses eyes tracking from data; default value - `true`.
* **Use blinking:** uses blinking from data; default value - `true`.
* **Mirrored movement:** mirrors movement and gaze along 0YZ plane; default value - `false`.
* **Movement smoothing:** smoothing factor between new and old movement data; default value - `50`.
* **Override face tracking:** overrides and activates avatar's `VRC Face Tracking` components. List of used shapes: `Jaw_Open`, `Mouth_Pout`, `Mouth_Smile_Left`, `Mouth_Smile_Right`; default value - `true`.
# Known compatible tracking software
* [VSeeFace](https://www.vseeface.icu) with [Tracking Data Parser mod](https://github.com/SDraw/ml_mods_vsf)

View file

@ -1,26 +0,0 @@
using System;
using System.IO;
using System.Reflection;
namespace ml_dht
{
static class Scripts
{
public static string GetEmbeddedScript(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;
}
}
}

View file

@ -1,163 +0,0 @@
using ABI_RC.Core.InteractionSystem;
using System;
using System.Collections.Generic;
namespace ml_dht
{
static class Settings
{
enum ModSetting
{
Enabled = 0,
HeadTracking,
EyeTracking,
Blinking,
Mirrored,
Smoothing,
FaceOverride
}
public static bool Enabled { get; private set; } = false;
public static bool HeadTracking { get; private set; } = true;
public static bool EyeTracking { get; private set; } = true;
public static bool Blinking { get; private set; } = true;
public static bool Mirrored { get; private set; } = false;
public static float Smoothing { get; private set; } = 0.5f;
public static bool FaceOverride { 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<bool> HeadTrackingChange;
static public event Action<bool> EyeTrackingChange;
static public event Action<bool> BlinkingChange;
static public event Action<bool> MirroredChange;
static public event Action<float> SmoothingChange;
static public event Action<bool> FaceOverrideChange;
internal static void Init()
{
ms_category = MelonLoader.MelonPreferences.CreateCategory("DHT");
ms_entries = new List<MelonLoader.MelonPreferences_Entry>()
{
ms_category.CreateEntry(ModSetting.Enabled.ToString(), Enabled),
ms_category.CreateEntry(ModSetting.HeadTracking.ToString(), HeadTracking),
ms_category.CreateEntry(ModSetting.EyeTracking.ToString(), EyeTracking),
ms_category.CreateEntry(ModSetting.Blinking.ToString(), Blinking),
ms_category.CreateEntry(ModSetting.Mirrored.ToString(), Mirrored),
ms_category.CreateEntry(ModSetting.Smoothing.ToString(), (int)(Smoothing * 50f)),
ms_category.CreateEntry(ModSetting.FaceOverride.ToString(), FaceOverride)
};
Load();
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("MelonMod_DHT_Call_InpSlider", new Action<string, string>(OnSliderUpdate));
ViewManager.Instance.gameMenuView.View.BindCall("MelonMod_DHT_Call_InpToggle", new Action<string, string>(OnToggleUpdate));
};
ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) =>
{
ViewManager.Instance.gameMenuView.View.ExecuteScript(Scripts.GetEmbeddedScript("menu.js"));
foreach(var l_entry in ms_entries)
ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSettingDHT", l_entry.DisplayName, l_entry.GetValueAsString());
};
}
static void Load()
{
Enabled = (bool)ms_entries[(int)ModSetting.Enabled].BoxedValue;
HeadTracking = (bool)ms_entries[(int)ModSetting.HeadTracking].BoxedValue;
EyeTracking = (bool)ms_entries[(int)ModSetting.EyeTracking].BoxedValue;
Blinking = (bool)ms_entries[(int)ModSetting.Blinking].BoxedValue;
Mirrored = (bool)ms_entries[(int)ModSetting.Mirrored].BoxedValue;
Smoothing = ((int)ms_entries[(int)ModSetting.Smoothing].BoxedValue) * 0.01f;
FaceOverride = (bool)ms_entries[(int)ModSetting.FaceOverride].BoxedValue;
}
static void OnSliderUpdate(string p_name, string p_value)
{
if(Enum.TryParse(p_name, out ModSetting l_setting))
{
switch(l_setting)
{
case ModSetting.Smoothing:
{
Smoothing = int.Parse(p_value) * 0.01f;
SmoothingChange?.Invoke(Smoothing);
}
break;
}
ms_entries[(int)l_setting].BoxedValue = int.Parse(p_value);
}
}
static void OnToggleUpdate(string p_name, string p_value)
{
if(Enum.TryParse(p_name, out ModSetting l_setting))
{
switch(l_setting)
{
case ModSetting.Enabled:
{
Enabled = bool.Parse(p_value);
EnabledChange?.Invoke(Enabled);
}
break;
case ModSetting.HeadTracking:
{
HeadTracking = bool.Parse(p_value);
HeadTrackingChange?.Invoke(HeadTracking);
}
break;
case ModSetting.EyeTracking:
{
EyeTracking = bool.Parse(p_value);
EyeTrackingChange?.Invoke(EyeTracking);
}
break;
case ModSetting.Blinking:
{
Blinking = bool.Parse(p_value);
BlinkingChange?.Invoke(Blinking);
}
break;
case ModSetting.Mirrored:
{
Mirrored = bool.Parse(p_value);
MirroredChange?.Invoke(Mirrored);
}
break;
case ModSetting.FaceOverride:
{
FaceOverride = bool.Parse(p_value);
FaceOverrideChange?.Invoke(FaceOverride);
}
break;
}
ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
}
}
}
}

View file

@ -1,46 +0,0 @@
using System;
using System.Runtime.InteropServices;
struct TrackingData
{
public float m_headPositionX; // Not used yet
public float m_headPositionY; // Not used yet
public float m_headPositionZ; // Not used yet
public float m_headRotationX;
public float m_headRotationY;
public float m_headRotationZ;
public float m_headRotationW;
public float m_gazeX; // Range - [0;1], 0.5 - center
public float m_gazeY; // Range - [0;1], 0.5 - center
public float m_blink; // Range - [0;1], 1.0 - closed
public float m_mouthOpen; // Range - [0;1]
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)
{
int l_size = Marshal.SizeOf(p_faceData);
byte[] l_arr = new byte[l_size];
IntPtr ptr = Marshal.AllocHGlobal(l_size);
Marshal.StructureToPtr(p_faceData, ptr, true);
Marshal.Copy(ptr, l_arr, 0, l_size);
Marshal.FreeHGlobal(ptr);
return l_arr;
}
static public TrackingData ToObject(byte[] p_buffer)
{
TrackingData l_faceData = new TrackingData();
int l_size = Marshal.SizeOf(l_faceData);
IntPtr l_ptr = Marshal.AllocHGlobal(l_size);
Marshal.Copy(p_buffer, 0, l_ptr, l_size);
l_faceData = (TrackingData)Marshal.PtrToStructure(l_ptr, l_faceData.GetType());
Marshal.FreeHGlobal(l_ptr);
return l_faceData;
}
}

View file

@ -1,18 +0,0 @@
using ABI_RC.Core.UI;
using System.Reflection;
using UnityEngine;
namespace ml_dht
{
static class Utils
{
static FieldInfo ms_cohtmlView = typeof(CohtmlControlledViewDisposable).GetField("_view", BindingFlags.NonPublic | BindingFlags.Instance);
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);
}
public static void ExecuteScript(this CohtmlControlledViewDisposable p_viewDisposable, string p_script) => ((cohtml.Net.View)ms_cohtmlView.GetValue(p_viewDisposable))?.ExecuteScript(p_script);
}
}

View file

@ -1,71 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<PackageId>DesktopHeadTracking</PackageId>
<Authors>SDraw</Authors>
<Company>None</Company>
<Product>DesktopHeadTracking</Product>
<Version>1.1.2</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\menu.js" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="resources\menu.js" />
</ItemGroup>
<ItemGroup>
<Reference Include="0Harmony">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\0Harmony.dll</HintPath>
<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>
</Reference>
<Reference Include="Assembly-CSharp-firstpass">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="cohtml.Net">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\cohtml.Net.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="Cohtml.Runtime">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="MelonLoader">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\MelonLoader.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="UnityEngine">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="UnityEngine.AnimationModule">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="UnityEngine.CoreModule">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
<Private>false</Private>
</Reference>
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="copy /y &quot;$(TargetPath)&quot; &quot;D:\Games\Steam\steamapps\common\ChilloutVR\Mods\&quot;" />
</Target>
</Project>

View file

@ -1,245 +0,0 @@
// Add settings
var g_modSettingsDHT = [];
engine.on('updateModSettingDHT', function (_name, _value) {
for (var i = 0; i < g_modSettingsDHT.length; i++) {
if (g_modSettingsDHT[i].name == _name) {
g_modSettingsDHT[i].updateValue(_value);
break;
}
}
});
// Modified from original `inp` types, because I have no js knowledge to hook stuff
function inp_slider_mod_dht(_obj, _callbackName) {
this.obj = _obj;
this.callbackName = _callbackName;
this.minValue = parseFloat(_obj.getAttribute('data-min'));
this.maxValue = parseFloat(_obj.getAttribute('data-max'));
this.percent = 0;
this.value = parseFloat(_obj.getAttribute('data-current'));
this.dragActive = false;
this.name = _obj.id;
this.type = _obj.getAttribute('data-type');
this.stepSize = _obj.getAttribute('data-stepSize') || 0;
this.format = _obj.getAttribute('data-format') || '{value}';
var self = this;
if (this.stepSize != 0)
this.value = Math.round(this.value / this.stepSize) * this.stepSize;
else
this.value = Math.round(this.value);
this.valueLabelBackground = document.createElement('div');
this.valueLabelBackground.className = 'valueLabel background';
this.valueLabelBackground.innerHTML = this.format.replace('{value}', this.value);
this.obj.appendChild(this.valueLabelBackground);
this.valueBar = document.createElement('div');
this.valueBar.className = 'valueBar';
this.valueBar.setAttribute('style', 'width: ' + (((this.value - this.minValue) / (this.maxValue - this.minValue)) * 100) + '%;');
this.obj.appendChild(this.valueBar);
this.valueLabelForeground = document.createElement('div');
this.valueLabelForeground.className = 'valueLabel foreground';
this.valueLabelForeground.innerHTML = this.format.replace('{value}', this.value);
this.valueLabelForeground.setAttribute('style', 'width: ' + (1.0 / ((this.value - this.minValue) / (this.maxValue - this.minValue)) * 100) + '%;');
this.valueBar.appendChild(this.valueLabelForeground);
this.mouseDown = function (_e) {
self.dragActive = true;
self.mouseMove(_e, false);
}
this.mouseMove = function (_e, _write) {
if (self.dragActive) {
var rect = _obj.getBoundingClientRect();
var start = rect.left;
var end = rect.right;
self.percent = Math.min(Math.max((_e.clientX - start) / rect.width, 0), 1);
var value = self.percent;
value *= (self.maxValue - self.minValue);
value += self.minValue;
if (self.stepSize != 0) {
value = Math.round(value / self.stepSize);
self.value = value * self.stepSize;
self.percent = (self.value - self.minValue) / (self.maxValue - self.minValue);
}
else
self.value = Math.round(value);
self.valueBar.setAttribute('style', 'width: ' + (self.percent * 100) + '%;');
self.valueLabelForeground.setAttribute('style', 'width: ' + (1.0 / self.percent * 100) + '%;');
self.valueLabelBackground.innerHTML = self.valueLabelForeground.innerHTML = self.format.replace('{value}', self.value);
engine.call(self.callbackName, self.name, "" + self.value);
self.displayImperial();
}
}
this.mouseUp = function (_e) {
self.mouseMove(_e, true);
self.dragActive = false;
}
_obj.addEventListener('mousedown', this.mouseDown);
document.addEventListener('mousemove', this.mouseMove);
document.addEventListener('mouseup', this.mouseUp);
this.getValue = function () {
return self.value;
}
this.updateValue = function (value) {
if (self.stepSize != 0)
self.value = Math.round(value * self.stepSize) / self.stepSize;
else
self.value = Math.round(value);
self.percent = (self.value - self.minValue) / (self.maxValue - self.minValue);
self.valueBar.setAttribute('style', 'width: ' + (self.percent * 100) + '%;');
self.valueLabelForeground.setAttribute('style', 'width: ' + (1.0 / self.percent * 100) + '%;');
self.valueLabelBackground.innerHTML = self.valueLabelForeground.innerHTML = self.format.replace('{value}', self.value);
self.displayImperial();
}
this.displayImperial = function () {
var displays = document.querySelectorAll('.imperialDisplay');
for (var i = 0; i < displays.length; i++) {
var binding = displays[i].getAttribute('data-binding');
if (binding == self.name) {
var realFeet = ((self.value * 0.393700) / 12);
var feet = Math.floor(realFeet);
var inches = Math.floor((realFeet - feet) * 12);
displays[i].innerHTML = feet + "&apos;" + inches + '&apos;&apos;';
}
}
}
return {
name: this.name,
value: this.getValue,
updateValue: this.updateValue
}
}
// Modified from original `inp` types, because I have no js knowledge to hook stuff
function inp_toggle_mod_dht(_obj, _callbackName) {
this.obj = _obj;
this.callbackName = _callbackName;
this.value = _obj.getAttribute('data-current');
this.name = _obj.id;
this.type = _obj.getAttribute('data-type');
var self = this;
this.mouseDown = function (_e) {
self.value = self.value == "True" ? "False" : "True";
self.updateState();
}
this.updateState = function () {
self.obj.classList.remove("checked");
if (self.value == "True") {
self.obj.classList.add("checked");
}
engine.call(self.callbackName, self.name, self.value);
}
_obj.addEventListener('mousedown', this.mouseDown);
this.getValue = function () {
return self.value;
}
this.updateValue = function (value) {
self.value = value;
self.obj.classList.remove("checked");
if (self.value == "True") {
self.obj.classList.add("checked");
}
}
this.updateValue(this.value);
return {
name: this.name,
value: this.getValue,
updateValue: this.updateValue
}
}
// Add own menu
{
let l_block = document.createElement('div');
l_block.innerHTML = `
<div class ="settings-subcategory">
<div class ="subcategory-name">Desktop Head Tracking</div>
<div class ="subcategory-description"></div>
</div>
<div class ="row-wrapper">
<div class ="option-caption">Enabled: </div>
<div class ="option-input">
<div id="Enabled" class ="inp_toggle no-scroll" data-current="false"></div>
</div>
</div>
<div class ="row-wrapper">
<div class ="option-caption">Use head tracking: </div>
<div class ="option-input">
<div id="HeadTracking" class ="inp_toggle no-scroll" data-current="true"></div>
</div>
</div>
<div class ="row-wrapper">
<div class ="option-caption">Use eyes tracking: </div>
<div class ="option-input">
<div id="EyeTracking" class ="inp_toggle no-scroll" data-current="true"></div>
</div>
</div>
<div class ="row-wrapper">
<div class ="option-caption">Use blinking: </div>
<div class ="option-input">
<div id="Blinking" class ="inp_toggle no-scroll" data-current="true"></div>
</div>
</div>
<div class ="row-wrapper">
<div class ="option-caption">Mirrored movement: </div>
<div class ="option-input">
<div id="Mirrored" class ="inp_toggle no-scroll" data-current="false"></div>
</div>
</div>
<div class ="row-wrapper">
<div class ="option-caption">Movement smoothing: </div>
<div class ="option-input">
<div id="Smoothing" class ="inp_slider no-scroll" data-min="0" data-max="99" data-current="50"></div>
</div>
</div>
<div class ="row-wrapper">
<div class ="option-caption">Override face tracking: </div>
<div class ="option-input">
<div id="FaceOverride" class ="inp_toggle no-scroll" data-current="true"></div>
</div>
</div>
`;
document.getElementById('settings-implementation').appendChild(l_block);
// Update sliders in new menu block
let l_sliders = l_block.querySelectorAll('.inp_slider');
for (var i = 0; i < l_sliders.length; i++) {
g_modSettingsDHT[g_modSettingsDHT.length] = new inp_slider_mod_dht(l_sliders[i], 'MelonMod_DHT_Call_InpSlider');
}
// Update toggles in new menu block
let l_toggles = l_block.querySelectorAll('.inp_toggle');
for (var i = 0; i < l_toggles.length; i++) {
g_modSettingsDHT[g_modSettingsDHT.length] = new inp_toggle_mod_dht(l_toggles[i], 'MelonMod_DHT_Call_InpToggle');
}
}