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 TurnOffLandmines v1.0.0
BepInEx/plugins/TurnOffLandmines/TurnOffLandmines.dll
Decompiled 13 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.SceneManagement; [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("erockuli")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © 2026 erockuli")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("TurnOffLandmines")] [assembly: AssemblyTitle("TurnOffLandmines")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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; } } } namespace TurnOffLandmines { [BepInPlugin("com.turnofflandmines.plugin", "Turn Off Landmines", "1.0.0")] public sealed class Plugin : BaseUnityPlugin { private sealed class MineInteraction { public Landmine Mine; public GameObject Zone; public SphereCollider Collider; public InteractTrigger Trigger; public bool Processing; public GameObject WarningAudioObject; public AudioSource WarningAudioSource; } public const string ModGuid = "com.turnofflandmines.plugin"; public const string ModName = "Turn Off Landmines"; public const string ModVersion = "1.0.0"; private static Plugin _instance; private Harmony _spawnCompatibilityHarmony; private ConfigEntry<bool> _repairExplicitHazardMarkers; private string _lastTargetedSpawnRepairKey = string.Empty; private ConfigEntry<bool> _modEnabled; private ConfigEntry<bool> _failureEnabled; private ConfigEntry<float> _failureChance; private ConfigEntry<bool> _failureScalingEnabled; private ConfigEntry<float> _failureIncreasePerSuccess; private ConfigEntry<float> _radius; private int _successfulDisarmsThisRound; private AudioClip _failureWarningBeepClip; private NetworkManager _registeredNetworkManager; private bool _networkMessageHandlersRegistered; private const string FailureWarningRequestMessage = "TurnOffLandmines.FailureWarningRequest.v1"; private const string FailureWarningBroadcastMessage = "TurnOffLandmines.FailureWarningBroadcast.v1"; private const string SuccessfulDisarmRequestMessage = "TurnOffLandmines.SuccessfulDisarmRequest.v1"; private const string SuccessfulDisarmResultMessage = "TurnOffLandmines.SuccessfulDisarmResult.v1"; private const string FailureWarningText = "FAILURE, RUN."; private const float HoldDuration = 0.45f; private const float ScanInterval = 0.2f; private const float DiscoveryInterval = 1.25f; private const float IdleMaintenanceInterval = 0.75f; private const float ExplosionDelay = 0.7f; private const float InteractionZoneRadius = 0.72f; private const float MinInteractionRadius = 0.5f; private const float DefaultInteractionRadius = 1f; private const float MaxInteractionRadius = 1.5f; private const float ServerDistanceTolerance = 0.15f; private readonly Dictionary<int, MineInteraction> _interactions = new Dictionary<int, MineInteraction>(); private readonly HashSet<ulong> _successfulDisarmedNetworkIds = new HashSet<ulong>(); private readonly HashSet<int> _seenMineIds = new HashSet<int>(); private readonly List<int> _staleMineIds = new List<int>(); private float _nextMineDiscoveryTime; private Landmine[] _cachedMines; private Coroutine _maintenanceCoroutine; private Sprite _vanillaInteractionIcon; private int _vanillaInteractionLayer = -1; private float _nextIconScanTime; private bool _roundWasActive; private string _lastLoggedSceneName = string.Empty; private string _lastDiscoverySceneName = string.Empty; private int _lastLoggedMineCount = -1; private void Awake() { //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown _modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable or disable the Turn Off Landmines interaction entirely."); _failureEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Failure", "Enabled", true, "Enable chance-based disarm failure. Set ChancePercent to 0 to make disarming safe."); _failureChance = ((BaseUnityPlugin)this).Config.Bind<float>("Failure", "ChancePercent", 15f, "Base failure chance (0-100%) before success-based scaling; the active chance is capped at 100%."); _failureScalingEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Failure Scaling", "Enabled", true, "If enabled, each successful modded disarm this moon adds a configured number of percentage points to later failure rolls."); _failureIncreasePerSuccess = ((BaseUnityPlugin)this).Config.Bind<float>("Failure Scaling", "IncreasePercentPerSuccess", 10f, "Percentage points added to the failure chance after each successful modded disarm in the current moon. Ignored when scaling is disabled."); _radius = ((BaseUnityPlugin)this).Config.Bind<float>("Interaction", "Radius", 1f, new ConfigDescription("Maximum horizontal distance from a landmine where its disarm interaction is available (metres). Default is 1.0m; set 1.5 for the longer reach. Values are limited to 0.5–1.5m.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 1.5f), Array.Empty<object>())); float num = Mathf.Clamp(_radius.Value, 0.5f, 1.5f); if (Mathf.Abs(_radius.Value - num) > 0.001f) { _radius.Value = num; ((BaseUnityPlugin)this).Config.Save(); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Failure warning beep creation deferred until a failed disarm; no custom AudioClip is created during startup."); _instance = this; _repairExplicitHazardMarkers = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawn Compatibility", "RepairExplicitHazardMarkers", true, "Only add a missing RandomMapObject component on exact MapHazardSpawnType<number> placeholders when at least one matching active-level spawn-table entry has a positive curve at the current time. Checks all duplicate matching entries. Existing marker components/lists and vanilla spawn counts are preserved."); InstallSpawnCompatibilityPatch(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Turn Off Landmines v1.0.0 loaded. Enabled=" + _modEnabled.Value + ", failure enabled=" + _failureEnabled.Value + ", base failure chance=" + Mathf.Clamp(_failureChance.Value, 0f, 100f) + "%, scaling=" + _failureScalingEnabled.Value + ", increase per successful disarm=" + Mathf.Max(0f, _failureIncreasePerSuccess.Value) + " percentage points, interaction radius=" + Mathf.Clamp(_radius.Value, 0.5f, 1.5f).ToString("0.##") + "m (allowed " + 0.5f.ToString("0.##") + "–" + 1.5f.ToString("0.##") + "m).")); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Multiplayer: successful disarms are requested by the interacting client, validated and applied by the host, then replicated to all clients. Host-configured radius is authoritative; default " + 1f.ToString("0.0") + "m, configurable up to " + 1.5f.ToString("0.0") + "m.")); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Performance: interaction refresh runs every " + 0.2f.ToString("0.##") + "s, landmine discovery is cached for " + 1.25f.ToString("0.##") + "s, and idle/game-readiness checks run every " + 0.75f.ToString("0.##") + "s (no plugin Update polling).")); _maintenanceCoroutine = ((MonoBehaviour)this).StartCoroutine(MaintenanceLoop()); } private void InstallSpawnCompatibilityPatch() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method(typeof(RoundManager), "SpawnMapObjects", (Type[])null, (Type[])null); MethodInfo method = typeof(Plugin).GetMethod("RepairExplicitHazardMarkersPrefix", BindingFlags.Static | BindingFlags.NonPublic); if (methodInfo == null || method == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"Targeted spawn compatibility patch not installed: RoundManager.SpawnMapObjects or its prefix was not found."); return; } _spawnCompatibilityHarmony = new Harmony("com.turnofflandmines.plugin.TargetedSpawnCompatibility"); HarmonyMethod val = new HarmonyMethod(method); val.priority = 0; _spawnCompatibilityHarmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Targeted spawn compatibility installed. It repairs only exact MapHazardSpawnType<number> placeholders missing RandomMapObject, and only if at least one matching active-level spawn-table entry has a positive curve at the current time. It checks every duplicate matching entry; existing marker lists and vanilla counts are preserved."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Could not install targeted hazard-spawner compatibility: " + ex)); } } private static void RepairExplicitHazardMarkersPrefix(RoundManager __instance) { Plugin instance = _instance; if ((Object)(object)instance == (Object)null || instance._repairExplicitHazardMarkers == null || !instance._repairExplicitHazardMarkers.Value) { return; } try { instance.RepairExplicitHazardMarkers(__instance, "Landmine"); } catch (Exception ex) { ((BaseUnityPlugin)instance).Logger.LogError((object)("Targeted spawn-marker repair failed for Landmine: " + ex)); } } private void RepairExplicitHazardMarkers(RoundManager roundManager, string targetPrefabName) { //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_0303: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)roundManager == (Object)null || (Object)(object)roundManager.currentLevel == (Object)null || roundManager.currentLevel.spawnableMapObjects == null || (Object)(object)TimeOfDay.Instance == (Object)null) { return; } GameObject val = null; int num = 0; List<string> list = new List<string>(); float normalizedTimeOfDay = TimeOfDay.Instance.normalizedTimeOfDay; SpawnableMapObject[] spawnableMapObjects = roundManager.currentLevel.spawnableMapObjects; foreach (SpawnableMapObject val2 in spawnableMapObjects) { if (val2 == null || (Object)(object)val2.prefabToSpawn == (Object)null || !NamesMatch(((Object)val2.prefabToSpawn).name, targetPrefabName)) { continue; } num++; if (val2.numberToSpawn == null) { list.Add("unavailable"); continue; } float num2 = val2.numberToSpawn.Evaluate(normalizedTimeOfDay); list.Add(num2.ToString("0.###")); if (!(num2 <= 0f) && (Object)(object)val == (Object)null) { val = val2.prefabToSpawn; } } if ((Object)(object)val == (Object)null) { if (num > 0) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Targeted spawn repair skipped for " + targetPrefabName + ": all " + num + " matching active-level spawn-table entry/entries had no positive curve at normalized time " + normalizedTimeOfDay.ToString("0.###") + " (evaluated values: " + string.Join(", ", list.ToArray()) + "). No spawn markers or spawn rates were changed.")); } else { ((BaseUnityPlugin)this).Logger.LogDebug((object)("Targeted spawn repair skipped for " + targetPrefabName + ": the active level does not list it in spawnableMapObjects.")); } return; } if (num > 1) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("Targeted spawn repair found " + num + " matching " + targetPrefabName + " spawn-table entries at normalized time " + normalizedTimeOfDay.ToString("0.###") + " (evaluated values: " + string.Join(", ", list.ToArray()) + "); at least one is positive, so normal targeted-marker checks may continue.")); } RandomMapObject[] array = Object.FindObjectsOfType<RandomMapObject>(); foreach (RandomMapObject val3 in array) { if ((Object)(object)val3 == (Object)null || val3.spawnablePrefabs == null) { continue; } foreach (GameObject spawnablePrefab in val3.spawnablePrefabs) { if ((Object)(object)spawnablePrefab != (Object)null && NamesMatch(((Object)spawnablePrefab).name, targetPrefabName)) { return; } } } List<GameObject> eligibleVanillaHazardPrefabs = GetEligibleVanillaHazardPrefabs(roundManager.currentLevel); GameObject[] array2 = Object.FindObjectsOfType<GameObject>(); int num3 = 0; int num4 = 0; GameObject[] array3 = array2; foreach (GameObject val4 in array3) { if (!((Object)(object)val4 == (Object)null) && IsExplicitHazardSpawnMarker(((Object)val4).name)) { num3++; if (!((Object)(object)val4.GetComponent<RandomMapObject>() != (Object)null)) { val4.AddComponent<RandomMapObject>().spawnablePrefabs = new List<GameObject>(eligibleVanillaHazardPrefabs); num4++; } } } Scene activeScene = SceneManager.GetActiveScene(); string name = ((Scene)(ref activeScene)).name; string name2 = ((Object)roundManager.currentLevel).name; if (num3 == 0) { string text = name + "|" + name2 + "|" + targetPrefabName; if (_lastTargetedSpawnRepairKey != text) { _lastTargetedSpawnRepairKey = text; ((BaseUnityPlugin)this).Logger.LogWarning((object)("Targeted spawn repair found no exact MapHazardSpawnType<number> placeholder for " + targetPrefabName + " in scene '" + name + "' / level '" + name2 + "'. No other objects or spawn lists were changed.")); } } else if (num4 == 0) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Targeted spawn repair found " + num3 + " explicit placeholder(s), but each already had a RandomMapObject component and no compatible spawner exists for " + targetPrefabName + ". Existing marker lists were intentionally left unchanged to preserve interior/event restrictions.")); } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Targeted spawn repair on level '" + name2 + "': added RandomMapObject to " + num4 + " missing component(s) on explicitly named MapHazardSpawnType<number> placeholders. Added prefab links only for hazards already in the active level's spawn table with positive vanilla spawn curves; table entries/curves/counts were not changed.")); } } private List<GameObject> GetEligibleVanillaHazardPrefabs(SelectableLevel level) { List<GameObject> list = new List<GameObject>(); if ((Object)(object)level == (Object)null || level.spawnableMapObjects == null || (Object)(object)TimeOfDay.Instance == (Object)null) { return list; } SpawnableMapObject[] spawnableMapObjects = level.spawnableMapObjects; foreach (SpawnableMapObject val in spawnableMapObjects) { if (val == null || (Object)(object)val.prefabToSpawn == (Object)null || val.numberToSpawn == null) { continue; } string name = ((Object)val.prefabToSpawn).name; if ((!NamesMatch(name, "Landmine") && !NamesMatch(name, "TurretContainer")) || val.numberToSpawn.Evaluate(TimeOfDay.Instance.normalizedTimeOfDay) <= 0f) { continue; } bool flag = false; foreach (GameObject item in list) { if ((Object)(object)item != (Object)null && NamesMatch(((Object)item).name, name)) { flag = true; break; } } if (!flag) { list.Add(val.prefabToSpawn); } } return list; } private static bool IsExplicitHazardSpawnMarker(string objectName) { if (string.IsNullOrEmpty(objectName)) { return false; } string text = objectName.Replace("(Clone)", string.Empty).Trim(); if (!text.StartsWith("MapHazardSpawnType", StringComparison.OrdinalIgnoreCase)) { return false; } string text2 = text.Substring("MapHazardSpawnType".Length); if (text2.Length == 0) { return false; } for (int i = 0; i < text2.Length; i++) { if (text2[i] < '0' || text2[i] > '9') { return false; } } return true; } private static bool NamesMatch(string actual, string expected) { if (string.IsNullOrEmpty(actual) || string.IsNullOrEmpty(expected)) { return false; } return string.Equals(actual.Replace("(Clone)", string.Empty).Trim(), expected, StringComparison.OrdinalIgnoreCase); } private IEnumerator MaintenanceLoop() { WaitForSecondsRealtime activeWait = new WaitForSecondsRealtime(0.2f); WaitForSecondsRealtime idleWait = new WaitForSecondsRealtime(0.75f); while (true) { EnsureNetworkMessageHandlersRegistered(); if (!IsGameplayReady()) { if (_roundWasActive || _interactions.Count > 0) { if (_roundWasActive && _successfulDisarmsThisRound > 0) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Moon ended; resetting landmine failure-scaling progress after " + _successfulDisarmsThisRound + " successful modded disarm(s).")); } _successfulDisarmsThisRound = 0; _successfulDisarmedNetworkIds.Clear(); ClearInteractions(); } _roundWasActive = false; _cachedMines = null; _lastDiscoverySceneName = string.Empty; _nextMineDiscoveryTime = 0f; yield return idleWait; continue; } if (!_roundWasActive) { _roundWasActive = true; _successfulDisarmsThisRound = 0; _successfulDisarmedNetworkIds.Clear(); _lastLoggedSceneName = string.Empty; _lastLoggedMineCount = -1; _cachedMines = null; _lastDiscoverySceneName = string.Empty; _nextMineDiscoveryTime = 0f; } if (!_modEnabled.Value) { if (_interactions.Count > 0) { ClearInteractions(); } yield return idleWait; continue; } try { RefreshInteractions(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Landmine interaction scan failed: " + ex)); } yield return activeWait; } } private void EnsureNetworkMessageHandlersRegistered() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsListening || singleton.CustomMessagingManager == null || (_networkMessageHandlersRegistered && (Object)(object)_registeredNetworkManager == (Object)(object)singleton)) { return; } UnregisterNetworkMessageHandlers(); bool flag = false; bool flag2 = false; bool flag3 = false; bool flag4 = false; try { singleton.CustomMessagingManager.RegisterNamedMessageHandler("TurnOffLandmines.FailureWarningRequest.v1", new HandleNamedMessageDelegate(HandleFailureWarningRequest)); flag = true; singleton.CustomMessagingManager.RegisterNamedMessageHandler("TurnOffLandmines.FailureWarningBroadcast.v1", new HandleNamedMessageDelegate(HandleFailureWarningBroadcast)); flag2 = true; singleton.CustomMessagingManager.RegisterNamedMessageHandler("TurnOffLandmines.SuccessfulDisarmRequest.v1", new HandleNamedMessageDelegate(HandleSuccessfulDisarmRequest)); flag3 = true; singleton.CustomMessagingManager.RegisterNamedMessageHandler("TurnOffLandmines.SuccessfulDisarmResult.v1", new HandleNamedMessageDelegate(HandleSuccessfulDisarmResult)); flag4 = true; _registeredNetworkManager = singleton; _networkMessageHandlersRegistered = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Networked landmine warning and successful-disarm messaging registered."); } catch (Exception ex) { try { if (flag4) { singleton.CustomMessagingManager.UnregisterNamedMessageHandler("TurnOffLandmines.SuccessfulDisarmResult.v1"); } if (flag3) { singleton.CustomMessagingManager.UnregisterNamedMessageHandler("TurnOffLandmines.SuccessfulDisarmRequest.v1"); } if (flag2) { singleton.CustomMessagingManager.UnregisterNamedMessageHandler("TurnOffLandmines.FailureWarningBroadcast.v1"); } if (flag) { singleton.CustomMessagingManager.UnregisterNamedMessageHandler("TurnOffLandmines.FailureWarningRequest.v1"); } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("Could not clean up partial landmine network handler registration: " + ex2.Message)); } ((BaseUnityPlugin)this).Logger.LogError((object)("Could not register landmine network messaging; partial handlers were rolled back: " + ex)); _registeredNetworkManager = null; _networkMessageHandlersRegistered = false; } } private void UnregisterNetworkMessageHandlers() { if (!_networkMessageHandlersRegistered || (Object)(object)_registeredNetworkManager == (Object)null) { _registeredNetworkManager = null; _networkMessageHandlersRegistered = false; return; } try { if (_registeredNetworkManager.CustomMessagingManager != null) { _registeredNetworkManager.CustomMessagingManager.UnregisterNamedMessageHandler("TurnOffLandmines.FailureWarningRequest.v1"); _registeredNetworkManager.CustomMessagingManager.UnregisterNamedMessageHandler("TurnOffLandmines.FailureWarningBroadcast.v1"); _registeredNetworkManager.CustomMessagingManager.UnregisterNamedMessageHandler("TurnOffLandmines.SuccessfulDisarmRequest.v1"); _registeredNetworkManager.CustomMessagingManager.UnregisterNamedMessageHandler("TurnOffLandmines.SuccessfulDisarmResult.v1"); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("Could not unregister landmine network messages during teardown: " + ex.Message)); } _registeredNetworkManager = null; _networkMessageHandlersRegistered = false; } private unsafe void SendFailureWarningRequest(Landmine mine) { //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) EnsureNetworkMessageHandlersRegistered(); NetworkManager singleton = NetworkManager.Singleton; NetworkObject val = (((Object)(object)mine != (Object)null) ? ((Component)mine).GetComponent<NetworkObject>() : null); if ((Object)(object)val == (Object)null && (Object)(object)mine != (Object)null) { val = ((Component)mine).GetComponentInParent<NetworkObject>(); } if ((Object)(object)val == (Object)null && (Object)(object)mine != (Object)null) { val = ((Component)mine).GetComponentInChildren<NetworkObject>(true); } if ((Object)(object)singleton == (Object)null || !singleton.IsListening || singleton.CustomMessagingManager == null || (Object)(object)val == (Object)null || !val.IsSpawned) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not network the landmine failure beep because the mine's spawned NetworkObject was unavailable. The local warning beep still played."); return; } ulong networkObjectId = val.NetworkObjectId; try { if (singleton.IsServer) { SendFailureWarningBroadcastToClients(singleton, networkObjectId, null); return; } if (!_networkMessageHandlersRegistered || (Object)(object)_registeredNetworkManager != (Object)(object)singleton) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Network warning handlers are not ready; this failed disarm's beep will be local only."); return; } FastBufferWriter val2 = default(FastBufferWriter); ((FastBufferWriter)(ref val2))..ctor(8, (Allocator)2, -1); try { ((FastBufferWriter)(ref val2)).WriteValueSafe<ulong>(ref networkObjectId, default(ForPrimitives)); singleton.CustomMessagingManager.SendNamedMessage("TurnOffLandmines.FailureWarningRequest.v1", 0uL, val2, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val2))/*cast due to .constrained prefix*/).Dispose(); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not send the networked landmine failure warning; the local beep still played: " + ex.Message)); } } private void HandleFailureWarningRequest(ulong senderClientId, FastBufferReader reader) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && singleton.IsServer) { ulong networkObjectId = default(ulong); try { ((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref networkObjectId, default(ForPrimitives)); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Ignored malformed landmine warning request from client " + senderClientId + ": " + ex.Message)); return; } if (singleton.ConnectedClients == null || !singleton.ConnectedClients.ContainsKey(senderClientId)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Ignored landmine warning request from unconnected client " + senderClientId + ".")); return; } if (!TryGetSpawnedMine(singleton, networkObjectId, out var mine)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Ignored landmine warning request because NetworkObject " + networkObjectId + " did not resolve to a spawned Landmine.")); return; } PlayFailureWarningForMine(mine); SendFailureWarningBroadcastToClients(singleton, networkObjectId, senderClientId); ((BaseUnityPlugin)this).Logger.LogDebug((object)("Relayed landmine failure beep for NetworkObject " + networkObjectId + " from client " + senderClientId + ".")); } } private void HandleFailureWarningBroadcast(ulong senderClientId, FastBufferReader reader) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && !singleton.IsServer && senderClientId == 0L) { ulong networkObjectId = default(ulong); try { ((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref networkObjectId, default(ForPrimitives)); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Ignored malformed relayed landmine warning: " + ex.Message)); return; } if (TryGetSpawnedMine(singleton, networkObjectId, out var mine)) { PlayFailureWarningForMine(mine); ((BaseUnityPlugin)this).Logger.LogDebug((object)("Played relayed landmine failure beep for NetworkObject " + networkObjectId + ".")); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not play relayed landmine warning because NetworkObject " + networkObjectId + " was not found on this client.")); } } } private unsafe void SendFailureWarningBroadcastToClients(NetworkManager manager, ulong networkObjectId, ulong? excludedClientId) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)manager == (Object)null || !manager.IsServer || manager.CustomMessagingManager == null) { return; } List<ulong> list = new List<ulong>(); try { foreach (ulong connectedClientsId in manager.ConnectedClientsIds) { if (connectedClientsId != manager.LocalClientId && (!excludedClientId.HasValue || connectedClientsId != excludedClientId.Value)) { list.Add(connectedClientsId); } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not snapshot clients for landmine warning relay: " + ex.Message)); return; } FastBufferWriter val = default(FastBufferWriter); foreach (ulong item in list) { try { ((FastBufferWriter)(ref val))..ctor(8, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref networkObjectId, default(ForPrimitives)); manager.CustomMessagingManager.SendNamedMessage("TurnOffLandmines.FailureWarningBroadcast.v1", item, val, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not relay landmine warning for NetworkObject " + networkObjectId + " to client " + item + ": " + ex2.Message)); } } } private static bool TryGetSpawnedMine(NetworkManager manager, ulong networkObjectId, out Landmine mine) { mine = null; if ((Object)(object)manager == (Object)null || manager.SpawnManager == null || manager.SpawnManager.SpawnedObjects == null) { return false; } if (!manager.SpawnManager.SpawnedObjects.TryGetValue(networkObjectId, out var value) || (Object)(object)value == (Object)null || !value.IsSpawned) { return false; } mine = ((Component)value).GetComponent<Landmine>(); if ((Object)(object)mine == (Object)null) { mine = ((Component)value).GetComponentInChildren<Landmine>(true); } return (Object)(object)mine != (Object)null; } private void PlayFailureWarningForMine(Landmine mine) { if ((Object)(object)mine == (Object)null) { return; } foreach (MineInteraction value in _interactions.Values) { if (value != null && (Object)(object)value.Mine == (Object)(object)mine) { if (!((Object)(object)value.WarningAudioSource != (Object)null) || !value.WarningAudioSource.isPlaying) { StartFailureWarningBeep(value); } return; } } MineInteraction state = new MineInteraction { Mine = mine }; StartFailureWarningBeep(state); } private unsafe void RequestSuccessfulDisarm(MineInteraction state) { //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) Landmine val = state?.Mine; if ((Object)(object)val == (Object)null) { ResetDisarmProcessing(val); return; } NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsListening || singleton.CustomMessagingManager == null) { ApplySuccessfulDisarmLocally(val); ((BaseUnityPlugin)this).Logger.LogWarning((object)"No active Netcode session was available; applied the successful disarm locally."); return; } NetworkObject mineNetworkObject = GetMineNetworkObject(val); if ((Object)(object)mineNetworkObject == (Object)null || !mineNetworkObject.IsSpawned) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not synchronize a successful disarm because the landmine's spawned NetworkObject was unavailable; the interaction was cancelled instead of changing only this client."); ResetDisarmProcessing(val); return; } EnsureNetworkMessageHandlersRegistered(); ulong networkObjectId = mineNetworkObject.NetworkObjectId; if (singleton.IsServer) { ProcessSuccessfulDisarmRequest(singleton.LocalClientId, networkObjectId); return; } if (!_networkMessageHandlersRegistered || (Object)(object)_registeredNetworkManager != (Object)(object)singleton) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Successful disarm cancelled because the network message handlers were not ready; retry the interaction."); ResetDisarmProcessing(val); return; } try { FastBufferWriter val2 = default(FastBufferWriter); ((FastBufferWriter)(ref val2))..ctor(8, (Allocator)2, -1); try { ((FastBufferWriter)(ref val2)).WriteValueSafe<ulong>(ref networkObjectId, default(ForPrimitives)); singleton.CustomMessagingManager.SendNamedMessage("TurnOffLandmines.SuccessfulDisarmRequest.v1", 0uL, val2, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val2))/*cast due to .constrained prefix*/).Dispose(); } ((BaseUnityPlugin)this).Logger.LogDebug((object)("Requested host-authoritative successful disarm for Landmine NetworkObject " + networkObjectId + ".")); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not send the successful-disarm request; interaction cancelled: " + ex.Message)); ResetDisarmProcessing(val); } } private void HandleSuccessfulDisarmRequest(ulong senderClientId, FastBufferReader reader) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && singleton.IsServer) { ulong networkObjectId = default(ulong); try { ((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref networkObjectId, default(ForPrimitives)); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Ignored malformed successful-disarm request from client " + senderClientId + ": " + ex.Message)); return; } ProcessSuccessfulDisarmRequest(senderClientId, networkObjectId); } } private void ProcessSuccessfulDisarmRequest(ulong senderClientId, ulong networkObjectId) { //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsServer || singleton.CustomMessagingManager == null) { return; } if (senderClientId != singleton.LocalClientId && (singleton.ConnectedClients == null || !singleton.ConnectedClients.ContainsKey(senderClientId))) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Rejected successful-disarm request from unconnected client " + senderClientId + ".")); return; } if (!IsGameplayReady() || !TryGetSpawnedMine(singleton, networkObjectId, out var mine) || (Object)(object)mine == (Object)null || !((Behaviour)mine).isActiveAndEnabled || IsMineSpent(mine)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Rejected successful-disarm request for invalid, inactive, or already-spent Landmine NetworkObject " + networkObjectId + ".")); SendSuccessfulDisarmResult(singleton, senderClientId, networkObjectId, accepted: false); return; } PlayerControllerB val = FindPlayerForClientId(singleton, senderClientId); if ((Object)(object)val == (Object)null || val.isPlayerDead || !val.isPlayerControlled) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Rejected successful-disarm request for NetworkObject " + networkObjectId + " because the requesting player was not alive/controlled.")); SendSuccessfulDisarmResult(singleton, senderClientId, networkObjectId, accepted: false); return; } Vector3 val2 = ((Component)val).transform.position - ((Component)mine).transform.position; val2.y = 0f; float magnitude = ((Vector3)(ref val2)).magnitude; float num = Mathf.Clamp(_radius.Value, 0.5f, 1.5f); if (magnitude > num + 0.15f) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Rejected successful-disarm request for NetworkObject " + networkObjectId + ": player was " + magnitude.ToString("0.00") + "m away, beyond the host's configured " + num.ToString("0.00") + "m radius (plus " + 0.15f.ToString("0.00") + "m network tolerance).")); SendSuccessfulDisarmResult(singleton, senderClientId, networkObjectId, accepted: false); } else if (!ApplySuccessfulDisarmLocally(mine)) { SendSuccessfulDisarmResult(singleton, senderClientId, networkObjectId, accepted: false); } else { SendSuccessfulDisarmResult(singleton, senderClientId, networkObjectId, accepted: true); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Host accepted and replicated successful landmine disarm for NetworkObject " + networkObjectId + " from client " + senderClientId + ". Distance=" + magnitude.ToString("0.00") + "m; host radius=" + num.ToString("0.00") + "m.")); } } private void HandleSuccessfulDisarmResult(ulong senderClientId, FastBufferReader reader) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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) //IL_003b: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && !singleton.IsServer && senderClientId == 0L) { ulong networkObjectId = default(ulong); bool flag = default(bool); try { ((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref networkObjectId, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref flag, default(ForPrimitives)); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Ignored malformed successful-disarm result: " + ex.Message)); return; } if (!TryGetSpawnedMine(singleton, networkObjectId, out var mine)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not apply successful-disarm result because Landmine NetworkObject " + networkObjectId + " was not found on this client.")); } else if (flag) { ApplySuccessfulDisarmLocally(mine); ((BaseUnityPlugin)this).Logger.LogDebug((object)("Applied host-replicated successful disarm for Landmine NetworkObject " + networkObjectId + ".")); } else { ResetDisarmProcessing(mine); ((BaseUnityPlugin)this).Logger.LogDebug((object)("Host rejected successful disarm for Landmine NetworkObject " + networkObjectId + "; the interaction has been released.")); } } } private unsafe void SendSuccessfulDisarmResult(NetworkManager manager, ulong requestingClientId, ulong networkObjectId, bool accepted) { //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)manager == (Object)null || !manager.IsServer || manager.CustomMessagingManager == null) { return; } List<ulong> list = new List<ulong>(); try { if (accepted) { foreach (ulong connectedClientsId in manager.ConnectedClientsIds) { if (connectedClientsId != manager.LocalClientId) { list.Add(connectedClientsId); } } } else if (requestingClientId != manager.LocalClientId && manager.ConnectedClients != null && manager.ConnectedClients.ContainsKey(requestingClientId)) { list.Add(requestingClientId); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not build recipient list for landmine disarm result: " + ex.Message)); return; } if (!accepted && requestingClientId == manager.LocalClientId) { if (TryGetSpawnedMine(manager, networkObjectId, out var mine)) { ResetDisarmProcessing(mine); } return; } FastBufferWriter val = default(FastBufferWriter); foreach (ulong item in list) { try { ((FastBufferWriter)(ref val))..ctor(9, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref networkObjectId, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref accepted, default(ForPrimitives)); manager.CustomMessagingManager.SendNamedMessage("TurnOffLandmines.SuccessfulDisarmResult.v1", item, val, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not send landmine disarm result for NetworkObject " + networkObjectId + " to client " + item + ": " + ex2.Message)); } } } private bool ApplySuccessfulDisarmLocally(Landmine mine) { if ((Object)(object)mine == (Object)null) { return false; } ulong mineNetworkObjectId = GetMineNetworkObjectId(mine); if (mineNetworkObjectId != 0L && !_successfulDisarmedNetworkIds.Add(mineNetworkObjectId)) { DisableInteractionForMine(mine); return true; } if (!IsMineSpent(mine)) { DisarmMine(mine); } DisableInteractionForMine(mine); _successfulDisarmsThisRound++; float num = Mathf.Clamp(Mathf.Clamp(_failureChance.Value, 0f, 100f) + (_failureScalingEnabled.Value ? (Mathf.Max(0f, _failureIncreasePerSuccess.Value) * (float)_successfulDisarmsThisRound) : 0f), 0f, 100f); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Landmine disarmed successfully on this peer. Successful modded disarms this moon=" + _successfulDisarmsThisRound + "; next failure chance=" + num.ToString("0.##") + "%. NetworkObject=" + mineNetworkObjectId + ".")); return true; } private void DisableInteractionForMine(Landmine mine) { foreach (MineInteraction value in _interactions.Values) { if (value != null && !((Object)(object)value.Mine != (Object)(object)mine)) { value.Processing = false; if ((Object)(object)value.Trigger != (Object)null) { value.Trigger.interactable = false; } if ((Object)(object)value.Zone != (Object)null) { value.Zone.SetActive(false); } } } } private void ResetDisarmProcessing(Landmine mine) { if ((Object)(object)mine == (Object)null) { return; } foreach (MineInteraction value in _interactions.Values) { if (value != null && !((Object)(object)value.Mine != (Object)(object)mine)) { value.Processing = false; if ((Object)(object)value.Trigger != (Object)null) { value.Trigger.interactable = false; } } } } private static ulong GetMineNetworkObjectId(Landmine mine) { NetworkObject mineNetworkObject = GetMineNetworkObject(mine); if (!((Object)(object)mineNetworkObject != (Object)null) || !mineNetworkObject.IsSpawned) { return 0uL; } return mineNetworkObject.NetworkObjectId; } private static NetworkObject GetMineNetworkObject(Landmine mine) { if ((Object)(object)mine == (Object)null) { return null; } NetworkObject val = ((Component)mine).GetComponent<NetworkObject>(); if ((Object)(object)val == (Object)null) { val = ((Component)mine).GetComponentInParent<NetworkObject>(); } if ((Object)(object)val == (Object)null) { val = ((Component)mine).GetComponentInChildren<NetworkObject>(true); } return val; } private static PlayerControllerB FindPlayerForClientId(NetworkManager manager, ulong clientId) { try { if ((Object)(object)manager != (Object)null && manager.ConnectedClients != null && manager.ConnectedClients.TryGetValue(clientId, out var value) && value != null && (Object)(object)value.PlayerObject != (Object)null) { PlayerControllerB val = ((Component)value.PlayerObject).GetComponent<PlayerControllerB>(); if ((Object)(object)val == (Object)null) { val = ((Component)value.PlayerObject).GetComponentInChildren<PlayerControllerB>(true); } if ((Object)(object)val != (Object)null) { return val; } } Type type = Type.GetType("StartOfRound, Assembly-CSharp"); if (GetMember((type != null) ? GetStaticMember(type, "Instance") : null, "allPlayerScripts") is IEnumerable enumerable) { foreach (object item in enumerable) { PlayerControllerB val2 = (PlayerControllerB)((item is PlayerControllerB) ? item : null); if (!((Object)(object)val2 == (Object)null)) { object member = GetMember(val2, "playerClientId"); if (member is ulong && (ulong)member == clientId) { return val2; } if (member is int && (ulong)(int)member == clientId) { return val2; } } } } } catch { } return null; } private static bool IsGameplayReady() { try { Type type = Type.GetType("StartOfRound, Assembly-CSharp"); object obj = ((type != null) ? GetStaticMember(type, "Instance") : null); if (obj == null) { return false; } object member = GetMember(obj, "shipHasLanded"); if (!(member is bool) || !(bool)member) { return false; } object member2 = GetMember(obj, "inShipPhase"); if (member2 is bool && (bool)member2) { return false; } Type type2 = Type.GetType("RoundManager, Assembly-CSharp"); object obj2 = ((type2 != null) ? GetStaticMember(type2, "Instance") : null); return obj2 != null && GetMember(obj2, "currentLevel") != null; } catch { return false; } } private void RefreshInteractions() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_02df: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_038b: Unknown result type (might be due to invalid IL or missing references) //IL_0390: Unknown result type (might be due to invalid IL or missing references) //IL_039a: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Unknown result type (might be due to invalid IL or missing references) RefreshVanillaInteractionIconIfNeeded(); string turnOffPrompt = GetTurnOffPrompt(); if (!_modEnabled.Value) { ClearInteractions(); return; } Scene activeScene = SceneManager.GetActiveScene(); string name = ((Scene)(ref activeScene)).name; if (_cachedMines == null || name != _lastDiscoverySceneName || Time.unscaledTime >= _nextMineDiscoveryTime) { _cachedMines = Object.FindObjectsOfType<Landmine>(); _lastDiscoverySceneName = name; _nextMineDiscoveryTime = Time.unscaledTime + 1.25f; } Landmine[] array = _cachedMines ?? Array.Empty<Landmine>(); Landmine[] array2; if (name != _lastLoggedSceneName || array.Length != _lastLoggedMineCount) { _lastLoggedSceneName = name; _lastLoggedMineCount = array.Length; RoundManager instance = RoundManager.Instance; string text = (((Object)(object)instance != (Object)null && (Object)(object)instance.currentLevel != (Object)null) ? ((Object)instance.currentLevel).name : "<unknown>"); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Spawn-safe scan in scene '" + name + "' on level '" + text + "': found " + array.Length + " active Landmine component(s). This mod does not register or spawn landmine prefabs.")); array2 = array; foreach (Landmine val in array2) { if ((Object)(object)val != (Object)null) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Detected active Landmine instance " + ((Object)val).GetInstanceID() + " at world position " + ((object)((Component)val).transform.position/*cast due to .constrained prefix*/).ToString() + ".")); } } } _seenMineIds.Clear(); PlayerControllerB localPlayer = GetLocalPlayer(); array2 = array; foreach (Landmine val2 in array2) { if ((Object)(object)val2 == (Object)null || !((Behaviour)val2).isActiveAndEnabled) { continue; } int instanceID = ((Object)val2).GetInstanceID(); _seenMineIds.Add(instanceID); if (IsMineSpent(val2)) { if (_interactions.TryGetValue(instanceID, out var value) && value != null && (Object)(object)value.Zone != (Object)null) { if ((Object)(object)value.Trigger != (Object)null) { value.Trigger.interactable = false; } value.Zone.SetActive(false); } continue; } if (!_interactions.TryGetValue(instanceID, out var value2) || (Object)(object)value2.Mine == (Object)null) { value2 = CreateInteraction(val2); _interactions[instanceID] = value2; } if (value2 != null && !((Object)(object)value2.Zone == (Object)null) && !((Object)(object)value2.Trigger == (Object)null)) { Vector3 val3 = (((Object)(object)localPlayer != (Object)null) ? (((Component)localPlayer).transform.position - ((Component)val2).transform.position) : (Vector3.one * 999f)); val3.y = 0f; float num = Mathf.Clamp(_radius.Value, 0.5f, 1.5f); bool flag = (Object)(object)localPlayer != (Object)null && ((Vector3)(ref val3)).magnitude <= num && !value2.Processing && !IsMineSpent(val2); value2.Trigger.interactable = flag; value2.Zone.transform.position = ((Component)val2).transform.position + Vector3.up * 0.45f; if ((Object)(object)value2.Trigger.hoverIcon == (Object)null && (Object)(object)_vanillaInteractionIcon != (Object)null) { value2.Trigger.hoverIcon = _vanillaInteractionIcon; } if (value2.Zone.activeSelf != flag) { value2.Zone.SetActive(flag); } string text2 = (value2.Processing ? "FAILURE, RUN." : turnOffPrompt); if (value2.Trigger.hoverTip != text2) { value2.Trigger.hoverTip = text2; } value2.Trigger.holdTip = (value2.Processing ? "FAILURE, RUN." : "Turning off..."); } } _staleMineIds.Clear(); foreach (KeyValuePair<int, MineInteraction> interaction in _interactions) { if (!_seenMineIds.Contains(interaction.Key) || interaction.Value == null || (Object)(object)interaction.Value.Mine == (Object)null) { _staleMineIds.Add(interaction.Key); } } foreach (int staleMineId in _staleMineIds) { StopFailureWarningBeep(_interactions[staleMineId]); if (_interactions[staleMineId] != null && (Object)(object)_interactions[staleMineId].Zone != (Object)null) { Object.Destroy((Object)(object)_interactions[staleMineId].Zone); } _interactions.Remove(staleMineId); } } private MineInteraction CreateInteraction(Landmine mine) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected O, but got Unknown //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Expected O, but got Unknown //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Expected O, but got Unknown //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Expected O, but got Unknown //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Expected O, but got Unknown GameObject val = new GameObject("TurnOffLandmines_Interaction"); EnsureNativeInteractionObject(val); val.SetActive(false); SphereCollider val2 = val.AddComponent<SphereCollider>(); ((Collider)val2).isTrigger = true; val2.radius = 0.72f; EnsureNativeInteractionObject(val); InteractTrigger val3 = val.AddComponent<InteractTrigger>(); val3.hoverTip = GetTurnOffPrompt(); val3.holdTip = "Turning off..."; val3.disabledHoverTip = string.Empty; val3.animationString = string.Empty; val3.interactable = false; val3.hoverIcon = _vanillaInteractionIcon; val3.oneHandedItemAllowed = true; val3.twoHandedItemAllowed = true; val3.holdInteraction = true; val3.timeToHold = 0.45f; val3.timeToHoldSpeedMultiplier = 1f; val3.interactCooldown = true; val3.cooldownTime = 0.5f; val3.triggerOnce = false; val3.stopAnimationString = "SA_stopAnimation"; val3.animationWaitTime = 2f; val3.lockPlayerPosition = false; val3.disableTriggerMesh = true; val3.holdingInteractEvent = new InteractEventFloat(); val3.onInteract = new InteractEvent(); val3.onInteractEarly = new InteractEvent(); val3.onStopInteract = new InteractEvent(); val3.onCancelAnimation = new InteractEvent(); MineInteraction state = new MineInteraction { Mine = mine, Zone = val, Collider = val2, Trigger = val3 }; ((UnityEvent<PlayerControllerB>)(object)val3.onInteract).AddListener((UnityAction<PlayerControllerB>)delegate(PlayerControllerB player) { TryTurnOff(state, player); }); return state; } private AudioClip CreateFailureWarningBeepClip() { int num = Mathf.CeilToInt(30870f); float[] array = new float[num]; for (int i = 0; i < num; i++) { float num2 = (float)i / 44100f; float num3 = num2 % 0.1f; if (!(num3 >= 0.055f)) { float num4 = Mathf.Clamp01(Mathf.Min(num3 / 0.003f, (0.055f - num3) / 0.003f)); array[i] = Mathf.Sin(MathF.PI * 3100f * num2) * 0.32f * num4; } } AudioClip val = AudioClip.Create("TurnOffLandmines_FailureWarningBeep", num, 1, 44100, false); if ((Object)(object)val == (Object)null) { return null; } val.SetData(array, 0); return val; } private void StartFailureWarningBeep(MineInteraction state) { //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) if (state == null || (Object)(object)state.Mine == (Object)null) { return; } if ((Object)(object)_failureWarningBeepClip == (Object)null) { try { _failureWarningBeepClip = CreateFailureWarningBeepClip(); if ((Object)(object)_failureWarningBeepClip == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not create the landmine failure warning beep; text warning and explosion path will still run."); return; } ((BaseUnityPlugin)this).Logger.LogDebug((object)"Created the landmine failure warning beep lazily after a failed disarm."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not create the landmine failure warning beep; text warning and explosion path will still run: " + ex.Message)); return; } } try { StopFailureWarningBeep(state); GameObject val = new GameObject("TurnOffLandmines_FailureWarningAudio"); val.transform.SetParent(((Component)state.Mine).transform, false); val.transform.localPosition = Vector3.up * 0.35f; AudioSource val2 = val.AddComponent<AudioSource>(); val2.playOnAwake = false; val2.loop = false; val2.clip = _failureWarningBeepClip; val2.volume = 0.85f; val2.pitch = 1f; val2.spatialBlend = 1f; val2.dopplerLevel = 0f; val2.rolloffMode = (AudioRolloffMode)0; val2.minDistance = 1f; val2.maxDistance = 20f; state.WarningAudioObject = val; state.WarningAudioSource = val2; val2.Play(); Object.Destroy((Object)(object)val, _failureWarningBeepClip.length + 0.1f); } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not start the landmine failure warning beep: " + ex2.Message)); } } private void StopFailureWarningBeep(MineInteraction state) { if (state != null) { if ((Object)(object)state.WarningAudioSource != (Object)null) { state.WarningAudioSource.Stop(); } if ((Object)(object)state.WarningAudioObject != (Object)null) { Object.Destroy((Object)(object)state.WarningAudioObject); } state.WarningAudioSource = null; state.WarningAudioObject = null; } } private void TryTurnOff(MineInteraction state, PlayerControllerB player) { if (!_modEnabled.Value || state == null || (Object)(object)state.Mine == (Object)null || state.Processing || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)GetLocalPlayer() || IsMineSpent(state.Mine)) { return; } state.Processing = true; state.Trigger.interactable = false; float num = Mathf.Clamp(_failureChance.Value, 0f, 100f); float num2 = num; if (_failureScalingEnabled.Value) { float num3 = Mathf.Max(0f, _failureIncreasePerSuccess.Value); num2 = Mathf.Clamp(num + num3 * (float)_successfulDisarmsThisRound, 0f, 100f); } ((BaseUnityPlugin)this).Logger.LogDebug((object)("Landmine disarm roll: active failure chance=" + num2.ToString("0.##") + "%, base=" + num.ToString("0.##") + "%, successful modded disarms this moon=" + _successfulDisarmsThisRound + ", scaling=" + _failureScalingEnabled.Value + ".")); if (_failureEnabled.Value && num2 > 0f && Random.Range(0f, 100f) < num2) { state.Trigger.hoverTip = "FAILURE, RUN."; state.Trigger.holdTip = "FAILURE, RUN."; HUDManager instance = HUDManager.Instance; if (instance != null) { instance.DisplayTip("FAILURE, RUN.", string.Empty, true, false, "LC_Tip1"); } StartFailureWarningBeep(state); SendFailureWarningRequest(state.Mine); ((BaseUnityPlugin)this).Logger.LogWarning((object)("Landmine turn-off attempt failed; local warning started, network relay requested, and explosion scheduled in " + 0.7f.ToString("0.0") + " seconds.")); ((MonoBehaviour)this).StartCoroutine(ExplodeAfterDelay(state, 0.7f)); } else { RequestSuccessfulDisarm(state); } } private IEnumerator ExplodeAfterDelay(MineInteraction state, float delay) { yield return (object)new WaitForSecondsRealtime(delay); if (state == null || (Object)(object)state.Mine == (Object)null) { StopFailureWarningBeep(state); yield break; } try { Landmine mine = state.Mine; bool flag = false; if (HasZeroArgumentMethod(mine, "ExplodeMineServerRpc")) { InvokeMineMethod(mine, "SetOffMineAnimation"); SetMember(mine, "sendingExplosionRPC", true); flag = InvokeMineMethod(mine, "ExplodeMineServerRpc"); } if (!flag) { flag = InvokeMineMethod(mine, "ExplodeMine"); } if (!flag) { flag = InvokeMineMethod(mine, "TriggerMineOnLocalClientByExiting"); } if (flag) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Invoked the landmine failure explosion path after " + delay.ToString("0.0") + " seconds. Instance=" + ((Object)mine).GetInstanceID() + ".")); } if (!flag) { bool flag2 = InvokeMineMethod(mine, "SetOffMineAnimation"); ((BaseUnityPlugin)this).Logger.LogError((object)(flag2 ? "Only the mine animation method was available; a server explosion method could not be called. The explosion could not be confirmed." : "Could not find a supported mine explosion method. The failure warning was shown, but the explosion could not be triggered.")); } if ((Object)(object)state.Zone != (Object)null) { state.Zone.SetActive(false); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Failed to trigger landmine explosion after disarm failure: " + ex)); } finally { StopFailureWarningBeep(state); if (state != null && (Object)(object)state.Zone != (Object)null) { state.Zone.SetActive(false); } } } private void DisarmMine(Landmine mine) { if ((Object)(object)mine == (Object)null) { return; } object member = GetMember(mine, "mineAnimator"); Animator val = (Animator)((member is Animator) ? member : null); if ((Object)(object)val != (Object)null) { ((Behaviour)val).enabled = false; } SetMember(mine, "hasExploded", true); bool num = InvokeMineMethod(mine, "ToggleMine", argument: false); SetMember(mine, "mineActivated", false); if (num) { return; } Collider[] componentsInChildren = ((Component)mine).GetComponentsInChildren<Collider>(true); foreach (Collider val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)null) { val2.enabled = false; } } ((BaseUnityPlugin)this).Logger.LogWarning((object)"ToggleMine(false) was unavailable; used the local safety fallback for this landmine."); } private static bool HasZeroArgumentMethod(Landmine mine, string name) { if ((Object)(object)mine == (Object)null) { return false; } return ((object)mine).GetType().GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) != null; } private static bool InvokeMineMethod(Landmine mine, string name) { if ((Object)(object)mine == (Object)null) { return false; } MethodInfo method = ((object)mine).GetType().GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (method == null) { return false; } try { method.Invoke(mine, null); return true; } catch { return false; } } private static bool InvokeMineMethod(Landmine mine, string name, bool argument) { if ((Object)(object)mine == (Object)null) { return false; } MethodInfo method = ((object)mine).GetType().GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(bool) }, null); if (method == null) { return false; } try { method.Invoke(mine, new object[1] { argument }); return true; } catch { return false; } } private static bool IsMineSpent(Landmine mine) { if ((Object)(object)mine == (Object)null) { return true; } object member = GetMember(mine, "hasExploded"); if (member is bool) { return (bool)member; } return false; } private static PlayerControllerB GetLocalPlayer() { GameNetworkManager instance = GameNetworkManager.Instance; PlayerControllerB val = (((Object)(object)instance != (Object)null) ? instance.localPlayerController : null); if (!((Object)(object)val != (Object)null) || !val.isPlayerControlled || val.isPlayerDead || val.isTypingChat || val.inTerminalMenu) { return null; } return val; } private static object GetMember(object instance, string name) { if (instance == null) { return null; } BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; FieldInfo field = instance.GetType().GetField(name, bindingAttr); if (field != null) { return field.GetValue(instance); } PropertyInfo property = instance.GetType().GetProperty(name, bindingAttr); if (!(property != null)) { return null; } return property.GetValue(instance, null); } private static void SetMember(object instance, string name, object value) { if (instance == null) { return; } BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; FieldInfo field = instance.GetType().GetField(name, bindingAttr); if (field != null && (value == null || field.FieldType.IsInstanceOfType(value))) { try { field.SetValue(instance, value); return; } catch { return; } } PropertyInfo property = instance.GetType().GetProperty(name, bindingAttr); if (!(property != null) || !property.CanWrite || (value != null && !property.PropertyType.IsInstanceOfType(value))) { return; } try { property.SetValue(instance, value, null); } catch { } } private string GetTurnOffPrompt() { string text = GetInteractBindingDisplayName(); if (string.IsNullOrWhiteSpace(text)) { text = "E"; } text = text.Trim().Trim('[', ']'); return "Turn off : [" + text + "]"; } private string GetInteractBindingDisplayName() { //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) try { Type type = Type.GetType("IngamePlayerSettings, Assembly-CSharp"); if (type == null) { return "E"; } object staticMember = GetStaticMember(type, "Instance"); if (staticMember == null) { return "E"; } object member = GetMember(GetMember(staticMember, "playerInput"), "actions"); InputActionAsset val = (InputActionAsset)((member is InputActionAsset) ? member : null); if ((Object)(object)val == (Object)null) { return "E"; } InputAction val2 = val.FindAction("Interact", false); if (val2 == null) { val2 = val.FindAction("Movement/Interact", false); } if (val2 == null) { return "E"; } int num = -1; if (val2.activeControl != null) { num = InputActionRebindingExtensions.GetBindingIndexForControl(val2, val2.activeControl); } if (num < 0) { bool flag = Gamepad.current != null && (Keyboard.current == null || ((InputDevice)Gamepad.current).lastUpdateTime > ((InputDevice)Keyboard.current).lastUpdateTime); for (int i = 0; i < val2.bindings.Count; i++) { InputBinding val3 = val2.bindings[i]; object obj = ((InputBinding)(ref val3)).effectivePath; if (obj == null) { val3 = val2.bindings[i]; obj = ((InputBinding)(ref val3)).path ?? string.Empty; } string text = (string)obj; if (flag && text.IndexOf("<Gamepad>/", StringComparison.OrdinalIgnoreCase) >= 0) { num = i; break; } if (!flag && text.IndexOf("<Keyboard>/", StringComparison.OrdinalIgnoreCase) >= 0) { num = i; break; } } } string text2 = ((num >= 0) ? InputActionRebindingExtensions.GetBindingDisplayString(val2, num, (DisplayStringOptions)0) : InputActionRebindingExtensions.GetBindingDisplayString(val2, (DisplayStringOptions)0, (string)null)); return string.IsNullOrWhiteSpace(text2) ? "E" : text2; } catch { return "E"; } } private static object GetStaticMember(Type type, string name) { BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; FieldInfo field = type.GetField(name, bindingAttr); if (field != null) { return field.GetValue(null); } PropertyInfo property = type.GetProperty(name, bindingAttr); if (!(property != null)) { return null; } return property.GetValue(null, null); } private void RefreshVanillaInteractionIconIfNeeded() { if ((Object)(object)_vanillaInteractionIcon != (Object)null || Time.unscaledTime < _nextIconScanTime) { return; } _nextIconScanTime = Time.unscaledTime + 1f; InteractTrigger[] array = Object.FindObjectsOfType<InteractTrigger>(); InteractTrigger[] array2 = array; foreach (InteractTrigger val in array2) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val.hoverIcon == (Object)null) && !(((Object)((Component)val).gameObject).name == "TurnOffLandmines_Interaction")) { string text = val.hoverTip ?? string.Empty; if (text.IndexOf("open", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("door", StringComparison.OrdinalIgnoreCase) >= 0) { ApplyVanillaInteractionStyle(val); break; } } } if (!((Object)(object)_vanillaInteractionIcon == (Object)null)) { return; } array2 = array; foreach (InteractTrigger val2 in array2) { if ((Object)(object)val2 != (Object)null && (Object)(object)val2.hoverIcon != (Object)null && ((Object)((Component)val2).gameObject).name != "TurnOffLandmines_Interaction") { ApplyVanillaInteractionStyle(val2); break; } } } private void ApplyVanillaInteractionStyle(InteractTrigger source) { if ((Object)(object)source == (Object)null || (Object)(object)source.hoverIcon == (Object)null) { return; } _vanillaInteractionIcon = source.hoverIcon; _vanillaInteractionLayer = ((Component)source).gameObject.layer; foreach (MineInteraction value in _interactions.Values) { if (value != null && !((Object)(object)value.Zone == (Object)null) && !((Object)(object)value.Trigger == (Object)null)) { EnsureNativeInteractionObject(value.Zone); value.Trigger.hoverIcon = _vanillaInteractionIcon; } } } private void EnsureNativeInteractionObject(GameObject obj) { if ((Object)(object)obj == (Object)null) { return; } try { if (!string.Equals(obj.tag, "InteractTrigger", StringComparison.Ordinal)) { obj.tag = "InteractTrigger"; } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not assign the InteractTrigger tag to interaction zone: " + ex.Message)); } int num = LayerMask.NameToLayer("InteractableObject"); if (num < 0) { num = LayerMask.NameToLayer("Interactable"); } if (num >= 0) { obj.layer = num; } else if (_vanillaInteractionLayer >= 0) { obj.layer = _vanillaInteractionLayer; } Collider component = obj.GetComponent<Collider>(); if ((Object)(object)component != (Object)null) { component.isTrigger = true; } } private void ClearInteractions() { foreach (MineInteraction value in _interactions.Values) { StopFailureWarningBeep(value); if (value != null && (Object)(object)value.Zone != (Object)null) { Object.Destroy((Object)(object)value.Zone); } } _interactions.Clear(); } private void OnDestroy() { if (_maintenanceCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_maintenanceCoroutine); _maintenanceCoroutine = null; } _cachedMines = null; UnregisterNetworkMessageHandlers(); ClearInteractions(); if ((Object)(object)_failureWarningBeepClip != (Object)null) { Object.Destroy((Object)(object)_failureWarningBeepClip); } _failureWarningBeepClip = null; } } }