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<string, FileInfo> FeedbackMap = new Dictionary<string, FileInfo>();
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<float, float> 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<SlotContainer>)(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<SlotContainer>)(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<bool>)delegate(bool value)
{
tactsuitVr.suitDisabled = value;
});
obj.CreateBool("Visor Connected", Color.white, tactsuitVr.faceConnected, (Action<bool>)delegate(bool value)
{
tactsuitVr.faceConnected = value;
});
obj.CreateBool("Sleeves Connected", Color.white, tactsuitVr.armsConnected, (Action<bool>)delegate(bool value)
{
tactsuitVr.armsConnected = value;
});
obj.CreateBool("Disable In Fusion", Color.blue, disablefusion, (Action<bool>)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<Hand> 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<Grip>)(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<float, float> 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<float, float>(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");
}
}
}
}