Decompiled source of EnemyCompatibilityFixes v1.2.0

EnemyCompatibilityFixes.dll

Decompiled 3 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;

[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("EnemyCompatibilityFixes")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.2.0.0")]
[assembly: AssemblyInformationalVersion("1.2.0")]
[assembly: AssemblyProduct("EnemyCompatibilityFixes")]
[assembly: AssemblyTitle("EnemyCompatibilityFixes")]
[assembly: AssemblyVersion("1.2.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 EnemyCompatibilityFixes
{
	[BepInPlugin("enemycompatibilityfixes.plugin", "Enemy Compatibility Fixes", "1.2.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "enemycompatibilityfixes.plugin";

		public const string PluginName = "Enemy Compatibility Fixes";

		public const string PluginVersion = "1.2.0";

		private Harmony _harmony;

		private ConfigEntry<bool> _fixMinecraftSpider;

		private ConfigEntry<bool> _guardScp999Targeting;

		private ConfigEntry<bool> _fixModelReplacementSlots;

		private ConfigEntry<bool> _fixModDataRegistration;

		private ConfigEntry<bool> _fixLethalCasinoMenu;

		private ConfigEntry<bool> _fixUtilitySlotDestruction;

		private ConfigEntry<bool> _fixOccludedAudio;

		private ConfigEntry<bool> _fixPermanentMoonsDisconnect;

		private ConfigEntry<bool> _enableDaySpeed;

		private ConfigEntry<float> _daySpeedMultiplier;

		private ConfigEntry<bool> _enableDifficultyScrap;

		private ConfigEntry<int> _scrapD;

		private ConfigEntry<int> _scrapC;

		private ConfigEntry<int> _scrapB;

		private ConfigEntry<int> _scrapA;

		private ConfigEntry<int> _scrapS;

		private ConfigEntry<int> _scrapSS;

		private ConfigEntry<int> _scrapUnknown;

		private ConfigEntry<bool> _showMoonPrices;

		private ConfigEntry<bool> _compensateEnemySchedule;

		private ConfigEntry<float> _enemyScheduleMultiplier;

		private ConfigEntry<int> _minimumInsideEnemies;

		private ConfigEntry<int> _minimumOutsideEnemies;

		private ConfigEntry<bool> _showShipScanNode;

		private ConfigEntry<bool> _showMainEntranceScanNode;

		private ConfigEntry<int> _navigationScanRange;

		private ConfigEntry<bool> _compressInteriorWeights;

		private ConfigEntry<int> _interiorWeightExponent;

		private void Awake()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			BindFixSettings();
			BindGameplaySettings();
			_harmony = new Harmony("enemycompatibilityfixes.plugin");
			if (_fixMinecraftSpider.Value)
			{
				PatchMinecraftSpider();
			}
			if (_guardScp999Targeting.Value)
			{
				PatchScp999Targeting();
			}
			if (_fixModelReplacementSlots.Value)
			{
				PatchModelReplacementSlots();
			}
			if (_fixModDataRegistration.Value)
			{
				PatchModDataRegistration();
			}
			if (_fixLethalCasinoMenu.Value)
			{
				PatchLethalCasinoMenu();
			}
			if (_fixUtilitySlotDestruction.Value)
			{
				PatchUtilitySlotDestruction();
			}
			if (_fixOccludedAudio.Value)
			{
				PatchOccludedAudio();
			}
			if (_fixPermanentMoonsDisconnect.Value)
			{
				PatchPermanentMoonsDisconnect();
			}
			PatchGameplaySettings();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Enemy Compatibility Fixes 1.2.0 loaded.");
		}

		private void BindFixSettings()
		{
			_fixMinecraftSpider = ((BaseUnityPlugin)this).Config.Bind<bool>("Fixes", "Fix Minecraft Spider state", true, "Prevents MinecraftSpiderMod from accessing invalid state after level transitions, unusual spawning, or enemy cleanup.");
			_guardScp999Targeting = ((BaseUnityPlugin)this).Config.Bind<bool>("Fixes", "Guard SCP-999 enemy targeting", true, "Stops SCP-999 enemy targeting from flooding the log when another enemy has incomplete targeting data.");
			_fixModelReplacementSlots = ((BaseUnityPlugin)this).Config.Bind<bool>("Fixes", "Fix ModelReplacement item slots", true, "Prevents ModelReplacementAPI from reading outside the inventory array when a tool or reserved slot is selected.");
			_fixModDataRegistration = ((BaseUnityPlugin)this).Config.Bind<bool>("Fixes", "Fix LethalModDataLib registration", true, "Skips unloaded plugin instances while LethalModDataLib scans mod data attributes.");
			_fixLethalCasinoMenu = ((BaseUnityPlugin)this).Config.Bind<bool>("Fixes", "Fix LethalCasino menu check", true, "Skips an obsolete LC_API warning check that calls a menu method removed from the current game.");
			_fixUtilitySlotDestruction = ((BaseUnityPlugin)this).Config.Bind<bool>("Fixes", "Fix utility slot item destruction", true, "Uses the correct HUD icon when an item in the game's utility-only slot is destroyed.");
			_fixOccludedAudio = ((BaseUnityPlugin)this).Config.Bind<bool>("Fixes", "Guard broken occluded audio", true, "Stops invalid OccludeAudio components from flooding the log every frame on broken custom scenes.");
			_fixPermanentMoonsDisconnect = ((BaseUnityPlugin)this).Config.Bind<bool>("Fixes", "Fix Permanent Moons disconnect", true, "Prevents Permanent Moons from accessing the messaging manager after networking has already shut down.");
		}

		private void BindGameplaySettings()
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Expected O, but got Unknown
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Expected O, but got Unknown
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Expected O, but got Unknown
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Expected O, but got Unknown
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Expected O, but got Unknown
			_enableDaySpeed = ((BaseUnityPlugin)this).Config.Bind<bool>("Time", "Enable day speed multiplier", true, "Enables the global day speed setting below. This stacks with each moon's DaySpeedMultiplier.");
			_daySpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Time", "Day speed multiplier", 1f, new ConfigDescription("How quickly time passes. 0 pauses the day, 0.5 makes it twice as long, 1 is normal, and 2 makes it twice as fast.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			_enableDifficultyScrap = ((BaseUnityPlugin)this).Config.Bind<bool>("Scrap by moon difficulty", "Enable scrap count multipliers", true, "Changes the number of spawned scrap items according to the moon's displayed risk level. The host controls the result.");
			_scrapD = BindPercent("D or easier percent", 150, "Scrap count on D, safe, and similarly easy moons.");
			_scrapC = BindPercent("C percent", 135, "Scrap count on C and C+ moons.");
			_scrapB = BindPercent("B percent", 120, "Scrap count on B and B+ moons.");
			_scrapA = BindPercent("A percent", 110, "Scrap count on A and A+ moons.");
			_scrapS = BindPercent("S percent", 100, "Scrap count on S and S+ moons.");
			_scrapSS = BindPercent("SS or harder percent", 100, "Scrap count on SS, SSS, and harder moons.");
			_scrapUnknown = BindPercent("Unknown difficulty percent", 100, "Scrap count when a custom moon uses an unrecognized risk label.");
			_showMoonPrices = ((BaseUnityPlugin)this).Config.Bind<bool>("Terminal", "Show current moon prices", true, "Adds each moon's current route price after its weather in the moons catalogue.");
			_compensateEnemySchedule = ((BaseUnityPlugin)this).Config.Bind<bool>("Enemy spawning", "Compensate for slower days", true, "Moves scheduled indoor enemy spawns earlier when the day speed multiplier is below 1. The host controls spawning.");
			_enemyScheduleMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Enemy spawning", "Enemy schedule multiplier", 0f, new ConfigDescription("0 automatically follows the day speed multiplier. Values below 1 make scheduled enemies appear earlier; 1 leaves timing unchanged.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
			_minimumInsideEnemies = ((BaseUnityPlugin)this).Config.Bind<int>("Enemy spawning", "Minimum inside enemies per batch", 1, new ConfigDescription("Minimum number considered for each indoor spawn batch. 0 keeps the game's normal minimum.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 20), Array.Empty<object>()));
			_minimumOutsideEnemies = ((BaseUnityPlugin)this).Config.Bind<int>("Enemy spawning", "Minimum outside enemies per batch", 1, new ConfigDescription("Minimum number considered for each outside spawn batch. 0 keeps the game's normal minimum.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 20), Array.Empty<object>()));
			_showShipScanNode = ((BaseUnityPlugin)this).Config.Bind<bool>("Outside scanner", "Always show ship", true, "Shows the ship as a navigation marker whenever the scanner is used outside.");
			_showMainEntranceScanNode = ((BaseUnityPlugin)this).Config.Bind<bool>("Outside scanner", "Always show main entrance", true, "Shows the main entrance as a navigation marker whenever the scanner is used outside.");
			_navigationScanRange = ((BaseUnityPlugin)this).Config.Bind<int>("Outside scanner", "Navigation marker range", 10000, new ConfigDescription("Maximum range of the ship and main entrance scan markers.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(50, 50000), Array.Empty<object>()));
			_compressInteriorWeights = ((BaseUnityPlugin)this).Config.Bind<bool>("Interior variety", "Compress interior weight differences", true, "Reduces extreme rarity differences among interiors that are actually valid for the selected moon.");
			_interiorWeightExponent = ((BaseUnityPlugin)this).Config.Bind<int>("Interior variety", "Weight exponent percent", 50, new ConfigDescription("100 keeps original weights, 50 uses their square root, and 0 makes all valid interiors equally likely.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
		}

		private ConfigEntry<int> BindPercent(string key, int defaultValue, string description)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			return ((BaseUnityPlugin)this).Config.Bind<int>("Scrap by moon difficulty", key, defaultValue, new ConfigDescription(description + " 100 means unchanged.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 500), Array.Empty<object>()));
		}

		private void PatchMinecraftSpider()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Expected O, but got Unknown
			Type type = FindType("MinecraftSpiderMod.Patches.SandSpiderAIPatch");
			if (type == null)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"MinecraftSpiderMod was not found; its compatibility fix was skipped.");
				return;
			}
			SpiderStateGuard.Initialize(type, ((BaseUnityPlugin)this).Logger);
			HarmonyMethod val = new HarmonyMethod(typeof(SpiderStateGuard), "EnsureStatePrefix", (Type[])null);
			val.priority = 800;
			val.before = new string[1] { "SkunkWerx.MinecraftSpiderMod" };
			HarmonyMethod val2 = val;
			string[] array = new string[2] { "Update", "MoveLegsProcedurally" };
			foreach (string text in array)
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(SandSpiderAI), text, (Type[])null, (Type[])null);
				if (methodInfo != null)
				{
					_harmony.Patch((MethodBase)methodInfo, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			MethodInfo methodInfo2 = AccessTools.Method(typeof(SandSpiderAI), "KillEnemy", (Type[])null, (Type[])null);
			if (methodInfo2 != null)
			{
				HarmonyMethod val3 = new HarmonyMethod(typeof(SpiderStateGuard), "KillEnemyFinalizer", (Type[])null);
				_harmony.Patch((MethodBase)methodInfo2, val2, (HarmonyMethod)null, (HarmonyMethod)null, val3, (HarmonyMethod)null);
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"MinecraftSpiderMod state guard enabled.");
		}

		private void PatchScp999Targeting()
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			Type type = FindType("SnowyLib.EnemyAIExtensions");
			if (type == null)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"SnowyLib was not found; the SCP-999 targeting guard was skipped.");
				return;
			}
			MethodInfo methodInfo = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo method) => method.Name == "TargetClosestEnemy" && method.ReturnType == typeof(bool));
			if (methodInfo == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"SnowyLib.TargetClosestEnemy was not found; the SCP-999 targeting guard could not be applied.");
				return;
			}
			Scp999TargetingGuard.SetLogger(((BaseUnityPlugin)this).Logger);
			_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(Scp999TargetingGuard), "Finalizer", (Type[])null), (HarmonyMethod)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"SCP-999 targeting exception guard enabled.");
		}

		private void PatchModelReplacementSlots()
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			Type type = FindType("ModelReplacement.BodyReplacementBase");
			MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "UpdateItemTransform", (Type[])null, (Type[])null));
			if (methodInfo == null)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"ModelReplacementAPI was not found; its item-slot guard was skipped.");
				return;
			}
			ModelReplacementSlotGuard.Initialize(type, ((BaseUnityPlugin)this).Logger);
			_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ModelReplacementSlotGuard), "Prefix", (Type[])null)
			{
				priority = 800
			}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"ModelReplacementAPI item-slot guard enabled.");
		}

		private void PatchModDataRegistration()
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			Type type = FindType("LethalModDataLib.Features.ModDataAttributeCollector");
			MethodInfo methodInfo = type?.GetMethod("RegisterModDataAttributes", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			MethodInfo methodInfo2 = type?.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo method) => method.Name == "RegisterModDataAttributes" && method.GetParameters().Length == 4);
			if (methodInfo == null || methodInfo2 == null)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"LethalModDataLib was not found; its registration guard was skipped.");
				return;
			}
			ModDataRegistrationGuard.Initialize(methodInfo2, ((BaseUnityPlugin)this).Logger);
			_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ModDataRegistrationGuard), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"LethalModDataLib registration guard enabled.");
		}

		private void PatchLethalCasinoMenu()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			Type type = FindType("LethalCasino.Patches.MenuManagerPatch");
			MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "StartPatch", (Type[])null, (Type[])null));
			if (methodInfo == null)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"LethalCasino was not found; its obsolete menu check guard was skipped.");
				return;
			}
			_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(LethalCasinoMenuGuard), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"LethalCasino obsolete menu check disabled.");
		}

		private void PatchUtilitySlotDestruction()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(PlayerControllerB), "DestroyItemInSlot", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"PlayerControllerB.DestroyItemInSlot was not found; its utility-slot fix was skipped.");
				return;
			}
			UtilitySlotDestructionPatch.SetLogger(((BaseUnityPlugin)this).Logger);
			_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(UtilitySlotDestructionPatch), "Transpiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Utility-only slot destruction fix enabled.");
		}

		private void PatchGameplaySettings()
		{
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Expected O, but got Unknown
			//IL_0127: Expected O, but got Unknown
			//IL_0127: Expected O, but got Unknown
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Expected O, but got Unknown
			//IL_019c: Expected O, but got Unknown
			//IL_019c: Expected O, but got Unknown
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Expected O, but got Unknown
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Expected O, but got Unknown
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Expected O, but got Unknown
			//IL_0297: Expected O, but got Unknown
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Expected O, but got Unknown
			TimeSpeedPatch.Initialize(_enableDaySpeed, _daySpeedMultiplier);
			ScrapAmountPatch.Initialize(_enableDifficultyScrap, _scrapD, _scrapC, _scrapB, _scrapA, _scrapS, _scrapSS, _scrapUnknown, ((BaseUnityPlugin)this).Logger);
			EnemySpawnTimingPatch.Initialize(_compensateEnemySchedule, _enemyScheduleMultiplier, _enableDaySpeed, _daySpeedMultiplier, _minimumInsideEnemies, _minimumOutsideEnemies, ((BaseUnityPlugin)this).Logger);
			TerminalMoonPricePatch.Initialize(_showMoonPrices, ((BaseUnityPlugin)this).Logger);
			NavigationScanPatch.Initialize(_showShipScanNode, _showMainEntranceScanNode, _navigationScanRange);
			InteriorWeightPatch.Initialize(_compressInteriorWeights, _interiorWeightExponent, ((BaseUnityPlugin)this).Logger);
			MethodInfo methodInfo = AccessTools.Method(typeof(TimeOfDay), "MoveGlobalTime", (Type[])null, (Type[])null);
			if (methodInfo != null)
			{
				_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(TimeSpeedPatch), "Prefix", (Type[])null), new HarmonyMethod(typeof(TimeSpeedPatch), "Restore", (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(TimeSpeedPatch), "Finalizer", (Type[])null), (HarmonyMethod)null);
			}
			MethodInfo methodInfo2 = AccessTools.Method(typeof(RoundManager), "SpawnScrapInLevel", (Type[])null, (Type[])null);
			if (methodInfo2 != null)
			{
				_harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(ScrapAmountPatch), "Prefix", (Type[])null)
				{
					priority = 0
				}, new HarmonyMethod(typeof(ScrapAmountPatch), "Restore", (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(ScrapAmountPatch), "Finalizer", (Type[])null), (HarmonyMethod)null);
			}
			MethodInfo methodInfo3 = AccessTools.Method(typeof(RoundManager), "PlotOutEnemiesForNextHour", (Type[])null, (Type[])null);
			if (methodInfo3 != null)
			{
				_harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(typeof(EnemySpawnTimingPatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo methodInfo4 = AccessTools.Method(typeof(RoundManager), "BeginEnemySpawning", (Type[])null, (Type[])null);
			if (methodInfo4 != null)
			{
				_harmony.Patch((MethodBase)methodInfo4, new HarmonyMethod(typeof(EnemySpawnTimingPatch), "BeginPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo methodInfo5 = AccessTools.Method(typeof(Terminal), "TextPostProcess", (Type[])null, (Type[])null);
			if (methodInfo5 != null)
			{
				_harmony.Patch((MethodBase)methodInfo5, new HarmonyMethod(typeof(TerminalMoonPricePatch), "Prefix", (Type[])null)
				{
					priority = 800
				}, new HarmonyMethod(typeof(TerminalMoonPricePatch), "Postfix", (Type[])null)
				{
					priority = 0
				}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo methodInfo6 = AccessTools.Method(typeof(HUDManager), "AssignNewNodes", (Type[])null, (Type[])null);
			if (methodInfo6 != null)
			{
				_harmony.Patch((MethodBase)methodInfo6, (HarmonyMethod)null, new HarmonyMethod(typeof(NavigationScanPatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			PatchInteriorWeights();
		}

		private void PatchOccludedAudio()
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(OccludeAudio), "Update", (Type[])null, (Type[])null);
			if (!(methodInfo == null))
			{
				OccludedAudioGuard.SetLogger(((BaseUnityPlugin)this).Logger);
				_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(OccludedAudioGuard), "Finalizer", (Type[])null), (HarmonyMethod)null);
				((BaseUnityPlugin)this).Logger.LogInfo((object)"OccludeAudio exception guard enabled.");
			}
		}

		private void PatchPermanentMoonsDisconnect()
		{
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Expected O, but got Unknown
			Type type = FindType("Plugin");
			MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "UnregisterMessages", (Type[])null, (Type[])null));
			if (methodInfo == null || type.Assembly.GetName().Name != "PermanentMoons")
			{
				methodInfo = (from assembly in AppDomain.CurrentDomain.GetAssemblies()
					where assembly.GetName().Name == "PermanentMoons"
					select assembly.GetType("Plugin", throwOnError: false) into type2
					where type2 != null
					select AccessTools.Method(type2, "UnregisterMessages", (Type[])null, (Type[])null)).FirstOrDefault((MethodInfo method) => method != null);
			}
			if (methodInfo == null)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Permanent Moons was not found; its disconnect guard was skipped.");
				return;
			}
			_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(PermanentMoonsDisconnectGuard), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Permanent Moons disconnect guard enabled.");
		}

		private void PatchInteriorWeights()
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			Type type = FindType("LethalLevelLoader.DungeonManager");
			MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "GetValidExtendedDungeonFlows", (Type[])null, (Type[])null));
			if (methodInfo == null)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"LethalLevelLoader was not found; interior weight compression was skipped.");
				return;
			}
			InteriorWeightPatch.InitializeResultType(methodInfo.ReturnType);
			_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(InteriorWeightPatch), "Postfix", (Type[])null)
			{
				priority = 0
			}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Interior weight compression support enabled.");
		}

		private static Type FindType(string fullName)
		{
			return (from assembly in AppDomain.CurrentDomain.GetAssemblies()
				select assembly.GetType(fullName, throwOnError: false)).FirstOrDefault((Type type) => type != null);
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal static class SpiderStateGuard
	{
		private static FieldInfo _timerDictionaryField;

		private static ManualLogSource _logger;

		private static int _repairNoticeWritten;

		private static int _killNoticeWritten;

		internal static void Initialize(Type spiderPatchType, ManualLogSource logger)
		{
			_timerDictionaryField = AccessTools.Field(spiderPatchType, "_timeSinceMovingLegs");
			_logger = logger;
		}

		public static void EnsureStatePrefix(SandSpiderAI __instance)
		{
			if ((Object)(object)__instance == (Object)null || _timerDictionaryField == null)
			{
				return;
			}
			try
			{
				IDictionary dictionary = _timerDictionaryField.GetValue(null) as IDictionary;
				if (dictionary == null)
				{
					dictionary = Activator.CreateInstance(_timerDictionaryField.FieldType) as IDictionary;
					_timerDictionaryField.SetValue(null, dictionary);
				}
				if (dictionary == null || dictionary.Contains(__instance))
				{
					return;
				}
				dictionary.Add(__instance, Random.Range(0.1f, 0.9f));
				if (Interlocked.Exchange(ref _repairNoticeWritten, 1) == 0)
				{
					ManualLogSource logger = _logger;
					if (logger != null)
					{
						logger.LogInfo((object)"Repaired missing MinecraftSpiderMod leg state.");
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger2 = _logger;
				if (logger2 != null)
				{
					logger2.LogWarning((object)("Could not initialize MinecraftSpiderMod state: " + ex.Message));
				}
			}
		}

		public static Exception KillEnemyFinalizer(Exception __exception)
		{
			if (__exception is NullReferenceException)
			{
				if (Interlocked.Exchange(ref _killNoticeWritten, 1) == 0)
				{
					ManualLogSource logger = _logger;
					if (logger != null)
					{
						logger.LogWarning((object)"Ignored invalid MinecraftSpiderMod cleanup data while a spider was being removed.");
					}
				}
				return null;
			}
			return __exception;
		}
	}
	internal static class Scp999TargetingGuard
	{
		private static ManualLogSource _logger;

		private static int _noticeWritten;

		internal static void SetLogger(ManualLogSource logger)
		{
			_logger = logger;
		}

		public static Exception Finalizer(Exception __exception, ref bool __result)
		{
			if (__exception is NullReferenceException)
			{
				__result = false;
				if (Interlocked.Exchange(ref _noticeWritten, 1) == 0)
				{
					ManualLogSource logger = _logger;
					if (logger != null)
					{
						logger.LogWarning((object)"Ignored invalid enemy data while SCP-999 was selecting a target.");
					}
				}
				return null;
			}
			return __exception;
		}
	}
	internal static class ModelReplacementSlotGuard
	{
		private static FieldInfo _heldItemField;

		private static MethodInfo _controllerGetter;

		private static ManualLogSource _logger;

		private static int _noticeWritten;

		internal static void Initialize(Type bodyType, ManualLogSource logger)
		{
			_heldItemField = AccessTools.Field(bodyType, "heldItem");
			_controllerGetter = AccessTools.PropertyGetter(bodyType, "controller");
			_logger = logger;
		}

		public static bool Prefix(object __instance)
		{
			if (__instance == null || _heldItemField == null || _controllerGetter == null)
			{
				return true;
			}
			try
			{
				object? value = _heldItemField.GetValue(__instance);
				GrabbableObject val = (GrabbableObject)((value is GrabbableObject) ? value : null);
				if ((Object)(object)val == (Object)null || val is BeltBagItem)
				{
					return true;
				}
				object? obj = _controllerGetter.Invoke(__instance, null);
				object? obj2 = ((obj is PlayerControllerB) ? obj : null);
				int num = ((PlayerControllerB)(obj2?)).currentItemSlot ?? (-1);
				int valueOrDefault = (((PlayerControllerB)(obj2?)).ItemSlots?.Length).GetValueOrDefault();
				if (num >= 0 && num < valueOrDefault)
				{
					return true;
				}
				_heldItemField.SetValue(__instance, null);
				if (Interlocked.Exchange(ref _noticeWritten, 1) == 0)
				{
					ManualLogSource logger = _logger;
					if (logger != null)
					{
						logger.LogWarning((object)$"Prevented ModelReplacementAPI item-slot overflow (slot {num}, inventory size {valueOrDefault}).");
					}
				}
				return false;
			}
			catch (Exception ex)
			{
				if (Interlocked.Exchange(ref _noticeWritten, 1) == 0)
				{
					ManualLogSource logger2 = _logger;
					if (logger2 != null)
					{
						logger2.LogWarning((object)("Could not validate a ModelReplacementAPI item slot: " + ex.Message));
					}
				}
				return true;
			}
		}
	}
	internal static class ModDataRegistrationGuard
	{
		private static MethodInfo _registerOne;

		private static ManualLogSource _logger;

		internal static void Initialize(MethodInfo registerOne, ManualLogSource logger)
		{
			_registerOne = registerOne;
			_logger = logger;
		}

		public static bool Prefix()
		{
			if (_registerOne == null)
			{
				return true;
			}
			int num = 0;
			foreach (PluginInfo value in Chainloader.PluginInfos.Values)
			{
				BaseUnityPlugin val = ((value != null) ? value.Instance : null);
				if ((Object)(object)val == (Object)null)
				{
					num++;
					continue;
				}
				IEnumerable<Type> loadableTypes;
				try
				{
					loadableTypes = GetLoadableTypes(((object)val).GetType().Assembly);
				}
				catch (Exception ex)
				{
					ManualLogSource logger = _logger;
					if (logger != null)
					{
						BepInPlugin metadata = value.Metadata;
						logger.LogWarning((object)("Could not inspect " + (((metadata != null) ? metadata.GUID : null) ?? "an unknown plugin") + " for mod data: " + ex.Message));
					}
					continue;
				}
				foreach (Type item in loadableTypes)
				{
					try
					{
						_registerOne.Invoke(null, new object[4]
						{
							value.Metadata.GUID,
							item,
							null,
							null
						});
					}
					catch (TargetInvocationException ex2)
					{
						ManualLogSource logger2 = _logger;
						if (logger2 != null)
						{
							logger2.LogWarning((object)("Could not register mod data from " + item.FullName + ": " + (ex2.InnerException ?? ex2).Message));
						}
					}
					catch (Exception ex3)
					{
						ManualLogSource logger3 = _logger;
						if (logger3 != null)
						{
							logger3.LogWarning((object)("Could not register mod data from " + item.FullName + ": " + ex3.Message));
						}
					}
				}
			}
			if (num > 0)
			{
				ManualLogSource logger4 = _logger;
				if (logger4 != null)
				{
					logger4.LogInfo((object)$"Skipped {num} unloaded plugin instance(s) during LethalModDataLib registration.");
				}
			}
			return false;
		}

		private static IEnumerable<Type> GetLoadableTypes(Assembly assembly)
		{
			try
			{
				return assembly.GetTypes();
			}
			catch (ReflectionTypeLoadException ex)
			{
				return ex.Types.Where((Type type) => type != null);
			}
		}
	}
	internal static class LethalCasinoMenuGuard
	{
		public static bool Prefix()
		{
			return false;
		}
	}
	internal static class UtilitySlotDestructionPatch
	{
		private static ManualLogSource _logger;

		internal static void SetLogger(ManualLogSource logger)
		{
			_logger = logger;
		}

		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Expected O, but got Unknown
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Expected O, but got Unknown
			List<CodeInstruction> list = instructions.ToList();
			MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(HUDManager), "Instance");
			FieldInfo fieldInfo = AccessTools.Field(typeof(HUDManager), "itemSlotIcons");
			MethodInfo methodInfo2 = AccessTools.PropertySetter(typeof(Behaviour), "enabled");
			MethodInfo methodInfo3 = AccessTools.Method(typeof(UtilitySlotDestructionPatch), "DisableCorrectSlotIcon", (Type[])null, (Type[])null);
			for (int i = 0; i <= list.Count - 6; i++)
			{
				if (CodeInstructionExtensions.Calls(list[i], methodInfo) && CodeInstructionExtensions.LoadsField(list[i + 1], fieldInfo, false) && !(list[i + 2].opcode != OpCodes.Ldarg_1) && !(list[i + 3].opcode != OpCodes.Ldelem_Ref) && !(list[i + 4].opcode != OpCodes.Ldc_I4_0) && CodeInstructionExtensions.Calls(list[i + 5], methodInfo2))
				{
					CodeInstruction item = new CodeInstruction(OpCodes.Call, (object)methodInfo3);
					list.RemoveRange(i, 6);
					list.Insert(i, new CodeInstruction(OpCodes.Ldarg_1, (object)null));
					list.Insert(i + 1, item);
					ManualLogSource logger = _logger;
					if (logger != null)
					{
						logger.LogInfo((object)"Patched DestroyItemInSlot for the utility-only HUD slot.");
					}
					return list;
				}
			}
			ManualLogSource logger2 = _logger;
			if (logger2 != null)
			{
				logger2.LogWarning((object)"Could not locate the utility-slot HUD sequence in DestroyItemInSlot; original code was left unchanged.");
			}
			return list;
		}

		public static void DisableCorrectSlotIcon(int itemSlot)
		{
			HUDManager instance = HUDManager.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			if (itemSlot == 50)
			{
				if ((Object)(object)instance.itemOnlySlotIcon != (Object)null)
				{
					((Behaviour)instance.itemOnlySlotIcon).enabled = false;
				}
			}
			else if (instance.itemSlotIcons != null && itemSlot >= 0 && itemSlot < instance.itemSlotIcons.Length && (Object)(object)instance.itemSlotIcons[itemSlot] != (Object)null)
			{
				((Behaviour)instance.itemSlotIcons[itemSlot]).enabled = false;
			}
		}
	}
	internal static class TimeSpeedPatch
	{
		private static ConfigEntry<bool> _enabled;

		private static ConfigEntry<float> _multiplier;

		internal static void Initialize(ConfigEntry<bool> enabled, ConfigEntry<float> multiplier)
		{
			_enabled = enabled;
			_multiplier = multiplier;
		}

		public static void Prefix(TimeOfDay __instance, out float __state)
		{
			__state = __instance.globalTimeSpeedMultiplier;
			if (_enabled.Value)
			{
				__instance.globalTimeSpeedMultiplier = __state * _multiplier.Value;
			}
		}

		public static void Restore(TimeOfDay __instance, float __state)
		{
			__instance.globalTimeSpeedMultiplier = __state;
		}

		public static Exception Finalizer(TimeOfDay __instance, float __state, Exception __exception)
		{
			__instance.globalTimeSpeedMultiplier = __state;
			return __exception;
		}
	}
	internal static class ScrapAmountPatch
	{
		private static ConfigEntry<bool> _enabled;

		private static ConfigEntry<int> _d;

		private static ConfigEntry<int> _c;

		private static ConfigEntry<int> _b;

		private static ConfigEntry<int> _a;

		private static ConfigEntry<int> _s;

		private static ConfigEntry<int> _ss;

		private static ConfigEntry<int> _unknown;

		private static ManualLogSource _logger;

		internal static void Initialize(ConfigEntry<bool> enabled, ConfigEntry<int> d, ConfigEntry<int> c, ConfigEntry<int> b, ConfigEntry<int> a, ConfigEntry<int> s, ConfigEntry<int> ss, ConfigEntry<int> unknown, ManualLogSource logger)
		{
			_enabled = enabled;
			_d = d;
			_c = c;
			_b = b;
			_a = a;
			_s = s;
			_ss = ss;
			_unknown = unknown;
			_logger = logger;
		}

		public static void Prefix(RoundManager __instance, out float __state)
		{
			__state = __instance.scrapAmountMultiplier;
			if (_enabled.Value && !((Object)(object)__instance.currentLevel == (Object)null))
			{
				string text = (__instance.currentLevel.riskLevel ?? string.Empty).Trim().ToUpperInvariant();
				int percent = GetPercent(text);
				__instance.scrapAmountMultiplier = __state * (float)percent / 100f;
				ManualLogSource logger = _logger;
				if (logger != null)
				{
					logger.LogInfo((object)$"Scrap count multiplier for {__instance.currentLevel.PlanetName} (risk {text}): {percent}%.");
				}
			}
		}

		public static void Restore(RoundManager __instance, float __state)
		{
			__instance.scrapAmountMultiplier = __state;
		}

		public static Exception Finalizer(RoundManager __instance, float __state, Exception __exception)
		{
			__instance.scrapAmountMultiplier = __state;
			return __exception;
		}

		private static int GetPercent(string risk)
		{
			if (risk.StartsWith("SS", StringComparison.Ordinal))
			{
				return _ss.Value;
			}
			if (risk.StartsWith("S", StringComparison.Ordinal))
			{
				return _s.Value;
			}
			if (risk.StartsWith("A", StringComparison.Ordinal))
			{
				return _a.Value;
			}
			if (risk.StartsWith("B", StringComparison.Ordinal))
			{
				return _b.Value;
			}
			if (risk.StartsWith("C", StringComparison.Ordinal))
			{
				return _c.Value;
			}
			if (risk.StartsWith("D", StringComparison.Ordinal) || risk.Contains("SAFE") || risk.Contains("EASY"))
			{
				return _d.Value;
			}
			return _unknown.Value;
		}
	}
	internal static class OccludedAudioGuard
	{
		private static ManualLogSource _logger;

		private static int _noticeWritten;

		internal static void SetLogger(ManualLogSource logger)
		{
			_logger = logger;
		}

		public static Exception Finalizer(OccludeAudio __instance, Exception __exception)
		{
			if (!(__exception is NullReferenceException))
			{
				return __exception;
			}
			if ((Object)(object)__instance != (Object)null)
			{
				((Behaviour)__instance).enabled = false;
			}
			if (Interlocked.Exchange(ref _noticeWritten, 1) == 0)
			{
				ManualLogSource logger = _logger;
				if (logger != null)
				{
					logger.LogWarning((object)"Disabled a broken OccludeAudio component that was throwing every frame.");
				}
			}
			return null;
		}
	}
	internal static class PermanentMoonsDisconnectGuard
	{
		public static bool Prefix()
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton != (Object)null)
			{
				return singleton.CustomMessagingManager != null;
			}
			return false;
		}
	}
	internal static class EnemySpawnTimingPatch
	{
		private static ConfigEntry<bool> _enabled;

		private static ConfigEntry<float> _scheduleMultiplier;

		private static ConfigEntry<bool> _daySpeedEnabled;

		private static ConfigEntry<float> _daySpeedMultiplier;

		private static ConfigEntry<int> _minimumInside;

		private static ConfigEntry<int> _minimumOutside;

		private static ManualLogSource _logger;

		private static int _lastLoggedDay = int.MinValue;

		internal static void Initialize(ConfigEntry<bool> enabled, ConfigEntry<float> scheduleMultiplier, ConfigEntry<bool> daySpeedEnabled, ConfigEntry<float> daySpeedMultiplier, ConfigEntry<int> minimumInside, ConfigEntry<int> minimumOutside, ManualLogSource logger)
		{
			_enabled = enabled;
			_scheduleMultiplier = scheduleMultiplier;
			_daySpeedEnabled = daySpeedEnabled;
			_daySpeedMultiplier = daySpeedMultiplier;
			_minimumInside = minimumInside;
			_minimumOutside = minimumOutside;
			_logger = logger;
		}

		public static void BeginPrefix(RoundManager __instance)
		{
			if (_enabled.Value && !((Object)(object)__instance == (Object)null))
			{
				__instance.minEnemiesToSpawn = Math.Max(__instance.minEnemiesToSpawn, _minimumInside.Value);
				__instance.minOutsideEnemiesToSpawn = Math.Max(__instance.minOutsideEnemiesToSpawn, _minimumOutside.Value);
			}
		}

		public static void Postfix(RoundManager __instance)
		{
			if (!_enabled.Value || (Object)(object)__instance == (Object)null || !((NetworkBehaviour)__instance).IsServer || (Object)(object)__instance.timeScript == (Object)null)
			{
				return;
			}
			float num = _scheduleMultiplier.Value;
			if (num <= 0f)
			{
				num = (_daySpeedEnabled.Value ? _daySpeedMultiplier.Value : 1f);
			}
			num = Mathf.Clamp(num, 0.05f, 5f);
			if (num >= 0.999f)
			{
				return;
			}
			float currentDayTime = __instance.timeScript.currentDayTime;
			for (int i = 0; i < __instance.enemySpawnTimes.Count; i++)
			{
				int num2 = __instance.enemySpawnTimes[i];
				int value = Mathf.CeilToInt(currentDayTime + Math.Max(1f, (float)num2 - currentDayTime) * num);
				__instance.enemySpawnTimes[i] = value;
			}
			__instance.enemySpawnTimes.Sort();
			if (__instance.allEnemyVents != null)
			{
				EnemyVent[] allEnemyVents = __instance.allEnemyVents;
				foreach (EnemyVent val in allEnemyVents)
				{
					if (!((Object)(object)val == (Object)null) && val.occupied && !(val.spawnTime <= currentDayTime))
					{
						val.spawnTime = currentDayTime + Math.Max(1f, val.spawnTime - currentDayTime) * num;
					}
				}
			}
			int num3 = StartOfRound.Instance?.gameStats?.daysSpent ?? (-1);
			if (_lastLoggedDay != num3)
			{
				_lastLoggedDay = num3;
				ManualLogSource logger = _logger;
				if (logger != null)
				{
					logger.LogInfo((object)$"Enemy schedule compensation active at {num:0.##}x with minimum batches inside/outside {_minimumInside.Value}/{_minimumOutside.Value}.");
				}
			}
		}
	}
	internal static class TerminalMoonPricePatch
	{
		private const string MarkerPrefix = "[ecfMoonPrice:";

		private static ConfigEntry<bool> _enabled;

		private static ManualLogSource _logger;

		private static readonly Regex MarkerRegex = new Regex("\\[ecfMoonPrice:(\\d+)\\]", RegexOptions.Compiled);

		internal static void Initialize(ConfigEntry<bool> enabled, ManualLogSource logger)
		{
			_enabled = enabled;
			_logger = logger;
		}

		public static void Prefix(ref string modifiedDisplayText)
		{
			if (_enabled.Value && !string.IsNullOrEmpty(modifiedDisplayText) && modifiedDisplayText.Contains("[planetTime]"))
			{
				int index = 0;
				modifiedDisplayText = Regex.Replace(modifiedDisplayText, Regex.Escape("[planetTime]"), (Match _) => "[planetTime][ecfMoonPrice:" + index++ + "]");
			}
		}

		public static void Postfix(Terminal __instance, ref string __result)
		{
			if (!_enabled.Value || string.IsNullOrEmpty(__result) || !__result.Contains("[ecfMoonPrice:"))
			{
				return;
			}
			try
			{
				__result = MarkerRegex.Replace(__result, delegate(Match match)
				{
					if (!int.TryParse(match.Groups[1].Value, out var result) || __instance?.moonsCatalogueList == null || result < 0 || result >= __instance.moonsCatalogueList.Length)
					{
						return string.Empty;
					}
					int currentRoutePrice = GetCurrentRoutePrice(__instance.moonsCatalogueList[result]);
					return $" // Price: ${Math.Max(0, currentRoutePrice)}";
				});
			}
			catch (Exception ex)
			{
				ManualLogSource logger = _logger;
				if (logger != null)
				{
					logger.LogWarning((object)("Could not add moon prices to the terminal: " + ex.Message));
				}
				__result = MarkerRegex.Replace(__result, string.Empty);
			}
		}

		private static int GetCurrentRoutePrice(SelectableLevel level)
		{
			if ((Object)(object)level == (Object)null)
			{
				return 0;
			}
			try
			{
				Type type = (from assembly in AppDomain.CurrentDomain.GetAssemblies()
					select assembly.GetType("LethalLevelLoader.PatchedContent", throwOnError: false)).FirstOrDefault((Type type3) => type3 != null);
				if (((type == null) ? null : AccessTools.Property(type, "ExtendedLevels"))?.GetValue(null, null) is IEnumerable enumerable)
				{
					foreach (object item in enumerable)
					{
						Type type2 = item.GetType();
						object? obj = AccessTools.Property(type2, "SelectableLevel")?.GetValue(item, null);
						if (!((Object)((obj is SelectableLevel) ? obj : null) != (Object)(object)level))
						{
							object obj2 = AccessTools.Property(type2, "RoutePrice")?.GetValue(item, null) ?? AccessTools.Field(type2, "routePrice")?.GetValue(item);
							if (obj2 is int)
							{
								return (int)obj2;
							}
						}
					}
				}
			}
			catch
			{
			}
			Terminal val = Object.FindObjectOfType<Terminal>();
			if (val?.terminalNodes?.allKeywords != null)
			{
				TerminalKeyword[] allKeywords = val.terminalNodes.allKeywords;
				foreach (TerminalKeyword val2 in allKeywords)
				{
					if (val2?.compatibleNouns == null)
					{
						continue;
					}
					CompatibleNoun[] compatibleNouns = val2.compatibleNouns;
					for (int num2 = 0; num2 < compatibleNouns.Length; num2++)
					{
						TerminalNode val3 = compatibleNouns[num2]?.result;
						if ((Object)(object)val3 != (Object)null && val3.displayPlanetInfo == level.levelID && val3.itemCost >= 0)
						{
							return val3.itemCost;
						}
					}
				}
			}
			return 0;
		}
	}
	internal static class NavigationScanPatch
	{
		private static ConfigEntry<bool> _shipEnabled;

		private static ConfigEntry<bool> _entranceEnabled;

		private static ConfigEntry<int> _range;

		private static ScanNodeProperties _shipNode;

		private static ScanNodeProperties _entranceNode;

		private static MethodInfo _attemptScanNode;

		internal static void Initialize(ConfigEntry<bool> shipEnabled, ConfigEntry<bool> entranceEnabled, ConfigEntry<int> range)
		{
			_shipEnabled = shipEnabled;
			_entranceEnabled = entranceEnabled;
			_range = range;
			_attemptScanNode = AccessTools.Method(typeof(HUDManager), "AttemptScanNode", (Type[])null, (Type[])null);
		}

		public static void Postfix(HUDManager __instance, PlayerControllerB playerScript)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)playerScript == (Object)null || playerScript.isInsideFactory || (Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.inShipPhase)
			{
				return;
			}
			if (_shipEnabled.Value)
			{
				Transform anchor = (((Object)(object)StartOfRound.Instance.shipBounds != (Object)null) ? ((Component)StartOfRound.Instance.shipBounds).transform : StartOfRound.Instance.elevatorTransform);
				_shipNode = GetOrCreateNode(_shipNode, anchor, "ECF Ship Scan Node", "SHIP", "Navigation");
				if ((Object)(object)_shipNode != (Object)null)
				{
					_attemptScanNode?.Invoke(__instance, new object[3] { _shipNode, -1, playerScript });
				}
			}
			if (_entranceEnabled.Value)
			{
				EntranceTeleport val = ((IEnumerable<EntranceTeleport>)Object.FindObjectsOfType<EntranceTeleport>()).FirstOrDefault((Func<EntranceTeleport, bool>)((EntranceTeleport item) => (Object)(object)item != (Object)null && item.entranceId == 0 && item.isEntranceToBuilding));
				Transform anchor2 = (((Object)(object)val?.entrancePoint != (Object)null) ? val.entrancePoint : ((val != null) ? ((Component)val).transform : null));
				_entranceNode = GetOrCreateNode(_entranceNode, anchor2, "ECF Main Entrance Scan Node", "MAIN ENTRANCE", "Navigation");
				if ((Object)(object)_entranceNode != (Object)null)
				{
					_attemptScanNode?.Invoke(__instance, new object[3] { _entranceNode, -1, playerScript });
				}
			}
		}

		private static ScanNodeProperties GetOrCreateNode(ScanNodeProperties existing, Transform anchor, string objectName, string header, string subText)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)anchor == (Object)null)
			{
				return null;
			}
			if ((Object)(object)existing == (Object)null)
			{
				GameObject val = new GameObject(objectName);
				val.transform.SetParent(anchor, false);
				existing = val.AddComponent<ScanNodeProperties>();
			}
			else if ((Object)(object)((Component)existing).transform.parent != (Object)(object)anchor)
			{
				((Component)existing).transform.SetParent(anchor, false);
			}
			((Component)existing).transform.localPosition = Vector3.zero;
			existing.maxRange = _range.Value;
			existing.minRange = -1;
			existing.requiresLineOfSight = false;
			existing.headerText = header;
			existing.subText = subText;
			existing.nodeType = 1;
			return existing;
		}
	}
	internal static class InteriorWeightPatch
	{
		private static ConfigEntry<bool> _enabled;

		private static ConfigEntry<int> _exponentPercent;

		private static FieldInfo _rarityField;

		private static ManualLogSource _logger;

		private static int _noticeWritten;

		internal static void Initialize(ConfigEntry<bool> enabled, ConfigEntry<int> exponentPercent, ManualLogSource logger)
		{
			_enabled = enabled;
			_exponentPercent = exponentPercent;
			_logger = logger;
		}

		internal static void InitializeResultType(Type resultType)
		{
			Type type = (resultType.IsGenericType ? resultType.GetGenericArguments().FirstOrDefault() : null);
			_rarityField = ((type == null) ? null : AccessTools.Field(type, "rarity"));
		}

		public static void Postfix(object __result)
		{
			if (!_enabled.Value || _rarityField == null || !(__result is IEnumerable enumerable))
			{
				return;
			}
			float num = (float)_exponentPercent.Value / 100f;
			int num2 = 0;
			foreach (object item in enumerable)
			{
				if (item == null)
				{
					continue;
				}
				int num3 = (int)_rarityField.GetValue(item);
				if (num3 > 0)
				{
					int num4 = ((num <= 0f) ? 1 : Math.Max(1, Mathf.RoundToInt(Mathf.Pow((float)num3, num))));
					if (num4 != num3)
					{
						_rarityField.SetValue(item, num4);
						num2++;
					}
				}
			}
			if (num2 > 0 && Interlocked.Exchange(ref _noticeWritten, 1) == 0)
			{
				ManualLogSource logger = _logger;
				if (logger != null)
				{
					logger.LogInfo((object)$"Compressed {num2} valid interior selection weights using exponent {_exponentPercent.Value}%.");
				}
			}
		}
	}
}