Decompiled source of RepoEventsBhaptics v2.1.0

RepoEventsBhaptics.dll

Decompiled 10 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Photon.Pun;
using UnityEngine;
using tact_csharp2;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("RepoEventsBhaptics")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("RepoEventsBhaptics")]
[assembly: AssemblyTitle("RepoEventsBhaptics")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace RepoEventsHaptics
{
	[BepInPlugin("com.dylan.repoevents", "REPO bHaptics", "1.0.0")]
	public class RepoEventsHaptics : BaseUnityPlugin
	{
		private static bool isHolding = false;

		internal static bool FloaterSmashJustHappened = false;

		internal static bool PlayerJustDied = false;

		private static string appId = "692b843fe3348ff1af12474b";

		private static string sdkKey = "iqYVDIQZUv1ZUA6eq3RS";

		private const float ConnectionCheckIntervalSeconds = 15f;

		private bool reconnectInProgress;

		private bool startedBhapticsPlayer;

		private bool shuttingDown;

		private bool sdkInitialized;

		private int startupInitAttempt;

		private const int StartupInitAttempts = 10;

		private const float StartupInitRetrySeconds = 1.5f;

		private Coroutine initCoroutine;

		private bool isQuitting;

		private bool startupInitStartedLogged;

		private bool startupInitFailedLogged;

		private void Awake()
		{
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Expected O, but got Unknown
			((BaseUnityPlugin)this).Logger.LogInfo((object)"RepoEventsHaptics plugin loaded (grab + collision + gun logging + item upgrades).");
			EnsureBhapticsPlayerRunning();
			startupInitAttempt = 0;
			TryInitializeBhapticsOnce();
			if (!sdkInitialized)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[HAPTIC DEBUG] Scheduling startup retries.");
				((MonoBehaviour)this).InvokeRepeating("TryInitializeBhapticsOnce", 1.5f, 1.5f);
			}
			try
			{
				bool flag = SemiFunc.IsMasterClientOrSingleplayer();
				((BaseUnityPlugin)this).Logger.LogInfo((object)(flag ? "[HAPTIC DEBUG] Game started in SINGLEPLAYER mode." : "[HAPTIC DEBUG] Game started in MULTIPLAYER mode."));
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[HAPTIC DEBUG] Could not determine game mode at startup: " + ex.Message));
			}
			try
			{
				Harmony val = new Harmony("com.dylan.repoevents");
				val.PatchAll();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[HAPTIC DEBUG] Harmony PatchAll completed.");
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"[HAPTIC DEBUG] Harmony PatchAll failed: {arg}");
			}
			((MonoBehaviour)this).InvokeRepeating("CheckBhapticsConnection", 15f, 15f);
			PlayerCollision val2 = Object.FindObjectOfType<PlayerCollision>();
			if ((Object)(object)val2 != (Object)null && (Object)(object)((Component)val2).gameObject.GetComponent<PlayerCollisionRelay>() == (Object)null)
			{
				((Component)val2).gameObject.AddComponent<PlayerCollisionRelay>();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"PlayerCollisionRelay attached to player.");
			}
		}

		private void TryInitializeBhapticsOnce()
		{
			if (shuttingDown)
			{
				((MonoBehaviour)this).CancelInvoke("TryInitializeBhapticsOnce");
				return;
			}
			if (sdkInitialized)
			{
				((MonoBehaviour)this).CancelInvoke("TryInitializeBhapticsOnce");
				return;
			}
			if (!startupInitStartedLogged)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[HAPTIC DEBUG] Startup initialization started.");
				startupInitStartedLogged = true;
			}
			startupInitAttempt++;
			try
			{
				bool flag = false;
				try
				{
					flag = BhapticsSDK2Wrapper.wsIsConnected();
				}
				catch
				{
				}
				if (flag)
				{
					sdkInitialized = true;
					((BaseUnityPlugin)this).Logger.LogInfo((object)"[HAPTIC DEBUG] bHaptics already connected at startup.");
					((MonoBehaviour)this).CancelInvoke("TryInitializeBhapticsOnce");
					return;
				}
				if (!BhapticsSDK2Wrapper.isPlayerRunning())
				{
					bool flag2 = BhapticsSDK2Wrapper.launchPlayer(tryLaunch: true);
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"[HAPTIC DEBUG] Startup launch attempt={flag2}");
				}
				bool flag3 = false;
				try
				{
					flag3 = BhapticsSDK2Wrapper.reInitMessage(sdkKey, appId, "");
				}
				catch
				{
				}
				if (!flag3)
				{
					try
					{
						flag3 = BhapticsSDK2Wrapper.registryAndInit(sdkKey, appId, "");
					}
					catch
					{
					}
				}
				bool flag4 = false;
				try
				{
					flag4 = BhapticsSDK2Wrapper.wsIsConnected();
				}
				catch
				{
				}
				if (flag3 && flag4)
				{
					sdkInitialized = true;
					((BaseUnityPlugin)this).Logger.LogInfo((object)"[HAPTIC DEBUG] bHaptics startup initialization succeeded.");
					((MonoBehaviour)this).CancelInvoke("TryInitializeBhapticsOnce");
					return;
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[HAPTIC DEBUG] Startup init exception: " + ex.Message));
			}
			if (startupInitAttempt >= 10)
			{
				if (!startupInitFailedLogged)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[HAPTIC DEBUG] bHaptics startup initialization failed after max attempts.");
					startupInitFailedLogged = true;
				}
				((MonoBehaviour)this).CancelInvoke("TryInitializeBhapticsOnce");
			}
		}

		private void OnApplicationQuit()
		{
			isQuitting = true;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[HAPTIC DEBUG] OnApplicationQuit fired.");
			ShutdownBhaptics(allowClosePlayerProcess: true);
		}

		private void OnDestroy()
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"[HAPTIC DEBUG] OnDestroy fired. isQuitting={isQuitting}");
			if (isQuitting)
			{
				ShutdownBhaptics(allowClosePlayerProcess: false);
			}
		}

		private void ShutdownBhaptics(bool allowClosePlayerProcess)
		{
			if (!shuttingDown)
			{
				shuttingDown = true;
				try
				{
					((MonoBehaviour)this).CancelInvoke("CheckBhapticsConnection");
					((MonoBehaviour)this).CancelInvoke("TryInitializeBhapticsOnce");
				}
				catch
				{
				}
				try
				{
					BhapticsSDK2Wrapper.stopAll();
				}
				catch
				{
				}
				try
				{
					BhapticsSDK2Wrapper.wsClose();
				}
				catch
				{
				}
				if (allowClosePlayerProcess && startedBhapticsPlayer)
				{
					TryCloseBhapticsPlayerProcess();
				}
			}
		}

		private void TryCloseBhapticsPlayerProcess()
		{
			try
			{
				Process[] processesByName = Process.GetProcessesByName("bHapticsPlayer");
				foreach (Process process in processesByName)
				{
					try
					{
						if (!process.HasExited)
						{
							process.CloseMainWindow();
							if (!process.WaitForExit(2000))
							{
								process.Kill();
							}
						}
					}
					catch
					{
					}
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[HAPTIC DEBUG] Failed to close bHaptics Player process: " + ex.Message));
			}
		}

		private void CheckBhapticsConnection()
		{
			bool flag;
			try
			{
				flag = BhapticsSDK2Wrapper.wsIsConnected();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[HAPTIC DEBUG] wsIsConnected check failed: " + ex.Message));
				return;
			}
			if (flag || reconnectInProgress)
			{
				return;
			}
			reconnectInProgress = true;
			try
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"[HAPTIC DEBUG] bHaptics socket disconnected. Attempting reconnection...");
				try
				{
					if (!BhapticsSDK2Wrapper.isPlayerRunning())
					{
						bool flag2 = BhapticsSDK2Wrapper.launchPlayer(tryLaunch: true);
						((BaseUnityPlugin)this).Logger.LogInfo((object)$"[HAPTIC DEBUG] bHaptics Player launch attempted: {flag2}");
					}
				}
				catch (Exception ex2)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("[HAPTIC DEBUG] Could not verify/launch bHaptics Player: " + ex2.Message));
				}
				try
				{
					BhapticsSDK2Wrapper.wsClose();
				}
				catch
				{
				}
				bool flag3 = false;
				try
				{
					flag3 = BhapticsSDK2Wrapper.reInitMessage(sdkKey, appId, "");
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"[HAPTIC DEBUG] reInitMessage result={flag3}");
				}
				catch (Exception ex3)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)(ex3.Message ?? ""));
				}
				if (!flag3)
				{
					try
					{
						flag3 = BhapticsSDK2Wrapper.registryAndInit(sdkKey, appId, "");
						((BaseUnityPlugin)this).Logger.LogInfo((object)$"[HAPTIC DEBUG] registryAndInit retry result={flag3}");
					}
					catch (Exception ex4)
					{
						((BaseUnityPlugin)this).Logger.LogError((object)("[HAPTIC DEBUG] registryAndInit retry failed: " + ex4.Message));
					}
				}
				bool flag4 = false;
				try
				{
					flag4 = BhapticsSDK2Wrapper.wsIsConnected();
				}
				catch
				{
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[HAPTIC DEBUG] Reconnect finished. connected={flag4}");
			}
			finally
			{
				reconnectInProgress = false;
			}
		}

		private void EnsureBhapticsPlayerRunning()
		{
			try
			{
				if (!BhapticsSDK2Wrapper.isPlayerInstalled())
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[HAPTIC DEBUG] bHaptics Player is not installed.");
					return;
				}
				if (BhapticsSDK2Wrapper.isPlayerRunning())
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"[HAPTIC DEBUG] bHaptics Player already running.");
					return;
				}
				bool flag = (startedBhapticsPlayer = BhapticsSDK2Wrapper.launchPlayer(tryLaunch: true));
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[HAPTIC DEBUG] bHaptics Player launch requested. success={flag}");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[HAPTIC DEBUG] Failed to start bHaptics Player: " + ex.Message));
			}
		}

		internal static int Play(string eventId)
		{
			try
			{
				Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)("[bHaptics] Play called for event: " + eventId));
				Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)("[HAPTIC DEBUG] About to play haptic event: " + eventId));
				return BhapticsSDK2Wrapper.play(eventId);
			}
			catch (Exception ex)
			{
				Logger.CreateLogSource("RepoEventsHaptics").LogError((object)("Play failed for " + eventId + ": " + ex.Message));
				return -1;
			}
		}

		internal static void Stop(string eventId)
		{
			try
			{
				BhapticsSDK2Wrapper.stopByEventId(eventId);
			}
			catch (Exception ex)
			{
				Logger.CreateLogSource("RepoEventsHaptics").LogError((object)("Stop failed for " + eventId + ": " + ex.Message));
			}
		}

		internal static void OnGrabStarted()
		{
			if (!isHolding)
			{
				Play("grabfeedback");
				isHolding = true;
			}
		}

		internal static void OnGrabEnded()
		{
			if (isHolding)
			{
				Stop("grabfeedback");
				isHolding = false;
			}
		}

		internal static void OnCollisionStarted(Collision collision, PlayerCollision player)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			Play("collisionfeedback");
			ContactPoint[] contacts = collision.contacts;
			for (int i = 0; i < contacts.Length; i++)
			{
				ContactPoint val = contacts[i];
				Vector3 val2 = ((Component)player).transform.InverseTransformPoint(((ContactPoint)(ref val)).point);
				Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)$"Collision START at local {val2} with {((Object)collision.gameObject).name}");
			}
		}

		internal static void OnCollisionEnded(Collision collision, PlayerCollision player)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			Stop("collisionfeedback");
			ContactPoint[] contacts = collision.contacts;
			for (int i = 0; i < contacts.Length; i++)
			{
				ContactPoint val = contacts[i];
				Vector3 val2 = ((Component)player).transform.InverseTransformPoint(((ContactPoint)(ref val)).point);
				Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)$"Collision END at local {val2} with {((Object)collision.gameObject).name}");
			}
		}

		internal static void OnGunFired(ItemGun gun)
		{
			Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)("[HAPTIC DEBUG] OnGunFired called. Gun type: " + ((object)gun).GetType().FullName + ", Gun name: " + ((Object)gun).name));
			object obj = AccessTools.Field(((object)gun).GetType(), "physGrabObject")?.GetValue(gun);
			if (obj == null)
			{
				Logger.CreateLogSource("RepoEventsHaptics").LogWarning((object)"[HAPTIC DEBUG] physGrabObject is null. Cannot resolve player.");
				return;
			}
			object obj2 = AccessTools.Field(obj.GetType(), "lastPlayerGrabbing")?.GetValue(obj);
			if (obj2 == null)
			{
				Logger.CreateLogSource("RepoEventsHaptics").LogWarning((object)"[HAPTIC DEBUG] lastPlayerGrabbing is null. Cannot resolve player.");
				return;
			}
			Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)$"[HAPTIC DEBUG] lastPlayerGrabbing type: {obj2.GetType().FullName}, value: {obj2}");
			PlayerAvatar val = (PlayerAvatar)((obj2 is PlayerAvatar) ? obj2 : null);
			if ((Object)(object)val == (Object)null)
			{
				Type type = obj2.GetType();
				PropertyInfo propertyInfo = type.GetProperty("playerAvatar", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetProperty("avatar", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetProperty("owner", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (propertyInfo != null)
				{
					object? value = propertyInfo.GetValue(obj2, null);
					val = (PlayerAvatar)((value is PlayerAvatar) ? value : null);
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Type type2 = obj2.GetType();
				FieldInfo[] fields = type2.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)$"[HAPTIC DEBUG] lastPlayerGrabbing field: {fieldInfo.Name}, type: {fieldInfo.FieldType}");
				}
				PropertyInfo[] properties = type2.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (PropertyInfo propertyInfo2 in properties)
				{
					Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)$"[HAPTIC DEBUG] lastPlayerGrabbing property: {propertyInfo2.Name}, type: {propertyInfo2.PropertyType}");
				}
				Logger.CreateLogSource("RepoEventsHaptics").LogWarning((object)"[HAPTIC DEBUG] playerAvatar is null. Cannot resolve player.");
				return;
			}
			PhotonView component = ((Component)val).GetComponent<PhotonView>();
			if ((Object)(object)component == (Object)null)
			{
				Logger.CreateLogSource("RepoEventsHaptics").LogWarning((object)"[HAPTIC DEBUG] PhotonView is null on playerAvatar.");
				return;
			}
			bool flag = false;
			try
			{
				flag = SemiFunc.IsMasterClientOrSingleplayer();
			}
			catch
			{
			}
			if (!flag && !component.IsMine)
			{
				Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)"[HAPTIC DEBUG] PhotonView is not mine. Not playing haptic.");
				return;
			}
			if (flag)
			{
				Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)"[HAPTIC DEBUG] Singleplayer mode detected, skipping PhotonView check.");
			}
			string name = ((Object)gun).name;
			string text;
			if (name.Contains("Shotgun"))
			{
				text = "playershootsshotgun";
			}
			else if (name.Contains("Shockwave"))
			{
				text = "playershootsshockwave";
			}
			else if (name.Contains("Handgun"))
			{
				text = "playershootspistol";
			}
			else if (name.Contains("Stun"))
			{
				text = "playershootsstun";
			}
			else if (name.Contains("Laser"))
			{
				text = "playershootslaser";
			}
			else
			{
				text = "playershootsgeneric";
				Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)("[HAPTIC DEBUG] Uncaptured weapon: '" + name + "'. Playing generic haptic event."));
			}
			Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)("[HAPTIC DEBUG] Playing haptic event '" + text + "' for gun '" + name + "'."));
			Play(text);
		}

		internal static void OnStaffCast(MonoBehaviour staff)
		{
			PhotonView component = ((Component)staff).GetComponent<PhotonView>();
			bool flag = false;
			try
			{
				flag = SemiFunc.IsMasterClientOrSingleplayer();
			}
			catch
			{
			}
			if (!flag && ((Object)(object)component == (Object)null || !component.IsMine))
			{
				Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)"[HAPTIC DEBUG] StaffCast: PhotonView is not mine or null. Not playing haptic.");
				return;
			}
			if (flag)
			{
				Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)"[HAPTIC DEBUG] StaffCast: Singleplayer mode detected, skipping PhotonView check.");
			}
			string text = ((Object)staff).name ?? ((object)staff).GetType().Name;
			string text2 = ((text.IndexOf("Item Staff Void", StringComparison.OrdinalIgnoreCase) >= 0) ? "staff_cast_void" : ((text.IndexOf("Item Staff Torque", StringComparison.OrdinalIgnoreCase) >= 0) ? "staff_cast_torque" : ((text.IndexOf("Item Staff Zero Gravity", StringComparison.OrdinalIgnoreCase) < 0) ? "staff_cast_generic" : "staff_cast_zerog")));
			Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)("[HAPTIC DEBUG] Staff cast detected: '" + text + "', playing haptic '" + text2 + "'."));
			Play(text2);
		}
	}
	[HarmonyPatch(typeof(ItemGun), "Shoot")]
	internal class ItemGunShootPatch
	{
		private static void Postfix(ItemGun __instance)
		{
			RepoEventsHaptics.OnGunFired(__instance);
		}
	}
	[HarmonyPatch(typeof(PhysGrabObject), "GrabStarted")]
	internal class GrabStartedPatch
	{
		private static void Postfix(PhysGrabObject __instance)
		{
			FieldInfo fieldInfo = AccessTools.Field(typeof(PhysGrabObject), "heldByLocalPlayer");
			if (fieldInfo != null && (bool)fieldInfo.GetValue(__instance))
			{
				RepoEventsHaptics.OnGrabStarted();
			}
		}
	}
	[HarmonyPatch(typeof(PhysGrabObject), "GrabEnded")]
	internal class GrabEndedPatch
	{
		private static void Postfix(PhysGrabObject __instance)
		{
			FieldInfo fieldInfo = AccessTools.Field(typeof(PhysGrabObject), "heldByLocalPlayer");
			if (fieldInfo != null && (bool)fieldInfo.GetValue(__instance))
			{
				RepoEventsHaptics.OnGrabEnded();
			}
		}
	}
	[HarmonyPatch(typeof(ItemStaffVoid), "CastSpell", new Type[] { typeof(bool) })]
	internal class ItemStaffVoidCastSpellPatch
	{
		private static void Postfix(ItemStaffVoid __instance)
		{
			Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)"[HAPTIC DEBUG] ItemStaffVoidCastSpellPatch.Postfix called.");
			RepoEventsHaptics.OnStaffCast((MonoBehaviour)(object)__instance);
		}
	}
	[HarmonyPatch(typeof(ItemStaffTorque), "CastSpell", new Type[] { typeof(bool) })]
	internal class ItemStaffTorqueCastSpellPatch
	{
		private static void Postfix(ItemStaffTorque __instance)
		{
			Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)"[HAPTIC DEBUG] ItemStaffTorqueCastSpellPatch.Postfix called.");
			RepoEventsHaptics.OnStaffCast((MonoBehaviour)(object)__instance);
		}
	}
	[HarmonyPatch(typeof(ItemStaffZeroGravity), "CastSpell", new Type[] { typeof(bool) })]
	internal class ItemStaffZeroGravityCastSpellPatch
	{
		private static void Postfix(ItemStaffZeroGravity __instance)
		{
			Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)"[HAPTIC DEBUG] ItemStaffZeroGravityCastSpellPatch.Postfix called.");
			RepoEventsHaptics.OnStaffCast((MonoBehaviour)(object)__instance);
		}
	}
	public class PlayerCollisionRelay : MonoBehaviour
	{
		private PlayerCollision player;

		private void Awake()
		{
			player = ((Component)this).GetComponent<PlayerCollision>();
		}

		private void OnCollisionEnter(Collision other)
		{
			if ((Object)(object)player != (Object)null)
			{
				RepoEventsHaptics.OnCollisionStarted(other, player);
			}
		}

		private void OnCollisionExit(Collision other)
		{
			if ((Object)(object)player != (Object)null)
			{
				RepoEventsHaptics.OnCollisionEnded(other, player);
			}
		}
	}
	[HarmonyPatch(typeof(ItemUpgrade), "PlayerUpgrade")]
	internal class ItemUpgradePatch
	{
		private static FieldInfo playerIdField;

		private static void Postfix(ItemUpgrade __instance)
		{
			try
			{
				ItemToggle component = ((Component)__instance).GetComponent<ItemToggle>();
				if ((Object)(object)component == (Object)null)
				{
					return;
				}
				if (playerIdField == null)
				{
					playerIdField = typeof(ItemToggle).GetField("playerTogglePhotonID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(ItemToggle).GetField("field_Private_Int32_0", BindingFlags.Instance | BindingFlags.NonPublic) ?? typeof(ItemToggle).GetField("field_Public_Int32_0", BindingFlags.Instance | BindingFlags.Public) ?? typeof(ItemToggle).GetField("<playerTogglePhotonID>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic);
				}
				if (playerIdField == null)
				{
					return;
				}
				int num = (int)playerIdField.GetValue(component);
				PlayerAvatar val = SemiFunc.PlayerAvatarGetFromPhotonID(num);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				PhotonView component2 = ((Component)val).GetComponent<PhotonView>();
				bool flag = false;
				try
				{
					flag = SemiFunc.IsMasterClientOrSingleplayer();
				}
				catch
				{
				}
				if (flag || (!((Object)(object)component2 == (Object)null) && component2.IsMine))
				{
					if (flag)
					{
						Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)"[HAPTIC DEBUG] Singleplayer mode detected, skipping PhotonView check (ItemUpgradePatch).");
					}
					string name = ((Object)__instance).name;
					string eventId = "playerupgrade_generic";
					if (name.Contains("Tumble Climb"))
					{
						eventId = "playerupgrade_tumbleclimb";
					}
					else if (name.Contains("Map Player Count"))
					{
						eventId = "playerupgrade_mapcount";
					}
					else if (name.Contains("Sprint Speed"))
					{
						eventId = "playerupgrade_sprintspeed";
					}
					else if (name.Contains("Grab Range"))
					{
						eventId = "playerupgrade_grabrange";
					}
					else if (name.Contains("Energy"))
					{
						eventId = "playerupgrade_energy";
					}
					else if (name.Contains("Grab Strength"))
					{
						eventId = "playerupgrade_grabstrength";
					}
					else if (name.Contains("Extra Jump"))
					{
						eventId = "playerupgrade_extrajump";
					}
					else if (name.Contains("Health"))
					{
						eventId = "playerupgrade_health";
					}
					else if (name.Contains("Tumble Wing"))
					{
						eventId = "playerupgrade_tumblewings";
					}
					else if (name.Contains("Tumble Launch"))
					{
						eventId = "playerupgrade_tumblelaunch";
					}
					else if (name.Contains("Death Head Battery"))
					{
						eventId = "playerupgrade_deadhead";
					}
					else if (name.Contains("Crouch Rest"))
					{
						eventId = "playerupgrade_crouchrest";
					}
					RepoEventsHaptics.Play(eventId);
				}
			}
			catch (Exception ex)
			{
				Logger.CreateLogSource("RepoEventsHaptics").LogError((object)("ItemUpgradePatch failed: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(PlayerDeathEffects), "Trigger")]
	internal class PlayerDeathEffectsTriggerPatch
	{
		private static void Postfix(PlayerDeathEffects __instance)
		{
			try
			{
				Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)"[HAPTIC DEBUG] PlayerDeathEffects.Trigger postfix called.");
				PlayerAvatar componentInParent = ((Component)__instance).GetComponentInParent<PlayerAvatar>();
				if ((Object)(object)componentInParent == (Object)null)
				{
					Logger.CreateLogSource("RepoEventsHaptics").LogWarning((object)"[HAPTIC DEBUG] Death patch: PlayerAvatar not found.");
					return;
				}
				bool flag = false;
				try
				{
					flag = SemiFunc.IsMasterClientOrSingleplayer();
				}
				catch
				{
				}
				if (!flag)
				{
					PhotonView component = ((Component)componentInParent).GetComponent<PhotonView>();
					if ((Object)(object)component == (Object)null || !component.IsMine)
					{
						Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)"[HAPTIC DEBUG] Death patch: Not local player in multiplayer.");
						return;
					}
				}
				RepoEventsHaptics.PlayerJustDied = true;
				int num = RepoEventsHaptics.Play("playerdeath");
				Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)$"[HAPTIC DEBUG] playerdeath played. reqId={num}");
			}
			catch (Exception ex)
			{
				Logger.CreateLogSource("RepoEventsHaptics").LogError((object)("PlayerDeathEffectsTriggerPatch failed: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(PlayerTumble), "ImpactHurtSet")]
	internal class FloaterImpactHurtPatch
	{
		private static void Postfix(PlayerTumble __instance, object[] __args)
		{
			try
			{
				PhotonView componentInParent = ((Component)__instance).GetComponentInParent<PhotonView>();
				if ((Object)(object)componentInParent == (Object)null)
				{
					return;
				}
				bool flag = false;
				try
				{
					flag = SemiFunc.IsMasterClientOrSingleplayer();
				}
				catch
				{
				}
				if (flag || componentInParent.IsMine)
				{
					if (flag)
					{
						Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)"[HAPTIC DEBUG] Singleplayer mode detected, skipping PhotonView check.");
					}
					RepoEventsHaptics.FloaterSmashJustHappened = true;
					RepoEventsHaptics.Play("hurt_floater_smash");
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(EnemyHeartHugger), "StateLure")]
	internal class HeartHuggerDistanceScaledPullPatch
	{
		private static void Postfix(EnemyHeartHugger __instance)
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			object? obj = typeof(EnemyHeartHugger).GetField("currentTarget", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(__instance);
			PlayerAvatar val = (PlayerAvatar)((obj is PlayerAvatar) ? obj : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			PhotonView component = ((Component)val).GetComponent<PhotonView>();
			bool flag = false;
			try
			{
				flag = SemiFunc.IsMasterClientOrSingleplayer();
			}
			catch
			{
			}
			if (((Object)(object)component != (Object)null && component.IsMine) || ((Object)(object)PlayerAvatar.instance != (Object)null && (Object)(object)val == (Object)(object)PlayerAvatar.instance) || flag)
			{
				if (flag)
				{
					Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)"[HAPTIC DEBUG] Singleplayer mode detected, skipping PhotonView check (HeartHuggerDistanceScaledPullPatch).");
				}
				float num = Vector3.Distance(((Component)val).transform.position, ((Component)__instance).transform.position);
				RepoEventsHaptics.Play("heart_hugger_pull");
			}
		}
	}
	[HarmonyPatch(typeof(PlayerHealth))]
	public static class GenericHurtHapticPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch("Hurt", new Type[]
		{
			typeof(int),
			typeof(bool),
			typeof(int),
			typeof(bool)
		})]
		public static void Postfix_GenericHurt(PlayerHealth __instance, int damage, bool savingGrace, int enemyIndex, bool hurtByHeal)
		{
			Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)$"[HAPTIC DEBUG] PlayerHealth.Hurt postfix called: damage={damage}, savingGrace={savingGrace}, enemyIndex={enemyIndex}, hurtByHeal={hurtByHeal}");
			try
			{
				if (damage <= 0)
				{
					return;
				}
				bool flag = false;
				try
				{
					flag = SemiFunc.IsMasterClientOrSingleplayer();
				}
				catch
				{
				}
				if (!flag)
				{
					PhotonView componentInParent = ((Component)__instance).GetComponentInParent<PhotonView>();
					if ((Object)(object)componentInParent == (Object)null)
					{
						Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)"[HAPTIC DEBUG] Skipping: PhotonView is null (multiplayer)");
						return;
					}
					if (!componentInParent.IsMine)
					{
						Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)"[HAPTIC DEBUG] Skipping: PhotonView is not mine (multiplayer)");
						return;
					}
				}
				else
				{
					Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)"[HAPTIC DEBUG] Singleplayer mode detected, skipping PhotonView check.");
				}
				if (RepoEventsHaptics.FloaterSmashJustHappened)
				{
					Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)"[HAPTIC DEBUG] Skipping haptic: FloaterSmashJustHappened was true");
					RepoEventsHaptics.FloaterSmashJustHappened = false;
				}
				else if (RepoEventsHaptics.PlayerJustDied)
				{
					Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)"[HAPTIC DEBUG] Skipping haptic: PlayerJustDied was true");
					RepoEventsHaptics.PlayerJustDied = false;
				}
				else if (damage < 33)
				{
					Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)"[HAPTIC DEBUG] Playing haptic: player_hurt_low");
					RepoEventsHaptics.Play("player_hurt_low");
				}
				else if (damage < 67)
				{
					Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)"[HAPTIC DEBUG] Playing haptic: player_hurt_medium");
					RepoEventsHaptics.Play("player_hurt_medium");
				}
				else
				{
					Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)"[HAPTIC DEBUG] Playing haptic: player_hurt_high");
					RepoEventsHaptics.Play("player_hurt_high");
				}
			}
			catch (Exception arg)
			{
				Logger.CreateLogSource("RepoEventsHaptics").LogError((object)$"[GenericHurt] Error in Hurt postfix: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(FloaterAttackLogic), "StateLevitateFixed")]
	internal class FloaterLevitateLoopPatch
	{
		private static void Postfix(FloaterAttackLogic __instance)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Invalid comparison between Unknown and I4
			FieldInfo field = typeof(FloaterAttackLogic).GetField("state", BindingFlags.Instance | BindingFlags.NonPublic);
			FloaterAttackState val = (FloaterAttackState)field.GetValue(__instance);
			if ((int)val != 1)
			{
				return;
			}
			FieldInfo field2 = typeof(FloaterAttackLogic).GetField("capturedPlayerAvatars", BindingFlags.Instance | BindingFlags.NonPublic);
			if (!(field2.GetValue(__instance) is List<PlayerAvatar> list))
			{
				return;
			}
			foreach (PlayerAvatar item in list)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				PhotonView component = ((Component)item).GetComponent<PhotonView>();
				bool flag = false;
				try
				{
					flag = SemiFunc.IsMasterClientOrSingleplayer();
				}
				catch
				{
				}
				if (!(((Object)(object)component != (Object)null && component.IsMine) || ((Object)(object)PlayerAvatar.instance != (Object)null && (Object)(object)item == (Object)(object)PlayerAvatar.instance) || flag))
				{
					continue;
				}
				if (flag)
				{
					Logger.CreateLogSource("RepoEventsHaptics").LogInfo((object)"[HAPTIC DEBUG] Singleplayer mode detected, skipping PhotonView check (FloaterLevitateLoopPatch).");
				}
				RepoEventsHaptics.Play("floater_levitate_loop");
				break;
			}
		}
	}
}
namespace tact_csharp2
{
	public class BhapticsSDK2Wrapper
	{
		private const string ModuleName = "bhaptics_library";

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		public static extern bool registryAndInit(string sdkAPIKey, string workspaceId, string initData);

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		public static extern bool registryAndInitHost(string sdkAPIKey, string workspaceId, string initData, string url);

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		public static extern bool wsIsConnected();

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		public static extern void wsClose();

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		public static extern bool reInitMessage(string sdkAPIKey, string workspaceId, string initData);

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		public static extern int play(string eventId);

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		public static extern int playParam(string eventId, int requestId, float intensity, float duration, float angleX, float offsetY);

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		public static extern void playWithStartTime(string eventId, int requestId, int startMillis, float intensity, float duration, float angleX, float offsetY);

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		public static extern int playLoop(string eventId, int requestId, float intensity, float duration, float angleX, float offsetY, int interval, int maxCount);

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		public static extern int pause(string eventId);

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		public static extern bool resume(string eventId);

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		public static extern bool stop(int requestId);

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		public static extern bool stopByEventId(string eventId);

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		public static extern bool stopAll();

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		public static extern bool isPlaying();

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		public static extern bool isPlayingByRequestId(int requestId);

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		public static extern bool isPlayingByEventId(string eventId);

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		public static extern int playDot(int requestId, int position, int durationMillis, int[] motors, int size);

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		public static extern int playWaveform(int requestId, int position, int[] motorValues, int[] playTimeValues, int[] shapeValues, int motorLen);

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		public static extern int playPath(int requestId, int position, float[] xValues, float[] yValues, int[] intensityValues, int Len);

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		public static extern bool isbHapticsConnected(int position);

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		public static extern bool ping(string address);

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		public static extern bool pingAll();

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		public static extern bool swapPosition(string address);

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		public static extern bool setDeviceVsm(string address, int vsm);

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		public static extern IntPtr getDeviceInfoJson();

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		public static extern bool isPlayerInstalled();

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		public static extern bool isPlayerRunning();

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		public static extern bool launchPlayer(bool tryLaunch);

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		public static extern int getEventTime(string eventId);

		[DllImport("bhaptics_library", CallingConvention = CallingConvention.Cdecl)]
		public static extern IntPtr getHapticMappingsJson();
	}
}