Decompiled source of CrappyHapticTriggersforPSVR2 v1.0.0

Mods/hapticTriggers.dll

Decompiled a year ago
using System;
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.BoneMenu;
using MelonLoader;
using Microsoft.CodeAnalysis;
using PSVR2Toolkit.CAPI;
using UnityEngine;
using hapticTriggers;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(Core), "hapticTriggers", "1.0.0", "MajedCT", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("hapticTriggers")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("hapticTriggers")]
[assembly: AssemblyTitle("hapticTriggers")]
[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.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 = false;

		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 = null;

		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();
					return true;
				}
				return false;
			}
			catch (SocketException ex)
			{
				Console.WriteLine($"[IPC_CLIENT] Connection failed. LastError = {ex.SocketErrorCode}");
				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)
						{
							Console.WriteLine("[IPC_CLIENT] Disconnected from server.");
							break;
						}
						if (num2 < Marshal.SizeOf<CommandHeader>())
						{
							Console.WriteLine("[IPC_CLIENT] Received invalid command header size.");
						}
						else
						{
							HandleIpcCommand(array, num2);
						}
					}
					else
					{
						Thread.Sleep(1);
					}
				}
			}
			catch (OperationCanceledException)
			{
			}
			catch (Exception ex2)
			{
				if (m_running)
				{
					Console.WriteLine("[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:
				Console.WriteLine("[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:
						Console.WriteLine("[IPC_CLIENT] Handshake successful!");
						break;
					case EHandshakeResult.Failed:
						Console.WriteLine("[IPC_CLIENT] Handshake failed!");
						break;
					case EHandshakeResult.Outdated:
						Console.WriteLine($"[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);
				int num2 = Marshal.SizeOf<CommandHeader>() + num;
				byte[] array = new byte[num2];
				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)
			{
				int num = Marshal.SizeOf<CommandHeader>();
				byte[] array = new byte[num];
				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 hapticTriggers
{
	public class Core : MelonMod
	{
		private IpcClient ipcClient;

		private bool Toggle;

		public override void OnInitializeMelon()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			Page val = Page.Root.CreatePage("crappy haptic triggers", Color.magenta, 0, true);
			val.CreateBool("this shit doesnt even work", Color.yellow, false, (Action<bool>)delegate(bool value)
			{
				Toggle = value;
			});
			((MelonBase)this).LoggerInstance.Msg("Initializing PSVR2 triggers!");
			ipcClient = IpcClient.Instance();
			if (ipcClient.Start())
			{
				MelonLogger.Msg("connected to PSVR2Toolkit, i guess the mod works lmao");
			}
			else
			{
				MelonLogger.Msg("Failed to connect to PSVR2Toolkit, is PSVR2Toolkit running? \n(ur probably a stinky non-psvr2 user)");
			}
		}

		public override void OnUpdate()
		{
			bool toggle = Toggle;
			if (toggle = true)
			{
				EVRControllerType controllerType = EVRControllerType.Left;
				EVRControllerType controllerType2 = EVRControllerType.Right;
				ipcClient.TriggerEffectWeapon(controllerType, 2, 4, 3);
				ipcClient.TriggerEffectFeedback(controllerType, 128, 100);
				ipcClient.TriggerEffectWeapon(controllerType2, 2, 4, 3);
				ipcClient.TriggerEffectFeedback(controllerType2, 128, 100);
			}
			else
			{
				EVRControllerType controllerType3 = EVRControllerType.Left;
				EVRControllerType controllerType4 = EVRControllerType.Right;
				ipcClient.TriggerEffectWeapon(controllerType3, 0, 0, 0);
				ipcClient.TriggerEffectFeedback(controllerType3, 0, 0);
				ipcClient.TriggerEffectWeapon(controllerType4, 0, 0, 0);
				ipcClient.TriggerEffectFeedback(controllerType4, 0, 0);
			}
		}

		public override void OnApplicationQuit()
		{
			if (ipcClient != null)
			{
				EVRControllerType controllerType = EVRControllerType.Left;
				EVRControllerType controllerType2 = EVRControllerType.Right;
				ipcClient.TriggerEffectWeapon(controllerType, 0, 0, 0);
				ipcClient.TriggerEffectFeedback(controllerType, 0, 0);
				ipcClient.TriggerEffectWeapon(controllerType2, 0, 0, 0);
				ipcClient.TriggerEffectFeedback(controllerType2, 0, 0);
				ipcClient.Stop();
				MelonLogger.Msg("PSVR2 IPC Connection closed");
			}
		}
	}
}