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(); if ((Object)(object)val2 != (Object)null && (Object)(object)((Component)val2).gameObject.GetComponent() == (Object)null) { ((Component)val2).gameObject.AddComponent(); ((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(); 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(); 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(); } 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(); 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("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(); 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(); 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(); 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(); 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(); 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(); 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 list)) { return; } foreach (PlayerAvatar item in list) { if ((Object)(object)item == (Object)null) { continue; } PhotonView component = ((Component)item).GetComponent(); 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(); } }