Decompiled source of Stealth Ladders v1.0.1

BepInEx/plugins/StealthLadders.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LethalConfig;
using LethalConfig.ConfigItems;
using Microsoft.CodeAnalysis;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("StealthLadders")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Quiet ladders")]
[assembly: AssemblyFileVersion("0.0.1.0")]
[assembly: AssemblyInformationalVersion("0.0.1+e5cbd81f0600a57dc495868fb6d22c52fdca8366")]
[assembly: AssemblyProduct("StealthLadders")]
[assembly: AssemblyTitle("StealthLadders")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
internal static class LethalConfigCompat
{
	[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
	internal static void Register(ConfigEntry<bool> boolConfigEntry)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Expected O, but got Unknown
		LethalConfigManager.SkipAutoGenFor((ConfigEntryBase)(object)boolConfigEntry);
		LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(boolConfigEntry, false));
	}
}
namespace StealthLadders
{
	internal static class ConfigSettings
	{
		private static ConfigEntry<bool> _stealthLadders;

		private static ConfigEntry<bool> _stealthOnLadders;

		internal static bool StealthLadders = true;

		internal static bool StealthOnLadders = true;

		internal static void Init(BaseUnityPlugin plugin)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			ConfigFile config = plugin.Config;
			_stealthLadders = config.Bind<bool>("General", "StealthLadders", true, new ConfigDescription("When enabled, extension ladders can be deployed silently by crouching.", (AcceptableValueBase)null, Array.Empty<object>()));
			_stealthOnLadders = config.Bind<bool>("General", "StealthOnLadders", true, new ConfigDescription("When enabled, ladders can be climbed silently by crouching.", (AcceptableValueBase)null, Array.Empty<object>()));
			_stealthLadders.SettingChanged += OnStealthLaddersSettingChanged;
			_stealthOnLadders.SettingChanged += OnStealthOnLaddersSettingChanged;
			UpdateStealthLadders();
			UpdateStealthOnLadders();
		}

		private static void OnStealthLaddersSettingChanged(object sender, EventArgs e)
		{
			UpdateStealthLadders();
		}

		private static void OnStealthOnLaddersSettingChanged(object sender, EventArgs e)
		{
			UpdateStealthOnLadders();
		}

		private static void UpdateStealthLadders()
		{
			StealthLadders = _stealthLadders?.Value ?? true;
		}

		private static void UpdateStealthOnLadders()
		{
			StealthOnLadders = _stealthOnLadders?.Value ?? true;
		}

		internal static void RegisterWithLethalConfigIfPresent()
		{
			if (Chainloader.PluginInfos.ContainsKey("ainavt.lc.lethalconfig"))
			{
				LethalConfigCompat.Register(_stealthLadders);
				LethalConfigCompat.Register(_stealthOnLadders);
			}
		}
	}
	internal class Debug
	{
		internal static readonly bool DebugEnabled;

		internal static void Log(string message)
		{
			if (DebugEnabled)
			{
				Plugin.Log.LogInfo((object)message);
			}
		}
	}
	[Flags]
	public enum LadderFlags : byte
	{
		None = 0,
		Stealth = 1,
		Falling = 2
	}
	public class LadderState : MonoBehaviour
	{
		private LadderFlags _flags;

		public bool Is(LadderFlags f)
		{
			return (_flags & f) != 0;
		}

		public void Clear(LadderFlags f)
		{
			LadderFlags flags = _flags;
			_flags &= (LadderFlags)(byte)(~(int)f);
			Debug.Log($"[LadderState.Clear({f})] {flags} -> {_flags}");
		}

		public void ClearFlags()
		{
			LadderFlags flags = _flags;
			_flags = LadderFlags.None;
			Debug.Log($"[LadderState.ClearFlags] {flags} -> {_flags}");
		}

		public void SetFlag(LadderFlags f, bool value)
		{
			LadderFlags flags = _flags;
			_flags = (value ? (_flags | f) : (_flags & (LadderFlags)(~(uint)f)));
			Debug.Log($"[LadderState.SetFlag({f},{value})] {flags} -> {_flags}");
		}

		public void ApplyLocal(LadderFlags flags)
		{
			LadderFlags flags2 = _flags;
			_flags = flags;
			Debug.Log($"[LadderState.ApplyLocal({flags})] {flags2} -> {_flags}");
		}

		public override string ToString()
		{
			return $"LadderState({_flags})";
		}
	}
	public class StealthLaddersHub : MonoBehaviour
	{
		public static StealthLaddersHub Instance;

		private readonly Dictionary<ulong, LadderFlags> _pendingByLadderId = new Dictionary<ulong, LadderFlags>();

		private bool _handlersRegistered;

		private const string MSG_SET_NEXT = "StealthLadders.SetNext";

		private const string MSG_APPLY = "StealthLadders.Apply";

		private const string MSG_SET_CLIMB = "StealthLadders.SetClimb";

		private const string MSG_APPLY_CLIMB = "StealthLadders.ApplyClimb";

		public static StealthLaddersHub Ensure()
		{
			//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_0023: Expected O, but got Unknown
			if ((Object)(object)Instance != (Object)null)
			{
				return Instance;
			}
			GameObject val = new GameObject("StealthLaddersHub");
			Object.DontDestroyOnLoad((Object)val);
			Instance = val.AddComponent<StealthLaddersHub>();
			Instance.RegisterHandlers();
			Debug.Log("[Hub.Ensure] Using new Instance.");
			return Instance;
		}

		private void RegisterHandlers()
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			if (_handlersRegistered)
			{
				Debug.Log("[Hub.Register] Already registered; skipping.");
				return;
			}
			if ((Object)(object)NetworkManager.Singleton == (Object)null)
			{
				Debug.Log("[Hub.Register] NetworkManager missing; will register later.");
				return;
			}
			CustomMessagingManager customMessagingManager = NetworkManager.Singleton.CustomMessagingManager;
			if (customMessagingManager == null)
			{
				Debug.Log("[Hub.Register] CustomMessagingManager missing; cannot register.");
				return;
			}
			customMessagingManager.RegisterNamedMessageHandler("StealthLadders.SetNext", new HandleNamedMessageDelegate(OnSetNextActivationFlagsServer));
			customMessagingManager.RegisterNamedMessageHandler("StealthLadders.Apply", new HandleNamedMessageDelegate(OnApplyNextActivationFlagsClient));
			customMessagingManager.RegisterNamedMessageHandler("StealthLadders.SetClimb", new HandleNamedMessageDelegate(OnSetClimbStealthServer));
			customMessagingManager.RegisterNamedMessageHandler("StealthLadders.ApplyClimb", new HandleNamedMessageDelegate(OnApplyClimbStealthClient));
			Debug.Log("[Hub.Register] Handlers registered.");
			_handlersRegistered = true;
		}

		private void Update()
		{
			if (!_handlersRegistered && (Object)(object)NetworkManager.Singleton != (Object)null)
			{
				RegisterHandlers();
			}
		}

		public void SendNextActivationFlagsToServer(ulong ladderNetId, LadderFlags flags)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsClient)
			{
				Debug.Log("[Hub.SendNext] Not a client or NetworkManager missing; skipping.");
				return;
			}
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(9, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref ladderNetId, default(ForPrimitives));
				byte b = (byte)flags;
				((FastBufferWriter)(ref val)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
				Debug.Log($"[Hub.SendNext] Sending flags={flags} for ladder NetId={ladderNetId} to server.");
				NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("StealthLadders.SetNext", 0uL, val, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(FastBufferWriter)(ref val)).Dispose();
			}
		}

		private void OnSetNextActivationFlagsServer(ulong senderClientId, FastBufferReader reader)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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)
			if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsServer)
			{
				Debug.Log("[Hub.SetNext:ServerHandler] Not server; ignoring.");
				return;
			}
			if (!((FastBufferReader)(ref reader)).TryBeginRead(9))
			{
				Debug.Log("[Hub.SetNext:ServerHandler] Reader underflow.");
				return;
			}
			ulong num = default(ulong);
			((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref num, default(ForPrimitives));
			byte b = default(byte);
			((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b, default(ForPrimitives));
			LadderFlags ladderFlags = (LadderFlags)b;
			bool flag = _pendingByLadderId.ContainsKey(num);
			_pendingByLadderId[num] = ladderFlags;
			Debug.Log($"[Hub.SetNext:ServerHandler] From {senderClientId}: flags={ladderFlags} for ladder NetId={num} (replacing={flag}).");
		}

		public bool TryConsumePending(ulong ladderId, out LadderFlags flags)
		{
			if (_pendingByLadderId.TryGetValue(ladderId, out flags))
			{
				_pendingByLadderId.Remove(ladderId);
				Debug.Log($"[Hub.TryConsumePending] Consumed flags={flags} for ladder NetId={ladderId}.");
				return true;
			}
			flags = LadderFlags.None;
			Debug.Log($"[Hub.TryConsumePending] No pending flags for ladder NetId={ladderId}.");
			return false;
		}

		public void BroadcastApplyNextActivationFlags(ulong ladderId, LadderFlags flags)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsServer)
			{
				Debug.Log("[Hub.BroadcastApply] Not server or NetworkManager missing; skipping.");
				return;
			}
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(9, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref ladderId, default(ForPrimitives));
				byte b = (byte)flags;
				((FastBufferWriter)(ref val)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
				Debug.Log($"[Hub.BroadcastApply] Broadcasting ladder NetId={ladderId} flags={flags} to all clients.");
				NetworkManager.Singleton.CustomMessagingManager.SendNamedMessageToAll("StealthLadders.Apply", val, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(FastBufferWriter)(ref val)).Dispose();
			}
		}

		private void OnApplyNextActivationFlagsClient(ulong _senderClientId, FastBufferReader reader)
		{
			//IL_001c: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if (!((FastBufferReader)(ref reader)).TryBeginRead(9))
			{
				Debug.Log("[Hub.Apply:ClientHandler] Reader underflow.");
				return;
			}
			ulong num = default(ulong);
			((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref num, default(ForPrimitives));
			byte b = default(byte);
			((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b, default(ForPrimitives));
			LadderFlags ladderFlags = (LadderFlags)b;
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton == (Object)null)
			{
				Debug.Log("[Hub.Apply:ClientHandler] NetworkManager missing; cannot resolve ladder.");
				return;
			}
			if (!singleton.SpawnManager.SpawnedObjects.TryGetValue(num, out var value))
			{
				Debug.Log($"[Hub.Apply:ClientHandler] Could not find ladder NetId={num}; not applying.");
				return;
			}
			ExtensionLadderItem component = ((Component)value).GetComponent<ExtensionLadderItem>();
			if ((Object)(object)component == (Object)null)
			{
				Debug.Log($"[Hub.Apply:ClientHandler] NetId={num} is not a ladder; skipping.");
				return;
			}
			LadderState ladderState = ((Component)component).GetComponent<LadderState>() ?? ((Component)component).gameObject.AddComponent<LadderState>();
			if ((Object)(object)ladderState != (Object)null)
			{
				((object)ladderState).ToString();
			}
			ladderState.ApplyLocal(ladderFlags);
			Debug.Log($"[Hub.Apply:ClientHandler] Applied flags={ladderFlags} to ladder NetId={num}. NewState={ladderState}");
		}

		public void SendClimbStealthToServer(ulong playerNetObjId, bool muted)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsClient)
			{
				Debug.Log("[Hub.SendClimb] Not a client or NetworkManager missing; skipping.");
				return;
			}
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(9, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref playerNetObjId, default(ForPrimitives));
				byte b = (muted ? ((byte)1) : ((byte)0));
				((FastBufferWriter)(ref val)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
				Debug.Log($"[Hub.SendClimb] Sending climb-stealth muted={muted} for player NetId={playerNetObjId} to server.");
				NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("StealthLadders.SetClimb", 0uL, val, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(FastBufferWriter)(ref val)).Dispose();
			}
		}

		private void OnSetClimbStealthServer(ulong senderClientId, FastBufferReader reader)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_0058: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsServer)
			{
				Debug.Log("[Hub.SetClimb:ServerHandler] Not server; ignoring.");
				return;
			}
			if (!((FastBufferReader)(ref reader)).TryBeginRead(9))
			{
				Debug.Log("[Hub.SetClimb:ServerHandler] Reader underflow.");
				return;
			}
			ulong num = default(ulong);
			((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref num, default(ForPrimitives));
			byte b = default(byte);
			((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b, default(ForPrimitives));
			bool flag = b != 0;
			Debug.Log($"[Hub.SetClimb:ServerHandler] From {senderClientId}: player NetId={num} muted={flag}. Broadcasting...");
			BroadcastApplyClimbStealth(num, flag);
		}

		public void BroadcastApplyClimbStealth(ulong playerNetObjId, bool muted)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsServer)
			{
				Debug.Log("[Hub.BroadcastApplyClimb] Not server or NetworkManager missing; skipping.");
				return;
			}
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(9, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref playerNetObjId, default(ForPrimitives));
				byte b = (muted ? ((byte)1) : ((byte)0));
				((FastBufferWriter)(ref val)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
				NetworkManager.Singleton.CustomMessagingManager.SendNamedMessageToAll("StealthLadders.ApplyClimb", val, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(FastBufferWriter)(ref val)).Dispose();
			}
		}

		private void OnApplyClimbStealthClient(ulong _senderClientId, FastBufferReader reader)
		{
			//IL_001c: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if (!((FastBufferReader)(ref reader)).TryBeginRead(9))
			{
				Debug.Log("[Hub.ApplyClimb:ClientHandler] Reader underflow.");
				return;
			}
			ulong num = default(ulong);
			((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref num, default(ForPrimitives));
			byte b = default(byte);
			((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b, default(ForPrimitives));
			bool flag = b != 0;
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton == (Object)null)
			{
				Debug.Log("[Hub.ApplyClimb:ClientHandler] NetworkManager missing; cannot resolve player.");
				return;
			}
			if (!singleton.SpawnManager.SpawnedObjects.TryGetValue(num, out var value))
			{
				Debug.Log($"[Hub.ApplyClimb:ClientHandler] Could not find player NetId={num}; not applying.");
				return;
			}
			PlayerControllerB component = ((Component)value).GetComponent<PlayerControllerB>();
			if ((Object)(object)component == (Object)null)
			{
				Debug.Log($"[Hub.ApplyClimb:ClientHandler] NetId={num} is not a PlayerControllerB; skipping.");
				return;
			}
			(((Component)component).GetComponent<ClimbSilenceState>() ?? ((Component)component).gameObject.AddComponent<ClimbSilenceState>()).SetMuted(flag);
			Debug.Log("[Hub.ApplyClimb:ClientHandler] " + (flag ? "Muted" : "Unmuted") + " movementAudio on player '" + component.playerUsername + "'.");
		}
	}
	internal static class LadderPatch
	{
		[HarmonyPatch(typeof(GrabbableObject), "Start")]
		private static class Patch_GrabbableObject_Start
		{
			private static void Postfix(GrabbableObject __instance)
			{
				ExtensionLadderItem val = (ExtensionLadderItem)(object)((__instance is ExtensionLadderItem) ? __instance : null);
				if (val != null)
				{
					if ((Object)(object)((Component)val).GetComponent<LadderState>() == (Object)null)
					{
						((Component)val).gameObject.AddComponent<LadderState>();
						NetworkObject networkObject = ((NetworkBehaviour)val).NetworkObject;
						Debug.Log($"[GrabbableObject.Start:Postfix] Added LadderState to ladder NetId={((networkObject != null) ? new ulong?(networkObject.NetworkObjectId) : null)}");
					}
					else
					{
						NetworkObject networkObject2 = ((NetworkBehaviour)val).NetworkObject;
						Debug.Log($"[GrabbableObject.Start:Postfix] LadderState already present on ladder NetId={((networkObject2 != null) ? new ulong?(networkObject2.NetworkObjectId) : null)}");
					}
				}
			}
		}

		[HarmonyPatch(typeof(StartOfRound), "Awake")]
		private static class Patch_StartOfRound_Awake
		{
			private static void Postfix()
			{
				bool flag = Object.op_Implicit((Object)(object)NetworkManager.Singleton) && NetworkManager.Singleton.IsServer;
				bool flag2 = Object.op_Implicit((Object)(object)NetworkManager.Singleton) && NetworkManager.Singleton.IsClient;
				Debug.Log($"[StartOfRound.Awake:Postfix] IsServer={flag} IsClient={flag2}");
				StealthLaddersHub stealthLaddersHub = StealthLaddersHub.Ensure();
				Debug.Log("[StartOfRound.Awake:Postfix] Hub ensured (custom-messaging relay; no NetworkObject). hubInstance=" + (((stealthLaddersHub != null) ? ((Object)stealthLaddersHub).GetInstanceID().ToString() : null) ?? "null"));
			}
		}

		[HarmonyPatch(typeof(ExtensionLadderItem), "ItemActivate")]
		private static class Patch_ItemActivate
		{
			private static void Prefix(ExtensionLadderItem __instance)
			{
				ulong? obj;
				if (__instance == null)
				{
					obj = null;
				}
				else
				{
					NetworkObject networkObject = ((NetworkBehaviour)__instance).NetworkObject;
					obj = ((networkObject != null) ? new ulong?(networkObject.NetworkObjectId) : null);
				}
				Debug.Log($"[ItemActivate:Prefix] Ladder NetId={obj}");
			}
		}

		[HarmonyPatch(typeof(AudioSource), "Play", new Type[] { })]
		internal static class Patch_AudioSource_Play_NoArgs
		{
			private static bool Prefix(AudioSource __instance)
			{
				try
				{
					if (!Object.op_Implicit((Object)(object)__instance))
					{
						return true;
					}
					ExtensionLadderItem componentInParent = ((Component)__instance).GetComponentInParent<ExtensionLadderItem>();
					if (!Object.op_Implicit((Object)(object)componentInParent))
					{
						return true;
					}
					LadderState component = ((Component)componentInParent).GetComponent<LadderState>();
					bool flag = Object.op_Implicit((Object)(object)component) && component.Is(LadderFlags.Stealth);
					if ((Object)(object)__instance.clip == (Object)(object)componentInParent.ladderFallSFX)
					{
						component?.SetFlag(LadderFlags.Falling, value: true);
						NetworkObject networkObject = ((NetworkBehaviour)componentInParent).NetworkObject;
						object arg = ((networkObject != null) ? new ulong?(networkObject.NetworkObjectId) : null);
						AudioClip clip = __instance.clip;
						Debug.Log($"[Audio.Play()] Ladder NetId={arg} clip={((clip != null) ? ((Object)clip).name : null)} -> Set Falling=true");
					}
					bool flag2 = flag && ((Object)(object)__instance.clip == (Object)(object)componentInParent.ladderExtendSFX || (Object)(object)__instance.clip == (Object)(object)componentInParent.ladderFallSFX);
					object[] array = new object[4];
					NetworkObject networkObject2 = ((NetworkBehaviour)componentInParent).NetworkObject;
					array[0] = ((networkObject2 != null) ? new ulong?(networkObject2.NetworkObjectId) : null);
					AudioClip clip2 = __instance.clip;
					array[1] = ((clip2 != null) ? ((Object)clip2).name : null);
					array[2] = flag;
					array[3] = flag2;
					Debug.Log(string.Format("[Audio.Play()] Ladder NetId={0} clip={1} isStealth={2} block={3}", array));
					return !flag2;
				}
				catch (Exception arg2)
				{
					Debug.Log($"[Audio.Play()] Exception: {arg2}");
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(AudioSource), "Play", new Type[] { typeof(ulong) })]
		internal static class Patch_AudioSource_Play_WithDelay
		{
			private static bool Prefix(AudioSource __instance, ulong delay)
			{
				try
				{
					if (!Object.op_Implicit((Object)(object)__instance))
					{
						return true;
					}
					ExtensionLadderItem componentInParent = ((Component)__instance).GetComponentInParent<ExtensionLadderItem>();
					if (!Object.op_Implicit((Object)(object)componentInParent))
					{
						return true;
					}
					LadderState component = ((Component)componentInParent).GetComponent<LadderState>();
					bool flag = Object.op_Implicit((Object)(object)component) && component.Is(LadderFlags.Stealth);
					if ((Object)(object)__instance.clip == (Object)(object)componentInParent.ladderFallSFX)
					{
						component?.SetFlag(LadderFlags.Falling, value: true);
						object arg = delay;
						NetworkObject networkObject = ((NetworkBehaviour)componentInParent).NetworkObject;
						object arg2 = ((networkObject != null) ? new ulong?(networkObject.NetworkObjectId) : null);
						AudioClip clip = __instance.clip;
						Debug.Log($"[Audio.Play(delay={arg})] Ladder NetId={arg2} clip={((clip != null) ? ((Object)clip).name : null)} -> Set Falling=true");
					}
					bool flag2 = flag && ((Object)(object)__instance.clip == (Object)(object)componentInParent.ladderExtendSFX || (Object)(object)__instance.clip == (Object)(object)componentInParent.ladderFallSFX);
					object[] obj = new object[5] { delay, null, null, null, null };
					NetworkObject networkObject2 = ((NetworkBehaviour)componentInParent).NetworkObject;
					obj[1] = ((networkObject2 != null) ? new ulong?(networkObject2.NetworkObjectId) : null);
					AudioClip clip2 = __instance.clip;
					obj[2] = ((clip2 != null) ? ((Object)clip2).name : null);
					obj[3] = flag;
					obj[4] = flag2;
					Debug.Log(string.Format("[Audio.Play(delay={0})] Ladder NetId={1} clip={2} isStealth={3} block={4}", obj));
					return !flag2;
				}
				catch (Exception arg3)
				{
					Debug.Log($"[Audio.Play(delay)] Exception: {arg3}");
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(AudioSource), "PlayOneShot", new Type[]
		{
			typeof(AudioClip),
			typeof(float)
		})]
		internal static class Patch_AudioSource_PlayOneShot_WithVol
		{
			private static bool Prefix(AudioSource __instance, AudioClip clip, float volumeScale)
			{
				try
				{
					if (!Object.op_Implicit((Object)(object)__instance) || !Object.op_Implicit((Object)(object)clip))
					{
						return true;
					}
					ExtensionLadderItem componentInParent = ((Component)__instance).GetComponentInParent<ExtensionLadderItem>();
					if (!Object.op_Implicit((Object)(object)componentInParent))
					{
						return true;
					}
					LadderState component = ((Component)componentInParent).GetComponent<LadderState>();
					bool flag = Object.op_Implicit((Object)(object)component) && component.Is(LadderFlags.Stealth);
					bool flag2 = Object.op_Implicit((Object)(object)component) && component.Is(LadderFlags.Falling);
					if ((Object)(object)clip == (Object)(object)componentInParent.ladderShrinkSFX)
					{
						NetworkObject networkObject = ((NetworkBehaviour)componentInParent).NetworkObject;
						Debug.Log($"[Audio.PlayOneShot(vol)] Ladder NetId={((networkObject != null) ? new ulong?(networkObject.NetworkObjectId) : null)} clip={((Object)clip).name} -> ClearFlags()");
						component?.ClearFlags();
						return true;
					}
					if (flag && (Object)(object)clip == (Object)(object)componentInParent.hitWall)
					{
						if (flag2)
						{
							NetworkObject networkObject2 = ((NetworkBehaviour)componentInParent).NetworkObject;
							Debug.Log($"[Audio.PlayOneShot(vol)] Ladder NetId={((networkObject2 != null) ? new ulong?(networkObject2.NetworkObjectId) : null)} clip=hitWall during Falling -> ClearFlags(); allow");
							component?.ClearFlags();
							return true;
						}
						NetworkObject networkObject3 = ((NetworkBehaviour)componentInParent).NetworkObject;
						Debug.Log($"[Audio.PlayOneShot(vol)] Ladder NetId={((networkObject3 != null) ? new ulong?(networkObject3.NetworkObjectId) : null)} clip=hitWall stealth=true -> BLOCK");
						return false;
					}
					if (flag && ((Object)(object)clip == (Object)(object)componentInParent.lidOpenSFX || (Object)(object)clip == (Object)(object)componentInParent.fullExtend || (Object)(object)clip == (Object)(object)((GrabbableObject)componentInParent).itemProperties?.dropSFX))
					{
						NetworkObject networkObject4 = ((NetworkBehaviour)componentInParent).NetworkObject;
						Debug.Log($"[Audio.PlayOneShot(vol)] Ladder NetId={((networkObject4 != null) ? new ulong?(networkObject4.NetworkObjectId) : null)} clip={((Object)clip).name} (lid/full/drop) stealth=true -> BLOCK");
						return false;
					}
					object[] array = new object[4];
					NetworkObject networkObject5 = ((NetworkBehaviour)componentInParent).NetworkObject;
					array[0] = ((networkObject5 != null) ? new ulong?(networkObject5.NetworkObjectId) : null);
					array[1] = ((Object)clip).name;
					array[2] = flag;
					array[3] = flag2;
					Debug.Log(string.Format("[Audio.PlayOneShot(vol)] Ladder NetId={0} clip={1} isStealth={2} isFalling={3} -> allow", array));
					return true;
				}
				catch (Exception arg)
				{
					Debug.Log($"[Audio.PlayOneShot(vol)] Exception: {arg}");
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(AudioSource), "PlayOneShot", new Type[] { typeof(AudioClip) })]
		internal static class Patch_AudioSource_PlayOneShot_NoVol
		{
			private static bool Prefix(AudioSource __instance, AudioClip clip)
			{
				try
				{
					if (!Object.op_Implicit((Object)(object)__instance) || !Object.op_Implicit((Object)(object)clip))
					{
						return true;
					}
					ExtensionLadderItem componentInParent = ((Component)__instance).GetComponentInParent<ExtensionLadderItem>();
					if (!Object.op_Implicit((Object)(object)componentInParent))
					{
						return true;
					}
					LadderState component = ((Component)componentInParent).GetComponent<LadderState>();
					bool flag = Object.op_Implicit((Object)(object)component) && component.Is(LadderFlags.Stealth);
					bool flag2 = Object.op_Implicit((Object)(object)component) && component.Is(LadderFlags.Falling);
					if ((Object)(object)clip == (Object)(object)componentInParent.ladderShrinkSFX)
					{
						NetworkObject networkObject = ((NetworkBehaviour)componentInParent).NetworkObject;
						Debug.Log($"[Audio.PlayOneShot] Ladder NetId={((networkObject != null) ? new ulong?(networkObject.NetworkObjectId) : null)} clip={((Object)clip).name} -> ClearFlags()");
						component?.ClearFlags();
						return true;
					}
					if (flag && (Object)(object)clip == (Object)(object)componentInParent.hitWall)
					{
						if (flag2)
						{
							NetworkObject networkObject2 = ((NetworkBehaviour)componentInParent).NetworkObject;
							Debug.Log($"[Audio.PlayOneShot] Ladder NetId={((networkObject2 != null) ? new ulong?(networkObject2.NetworkObjectId) : null)} clip=hitWall during Falling -> Set Stealth=false,Falling=false; allow");
							component?.SetFlag(LadderFlags.Stealth, value: false);
							component?.SetFlag(LadderFlags.Falling, value: false);
							return true;
						}
						NetworkObject networkObject3 = ((NetworkBehaviour)componentInParent).NetworkObject;
						Debug.Log($"[Audio.PlayOneShot] Ladder NetId={((networkObject3 != null) ? new ulong?(networkObject3.NetworkObjectId) : null)} clip=hitWall stealth=true -> BLOCK");
						return false;
					}
					if (flag && ((Object)(object)clip == (Object)(object)componentInParent.lidOpenSFX || (Object)(object)clip == (Object)(object)componentInParent.fullExtend || (Object)(object)clip == (Object)(object)((GrabbableObject)componentInParent).itemProperties?.dropSFX))
					{
						NetworkObject networkObject4 = ((NetworkBehaviour)componentInParent).NetworkObject;
						Debug.Log($"[Audio.PlayOneShot] Ladder NetId={((networkObject4 != null) ? new ulong?(networkObject4.NetworkObjectId) : null)} clip={((Object)clip).name} (lid/full/drop) stealth=true -> BLOCK");
						return false;
					}
					object[] array = new object[4];
					NetworkObject networkObject5 = ((NetworkBehaviour)componentInParent).NetworkObject;
					array[0] = ((networkObject5 != null) ? new ulong?(networkObject5.NetworkObjectId) : null);
					array[1] = ((Object)clip).name;
					array[2] = flag;
					array[3] = flag2;
					Debug.Log(string.Format("[Audio.PlayOneShot] Ladder NetId={0} clip={1} isStealth={2} isFalling={3} -> allow", array));
					return true;
				}
				catch (Exception arg)
				{
					Debug.Log($"[Audio.PlayOneShot] Exception: {arg}");
					return true;
				}
			}
		}
	}
	[BepInPlugin("Azx.StealthLadders", "Stealth Ladders", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "Azx.StealthLadders";

		public const string PluginName = "Stealth Ladders";

		public const string PluginVersion = "1.0.0";

		internal static ManualLogSource Log;

		internal static Harmony Harmony;

		private GameObject _controllerGO;

		internal static Plugin Instance { get; private set; }

		private void Awake()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Harmony = new Harmony("Azx.StealthLadders");
			ConfigSettings.Init((BaseUnityPlugin)(object)this);
			ConfigSettings.RegisterWithLethalConfigIfPresent();
			Harmony.PatchAll();
			StealthLaddersHub.Ensure();
			_controllerGO = new GameObject("StealthLaddersController");
			_controllerGO.AddComponent<ClimbSilenceMonitor>();
			Object.DontDestroyOnLoad((Object)(object)_controllerGO);
			Log.LogInfo((object)"Stealth Ladders 1.0.0 loaded.");
		}

		private void OnDestroy()
		{
			if ((Object)(object)_controllerGO != (Object)null)
			{
				Object.Destroy((Object)(object)_controllerGO);
			}
		}

		internal static bool IsHost()
		{
			if (Object.op_Implicit((Object)(object)NetworkManager.Singleton))
			{
				if (!NetworkManager.Singleton.IsServer)
				{
					return NetworkManager.Singleton.IsHost;
				}
				return true;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(AudioSource))]
	internal static class ClimbAudioPatch
	{
		private const string TAG = "[Stealth Ladders] [ClimbAudioPatch]";

		private const bool Verbose = true;

		private const int MaxPerSourceNoisy = 8;

		private static readonly Dictionary<int, int> _noisyCount = new Dictionary<int, int>();

		private static bool EvaluateBlock(AudioSource src, out string reason, out PlayerControllerB player, out bool isMovementAudio, out bool mutedFlag)
		{
			reason = "";
			player = null;
			isMovementAudio = false;
			mutedFlag = false;
			try
			{
				if ((Object)(object)src == (Object)null)
				{
					reason = "src=null";
					return false;
				}
				player = ((Component)src).GetComponentInParent<PlayerControllerB>();
				if ((Object)(object)player == (Object)null)
				{
					reason = "no-PlayerControllerB-in-parent";
					return false;
				}
				isMovementAudio = (Object)(object)player.movementAudio == (Object)(object)src;
				if (!isMovementAudio)
				{
					string[] obj = new string[5]
					{
						"not-movementAudio src='",
						((Object)src).name,
						"' vs player.movementAudio='",
						null,
						null
					};
					AudioSource movementAudio = player.movementAudio;
					obj[3] = ((movementAudio != null) ? ((Object)movementAudio).name : null) ?? "null";
					obj[4] = "'";
					reason = string.Concat(obj);
					return false;
				}
				mutedFlag = ClimbSilenceState.IsClimbMuted(player);
				reason = (mutedFlag ? "muted=true" : "muted=false");
				return mutedFlag;
			}
			catch (Exception ex)
			{
				reason = "exception:" + ex.GetType().Name;
				Debug.Log(string.Format("{0} EvaluateBlock exception:\n{1}", "[Stealth Ladders] [ClimbAudioPatch]", ex));
				return false;
			}
		}

		private static bool GetAnimatorBool(Animator anim, string name)
		{
			try
			{
				return (Object)(object)anim != (Object)null && anim.GetBool(name);
			}
			catch
			{
				return false;
			}
		}

		private static bool GetBoolFieldOrProp(object obj, params string[] names)
		{
			if (obj == null)
			{
				return false;
			}
			Type type = obj.GetType();
			foreach (string name in names)
			{
				try
				{
					FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (field != null && field.FieldType == typeof(bool))
					{
						return (bool)field.GetValue(obj);
					}
					PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (property != null && property.PropertyType == typeof(bool))
					{
						return (bool)property.GetValue(obj);
					}
				}
				catch
				{
				}
			}
			return false;
		}

		private static void TraceDecision(string where, AudioSource src, string clipName, string reason, PlayerControllerB player, bool isMovementAudio, bool block, bool mutedFlag)
		{
			int num = (Object.op_Implicit((Object)(object)src) ? ((Object)src).GetInstanceID() : 0);
			bool flag = !block && !isMovementAudio;
			if (!flag || !_noisyCount.TryGetValue(num, out var value) || value < 8)
			{
				if (flag)
				{
					_noisyCount[num] = ((!_noisyCount.TryGetValue(num, out value)) ? 1 : (value + 1));
				}
				string text = (((Object)(object)player != (Object)null) ? $"{player.playerUsername} ({player.playerClientId})" : "null");
				string text2 = (((Object)(object)src != (Object)null) ? $"'{((Object)src).name}'#{num}" : "null");
				bool flag2 = GetAnimatorBool(player?.playerBodyAnimator, "ClimbingLadder") || GetAnimatorBool(player?.playerBodyAnimator, "climbingLadder");
				bool flag3 = player?.isClimbingLadder ?? flag2;
				bool boolFieldOrProp = GetBoolFieldOrProp(player, "isCrouching", "crouching", "playerIsCrouching", "IsCrouching");
				bool boolFieldOrProp2 = GetBoolFieldOrProp(player, "isGrounded", "grounded", "playerGrounded");
				bool boolFieldOrProp3 = GetBoolFieldOrProp(player, "isSprinting", "sprinting");
				string text3 = $"ctx[climb={flag3}, animClimb={flag2}, crouch?={boolFieldOrProp}, grounded?={boolFieldOrProp2}, sprint?={boolFieldOrProp3}, src.mute={((src != null) ? new bool?(src.mute) : null)}, src.vol={((src != null) ? new float?(src.volume) : null):0.00}]";
				Debug.Log(string.Format("{0} {1}: clip='{2}', src={3}, player={4}, isMovementAudio={5}, muted={6}, block={7}, reason={8}; {9}", "[Stealth Ladders] [ClimbAudioPatch]", where, clipName, text2, text, isMovementAudio, mutedFlag, block, reason, text3));
			}
		}

		[HarmonyPatch("Play", new Type[] { })]
		[HarmonyPrefix]
		private static bool Play_NoArgs(AudioSource __instance)
		{
			string reason;
			PlayerControllerB player;
			bool isMovementAudio;
			bool mutedFlag;
			bool flag = EvaluateBlock(__instance, out reason, out player, out isMovementAudio, out mutedFlag);
			TraceDecision("Play()", __instance, "<current-clip>", reason, player, isMovementAudio, flag, mutedFlag);
			if (flag)
			{
				Debug.Log("[Stealth Ladders] [ClimbAudioPatch] Blocked: AudioSource.Play()");
			}
			return !flag;
		}

		[HarmonyPatch("Play", new Type[] { typeof(ulong) })]
		[HarmonyPrefix]
		private static bool Play_WithDelay(AudioSource __instance, ulong delay)
		{
			string reason;
			PlayerControllerB player;
			bool isMovementAudio;
			bool mutedFlag;
			bool flag = EvaluateBlock(__instance, out reason, out player, out isMovementAudio, out mutedFlag);
			TraceDecision($"Play(delay={delay})", __instance, "<current-clip>", reason, player, isMovementAudio, flag, mutedFlag);
			if (flag)
			{
				Debug.Log(string.Format("{0} Blocked: AudioSource.Play({1})", "[Stealth Ladders] [ClimbAudioPatch]", delay));
			}
			return !flag;
		}

		[HarmonyPatch("PlayOneShot", new Type[] { typeof(AudioClip) })]
		[HarmonyPrefix]
		private static bool PlayOneShot_Clip(AudioSource __instance, AudioClip clip)
		{
			string text = (Object.op_Implicit((Object)(object)clip) ? ((Object)clip).name : "null");
			string reason;
			PlayerControllerB player;
			bool isMovementAudio;
			bool mutedFlag;
			bool flag = EvaluateBlock(__instance, out reason, out player, out isMovementAudio, out mutedFlag);
			TraceDecision("PlayOneShot(clip)", __instance, text, reason, player, isMovementAudio, flag, mutedFlag);
			if (flag)
			{
				Debug.Log("[Stealth Ladders] [ClimbAudioPatch] Blocked: PlayOneShot('" + text + "')");
			}
			return !flag;
		}

		[HarmonyPatch("PlayOneShot", new Type[]
		{
			typeof(AudioClip),
			typeof(float)
		})]
		[HarmonyPrefix]
		private static bool PlayOneShot_ClipFloat(AudioSource __instance, AudioClip clip, float volumeScale)
		{
			string text = (Object.op_Implicit((Object)(object)clip) ? ((Object)clip).name : "null");
			string reason;
			PlayerControllerB player;
			bool isMovementAudio;
			bool mutedFlag;
			bool flag = EvaluateBlock(__instance, out reason, out player, out isMovementAudio, out mutedFlag);
			TraceDecision($"PlayOneShot(clip,vol={volumeScale:0.00})", __instance, text, reason, player, isMovementAudio, flag, mutedFlag);
			if (flag)
			{
				Debug.Log(string.Format("{0} Blocked: PlayOneShot('{1}', {2:0.00})", "[Stealth Ladders] [ClimbAudioPatch]", text, volumeScale));
			}
			return !flag;
		}
	}
	public class ClimbSilenceMonitor : MonoBehaviour
	{
		private const string TAG = "[Stealth Ladders] [ClimbSilenceMonitor]";

		private static ClimbSilenceMonitor _singleton;

		private PlayerControllerB _local;

		private bool _lastMuted;

		private InputAction _crouchAction;

		private double _lastStatusAt;

		private string _lastStatus;

		public static ClimbSilenceMonitor Ensure(string cause)
		{
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Expected O, but got Unknown
			if ((Object)(object)_singleton != (Object)null)
			{
				if (!((Behaviour)_singleton).enabled)
				{
					((Behaviour)_singleton).enabled = true;
					Debug.Log("[Stealth Ladders] [ClimbSilenceMonitor] Ensure: re-enabled (cause=" + cause + ")");
				}
				if (!((Component)_singleton).gameObject.activeSelf)
				{
					((Component)_singleton).gameObject.SetActive(true);
					Debug.Log("[Stealth Ladders] [ClimbSilenceMonitor] Ensure: re-activated GO (cause=" + cause + ")");
				}
				return _singleton;
			}
			ClimbSilenceMonitor climbSilenceMonitor = Object.FindObjectsOfType<ClimbSilenceMonitor>(true).FirstOrDefault();
			if ((Object)(object)climbSilenceMonitor != (Object)null)
			{
				_singleton = climbSilenceMonitor;
				((Object)((Component)climbSilenceMonitor).gameObject).hideFlags = (HideFlags)61;
				((Behaviour)climbSilenceMonitor).enabled = true;
				((Component)climbSilenceMonitor).gameObject.SetActive(true);
				Object.DontDestroyOnLoad((Object)(object)((Component)climbSilenceMonitor).gameObject);
				Debug.Log("[Stealth Ladders] [ClimbSilenceMonitor] Ensure: found existing; revived (cause=" + cause + ")");
				return climbSilenceMonitor;
			}
			GameObject val = new GameObject("StealthLadders::Monitor")
			{
				hideFlags = (HideFlags)61
			};
			Object.DontDestroyOnLoad((Object)val);
			_singleton = val.AddComponent<ClimbSilenceMonitor>();
			Debug.Log("[Stealth Ladders] [ClimbSilenceMonitor] Ensure: created new (cause=" + cause + ")");
			return _singleton;
		}

		[RuntimeInitializeOnLoadMethod(/*Could not decode attribute arguments.*/)]
		private static void AutoInstall()
		{
			Ensure("AutoInstall");
		}

		private void Awake()
		{
			if ((Object)(object)_singleton != (Object)null && (Object)(object)_singleton != (Object)(object)this)
			{
				Debug.Log("[Stealth Ladders] [ClimbSilenceMonitor] Duplicate monitor destroyed.");
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
			else
			{
				_singleton = this;
				((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			}
		}

		private void OnEnable()
		{
			Debug.Log("[Stealth Ladders] [ClimbSilenceMonitor] OnEnable");
			TryBindCrouchAction();
		}

		private void OnDisable()
		{
			Debug.Log("[Stealth Ladders] [ClimbSilenceMonitor] OnDisable -> forcing unmute");
			ForceMute(mute: false, "OnDisable");
		}

		private void TryBindCrouchAction()
		{
			_crouchAction = null;
			try
			{
				IngamePlayerSettings instance = IngamePlayerSettings.Instance;
				object obj;
				if (instance == null)
				{
					obj = null;
				}
				else
				{
					PlayerInput playerInput = instance.playerInput;
					obj = ((playerInput != null) ? playerInput.actions : null);
				}
				InputActionAsset val = (InputActionAsset)obj;
				if ((Object)(object)val == (Object)null)
				{
					Debug.Log("[Stealth Ladders] [ClimbSilenceMonitor] PlayerInput actions null; will use PCB fallback.");
					return;
				}
				_crouchAction = val.FindAction("Crouch", true);
				if (_crouchAction == null)
				{
					_crouchAction = ((IEnumerable<InputAction>)val).Where((InputAction a) => a != null && !string.IsNullOrEmpty(a.name)).FirstOrDefault((Func<InputAction, bool>)((InputAction a) => a.name.ToLowerInvariant().Contains("crouch")));
				}
				if (_crouchAction != null)
				{
					Debug.Log("[Stealth Ladders] [ClimbSilenceMonitor] Bound InputAction '" + _crouchAction.name + "'.");
				}
				else
				{
					Debug.Log("[Stealth Ladders] [ClimbSilenceMonitor] Could not find any InputAction matching 'crouch' (will fall back to PCB fields).");
				}
			}
			catch (Exception arg)
			{
				Debug.Log(string.Format("{0} Exception binding InputAction: {1}", "[Stealth Ladders] [ClimbSilenceMonitor]", arg));
			}
		}

		private static bool GetBoolFieldOrProp(object obj, params string[] names)
		{
			if (obj == null)
			{
				return false;
			}
			Type type = obj.GetType();
			foreach (string name in names)
			{
				try
				{
					FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (field != null && field.FieldType == typeof(bool))
					{
						return (bool)field.GetValue(obj);
					}
					PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (property != null && property.PropertyType == typeof(bool))
					{
						return (bool)property.GetValue(obj);
					}
				}
				catch
				{
				}
			}
			return false;
		}

		private (bool value, string source, float rawAction) GetCrouchState(PlayerControllerB p)
		{
			float num = 0f;
			if (_crouchAction != null)
			{
				try
				{
					num = _crouchAction.ReadValue<float>();
				}
				catch
				{
					num = 0f;
				}
				if (num > 0.5f)
				{
					return (true, "InputAction('" + _crouchAction.name + "')>0.5", num);
				}
			}
			return (GetBoolFieldOrProp(p, "isCrouching", "crouching", "playerIsCrouching", "IsCrouching"), "ReflectedPCBBool", num);
		}

		private bool GetClimbState(PlayerControllerB p, out string source, out bool animFlag)
		{
			animFlag = false;
			try
			{
				animFlag = (Object)(object)p?.playerBodyAnimator != (Object)null && (p.playerBodyAnimator.GetBool("ClimbingLadder") || p.playerBodyAnimator.GetBool("climbingLadder"));
			}
			catch
			{
			}
			bool result = (p?.isClimbingLadder ?? false) | animFlag;
			source = ((p != null && p.isClimbingLadder) ? "PCB.isClimbingLadder" : (animFlag ? "Animator.ClimbingLadder" : "None"));
			return result;
		}

		private void Status(string msg, double minInterval = 0.33)
		{
			double realtimeSinceStartupAsDouble = Time.realtimeSinceStartupAsDouble;
			if (!(msg == _lastStatus) || !(realtimeSinceStartupAsDouble - _lastStatusAt < minInterval))
			{
				_lastStatus = msg;
				_lastStatusAt = realtimeSinceStartupAsDouble;
				Debug.Log("[Stealth Ladders] [ClimbSilenceMonitor] " + msg);
			}
		}

		private void Update()
		{
			if (!ConfigSettings.StealthOnLadders)
			{
				Status("ConfigOff -> unmuting");
				ForceMute(mute: false, "ConfigOff");
				return;
			}
			if (_crouchAction == null)
			{
				TryBindCrouchAction();
			}
			_local = GameNetworkManager.Instance?.localPlayerController;
			if ((Object)(object)_local == (Object)null)
			{
				Status("NoLocalPlayer -> unmuting");
				ForceMute(mute: false, "NoLocalPlayer");
				return;
			}
			string source;
			bool animFlag;
			bool climbState = GetClimbState(_local, out source, out animFlag);
			var (flag, text, num) = GetCrouchState(_local);
			if (!climbState)
			{
				Status($"NotClimbing(src={source}, anim={animFlag}) -> unmuting");
				ForceMute(mute: false, "NotClimbing");
				return;
			}
			bool flag2 = flag;
			Status($"Climbing({source}, anim={animFlag}) Crouch={flag}({text}, raw={num:0.00}) => wantMute={flag2}");
			ForceMute(flag2, "Update");
		}

		private void ForceMute(bool mute, string cause)
		{
			if (mute == _lastMuted)
			{
				Debug.Log(string.Format("{0} ForceMute no-change (mute={1}) cause={2}", "[Stealth Ladders] [ClimbSilenceMonitor]", mute, cause));
			}
			else
			{
				Debug.Log(string.Format("{0} ForceMute change {1} -> {2} cause={3}", "[Stealth Ladders] [ClimbSilenceMonitor]", _lastMuted, mute, cause));
				_lastMuted = mute;
			}
			if ((Object)(object)_local != (Object)null)
			{
				ClimbSilenceState.EnsureOn(((Component)_local).gameObject).SetMuted(mute, "local-fallback:" + cause);
			}
			NetworkManager singleton = NetworkManager.Singleton;
			PlayerControllerB local = _local;
			NetworkObject val = ((local != null) ? ((NetworkBehaviour)local).NetworkObject : null);
			StealthLaddersHub stealthLaddersHub = StealthLaddersHub.Ensure();
			if ((Object)(object)singleton == (Object)null || !singleton.IsListening || (Object)(object)val == (Object)null || (Object)(object)stealthLaddersHub == (Object)null)
			{
				Debug.Log(string.Format("{0} HubSend skipped (NMListening={1}, NetObj={2}, Hub={3})", "[Stealth Ladders] [ClimbSilenceMonitor]", singleton != null && singleton.IsListening, (Object)(object)val != (Object)null, (Object)(object)stealthLaddersHub != (Object)null));
			}
			else
			{
				Debug.Log(string.Format("{0} HubSend mute={1} for netId={2}", "[Stealth Ladders] [ClimbSilenceMonitor]", mute, val.NetworkObjectId));
				stealthLaddersHub.SendClimbStealthToServer(val.NetworkObjectId, mute);
			}
		}
	}
	public class ClimbSilenceState : MonoBehaviour
	{
		private const string TAG = "[Stealth Ladders] [ClimbSilenceState]";

		private AudioSource _movementAudioCached;

		private PlayerControllerB _player;

		public bool Muted { get; private set; }

		private void Awake()
		{
			_player = ((Component)this).GetComponent<PlayerControllerB>();
			_movementAudioCached = _player?.movementAudio;
			string[] obj = new string[5]
			{
				"[Stealth Ladders] [ClimbSilenceState] Awake: player='",
				_player?.playerUsername ?? "null",
				"' audio='",
				null,
				null
			};
			AudioSource movementAudioCached = _movementAudioCached;
			obj[3] = ((movementAudioCached != null) ? ((Object)movementAudioCached).name : null) ?? "null";
			obj[4] = "'";
			Debug.Log(string.Concat(obj));
		}

		private void OnEnable()
		{
			Debug.Log(string.Format("{0} OnEnable: Muted={1}", "[Stealth Ladders] [ClimbSilenceState]", Muted));
		}

		private void OnDisable()
		{
			ApplyLocalMute(mute: false, "OnDisable");
		}

		private void OnDestroy()
		{
			ApplyLocalMute(mute: false, "OnDestroy");
		}

		public void SetMuted(bool muted, string cause = null)
		{
			if (Muted == muted)
			{
				Debug.Log(string.Format("{0} SetMuted no-change ({1}) cause={2}", "[Stealth Ladders] [ClimbSilenceState]", muted, cause));
				return;
			}
			bool muted2 = Muted;
			Muted = muted;
			Debug.Log(string.Format("{0} SetMuted {1} -> {2} for '{3}' cause={4}", "[Stealth Ladders] [ClimbSilenceState]", muted2, Muted, _player?.playerUsername ?? "null", cause));
			ApplyLocalMute(Muted, "SetMuted:" + cause);
		}

		private void ApplyLocalMute(bool mute, string cause)
		{
			try
			{
				if ((Object)(object)_movementAudioCached == (Object)null)
				{
					_movementAudioCached = _player?.movementAudio;
				}
				if ((Object)(object)_movementAudioCached == (Object)null)
				{
					Debug.Log("[Stealth Ladders] [ClimbSilenceState] ApplyLocalMute skipped (no movementAudio) cause=" + cause);
				}
				else if (_movementAudioCached.mute != mute)
				{
					_movementAudioCached.mute = mute;
					Debug.Log(string.Format("{0} Local AudioSource.mute -> {1} ({2}) cause={3}", "[Stealth Ladders] [ClimbSilenceState]", mute, ((Object)_movementAudioCached).name, cause));
				}
				else
				{
					Debug.Log(string.Format("{0} Local AudioSource.mute already {1} ({2}) cause={3}", "[Stealth Ladders] [ClimbSilenceState]", mute, ((Object)_movementAudioCached).name, cause));
				}
			}
			catch (Exception arg)
			{
				Debug.Log(string.Format("{0} ApplyLocalMute exception: {1}", "[Stealth Ladders] [ClimbSilenceState]", arg));
			}
		}

		public static bool IsClimbMuted(PlayerControllerB player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			ClimbSilenceState climbSilenceState = default(ClimbSilenceState);
			if (((Component)player).TryGetComponent<ClimbSilenceState>(ref climbSilenceState))
			{
				return climbSilenceState.Muted;
			}
			return false;
		}

		public static ClimbSilenceState EnsureOn(GameObject go)
		{
			if ((Object)(object)go == (Object)null)
			{
				return null;
			}
			ClimbSilenceState result = default(ClimbSilenceState);
			if (!go.TryGetComponent<ClimbSilenceState>(ref result))
			{
				result = go.AddComponent<ClimbSilenceState>();
				Debug.Log("[Stealth Ladders] [ClimbSilenceState] EnsureOn: added new state component.");
			}
			return result;
		}
	}
	[HarmonyPatch]
	internal static class StealthLaddersBootstrap
	{
		[HarmonyPatch(typeof(GameNetworkManager), "Start")]
		[HarmonyPostfix]
		private static void GN_Start_Postfix()
		{
			ClimbSilenceMonitor.Ensure("GameNetworkManager.Start");
		}

		[HarmonyPatch(typeof(PlayerControllerB), "Start")]
		[HarmonyPostfix]
		private static void PCB_Start_Postfix(PlayerControllerB __instance)
		{
			ClimbSilenceMonitor.Ensure("PlayerControllerB.Start");
			ClimbSilenceState.EnsureOn(((Component)__instance).gameObject);
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "StealthLadders";

		public const string PLUGIN_NAME = "StealthLadders";

		public const string PLUGIN_VERSION = "0.0.1";
	}
}
namespace StealthLadders.Patches
{
	internal class ItemUsePatch
	{
		[HarmonyPatch(typeof(GrabbableObject), "UseItemOnClient")]
		private static class Patch_UseItemOnClient
		{
			private static void Prefix(GrabbableObject __instance, bool buttonDown)
			{
				if (!ConfigSettings.StealthLadders)
				{
					Debug.Log("[UseItemOnClient:Prefix] Disabled in config; skipping.");
					return;
				}
				if (!buttonDown)
				{
					Debug.Log("[UseItemOnClient:Prefix] buttonDown=false; skipping.");
					return;
				}
				ExtensionLadderItem val = (ExtensionLadderItem)(object)((__instance is ExtensionLadderItem) ? __instance : null);
				if (val == null)
				{
					Debug.Log("[UseItemOnClient:Prefix] Not a ladder (" + ((object)__instance)?.GetType().Name + "); skipping.");
					return;
				}
				if ((Object)(object)__instance.playerHeldBy == (Object)null)
				{
					Debug.Log("[UseItemOnClient:Prefix] playerHeldBy is null; skipping.");
					return;
				}
				bool isCrouching = __instance.playerHeldBy.isCrouching;
				object[] array = new object[5];
				NetworkObject networkObject = ((NetworkBehaviour)val).NetworkObject;
				array[0] = ((networkObject != null) ? new ulong?(networkObject.NetworkObjectId) : null);
				array[1] = isCrouching;
				array[2] = ((NetworkBehaviour)__instance).IsOwner;
				array[3] = ((NetworkBehaviour)__instance).IsClient;
				array[4] = ((NetworkBehaviour)__instance).IsServer;
				Debug.Log(string.Format("[UseItemOnClient:Prefix] ladder NetId={0} crouching={1} isOwner={2} isClient={3} isServer={4}", array));
				LadderState ladderState = ((Component)val).GetComponent<LadderState>();
				if ((Object)(object)ladderState == (Object)null)
				{
					ladderState = ((Component)val).gameObject.AddComponent<LadderState>();
					NetworkObject networkObject2 = ((NetworkBehaviour)val).NetworkObject;
					Debug.Log($"[UseItemOnClient:Prefix] Added LadderState to ladder NetId={((networkObject2 != null) ? new ulong?(networkObject2.NetworkObjectId) : null)}");
				}
				ladderState.ApplyLocal(isCrouching ? LadderFlags.Stealth : LadderFlags.None);
				Debug.Log($"[UseItemOnClient:Prefix] Local ApplyLocal -> {ladderState}");
				StealthLaddersHub stealthLaddersHub = StealthLaddersHub.Ensure();
				if ((Object)(object)NetworkManager.Singleton != (Object)null && (Object)(object)((NetworkBehaviour)val).NetworkObject != (Object)null)
				{
					ulong networkObjectId = ((NetworkBehaviour)val).NetworkObject.NetworkObjectId;
					Debug.Log($"[UseItemOnClient:Prefix] Sending SetNextActivationFlags (custom msg) flags={(isCrouching ? LadderFlags.Stealth : LadderFlags.None)} for ladder NetId={networkObjectId}.");
					stealthLaddersHub.SendNextActivationFlagsToServer(networkObjectId, isCrouching ? LadderFlags.Stealth : LadderFlags.None);
				}
				else
				{
					Debug.Log("[UseItemOnClient:Prefix] NetworkManager or Ladder.NetworkObject is null; cannot send.");
				}
			}
		}

		[HarmonyPatch(typeof(GrabbableObject), "ActivateItemClientRpc")]
		private static class Patch_SendActivateItemClientRpc
		{
			private static void Prefix(GrabbableObject __instance)
			{
				if (!((NetworkBehaviour)__instance).IsServer)
				{
					Debug.Log("[ActivateItemClientRpc:Prefix] Not server; skipping.");
					return;
				}
				ExtensionLadderItem val = (ExtensionLadderItem)(object)((__instance is ExtensionLadderItem) ? __instance : null);
				if (val == null)
				{
					Debug.Log("[ActivateItemClientRpc:Prefix] Non-ladder object (" + ((object)__instance)?.GetType().Name + "); skipping.");
					return;
				}
				StealthLaddersHub stealthLaddersHub = StealthLaddersHub.Ensure();
				if ((Object)(object)stealthLaddersHub == (Object)null)
				{
					Debug.Log("[ActivateItemClientRpc:Prefix] Hub Ensure() returned null; skipping.");
					return;
				}
				if ((Object)(object)((NetworkBehaviour)val).NetworkObject == (Object)null)
				{
					Debug.Log("[ActivateItemClientRpc:Prefix] Ladder NetworkObject is null; skipping.");
					return;
				}
				ulong networkObjectId = ((NetworkBehaviour)val).NetworkObject.NetworkObjectId;
				if (stealthLaddersHub.TryConsumePending(networkObjectId, out var flags))
				{
					Debug.Log($"[ActivateItemClientRpc:Prefix] Consumed pending flags={flags} for ladder NetId={networkObjectId}; broadcasting APPLY (custom msg) BEFORE base RPC.");
					stealthLaddersHub.BroadcastApplyNextActivationFlags(networkObjectId, flags);
				}
				else
				{
					Debug.Log($"[ActivateItemClientRpc:Prefix] No pending flags for ladder NetId={networkObjectId}; nothing to broadcast.");
				}
			}
		}
	}
}