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.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LethalHands;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("LethalHandsHandsFollowPatch")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("LethalHandsHandsFollowPatch")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("86729b87-dbc5-4c70-8934-7bfb73c9bdbe")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace BloodDraco.LethalHandsHandsFollowPatch;
[BepInPlugin("BloodDraco.LethalHandsHandsFollowPatch", "LethalHandsHandsFollowPatch", "2.3.1")]
public class LethalHandsHandsFollowPatch : BaseUnityPlugin
{
public const string ModGuid = "BloodDraco.LethalHandsHandsFollowPatch";
public const string ModName = "LethalHandsHandsFollowPatch";
public const string ModVersion = "2.3.1";
internal static LethalHandsHandsFollowPatch Instance;
internal static ManualLogSource Log;
internal static ConfigEntry<bool> Enabled;
internal static ConfigEntry<bool> OnlyWhenSquaredUp;
internal static ConfigEntry<float> MaxPitchDegrees;
internal static ConfigEntry<float> PitchStrength;
internal static ConfigEntry<float> UpperArmWeight;
internal static ConfigEntry<float> ForearmWeight;
internal static ConfigEntry<float> HandWeight;
internal static ConfigEntry<bool> EnableCameraHeightFollow;
internal static ConfigEntry<float> HeightFollowStrength;
internal static ConfigEntry<float> HeightMaxOffset;
internal static ConfigEntry<float> HeightSmoothingSpeed;
internal static ConfigEntry<float> DefaultArmHeight;
internal static ConfigEntry<float> DefaultArmForward;
internal static ConfigEntry<bool> EnableAutoForwardLookUp;
internal static ConfigEntry<float> AutoForwardMaxOffset;
internal static ConfigEntry<float> AutoForwardStrength;
internal static ConfigEntry<float> AutoForwardCurvePower;
internal static ConfigEntry<float> AutoForwardSmoothingSpeed;
internal static ConfigEntry<float> AutoForwardStartDegrees;
internal static ConfigEntry<bool> AutoForwardUpIsNegative;
internal static ConfigEntry<bool> AutoForwardUseCameraForward;
internal static ConfigEntry<string> ResetConfigBinding;
internal static ConfigEntry<bool> EnableThirdPersonReplication;
internal static ConfigEntry<float> NetSendRateHz;
internal static ConfigEntry<bool> NetOnlySendWhenSquaredUp;
internal static ConfigEntry<bool> DebugLogNetworking;
internal static ConfigEntry<bool> EnableThirdPersonSpineBlend;
internal static ConfigEntry<float> ThirdPersonMaxUpDegrees;
internal static ConfigEntry<float> ThirdPersonStrength;
internal static ConfigEntry<float> ThirdPersonSmoothingSpeed;
internal static ConfigEntry<float> SpineWeight;
internal static ConfigEntry<float> ChestWeight;
internal static ConfigEntry<float> UpperChestWeight;
internal static ConfigEntry<bool> ThirdPersonUpIsNegative;
private InputAction _resetAction;
private bool _resetActionHooked;
private float _nextSendTime;
private bool _lastSquaredUpState;
private void Awake()
{
//IL_04b2: Unknown result type (might be due to invalid IL or missing references)
//IL_04b7: Unknown result type (might be due to invalid IL or missing references)
//IL_04c7: Unknown result type (might be due to invalid IL or missing references)
//IL_04d7: Unknown result type (might be due to invalid IL or missing references)
Instance = this;
Log = ((BaseUnityPlugin)this).Logger;
Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable this patch.");
OnlyWhenSquaredUp = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "OnlyWhenSquaredUp", true, "Only apply while LethalHands is squared up.");
MaxPitchDegrees = ((BaseUnityPlugin)this).Config.Bind<float>("Look", "MaxPitchDegrees", 160f, "Clamp camera pitch.");
PitchStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Look", "PitchStrength", 1f, "Pitch multiplier (0..1).");
UpperArmWeight = ((BaseUnityPlugin)this).Config.Bind<float>("Weights", "UpperArmWeight", 0.85f, "Weight for upper arms.");
ForearmWeight = ((BaseUnityPlugin)this).Config.Bind<float>("Weights", "ForearmWeight", 0.35f, "Weight for forearms.");
HandWeight = ((BaseUnityPlugin)this).Config.Bind<float>("Weights", "HandWeight", 0.1f, "Weight for hands/wrists.");
EnableCameraHeightFollow = ((BaseUnityPlugin)this).Config.Bind<bool>("Height", "EnableCameraHeightFollow", true, "Follow camera height changes while squared up.");
HeightFollowStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Height", "HeightFollowStrength", 1f, "Multiplier for camera height delta.");
HeightMaxOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Height", "HeightMaxOffset", 0.12f, "Max absolute height offset in meters.");
HeightSmoothingSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Height", "HeightSmoothingSpeed", 18f, "Smoothing speed for height delta.");
DefaultArmHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Offsets", "DefaultArmHeight", 0.1f, "Base arm height offset in meters.");
DefaultArmForward = ((BaseUnityPlugin)this).Config.Bind<float>("Offsets", "DefaultArmForward", 0.05f, "Base arm forward offset in meters.");
EnableAutoForwardLookUp = ((BaseUnityPlugin)this).Config.Bind<bool>("AutoForward", "EnableAutoForwardLookUp", true, "Push arms forward the more you look UP (starts at level).");
AutoForwardMaxOffset = ((BaseUnityPlugin)this).Config.Bind<float>("AutoForward", "AutoForwardMaxOffset", 0.2f, "Max extra forward offset (meters) when looking fully up.");
AutoForwardStrength = ((BaseUnityPlugin)this).Config.Bind<float>("AutoForward", "AutoForwardStrength", 2f, "0..2 strength multiplier for auto-forward.");
AutoForwardCurvePower = ((BaseUnityPlugin)this).Config.Bind<float>("AutoForward", "AutoForwardCurvePower", 1.5f, "Curve shaping.");
AutoForwardSmoothingSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("AutoForward", "AutoForwardSmoothingSpeed", 20f, "Smoothing speed (higher = snappier).");
AutoForwardStartDegrees = ((BaseUnityPlugin)this).Config.Bind<float>("AutoForward", "AutoForwardStartDegrees", 0f, "Deadzone around level before auto-forward starts (degrees).");
AutoForwardUpIsNegative = ((BaseUnityPlugin)this).Config.Bind<bool>("AutoForward", "AutoForwardUpIsNegative", true, "If true, looking UP is negative pitch (typical Unity FPS).");
AutoForwardUseCameraForward = ((BaseUnityPlugin)this).Config.Bind<bool>("AutoForward", "AutoForwardUseCameraForward", true, "Use camera.forward projected into arm parent.");
ResetConfigBinding = ((BaseUnityPlugin)this).Config.Bind<string>("Controls", "ResetConfigBinding", "<Keyboard>/f8", "InputSystem binding path to reset this mod config.");
EnableThirdPersonReplication = ((BaseUnityPlugin)this).Config.Bind<bool>("Replication", "EnableThirdPersonReplication", true, "Send your look pitch to other clients so they can see third-person aim/spine pitch while squared up.");
NetSendRateHz = ((BaseUnityPlugin)this).Config.Bind<float>("Replication", "NetSendRateHz", 13f, "How often to send pitch (Hz). 10-20 recommended.");
NetOnlySendWhenSquaredUp = ((BaseUnityPlugin)this).Config.Bind<bool>("Replication", "NetOnlySendWhenSquaredUp", true, "Only send pitch while squared up (recommended).");
DebugLogNetworking = ((BaseUnityPlugin)this).Config.Bind<bool>("Replication", "DebugLogNetworking", false, "Log networking sends/receives (spammy).");
EnableThirdPersonSpineBlend = ((BaseUnityPlugin)this).Config.Bind<bool>("ThirdPerson", "EnableThirdPersonSpineBlend", true, "Apply replicated look pitch to other players' spines so you can see them aim/look up while squared up.");
ThirdPersonMaxUpDegrees = ((BaseUnityPlugin)this).Config.Bind<float>("ThirdPerson", "ThirdPersonMaxUpDegrees", 55f, "Max degrees of UP pitch applied in third person.");
ThirdPersonStrength = ((BaseUnityPlugin)this).Config.Bind<float>("ThirdPerson", "ThirdPersonStrength", 1f, "Multiplier for third-person spine pitch.");
ThirdPersonSmoothingSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("ThirdPerson", "ThirdPersonSmoothingSpeed", 18f, "Smoothing speed for third-person spine pitch.");
SpineWeight = ((BaseUnityPlugin)this).Config.Bind<float>("ThirdPerson", "SpineWeight", 0.2f, "Weight applied to Spine bone.");
ChestWeight = ((BaseUnityPlugin)this).Config.Bind<float>("ThirdPerson", "ChestWeight", 0.35f, "Weight applied to Chest bone.");
UpperChestWeight = ((BaseUnityPlugin)this).Config.Bind<float>("ThirdPerson", "UpperChestWeight", 0.45f, "Weight applied to UpperChest bone.");
ThirdPersonUpIsNegative = ((BaseUnityPlugin)this).Config.Bind<bool>("ThirdPerson", "ThirdPersonUpIsNegative", true, "If true, looking UP is negative pitch (typical Unity FPS).");
Harmony val = new Harmony("BloodDraco.LethalHandsHandsFollowPatch");
val.PatchAll(typeof(NetInitPatch));
val.PatchAll(typeof(NetLifecyclePatch));
val.PatchAll(typeof(AddSpineDriverPatch));
val.PatchAll(typeof(EmoteConstraintPitchPatch));
}
private void OnEnable()
{
TryHookResetAction();
}
private void Update()
{
if (!_resetActionHooked)
{
TryHookResetAction();
}
if (EnableThirdPersonReplication.Value)
{
HandsFollowLookNet.EnsureInitialized();
}
}
private void OnDisable()
{
UnhookResetAction();
HandsFollowLookNet.Shutdown();
}
private void OnDestroy()
{
UnhookResetAction();
HandsFollowLookNet.Shutdown();
}
private void LateUpdate()
{
//IL_0112: Unknown result type (might be due to invalid IL or missing references)
if (!Enabled.Value || !EnableThirdPersonReplication.Value || (Object)(object)StartOfRound.Instance == (Object)null)
{
return;
}
PlayerControllerB localPlayerController = StartOfRound.Instance.localPlayerController;
if ((Object)(object)localPlayerController == (Object)null || localPlayerController.isPlayerDead)
{
return;
}
bool flag = false;
if ((Object)(object)LethalHands.Instance != (Object)null)
{
flag = LethalHands.Instance.isSquaredUp;
}
if (flag != _lastSquaredUpState)
{
_lastSquaredUpState = flag;
if (flag)
{
Log.LogInfo((object)"[LethalHandsHandsFollowPatch] Active (squared up).");
}
else
{
Log.LogInfo((object)"[LethalHandsHandsFollowPatch] Inactive (not squared up).");
}
}
if (NetOnlySendWhenSquaredUp.Value && !flag)
{
HandsFollowLookNet.SendLocalPitch(localPlayerController, 0f, squaredUp: false);
return;
}
float num = Mathf.Max(1f, NetSendRateHz.Value);
float num2 = 1f / num;
if (Time.unscaledTime < _nextSendTime)
{
return;
}
_nextSendTime = Time.unscaledTime + num2;
Transform val = (((Object)(object)localPlayerController.gameplayCamera != (Object)null) ? ((Component)localPlayerController.gameplayCamera).transform : null);
if (!((Object)(object)val == (Object)null))
{
float num3 = val.localEulerAngles.x;
if (num3 > 180f)
{
num3 -= 360f;
}
HandsFollowLookNet.SendLocalPitch(localPlayerController, num3, flag);
}
}
private void TryHookResetAction()
{
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Expected O, but got Unknown
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
if (!_resetActionHooked && !((Object)(object)IngamePlayerSettings.Instance == (Object)null) && !((Object)(object)IngamePlayerSettings.Instance.playerInput == (Object)null) && !((Object)(object)IngamePlayerSettings.Instance.playerInput.actions == (Object)null))
{
_resetAction = new InputAction("BloodDraco_ResetLethalHandsHandsFollowPatch", (InputActionType)1, (string)null, (string)null, (string)null, (string)null);
string text = ResetConfigBinding.Value;
if (string.IsNullOrEmpty(text))
{
text = "<Keyboard>/f8";
}
InputActionSetupExtensions.AddBinding(_resetAction, text, (string)null, (string)null, (string)null);
_resetAction.performed += OnResetPerformed;
_resetAction.Enable();
_resetActionHooked = true;
Log.LogInfo((object)("[LethalHandsHandsFollowPatch] Reset action hooked: " + text));
}
}
private void UnhookResetAction()
{
if (_resetAction == null)
{
_resetActionHooked = false;
return;
}
try
{
_resetAction.performed -= OnResetPerformed;
_resetAction.Disable();
_resetAction.Dispose();
}
catch
{
}
_resetAction = null;
_resetActionHooked = false;
}
private void OnResetPerformed(CallbackContext ctx)
{
if (((CallbackContext)(ref ctx)).performed)
{
Log.LogInfo((object)"[LethalHandsHandsFollowPatch] Resetting config to defaults...");
((BaseUnityPlugin)this).Config.Reload();
}
}
}
[HarmonyPatch]
internal static class NetInitPatch
{
[HarmonyPatch(typeof(GameNetworkManager), "Start")]
[HarmonyPostfix]
private static void Postfix()
{
HandsFollowLookNet.EnsureInitialized();
}
}
[HarmonyPatch]
internal static class NetLifecyclePatch
{
[HarmonyPatch(typeof(GameNetworkManager), "Disconnect")]
[HarmonyPrefix]
private static void Prefix()
{
HandsFollowLookNet.Shutdown();
}
}
internal static class HandsFollowLookNet
{
private const string MsgName = "LH_HFP_PITCH";
internal static readonly Dictionary<ulong, float> PitchByClient = new Dictionary<ulong, float>();
internal static readonly Dictionary<ulong, bool> SquaredUpByClient = new Dictionary<ulong, bool>();
private static bool _initialized = false;
private static bool _handlerRegistered = false;
internal static void EnsureInitialized()
{
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Expected O, but got Unknown
if (_initialized)
{
return;
}
try
{
if ((Object)(object)NetworkManager.Singleton == (Object)null || NetworkManager.Singleton.CustomMessagingManager == null)
{
return;
}
if (!_handlerRegistered)
{
NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("LH_HFP_PITCH", new HandleNamedMessageDelegate(OnMessageReceived));
_handlerRegistered = true;
if (LethalHandsHandsFollowPatch.Log != null)
{
LethalHandsHandsFollowPatch.Log.LogInfo((object)"[LethalHandsHandsFollowPatch] Net handler registered.");
}
}
_initialized = true;
}
catch (Exception ex)
{
if (LethalHandsHandsFollowPatch.Log != null)
{
LethalHandsHandsFollowPatch.Log.LogWarning((object)("[LethalHandsHandsFollowPatch] Net init failed (will retry): " + ex.Message));
}
}
}
internal static void Shutdown()
{
_initialized = false;
try
{
if (_handlerRegistered && !((Object)(object)NetworkManager.Singleton == (Object)null) && NetworkManager.Singleton.CustomMessagingManager != null)
{
NetworkManager.Singleton.CustomMessagingManager.UnregisterNamedMessageHandler("LH_HFP_PITCH");
_handlerRegistered = false;
if (LethalHandsHandsFollowPatch.Log != null)
{
LethalHandsHandsFollowPatch.Log.LogInfo((object)"[LethalHandsHandsFollowPatch] Net handler unregistered.");
}
}
}
catch
{
}
}
internal static void SendLocalPitch(PlayerControllerB localPlayer, float pitchDeg, bool squaredUp)
{
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: 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_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
EnsureInitialized();
if ((Object)(object)NetworkManager.Singleton == (Object)null)
{
return;
}
CustomMessagingManager customMessagingManager = NetworkManager.Singleton.CustomMessagingManager;
if (customMessagingManager == null)
{
return;
}
FastBufferWriter val = default(FastBufferWriter);
((FastBufferWriter)(ref val))..ctor(13, (Allocator)2, -1);
try
{
ulong playerClientId = localPlayer.playerClientId;
((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref playerClientId, default(ForPrimitives));
((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref pitchDeg, default(ForPrimitives));
byte b = (squaredUp ? ((byte)1) : ((byte)0));
((FastBufferWriter)(ref val)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
if (NetworkManager.Singleton.IsServer)
{
ApplyPitch(playerClientId, pitchDeg, squaredUp);
customMessagingManager.SendNamedMessageToAll("LH_HFP_PITCH", val, (NetworkDelivery)3);
}
else
{
customMessagingManager.SendNamedMessage("LH_HFP_PITCH", 0uL, val, (NetworkDelivery)3);
}
if (LethalHandsHandsFollowPatch.DebugLogNetworking.Value && LethalHandsHandsFollowPatch.Log != null)
{
LethalHandsHandsFollowPatch.Log.LogInfo((object)("[Net] Send pitch=" + pitchDeg.ToString("F1") + " squared=" + squaredUp));
}
}
catch
{
}
finally
{
((FastBufferWriter)(ref val)).Dispose();
}
}
private static void OnMessageReceived(ulong senderClientId, FastBufferReader reader)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: 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_002c: 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_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: 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_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
try
{
ulong clientId = default(ulong);
((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref clientId, default(ForPrimitives));
float pitchDeg = default(float);
((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref pitchDeg, default(ForPrimitives));
byte b = default(byte);
((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b, default(ForPrimitives));
bool squaredUp = b != 0;
if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsServer)
{
ApplyPitch(clientId, pitchDeg, squaredUp);
FastBufferWriter val = default(FastBufferWriter);
((FastBufferWriter)(ref val))..ctor(13, (Allocator)2, -1);
try
{
((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref clientId, default(ForPrimitives));
((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref pitchDeg, default(ForPrimitives));
((FastBufferWriter)(ref val)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
NetworkManager.Singleton.CustomMessagingManager.SendNamedMessageToAll("LH_HFP_PITCH", val, (NetworkDelivery)3);
}
finally
{
((FastBufferWriter)(ref val)).Dispose();
}
}
else
{
ApplyPitch(clientId, pitchDeg, squaredUp);
}
if (LethalHandsHandsFollowPatch.DebugLogNetworking.Value && LethalHandsHandsFollowPatch.Log != null)
{
LethalHandsHandsFollowPatch.Log.LogInfo((object)("[Net] Recv id=" + clientId + " pitch=" + pitchDeg.ToString("F1") + " squared=" + squaredUp));
}
}
catch
{
}
}
private static void ApplyPitch(ulong clientId, float pitchDeg, bool squaredUp)
{
PitchByClient[clientId] = pitchDeg;
SquaredUpByClient[clientId] = squaredUp;
}
}
internal class ThirdPersonSpinePitchDriver : MonoBehaviour
{
private PlayerControllerB _player;
private Animator _anim;
private Transform _spine;
private Transform _chest;
private Transform _upperChest;
private float _smoothedUp;
private void Awake()
{
_player = ((Component)this).GetComponentInParent<PlayerControllerB>();
if ((Object)(object)_player == (Object)null)
{
((Behaviour)this).enabled = false;
return;
}
_anim = _player.playerBodyAnimator;
if ((Object)(object)_anim == (Object)null)
{
((Behaviour)this).enabled = false;
return;
}
_spine = SafeGetBone(_anim, (HumanBodyBones)7);
_chest = SafeGetBone(_anim, (HumanBodyBones)8);
_upperChest = SafeGetBone(_anim, (HumanBodyBones)54);
if ((Object)(object)_chest == (Object)null)
{
_chest = _spine;
}
if ((Object)(object)_upperChest == (Object)null)
{
_upperChest = _chest;
}
if ((Object)(object)_spine == (Object)null && (Object)(object)_chest == (Object)null && (Object)(object)_upperChest == (Object)null)
{
((Behaviour)this).enabled = false;
}
}
private Transform SafeGetBone(Animator a, HumanBodyBones b)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
try
{
return a.GetBoneTransform(b);
}
catch
{
return null;
}
}
private void LateUpdate()
{
//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
//IL_0219: Unknown result type (might be due to invalid IL or missing references)
//IL_021e: Unknown result type (might be due to invalid IL or missing references)
//IL_0229: Unknown result type (might be due to invalid IL or missing references)
//IL_022e: Unknown result type (might be due to invalid IL or missing references)
if (LethalHandsHandsFollowPatch.Enabled.Value && LethalHandsHandsFollowPatch.EnableThirdPersonSpineBlend.Value && !((Object)(object)_player == (Object)null) && !((Object)(object)_anim == (Object)null) && !((Object)(object)StartOfRound.Instance == (Object)null) && !_player.isPlayerDead && (!((Object)(object)StartOfRound.Instance.localPlayerController != (Object)null) || !((Object)(object)_player == (Object)(object)StartOfRound.Instance.localPlayerController)) && HandsFollowLookNet.SquaredUpByClient.TryGetValue(_player.playerClientId, out var value) && value && HandsFollowLookNet.PitchByClient.TryGetValue(_player.playerClientId, out var value2))
{
float num = (LethalHandsHandsFollowPatch.ThirdPersonUpIsNegative.Value ? (0f - value2) : value2);
if (num < 0f)
{
num = 0f;
}
float num2 = Mathf.Max(0f, LethalHandsHandsFollowPatch.ThirdPersonMaxUpDegrees.Value);
if (num > num2)
{
num = num2;
}
float num3 = Mathf.Clamp(LethalHandsHandsFollowPatch.ThirdPersonStrength.Value, 0f, 3f);
float num4 = num * num3;
float num5 = Mathf.Max(1f, LethalHandsHandsFollowPatch.ThirdPersonSmoothingSpeed.Value);
float num6 = 1f - Mathf.Exp((0f - num5) * Time.deltaTime);
_smoothedUp = Mathf.Lerp(_smoothedUp, num4, num6);
float num7 = Mathf.Clamp01(LethalHandsHandsFollowPatch.SpineWeight.Value);
float num8 = Mathf.Clamp01(LethalHandsHandsFollowPatch.ChestWeight.Value);
float num9 = Mathf.Clamp01(LethalHandsHandsFollowPatch.UpperChestWeight.Value);
if ((Object)(object)_spine != (Object)null)
{
_spine.localRotation = Quaternion.AngleAxis(_smoothedUp * num7, Vector3.right) * _spine.localRotation;
}
if ((Object)(object)_chest != (Object)null)
{
_chest.localRotation = Quaternion.AngleAxis(_smoothedUp * num8, Vector3.right) * _chest.localRotation;
}
if ((Object)(object)_upperChest != (Object)null)
{
_upperChest.localRotation = Quaternion.AngleAxis(_smoothedUp * num9, Vector3.right) * _upperChest.localRotation;
}
}
}
}
[HarmonyPatch]
internal static class AddSpineDriverPatch
{
[HarmonyPatch(typeof(PlayerControllerB), "Start")]
[HarmonyPostfix]
private static void Postfix(PlayerControllerB __instance)
{
try
{
if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance.playerBodyAnimator == (Object)null) && LethalHandsHandsFollowPatch.EnableThirdPersonSpineBlend.Value && !((Object)(object)((Component)__instance).GetComponent<ThirdPersonSpinePitchDriver>() != (Object)null))
{
((Component)__instance).gameObject.AddComponent<ThirdPersonSpinePitchDriver>();
}
}
catch
{
}
}
}
[HarmonyPatch]
internal static class EmoteConstraintPitchPatch
{
private struct SavedState
{
public bool appliedRot;
public Quaternion savedRot;
public bool appliedPos;
public Vector3 savedPos;
}
private static bool baselineValid = false;
private static float baselineCamY = 0f;
private static int baselinePlayerId = 0;
private static readonly Dictionary<int, float> smoothY = new Dictionary<int, float>();
private static readonly Dictionary<int, float> smoothForward = new Dictionary<int, float>();
[HarmonyPatch(typeof(EmoteConstraint), "ActUponConstraints")]
[HarmonyPrefix]
private static void Prefix(EmoteConstraint __instance, ref SavedState __state)
{
//IL_0121: Unknown result type (might be due to invalid IL or missing references)
//IL_0178: Unknown result type (might be due to invalid IL or missing references)
//IL_017d: Unknown result type (might be due to invalid IL or missing references)
//IL_0182: Unknown result type (might be due to invalid IL or missing references)
//IL_019d: Unknown result type (might be due to invalid IL or missing references)
//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
//IL_03b8: Unknown result type (might be due to invalid IL or missing references)
//IL_03bd: Unknown result type (might be due to invalid IL or missing references)
//IL_0200: Unknown result type (might be due to invalid IL or missing references)
//IL_03f3: Unknown result type (might be due to invalid IL or missing references)
//IL_03fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0402: Unknown result type (might be due to invalid IL or missing references)
//IL_0409: Unknown result type (might be due to invalid IL or missing references)
//IL_040e: Unknown result type (might be due to invalid IL or missing references)
//IL_0415: Unknown result type (might be due to invalid IL or missing references)
//IL_041a: Unknown result type (might be due to invalid IL or missing references)
//IL_03ce: Unknown result type (might be due to invalid IL or missing references)
//IL_03d3: Unknown result type (might be due to invalid IL or missing references)
//IL_03d8: Unknown result type (might be due to invalid IL or missing references)
//IL_0227: Unknown result type (might be due to invalid IL or missing references)
//IL_042d: Unknown result type (might be due to invalid IL or missing references)
//IL_0432: Unknown result type (might be due to invalid IL or missing references)
//IL_043b: Unknown result type (might be due to invalid IL or missing references)
//IL_0440: Unknown result type (might be due to invalid IL or missing references)
//IL_0442: Unknown result type (might be due to invalid IL or missing references)
//IL_03ef: Unknown result type (might be due to invalid IL or missing references)
//IL_03f1: Unknown result type (might be due to invalid IL or missing references)
__state.appliedRot = false;
__state.appliedPos = false;
if (!LethalHandsHandsFollowPatch.Enabled.Value || (Object)(object)__instance == (Object)null || !__instance.constraintActive || (Object)(object)__instance.emoteBone == (Object)null || (Object)(object)__instance.originalBone == (Object)null)
{
return;
}
PlayerControllerB componentInParent = ((Component)__instance).GetComponentInParent<PlayerControllerB>();
if ((Object)(object)componentInParent == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null)
{
return;
}
PlayerControllerB localPlayerController = StartOfRound.Instance.localPlayerController;
if ((Object)(object)localPlayerController == (Object)null || (Object)(object)componentInParent != (Object)(object)localPlayerController || componentInParent.isPlayerDead)
{
return;
}
bool flag = false;
if ((Object)(object)LethalHands.Instance != (Object)null)
{
flag = LethalHands.Instance.isSquaredUp;
}
if (LethalHandsHandsFollowPatch.OnlyWhenSquaredUp.Value && !flag)
{
baselineValid = false;
return;
}
Transform val = (((Object)(object)componentInParent.gameplayCamera != (Object)null) ? ((Component)componentInParent.gameplayCamera).transform : null);
if ((Object)(object)val == (Object)null)
{
return;
}
Transform emoteBone = __instance.emoteBone;
Transform parent = emoteBone.parent;
if ((Object)(object)parent == (Object)null)
{
return;
}
float boneWeight = GetBoneWeight(((Object)__instance.originalBone).name);
if (boneWeight <= 0f)
{
return;
}
float num = val.localEulerAngles.x;
if (num > 180f)
{
num -= 360f;
}
float value = LethalHandsHandsFollowPatch.MaxPitchDegrees.Value;
num = Mathf.Clamp(num, 0f - value, value);
float num2 = Mathf.Clamp01(LethalHandsHandsFollowPatch.PitchStrength.Value);
float num3 = num * num2 * boneWeight;
Vector3 val2 = parent.InverseTransformDirection(val.right);
if (((Vector3)(ref val2)).sqrMagnitude < 0.0001f)
{
return;
}
((Vector3)(ref val2)).Normalize();
__state.savedRot = emoteBone.localRotation;
emoteBone.localRotation = Quaternion.AngleAxis(num3, val2) * emoteBone.localRotation;
__state.appliedRot = true;
int instanceID = ((Object)componentInParent).GetInstanceID();
float num4 = 0f;
if (LethalHandsHandsFollowPatch.EnableCameraHeightFollow.Value)
{
if (!baselineValid || baselinePlayerId != instanceID)
{
baselinePlayerId = instanceID;
baselineCamY = val.localPosition.y;
baselineValid = true;
smoothY[instanceID] = 0f;
}
float target = val.localPosition.y - baselineCamY;
num4 = SmoothValue(smoothY, instanceID, target, LethalHandsHandsFollowPatch.HeightSmoothingSpeed.Value) * Mathf.Clamp(LethalHandsHandsFollowPatch.HeightFollowStrength.Value, 0f, 3f);
float num5 = Mathf.Max(0f, LethalHandsHandsFollowPatch.HeightMaxOffset.Value);
num4 = Mathf.Clamp(num4, 0f - num5, num5);
}
float value2 = LethalHandsHandsFollowPatch.DefaultArmHeight.Value;
float value3 = LethalHandsHandsFollowPatch.DefaultArmForward.Value;
float num6 = 0f;
if (LethalHandsHandsFollowPatch.EnableAutoForwardLookUp.Value)
{
float num7 = (LethalHandsHandsFollowPatch.AutoForwardUpIsNegative.Value ? (0f - num) : num);
if (num7 < 0f)
{
num7 = 0f;
}
float num8 = Mathf.Clamp(LethalHandsHandsFollowPatch.AutoForwardStartDegrees.Value, 0f, value - 1f);
if (num7 <= num8)
{
num6 = SmoothValue(smoothForward, instanceID, 0f, LethalHandsHandsFollowPatch.AutoForwardSmoothingSpeed.Value);
}
else
{
float num9 = Mathf.Max(0.001f, value - num8);
float num10 = Mathf.Clamp01((num7 - num8) / num9);
float num11 = Mathf.Max(0.1f, LethalHandsHandsFollowPatch.AutoForwardCurvePower.Value);
float num12 = Mathf.Pow(num10, num11);
float num13 = Mathf.Max(0f, LethalHandsHandsFollowPatch.AutoForwardMaxOffset.Value);
float num14 = Mathf.Clamp(LethalHandsHandsFollowPatch.AutoForwardStrength.Value, 0f, 2f);
float target2 = num12 * num13 * num14;
num6 = SmoothValue(smoothForward, instanceID, target2, LethalHandsHandsFollowPatch.AutoForwardSmoothingSpeed.Value);
}
}
Vector3 val3 = Vector3.forward;
if (LethalHandsHandsFollowPatch.AutoForwardUseCameraForward.Value)
{
Vector3 val4 = parent.InverseTransformDirection(val.forward);
if (((Vector3)(ref val4)).sqrMagnitude > 0.0001f)
{
((Vector3)(ref val4)).Normalize();
val3 = val4;
}
}
Vector3 val5 = (Vector3.up * (value2 + num4) + val3 * (value3 + num6)) * boneWeight;
if (((Vector3)(ref val5)).sqrMagnitude > 1E-07f)
{
__state.savedPos = emoteBone.localPosition;
emoteBone.localPosition += val5;
__state.appliedPos = true;
}
}
[HarmonyPatch(typeof(EmoteConstraint), "ActUponConstraints")]
[HarmonyPostfix]
private static void Postfix(EmoteConstraint __instance, ref SavedState __state)
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance.emoteBone == (Object)null))
{
if (__state.appliedRot)
{
__instance.emoteBone.localRotation = __state.savedRot;
}
if (__state.appliedPos)
{
__instance.emoteBone.localPosition = __state.savedPos;
}
}
}
private static float SmoothValue(Dictionary<int, float> dict, int key, float target, float speed)
{
if (!dict.TryGetValue(key, out var value))
{
value = 0f;
}
if (speed < 1f)
{
speed = 1f;
}
float num = 1f - Mathf.Exp((0f - speed) * Time.deltaTime);
return dict[key] = Mathf.Lerp(value, target, num);
}
private static float GetBoneWeight(string name)
{
if (string.IsNullOrEmpty(name))
{
return 0f;
}
if (ContainsAny(name, "UpperArm", "upperarm", "uparm", "Shoulder", "Clavicle"))
{
return Clamp01(LethalHandsHandsFollowPatch.UpperArmWeight.Value);
}
if (ContainsAny(name, "LowerArm", "lowerarm", "ForeArm", "forearm", "loarm", "Elbow"))
{
return Clamp01(LethalHandsHandsFollowPatch.ForearmWeight.Value);
}
if (ContainsAny(name, "Hand", "hand", "Wrist", "wrist", "Palm", "palm"))
{
return Clamp01(LethalHandsHandsFollowPatch.HandWeight.Value);
}
return 0f;
}
private static float Clamp01(float v)
{
if (v < 0f)
{
return 0f;
}
if (v > 1f)
{
return 1f;
}
return v;
}
private static bool ContainsAny(string s, params string[] needles)
{
for (int i = 0; i < needles.Length; i++)
{
if (s.IndexOf(needles[i], StringComparison.OrdinalIgnoreCase) >= 0)
{
return true;
}
}
return false;
}
}