Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Stealth Ladders v1.0.1
BepInEx/plugins/StealthLadders.dll
Decompiled 6 months agousing 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."); } } } } }