using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Threading; using BoneLib; using BoneLib.BoneMenu; using Bonelab_bhaptics; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSLZ.Marrow; using Il2CppSLZ.Marrow.Combat; using Il2CppSLZ.Marrow.Data; using Il2CppSLZ.VRMK; using Il2CppSystem.Collections.Generic; using LabFusion.Network; using MelonLoader; using Microsoft.CodeAnalysis; using MyBhapticsTactsuit; using UnityEngine; using bHapticsLib; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(global::Bonelab_bhaptics.Bonelab_bhaptics), "Bonelab_bhaptics", "3.3.0", "Florian Fahrenberger/SoapyScripter", null)] [assembly: MelonGame("Stress Level Zero", "BONELAB")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("Bonelab_bhaptics")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Bonelab_bhaptics")] [assembly: AssemblyTitle("Bonelab_bhaptics")] [assembly: AssemblyVersion("1.0.0.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace MyBhapticsTactsuit { public class TactsuitVR { public bool suitDisabled = true; public bool systemInitialized; public bool faceConnected; public bool armsConnected; private static ManualResetEvent HeartBeat_mrse = new ManualResetEvent(initialState: false); private static ManualResetEvent Water_mrse = new ManualResetEvent(initialState: false); private static ManualResetEvent Choking_mrse = new ManualResetEvent(initialState: false); public Dictionary FeedbackMap = new Dictionary(); private static RotationOption defaultRotationOption = new RotationOption(0f, 0f); public void HeartBeatFunc() { while (true) { HeartBeat_mrse.WaitOne(); bHapticsManager.PlayRegistered("HeartBeat"); Thread.Sleep(1000); } } public TactsuitVR() { LOG("Initializing suit"); if (!bHaptics.WasError) { suitDisabled = false; } RegisterAllTactFiles(); LOG("Starting HeartBeat thread..."); new Thread(HeartBeatFunc).Start(); LOG("Check if face or arms are connected..."); if (bHapticsManager.IsDeviceConnected((PositionID)4)) { faceConnected = true; } if (bHapticsManager.IsDeviceConnected((PositionID)10) | bHapticsManager.IsDeviceConnected((PositionID)11)) { armsConnected = true; } } public void LOG(string logStr) { MelonLogger.Msg(logStr); } private void RegisterAllTactFiles() { FileInfo[] files = new DirectoryInfo(Directory.GetCurrentDirectory() + "\\Mods\\bHaptics").GetFiles("*.tact", SearchOption.AllDirectories); for (int i = 0; i < files.Length; i++) { string name = files[i].Name; string fullName = files[i].FullName; string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(name); if (!(name == ".") && !(name == "..")) { string text = File.ReadAllText(fullName); try { bHapticsManager.RegisterPatternFromJson(fileNameWithoutExtension, text); LOG("Pattern registered: " + fileNameWithoutExtension); } catch (Exception ex) { LOG(ex.ToString()); } FeedbackMap.Add(fileNameWithoutExtension, files[i]); } } systemInitialized = true; } public void PlaybackHaptics(string key, float intensity = 1f, float duration = 1f) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown if (MelonBase.FindMelon("LabFusion", "Lakatrazz") == null || !NetworkInfo.HasServer || !global::Bonelab_bhaptics.Bonelab_bhaptics.disablefusion) { if (FeedbackMap.ContainsKey(key)) { ScaleOption val = new ScaleOption(intensity, duration); bHapticsManager.PlayRegistered(key, key, val, defaultRotationOption); } else { LOG("Feedback not registered: " + key); } } } public void PlayBackHit(string key, float xzAngle, float yShift) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown ScaleOption val = new ScaleOption(1f, 1f); RotationOption val2 = new RotationOption(xzAngle, yShift); bHapticsManager.PlayRegistered(key, key, val, val2); } public void GunRecoil(bool isRightHand, float intensity = 1f, bool twoHanded = false) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown float num = 1f; ScaleOption val = new ScaleOption(intensity, num); if (twoHanded) { val = new ScaleOption(intensity * 0.5f, num); } RotationOption val2 = new RotationOption(0f, 0f); string text = "_L"; string text2 = "_R"; if (isRightHand) { text = "_R"; text2 = "_L"; } string text3 = "Recoil" + text; string text4 = "RecoilVest" + text; string text5 = "RecoilHands" + text; string text6 = "Recoil" + text2; string text7 = "RecoilVest" + text2; string text8 = "RecoilHands" + text2; bHapticsManager.PlayRegistered(text5, text5, val, val2); bHapticsManager.PlayRegistered(text3, text3, val, val2); bHapticsManager.PlayRegistered(text4, text4, val, val2); if (twoHanded) { bHapticsManager.PlayRegistered(text8, text8, val, val2); bHapticsManager.PlayRegistered(text6, text6, val, val2); bHapticsManager.PlayRegistered(text7, text7, val, val2); } } public void SwordRecoil(bool isRightHand, float intensity = 1f) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown float num = 1f; ScaleOption val = new ScaleOption(intensity, num); RotationOption val2 = new RotationOption(0f, 0f); string text = "_L"; if (isRightHand) { text = "_R"; } string text2 = "Sword" + text; string text3 = "SwordVest" + text; string text4 = "RecoilHands" + text; bHapticsManager.PlayRegistered(text4, text4, val, val2); bHapticsManager.PlayRegistered(text2, text2, val, val2); bHapticsManager.PlayRegistered(text3, text3, val, val2); } public void HeadShot(float hitAngle) { if (bHapticsManager.IsDeviceConnected((PositionID)4)) { if (hitAngle < 45f || hitAngle > 315f) { PlaybackHaptics("Headshot_F"); } if (hitAngle > 45f && hitAngle < 135f) { PlaybackHaptics("Headshot_L"); } if (hitAngle > 135f && hitAngle < 225f) { PlaybackHaptics("Headshot_B"); } if (hitAngle > 225f && hitAngle < 315f) { PlaybackHaptics("Headshot_R"); } } else { PlayBackHit("BulletHit", hitAngle, 0.5f); } } public void FootStep(bool isRightFoot) { if (!(!bHapticsManager.IsDeviceConnected((PositionID)8) | !bHapticsManager.IsDeviceConnected((PositionID)9))) { string text = "_L"; if (isRightFoot) { text = "_R"; } string key = "FootStep" + text; PlaybackHaptics(key); } } public void StartHeartBeat() { HeartBeat_mrse.Set(); } public void StopHeartBeat() { HeartBeat_mrse.Reset(); } public void StartWater() { Water_mrse.Set(); } public void StopWater() { Water_mrse.Reset(); } public void StartChoking() { Choking_mrse.Set(); } public void StopChoking() { Choking_mrse.Reset(); bHapticsManager.StopPlaying("TeleportOpened"); } public bool IsPlaying(string effect) { return bHapticsManager.IsPlaying(effect); } public void StopHapticFeedback(string effect) { bHapticsManager.StopPlaying(effect); } public void StopAllHapticFeedback() { StopThreads(); foreach (string key in FeedbackMap.Keys) { bHapticsManager.StopPlaying(key); } } public void StopThreads() { StopHeartBeat(); StopWater(); StopChoking(); } } } namespace Bonelab_bhaptics { public class Bonelab_bhaptics : MelonMod { [HarmonyPatch(typeof(RigManager), "Awake", new Type[] { })] public class bhaptics_GameControlRigManager { [HarmonyPostfix] public static void Postfix(RigManager __instance) { if ((Object)(object)myRigManager == (Object)null) { tactsuitVr.LOG("Player RigManager initialized... " + ((Object)__instance).name); myRigManager = __instance; } } } [HarmonyPatch(typeof(PlayerDamageReceiver), "ReceiveAttack", new Type[] { typeof(Attack) })] public class bhaptics_ReceiveAttack { [HarmonyPostfix] public static void Postfix(PlayerDamageReceiver __instance, Attack attack) { //IL_003e: 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) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Invalid comparison between Unknown and I4 //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Invalid comparison between Unknown and I4 //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Invalid comparison between Unknown and I4 //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Invalid comparison between Unknown and I4 //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Invalid comparison between Unknown and I4 //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Invalid comparison between Unknown and I4 //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Invalid comparison between Unknown and I4 //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Invalid comparison between Unknown and I4 //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Invalid comparison between Unknown and I4 //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Invalid comparison between Unknown and I4 //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)myRigManager != (Object)null) || (Object)(object)__instance.health._rigManager != (Object)(object)myRigManager) { return; } float num = 0.2f; float num2 = 0.8f; float num3 = 0.5f; bool flag = false; AttackType attackType = attack.attackType; string key; if ((int)attackType <= 2) { if ((int)attackType != 1) { if ((int)attackType != 2) { goto IL_0091; } key = "Impact"; } else { key = "BulletHit"; } } else if ((int)attackType != 8) { if ((int)attackType != 16) { if ((int)attackType != 32) { goto IL_0091; } key = "BulletHit"; } else { key = "BladeHit"; } } else { key = "LavaballHit"; } goto IL_0097; IL_0091: key = "Impact"; goto IL_0097; IL_0097: float num4 = Math.Abs(attack.damage); if ((int)__instance.bodyPart == 0) { num4 *= num2; if (tactsuitVr.faceConnected) { tactsuitVr.PlaybackHaptics("Headshot_F"); flag = true; } } if ((int)__instance.bodyPart == 6 || (int)__instance.bodyPart == 5) { num4 *= num; if (tactsuitVr.armsConnected) { tactsuitVr.PlaybackHaptics("Recoil_L"); flag = true; } } if ((int)__instance.bodyPart == 9 || (int)__instance.bodyPart == 8) { num4 *= num; if (tactsuitVr.armsConnected) { tactsuitVr.PlaybackHaptics("Recoil_R"); flag = true; } } if (!flag) { KeyValuePair keyValuePair = ((!((Object)(object)attack.collider != (Object)null)) ? getAngleAndShift(((Component)__instance).transform, attack.direction) : getAngleAndShift(((Component)__instance).transform, ((Component)attack.collider).transform.position)); tactsuitVr.PlayBackHit(key, keyValuePair.Key, keyValuePair.Value); num4 *= num3; } } } [HarmonyPatch(typeof(InventorySlotReceiver), "OnHandGrab", new Type[] { typeof(Hand) })] public class bhaptics_SlotGrab { [HarmonyPostfix] public static void Postfix(InventorySlotReceiver __instance, Hand hand) { if (__instance.isInUIMode || (Object)(object)hand == (Object)null || !((Object)(object)myRigManager != (Object)null) || (Object)(object)hand.manager != (Object)(object)myRigManager) { return; } string text = "BackCt"; foreach (SlotContainer item in (Il2CppArrayBase)(object)myRigManager.inventory.bodySlots) { if ((Object)(object)item.inventorySlotReceiver == (Object)(object)__instance) { text = ((Object)item).name; break; } } switch (text) { case "SideLf": tactsuitVr.PlaybackHaptics("StoreGun_L"); break; case "SideRt": tactsuitVr.PlaybackHaptics("StoreGun_R"); break; case "BackLf": tactsuitVr.PlaybackHaptics("ReceiveShoulder_L"); break; case "BackRt": tactsuitVr.PlaybackHaptics("ReceiveShoulder_R"); break; default: tactsuitVr.PlaybackHaptics("StoreGun_R"); break; } } } [HarmonyPatch(typeof(InventorySlotReceiver), "OnHandDrop", new Type[] { typeof(IGrippable) })] public class bhaptics_SlotInsert { [HarmonyPostfix] public static void Postfix(InventorySlotReceiver __instance, IGrippable host) { Hand lastHand = host.GetLastHand(); if (__instance.isInUIMode || (Object)(object)lastHand == (Object)null || !((Object)(object)myRigManager != (Object)null) || (Object)(object)lastHand.manager != (Object)(object)myRigManager) { return; } string text = "BackCt"; foreach (SlotContainer item in (Il2CppArrayBase)(object)myRigManager.inventory.bodySlots) { if ((Object)(object)item.inventorySlotReceiver == (Object)(object)__instance) { text = ((Object)item).name; break; } } switch (text) { case "SideLf": tactsuitVr.PlaybackHaptics("StoreGun_L"); break; case "SideRt": tactsuitVr.PlaybackHaptics("StoreGun_R"); break; case "BackLf": tactsuitVr.PlaybackHaptics("StoreShoulder_L"); break; case "BackRt": tactsuitVr.PlaybackHaptics("StoreShoulder_R"); break; default: tactsuitVr.PlaybackHaptics("StoreGun_R"); break; } } } [HarmonyPatch(typeof(Player_Health), "UpdateHealth", new Type[] { typeof(float) })] public class bhaptics_PlayerHealthUpdate { [HarmonyPostfix] public static void Postfix(Player_Health __instance) { if ((Object)(object)myRigManager != (Object)null && !((Object)(object)((Health)__instance)._rigManager != (Object)(object)myRigManager)) { if (((Health)__instance).curr_Health <= 0.3f * ((Health)__instance).max_Health) { tactsuitVr.StartHeartBeat(); } else { tactsuitVr.StopHeartBeat(); } } } } public static TactsuitVR tactsuitVr = null; public static bool playerRightHanded = true; public static RigManager myRigManager = null; public static bool disablefusion = false; public override void OnInitializeMelon() { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) tactsuitVr = new TactsuitVR(); Hooking.OnPostFireGun += OnPostFireGun; Hooking.OnPlayerDeath += OnPlayerDeath; Hooking.OnSwitchAvatarPostfix += OnSwitchAvatarPostfix; Page obj = Page.Root.CreatePage("bHaptics Mod", Color.yellow, 0, true); obj.CreateBool("Suit Connected", Color.white, !tactsuitVr.suitDisabled, (Action)delegate(bool value) { tactsuitVr.suitDisabled = value; }); obj.CreateBool("Visor Connected", Color.white, tactsuitVr.faceConnected, (Action)delegate(bool value) { tactsuitVr.faceConnected = value; }); obj.CreateBool("Sleeves Connected", Color.white, tactsuitVr.armsConnected, (Action)delegate(bool value) { tactsuitVr.armsConnected = value; }); obj.CreateBool("Disable In Fusion", Color.blue, disablefusion, (Action)delegate(bool value) { disablefusion = value; }); obj.CreateFunction("Create New Tactsuit", Color.yellow, (Action)delegate { tactsuitVr = new TactsuitVR(); }); obj.CreateFunction("Test Haptics", Color.yellow, (Action)delegate { tactsuitVr.PlaybackHaptics("SwitchAvatar"); }); } private void OnPostFireGun(Gun gun) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Invalid comparison between Unknown and I4 bool isRightHand = false; bool flag = false; if ((Object)(object)gun == (Object)null || (Object)(object)gun.triggerGrip == (Object)null || (Object)(object)gun.chamberedCartridge == (Object)null) { return; } flag = gun.triggerGrip.attachedHands.Count > 1; Enumerator enumerator = gun.triggerGrip.attachedHands.GetEnumerator(); while (enumerator.MoveNext()) { Hand current = enumerator.Current; if ((Object)(object)myRigManager.ControllerRig != (Object)(object)current.Controller.contRig) { return; } if ((int)current.handedness == 2) { isRightHand = true; break; } } if (!flag) { foreach (Grip item in (Il2CppArrayBase)(object)gun.otherGrips) { if (!flag) { flag = item.attachedHands.Count > 0; break; } } } float intensity = Mathf.Min(gun.muzzleVelocity / 1000f, 1f); tactsuitVr.GunRecoil(isRightHand, intensity, flag); } private static KeyValuePair getAngleAndShift(Transform player, Vector3 hit) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(0f, 0f, 1f); Vector3 val2 = hit - player.position; Quaternion rotation = player.rotation; Vector3 eulerAngles = ((Quaternion)(ref rotation)).eulerAngles; Vector3 val3 = new Vector3(val2.x, 0f, val2.z); float num = Vector3.Angle(val3, val); if (Vector3.Cross(val3, val).y < 0f) { num *= -1f; } float num2 = num - eulerAngles.y; num2 *= -1f; if (num2 < 0f) { num2 = 360f + num2; } float y = val2.y; float num3 = 0.5f; float num4 = -0.5f; y = ((y > num3) ? 0.5f : ((!(y < num4)) ? ((y - num4) / (num3 - num4) - 0.5f) : (-0.5f))); return new KeyValuePair(num2, y); } private void OnPlayerDeath(RigManager rm) { if ((Object)(object)myRigManager != (Object)null && !((Object)(object)rm != (Object)(object)myRigManager)) { tactsuitVr.StopThreads(); } } private void OnSwitchAvatarPostfix(Avatar avatar) { if ((Object)(object)myRigManager != (Object)null && !((Object)(object)avatar != (Object)(object)myRigManager.avatar)) { tactsuitVr.PlaybackHaptics("SwitchAvatar"); } } } }