using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Sockets;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using System.Threading.Tasks;
using BoneLib;
using BoneLib.BoneMenu;
using EyeTracking;
using EyeTracking.EyeGaze;
using HarmonyLib;
using Il2CppSLZ.Marrow;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using PSVR2;
using PSVR2Toolkit.CAPI;
using PSVR2Toolkit.VRCFT;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "PSVR2", "1.0.2", "Checkerboard", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("PSVR2")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("PSVR2")]
[assembly: AssemblyTitle("PSVR2")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace PSVR2Toolkit.VRCFT
{
public class LowPassFilter
{
private readonly float[] _samples;
private int _index;
public LowPassFilter(int count)
{
_samples = new float[count - 1];
for (int i = 0; i < count - 1; i++)
{
_samples[i] = 0f;
}
}
private float Sum()
{
float num = 0f;
float[] samples = _samples;
foreach (float num2 in samples)
{
num += num2;
}
return num;
}
public float FilterValue(float newValue)
{
_index++;
if (_samples.Length == _index)
{
_index = 0;
}
_samples[_index] = newValue;
return Sum() / (float)_samples.Length;
}
}
}
namespace PSVR2Toolkit.CAPI
{
public class IpcClient
{
private const ushort IPC_SERVER_PORT = 3364;
private const ushort k_unIpcVersion = 1;
private static IpcClient m_pInstance;
private bool m_running;
private TcpClient? m_client;
private NetworkStream? m_stream;
private Thread? m_receiveThread;
private readonly object m_gazeStateLock = new object();
private TaskCompletionSource<CommandDataServerGazeDataResult>? m_gazeTask;
private CancellationTokenSource m_forceShutdownToken;
private int m_gazePumpPeriodMs = 8;
private CommandDataServerGazeDataResult? m_lastGazeState;
public static IpcClient Instance()
{
if (m_pInstance == null)
{
m_pInstance = new IpcClient();
}
return m_pInstance;
}
public bool Start()
{
if (m_running)
{
return false;
}
try
{
m_client = new TcpClient();
m_client.Connect("127.0.0.1", 3364);
if (m_client.Connected)
{
m_stream = m_client.GetStream();
m_running = true;
m_forceShutdownToken = new CancellationTokenSource();
m_receiveThread = new Thread((ThreadStart)delegate
{
ReceiveLoop(m_forceShutdownToken.Token);
});
m_receiveThread.Start();
((MelonBase)Core.Instance).LoggerInstance.Msg("[IPC_CLIENT] Connected to server successfully.");
return true;
}
return false;
}
catch (SocketException ex)
{
((MelonBase)Core.Instance).LoggerInstance.Error($"[IPC_CLIENT] Connection failed. LastError = {ex.SocketErrorCode}");
((MelonBase)Core.Instance).LoggerInstance.Msg("[IPC_CLIENT] Did you install PSVR2 Toolkit?");
return false;
}
}
public void Stop()
{
if (m_running)
{
m_running = false;
m_forceShutdownToken.Cancel();
lock (m_gazeStateLock)
{
m_gazeTask?.TrySetCanceled();
m_gazeTask = null;
}
try
{
m_stream?.Close();
m_client?.Close();
}
catch
{
}
if (m_receiveThread != null && m_receiveThread.IsAlive && !m_receiveThread.Join(2000))
{
m_receiveThread.Interrupt();
}
m_stream?.Dispose();
m_client?.Dispose();
m_forceShutdownToken.Dispose();
}
}
private void ReceiveLoop(CancellationToken token)
{
byte[] array = new byte[1024];
try
{
Socket client = m_client.Client;
m_stream.ReadTimeout = 1;
CommandDataClientRequestHandshake commandDataClientRequestHandshake = default(CommandDataClientRequestHandshake);
commandDataClientRequestHandshake.ipcVersion = 1;
commandDataClientRequestHandshake.processId = (uint)Process.GetCurrentProcess().Id;
CommandDataClientRequestHandshake data = commandDataClientRequestHandshake;
SendIpcCommand(ECommandType.ClientRequestHandshake, data);
Stopwatch stopwatch = Stopwatch.StartNew();
long num = stopwatch.ElapsedMilliseconds;
while (m_running && !token.IsCancellationRequested)
{
long elapsedMilliseconds = stopwatch.ElapsedMilliseconds;
if (elapsedMilliseconds >= num)
{
SendIpcCommand(ECommandType.ClientRequestGazeData);
num = elapsedMilliseconds + m_gazePumpPeriodMs;
}
if (client.Poll(1000, SelectMode.SelectRead) && client.Available > 0)
{
int available = client.Available;
if (available > array.Length)
{
array = new byte[Math.Max(available, array.Length * 2)];
}
int num2 = m_stream.Read(array, 0, Math.Min(array.Length, available));
if (num2 <= 0)
{
((MelonBase)Core.Instance).LoggerInstance.Warning("[IPC_CLIENT] Disconnected from server.");
break;
}
if (num2 < Marshal.SizeOf<CommandHeader>())
{
((MelonBase)Core.Instance).LoggerInstance.Warning("[IPC_CLIENT] Received invalid command header size.");
}
else
{
HandleIpcCommand(array, num2);
}
}
else
{
Thread.Sleep(1);
}
}
}
catch (OperationCanceledException)
{
}
catch (Exception ex2)
{
if (m_running)
{
((MelonBase)Core.Instance).LoggerInstance.Warning("[IPC_CLIENT] Error in receive loop: " + ex2.Message);
}
}
}
private void HandleIpcCommand(byte[] pBuffer, int bytesReceived)
{
CommandHeader commandHeader = ByteArrayToStructure<CommandHeader>(pBuffer, 0);
switch (commandHeader.type)
{
case ECommandType.ServerPong:
((MelonBase)Core.Instance).LoggerInstance.Msg("[IPC_CLIENT] Received Pong from server.");
break;
case ECommandType.ServerHandshakeResult:
if (commandHeader.dataLen == Marshal.SizeOf<CommandDataServerHandshakeResult>())
{
CommandDataServerHandshakeResult commandDataServerHandshakeResult = ByteArrayToStructure<CommandDataServerHandshakeResult>(pBuffer, Marshal.SizeOf<CommandHeader>());
switch (commandDataServerHandshakeResult.result)
{
case EHandshakeResult.Success:
((MelonBase)Core.Instance).LoggerInstance.Msg("[IPC_CLIENT] Handshake successful!");
break;
case EHandshakeResult.Failed:
((MelonBase)Core.Instance).LoggerInstance.Error("[IPC_CLIENT] Handshake failed!");
break;
case EHandshakeResult.Outdated:
((MelonBase)Core.Instance).LoggerInstance.Error($"[IPC_CLIENT] Handshake failed with reason: Outdated client. Please upgrade to an IPC version of {commandDataServerHandshakeResult.ipcVersion}");
break;
}
}
break;
case ECommandType.ServerGazeDataResult:
if (commandHeader.dataLen == Marshal.SizeOf<CommandDataServerGazeDataResult>())
{
CommandDataServerGazeDataResult value = ByteArrayToStructure<CommandDataServerGazeDataResult>(pBuffer, Marshal.SizeOf<CommandHeader>());
m_lastGazeState = value;
}
break;
case ECommandType.ClientRequestHandshake:
case ECommandType.ClientRequestGazeData:
break;
}
}
private void SendIpcCommand<T>(ECommandType type, T data = default(T)) where T : struct
{
if (m_running)
{
int num = ((!data.Equals(default(T))) ? Marshal.SizeOf<T>() : 0);
byte[] array = new byte[Marshal.SizeOf<CommandHeader>() + num];
CommandHeader commandHeader = default(CommandHeader);
commandHeader.type = type;
commandHeader.dataLen = num;
CommandHeader structure = commandHeader;
IntPtr intPtr = Marshal.AllocHGlobal(Marshal.SizeOf<CommandHeader>());
Marshal.StructureToPtr(structure, intPtr, fDeleteOld: false);
Marshal.Copy(intPtr, array, 0, Marshal.SizeOf<CommandHeader>());
Marshal.FreeHGlobal(intPtr);
if (num > 0)
{
IntPtr intPtr2 = Marshal.AllocHGlobal(num);
Marshal.StructureToPtr(data, intPtr2, fDeleteOld: false);
Marshal.Copy(intPtr2, array, Marshal.SizeOf<CommandHeader>(), num);
Marshal.FreeHGlobal(intPtr2);
}
m_stream.Write(array, 0, array.Length);
}
}
private void SendIpcCommand(ECommandType type)
{
if (m_running)
{
byte[] array = new byte[Marshal.SizeOf<CommandHeader>()];
CommandHeader commandHeader = default(CommandHeader);
commandHeader.type = type;
commandHeader.dataLen = 0;
CommandHeader structure = commandHeader;
IntPtr intPtr = Marshal.AllocHGlobal(Marshal.SizeOf<CommandHeader>());
Marshal.StructureToPtr(structure, intPtr, fDeleteOld: false);
Marshal.Copy(intPtr, array, 0, Marshal.SizeOf<CommandHeader>());
Marshal.FreeHGlobal(intPtr);
m_stream.Write(array, 0, array.Length);
}
}
private T ByteArrayToStructure<T>(byte[] bytes, int offset) where T : struct
{
int num = Marshal.SizeOf<T>();
if (num > bytes.Length - offset)
{
throw new ArgumentException("Byte array is too small to contain the structure.");
}
IntPtr intPtr = Marshal.AllocHGlobal(num);
Marshal.Copy(bytes, offset, intPtr, num);
T result = (T)Marshal.PtrToStructure(intPtr, typeof(T));
Marshal.FreeHGlobal(intPtr);
return result;
}
public CommandDataServerGazeDataResult RequestEyeTrackingData()
{
if (!m_running)
{
return default(CommandDataServerGazeDataResult);
}
return m_lastGazeState.GetValueOrDefault();
}
public void TriggerEffectDisable(EVRControllerType controllerType)
{
if (m_running)
{
CommandDataClientTriggerEffectOff commandDataClientTriggerEffectOff = default(CommandDataClientTriggerEffectOff);
commandDataClientTriggerEffectOff.controllerType = controllerType;
CommandDataClientTriggerEffectOff data = commandDataClientTriggerEffectOff;
SendIpcCommand(ECommandType.ClientTriggerEffectOff, data);
}
}
public void TriggerEffectFeedback(EVRControllerType controllerType, byte position, byte strength)
{
if (m_running)
{
CommandDataClientTriggerEffectFeedback commandDataClientTriggerEffectFeedback = default(CommandDataClientTriggerEffectFeedback);
commandDataClientTriggerEffectFeedback.controllerType = controllerType;
commandDataClientTriggerEffectFeedback.position = position;
commandDataClientTriggerEffectFeedback.strength = strength;
CommandDataClientTriggerEffectFeedback data = commandDataClientTriggerEffectFeedback;
SendIpcCommand(ECommandType.ClientTriggerEffectFeedback, data);
}
}
public void TriggerEffectWeapon(EVRControllerType controllerType, byte startPosition, byte endPosition, byte strength)
{
if (m_running)
{
CommandDataClientTriggerEffectWeapon commandDataClientTriggerEffectWeapon = default(CommandDataClientTriggerEffectWeapon);
commandDataClientTriggerEffectWeapon.controllerType = controllerType;
commandDataClientTriggerEffectWeapon.startPosition = startPosition;
commandDataClientTriggerEffectWeapon.endPosition = endPosition;
commandDataClientTriggerEffectWeapon.strength = strength;
CommandDataClientTriggerEffectWeapon data = commandDataClientTriggerEffectWeapon;
SendIpcCommand(ECommandType.ClientTriggerEffectWeapon, data);
}
}
public void TriggerEffectVibration(EVRControllerType controllerType, byte position, byte amplitude, byte frequency)
{
if (m_running)
{
CommandDataClientTriggerEffectVibration commandDataClientTriggerEffectVibration = default(CommandDataClientTriggerEffectVibration);
commandDataClientTriggerEffectVibration.controllerType = controllerType;
commandDataClientTriggerEffectVibration.position = position;
commandDataClientTriggerEffectVibration.amplitude = amplitude;
commandDataClientTriggerEffectVibration.frequency = frequency;
CommandDataClientTriggerEffectVibration data = commandDataClientTriggerEffectVibration;
SendIpcCommand(ECommandType.ClientTriggerEffectVibration, data);
}
}
public void TriggerEffectMultiplePositionFeedback(EVRControllerType controllerType, byte[] strength)
{
if (m_running)
{
CommandDataClientTriggerEffectMultiplePositionFeedback commandDataClientTriggerEffectMultiplePositionFeedback = default(CommandDataClientTriggerEffectMultiplePositionFeedback);
commandDataClientTriggerEffectMultiplePositionFeedback.controllerType = controllerType;
commandDataClientTriggerEffectMultiplePositionFeedback.strength = strength;
CommandDataClientTriggerEffectMultiplePositionFeedback data = commandDataClientTriggerEffectMultiplePositionFeedback;
SendIpcCommand(ECommandType.ClientTriggerEffectMultiplePositionFeedback, data);
}
}
public void TriggerEffectSlopeFeedback(EVRControllerType controllerType, byte startPosition, byte endPosition, byte startStrength, byte endStrength)
{
if (m_running)
{
CommandDataClientTriggerEffectSlopeFeedback commandDataClientTriggerEffectSlopeFeedback = default(CommandDataClientTriggerEffectSlopeFeedback);
commandDataClientTriggerEffectSlopeFeedback.controllerType = controllerType;
commandDataClientTriggerEffectSlopeFeedback.startPosition = startPosition;
commandDataClientTriggerEffectSlopeFeedback.endPosition = endPosition;
commandDataClientTriggerEffectSlopeFeedback.startStrength = startStrength;
commandDataClientTriggerEffectSlopeFeedback.endStrength = endStrength;
CommandDataClientTriggerEffectSlopeFeedback data = commandDataClientTriggerEffectSlopeFeedback;
SendIpcCommand(ECommandType.ClientTriggerEffectSlopeFeedback, data);
}
}
public void TriggerEffectMultiplePositionVibration(EVRControllerType controllerType, byte frequency, byte[] amplitude)
{
if (m_running)
{
CommandDataClientTriggerEffectMultiplePositionVibration commandDataClientTriggerEffectMultiplePositionVibration = default(CommandDataClientTriggerEffectMultiplePositionVibration);
commandDataClientTriggerEffectMultiplePositionVibration.controllerType = controllerType;
commandDataClientTriggerEffectMultiplePositionVibration.frequency = frequency;
commandDataClientTriggerEffectMultiplePositionVibration.amplitude = amplitude;
CommandDataClientTriggerEffectMultiplePositionVibration data = commandDataClientTriggerEffectMultiplePositionVibration;
SendIpcCommand(ECommandType.ClientTriggerEffectMultiplePositionVibration, data);
}
}
}
public enum ECommandType : ushort
{
ClientPing,
ServerPong,
ClientRequestHandshake,
ServerHandshakeResult,
ClientRequestGazeData,
ServerGazeDataResult,
ClientTriggerEffectOff,
ClientTriggerEffectFeedback,
ClientTriggerEffectWeapon,
ClientTriggerEffectVibration,
ClientTriggerEffectMultiplePositionFeedback,
ClientTriggerEffectSlopeFeedback,
ClientTriggerEffectMultiplePositionVibration
}
public enum EHandshakeResult : byte
{
Failed,
Success,
Outdated
}
public enum EVRControllerType : byte
{
Left,
Right,
Both
}
public struct CommandDataClientRequestHandshake
{
public ushort ipcVersion;
public uint processId;
}
public struct CommandDataServerHandshakeResult
{
public EHandshakeResult result;
public ushort ipcVersion;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct GazeVector3
{
public float x;
public float y;
public float z;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct GazeEyeResult
{
[MarshalAs(UnmanagedType.I1)]
public bool isGazeOriginValid;
public GazeVector3 gazeOriginMm;
[MarshalAs(UnmanagedType.I1)]
public bool isGazeDirValid;
public GazeVector3 gazeDirNorm;
[MarshalAs(UnmanagedType.I1)]
public bool isPupilDiaValid;
public float pupilDiaMm;
[MarshalAs(UnmanagedType.I1)]
public bool isBlinkValid;
[MarshalAs(UnmanagedType.I1)]
public bool blink;
}
public struct CommandDataServerGazeDataResult
{
public GazeEyeResult leftEye;
public GazeEyeResult rightEye;
}
public struct CommandHeader
{
public ECommandType type;
public int dataLen;
}
public struct CommandDataClientTriggerEffectOff
{
public EVRControllerType controllerType;
}
public struct CommandDataClientTriggerEffectFeedback
{
public EVRControllerType controllerType;
public byte position;
public byte strength;
}
public struct CommandDataClientTriggerEffectWeapon
{
public EVRControllerType controllerType;
public byte startPosition;
public byte endPosition;
public byte strength;
}
public struct CommandDataClientTriggerEffectVibration
{
public EVRControllerType controllerType;
public byte position;
public byte amplitude;
public byte frequency;
}
public struct CommandDataClientTriggerEffectMultiplePositionFeedback
{
public EVRControllerType controllerType;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public byte[] strength;
}
public struct CommandDataClientTriggerEffectSlopeFeedback
{
public EVRControllerType controllerType;
public byte startPosition;
public byte endPosition;
public byte startStrength;
public byte endStrength;
}
public struct CommandDataClientTriggerEffectMultiplePositionVibration
{
public EVRControllerType controllerType;
public byte frequency;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public byte[] amplitude;
}
}
namespace PSVR2
{
public static class AssemblyUtilities
{
public static void LoadAllValid<T>(Assembly assembly, Action<Type> runOnValid)
{
if (assembly.FullName.Contains("System"))
{
return;
}
Type[] types = assembly.GetTypes();
foreach (Type type in types)
{
if ((!type.Name.Contains("Mono") || !type.Name.Contains("Security")) && typeof(T).IsAssignableFrom(type) && !type.IsAbstract && !type.IsInterface)
{
try
{
runOnValid(type);
}
catch (Exception ex)
{
((MelonBase)Core.Instance).LoggerInstance.Error(ex.Message);
}
}
}
}
}
public class Core : MelonMod
{
internal static Core Instance { get; private set; }
internal static MelonPreferences_Category Category { get; private set; }
public static Page RootPage { get; private set; }
internal static bool ToolkitDriverLoaded { get; private set; }
public override void OnInitializeMelon()
{
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
Instance = this;
Category = MelonPreferences.CreateCategory("PSVR2", "PSVR2 Settings");
Category.SaveToFile(false);
RootPage = Page.Root.CreatePage("PSVR2", Color.cyan, 0, true);
FeatureManager.Initialize();
try
{
ToolkitDriverLoaded = IpcClient.Instance().Start();
}
catch (Exception ex)
{
((MelonBase)Instance).LoggerInstance.Error("Failed to start IPC client: " + ex.Message);
}
}
public override void OnUpdate()
{
FeatureManager.Update();
}
public override void OnFixedUpdate()
{
FeatureManager.FixedUpdate();
}
public override void OnLateUpdate()
{
FeatureManager.LateUpdate();
}
public override void OnGUI()
{
FeatureManager.OnGUI();
}
}
public abstract class Feature
{
public abstract void OnRegisterFeature();
public abstract void Update();
public abstract void FixedUpdate();
public abstract void LateUpdate();
public abstract void OnGUI();
}
internal static class FeatureManager
{
private static List<Feature> features;
internal static bool IsInitialized { get; private set; }
internal static void Initialize()
{
features = new List<Feature>();
LoadFeaturesFromAssembly(((MelonBase)Core.Instance).MelonAssembly.Assembly);
}
internal static void Update()
{
if (!IsInitialized)
{
return;
}
foreach (Feature feature in features)
{
feature.Update();
}
}
internal static void FixedUpdate()
{
if (!IsInitialized)
{
return;
}
foreach (Feature feature in features)
{
feature.FixedUpdate();
}
}
internal static void LateUpdate()
{
if (!IsInitialized)
{
return;
}
foreach (Feature feature in features)
{
feature.LateUpdate();
}
}
internal static void OnGUI()
{
if (!IsInitialized)
{
return;
}
foreach (Feature feature in features)
{
feature.OnGUI();
}
}
public static void LoadFeaturesFromAssembly(Assembly assembly)
{
if (assembly == null)
{
throw new NullReferenceException("Can't register from a null assembly!");
}
AssemblyUtilities.LoadAllValid<Feature>(assembly, RegisterFunction);
IsInitialized = true;
}
private static void RegisterFunction(Type type)
{
if (Activator.CreateInstance(type) is Feature feature)
{
feature.OnRegisterFeature();
features.Add(feature);
}
}
}
}
namespace PSVR2.EyeTracking
{
public class PSVR2EyeGazeImplementation : EyeGazeImplementation
{
private const int k_noiseFilterSamples = 15;
private LowPassFilter? leftEyeFilter;
private LowPassFilter? rightEyeFilter;
public override string Name => "PSVR2";
public override string DeviceId => "psvr2.ipc";
public override bool IsLoaded => Core.ToolkitDriverLoaded;
public override void Initialize()
{
if (Core.ToolkitDriverLoaded)
{
leftEyeFilter = new LowPassFilter(15);
rightEyeFilter = new LowPassFilter(15);
}
}
public override void Update()
{
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_0128: Unknown result type (might be due to invalid IL or missing references)
//IL_012d: Unknown result type (might be due to invalid IL or missing references)
//IL_0132: Unknown result type (might be due to invalid IL or missing references)
if (!Core.ToolkitDriverLoaded)
{
return;
}
CommandDataServerGazeDataResult commandDataServerGazeDataResult = IpcClient.Instance().RequestEyeTrackingData();
if (commandDataServerGazeDataResult.leftEye.isBlinkValid)
{
float num = ((!commandDataServerGazeDataResult.leftEye.blink) ? 1 : 0);
if (leftEyeFilter != null)
{
num = leftEyeFilter.FilterValue(num);
}
Tracking.Data.Eye.Left.Openness = num;
}
if (commandDataServerGazeDataResult.rightEye.isBlinkValid)
{
float num2 = ((!commandDataServerGazeDataResult.rightEye.blink) ? 1 : 0);
if (rightEyeFilter != null)
{
num2 = rightEyeFilter.FilterValue(num2);
}
Tracking.Data.Eye.Right.Openness = num2;
}
if (commandDataServerGazeDataResult.leftEye.isGazeDirValid)
{
Tracking.Data.Eye.Left.Gaze = Utils.FlipXCoordinates(new Vector2(commandDataServerGazeDataResult.leftEye.gazeDirNorm.x, commandDataServerGazeDataResult.leftEye.gazeDirNorm.y));
}
if (commandDataServerGazeDataResult.rightEye.isGazeDirValid)
{
Tracking.Data.Eye.Right.Gaze = Utils.FlipXCoordinates(new Vector2(commandDataServerGazeDataResult.rightEye.gazeDirNorm.x, commandDataServerGazeDataResult.rightEye.gazeDirNorm.y));
}
if (commandDataServerGazeDataResult.leftEye.isPupilDiaValid)
{
Tracking.Data.Eye.Left.PupilDiameterMm = commandDataServerGazeDataResult.leftEye.pupilDiaMm;
}
if (commandDataServerGazeDataResult.rightEye.isPupilDiaValid)
{
Tracking.Data.Eye.Right.PupilDiameterMm = commandDataServerGazeDataResult.rightEye.pupilDiaMm;
}
Tracking.Data.Eye.MinDilation = 0f;
Tracking.Data.Eye.MaxDilation = 10f;
}
}
}
namespace PSVR2.Features
{
public enum FeedbackMode
{
None,
Weapon,
Vibration
}
public class AdaptiveTriggers : Feature
{
[HarmonyPatch(typeof(Gun))]
private class GunPatches
{
[HarmonyPatch("Update")]
[HarmonyPostfix]
public static void Update(Gun __instance)
{
//IL_00df: Unknown result type (might be due to invalid IL or missing references)
//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
//IL_00f7: Expected I4, but got Unknown
if (!EnableAdaptiveTriggers.Value || !Player.HandsExist)
{
return;
}
Grip triggerGrip = __instance.triggerGrip;
Hand val = ((triggerGrip != null) ? triggerGrip.GetHand() : null);
if ((Object)(object)val == (Object)null)
{
return;
}
EVRControllerType eVRControllerType;
if ((Object)(object)val == (Object)(object)Player.LeftHand)
{
eVRControllerType = EVRControllerType.Left;
if (DisableLeft.Value)
{
return;
}
}
else
{
if (!((Object)(object)val == (Object)(object)Player.RightHand))
{
return;
}
eVRControllerType = EVRControllerType.Right;
}
if (__instance._magState == null)
{
if (GetCurrentFeedbackMode(eVRControllerType) != 0)
{
IpcClient.Instance().TriggerEffectDisable(eVRControllerType);
SetCurrentFeedbackMode(eVRControllerType, FeedbackMode.None);
}
return;
}
if ((Object)(object)__instance._ammoInventory == (Object)null)
{
if (GetCurrentFeedbackMode(eVRControllerType) != 0)
{
IpcClient.Instance().TriggerEffectDisable(eVRControllerType);
SetCurrentFeedbackMode(eVRControllerType, FeedbackMode.None);
}
return;
}
if (__instance.AmmoCount() <= 0 || (Object)(object)__instance.chamberedCartridge == (Object)null)
{
if (GetCurrentFeedbackMode(eVRControllerType) != 0)
{
IpcClient.Instance().TriggerEffectDisable(eVRControllerType);
SetCurrentFeedbackMode(eVRControllerType, FeedbackMode.None);
}
return;
}
FireMode fireMode = __instance.fireMode;
switch ((int)fireMode)
{
case 0:
if (GetCurrentFeedbackMode(eVRControllerType) != FeedbackMode.Weapon)
{
IpcClient.Instance().TriggerEffectWeapon(eVRControllerType, WeaponStart, WeaponEnd, WeaponStrength);
SetCurrentFeedbackMode(eVRControllerType, FeedbackMode.Weapon);
}
break;
case 1:
if (GetCurrentFeedbackMode(eVRControllerType) != FeedbackMode.Weapon)
{
IpcClient.Instance().TriggerEffectWeapon(eVRControllerType, WeaponStart, WeaponEnd, WeaponStrength);
SetCurrentFeedbackMode(eVRControllerType, FeedbackMode.Weapon);
}
break;
case 2:
if (GetCurrentFeedbackMode(eVRControllerType) != FeedbackMode.Vibration)
{
byte frequency = Convert.ToByte(Math.Min(40, (int)Math.Round(__instance.roundsPerMinute / 60f)));
IpcClient.Instance().TriggerEffectVibration(eVRControllerType, VibrationPosition, VibrationAmplitude, frequency);
SetCurrentFeedbackMode(eVRControllerType, FeedbackMode.Vibration);
}
break;
}
}
[HarmonyPatch("OnTriggerGripDetached")]
[HarmonyPostfix]
public static void OnTriggerGripDetached(Gun __instance, Hand hand)
{
if (!Player.HandsExist)
{
return;
}
EVRControllerType eVRControllerType;
if ((Object)(object)hand == (Object)(object)Player.LeftHand)
{
eVRControllerType = EVRControllerType.Left;
}
else
{
if (!((Object)(object)hand == (Object)(object)Player.RightHand))
{
return;
}
eVRControllerType = EVRControllerType.Right;
}
IpcClient.Instance().TriggerEffectDisable(eVRControllerType);
SetCurrentFeedbackMode(eVRControllerType, FeedbackMode.None);
}
}
internal static MelonPreferences_Entry<bool> EnableAdaptiveTriggers;
internal static MelonPreferences_Entry<bool> DisableLeft;
internal static MelonPreferences_Entry<byte> SingleFireFeedback;
public static byte WeaponStart = 2;
public static byte WeaponEnd = 4;
public static byte VibrationPosition = 4;
public static byte VibrationAmplitude = 8;
public static FeedbackMode CurrentRightFeedbackType = FeedbackMode.None;
public static FeedbackMode CurrentLeftFeedbackType = FeedbackMode.None;
public static byte WeaponStrength => SingleFireFeedback.Value;
public override void OnRegisterFeature()
{
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
EnableAdaptiveTriggers = Core.Category.CreateEntry<bool>("AdaptiveTriggers", true, "Adaptive Triggers", (string)null, false, false, (ValueValidator)null, (string)null);
DisableLeft = Core.Category.CreateEntry<bool>("DisableLeft", true, "Disable Left Controller", "Disables the (bugged) left controller use of adaptive triggers.", false, false, (ValueValidator)null, (string)null);
SingleFireFeedback = Core.Category.CreateEntry<byte>("SingleFireFeedback", (byte)4, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
Page obj = Core.RootPage.CreatePage("Adaptive Triggers", Color.white, 0, true);
obj.CreateBool("Enabled", Color.white, EnableAdaptiveTriggers.Value, (Action<bool>)delegate(bool b)
{
EnableAdaptiveTriggers.Value = b;
Core.Category.SaveToFile(false);
});
obj.CreateInt("Single Fire Resistance", Color.white, (int)SingleFireFeedback.Value, 1, 0, 8, (Action<int>)delegate(int i)
{
SingleFireFeedback.Value = Convert.ToByte(i);
Core.Category.SaveToFile(false);
});
obj.CreateBool("Disable Left Controller", Color.white, DisableLeft.Value, (Action<bool>)delegate(bool b)
{
DisableLeft.Value = b;
Core.Category.SaveToFile(false);
});
Hooking.OnLevelLoaded += OnLevelLoad;
Hooking.OnLevelUnloaded += OnLevelUnload;
}
private void OnLevelLoad(LevelInfo info)
{
SetCurrentFeedbackMode(EVRControllerType.Left, FeedbackMode.None);
SetCurrentFeedbackMode(EVRControllerType.Right, FeedbackMode.None);
IpcClient.Instance().TriggerEffectDisable(EVRControllerType.Left);
IpcClient.Instance().TriggerEffectDisable(EVRControllerType.Right);
}
private void OnLevelUnload()
{
SetCurrentFeedbackMode(EVRControllerType.Left, FeedbackMode.None);
SetCurrentFeedbackMode(EVRControllerType.Right, FeedbackMode.None);
IpcClient.Instance().TriggerEffectDisable(EVRControllerType.Left);
IpcClient.Instance().TriggerEffectDisable(EVRControllerType.Right);
}
public override void Update()
{
}
public override void FixedUpdate()
{
}
public override void LateUpdate()
{
}
public override void OnGUI()
{
}
public static void SetCurrentFeedbackMode(EVRControllerType controller, FeedbackMode feedbackMode)
{
switch (controller)
{
case EVRControllerType.Left:
CurrentLeftFeedbackType = feedbackMode;
break;
case EVRControllerType.Right:
CurrentRightFeedbackType = feedbackMode;
break;
}
}
public static FeedbackMode GetCurrentFeedbackMode(EVRControllerType controller)
{
return controller switch
{
EVRControllerType.Left => CurrentLeftFeedbackType,
EVRControllerType.Right => CurrentRightFeedbackType,
_ => FeedbackMode.None,
};
}
}
[HarmonyPatch]
internal class FingerCurl : Feature
{
[HarmonyPatch(typeof(OpenController))]
private class OpenControllerPatches
{
[HarmonyPatch("ProcessFingers")]
[HarmonyPostfix]
public static void ProcessFingers(OpenController __instance)
{
if (EnableFingerCurl.Value && Player.HandsExist)
{
((BaseController)__instance)._processedMiddle = Mathf.Clamp(((BaseController)__instance)._processedMiddle, 0.1f, 1f);
((BaseController)__instance)._processedIndex = Mathf.Clamp(((BaseController)__instance)._processedIndex, 0.1f, 1f);
((BaseController)__instance)._processedRing = Mathf.Clamp(((BaseController)__instance)._processedRing, 0.1f, 1f);
((BaseController)__instance)._processedPinky = Mathf.Clamp(((BaseController)__instance)._processedPinky, 0.1f, 1f);
}
}
}
internal static MelonPreferences_Entry<bool> EnableFingerCurl;
public override void OnRegisterFeature()
{
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
EnableFingerCurl = Core.Category.CreateEntry<bool>("FingerCurl", true, "Finger Curl", (string)null, false, false, (ValueValidator)null, (string)null);
Core.RootPage.CreateBool("Finger Curl", Color.white, EnableFingerCurl.Value, (Action<bool>)delegate(bool b)
{
EnableFingerCurl.Value = b;
Core.Category.SaveToFile(false);
});
}
public override void Update()
{
}
public override void FixedUpdate()
{
}
public override void LateUpdate()
{
}
public override void OnGUI()
{
}
}
}