Decompiled source of LCFairCompany v2.1.0

LCFairCompany.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LCFairCompany.Configs;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: AssemblyCompany("LCFairCompany")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Mod to tweak some monsters in Lethal Company to make them more balanced, now fully configurable and synced with the Host!")]
[assembly: AssemblyFileVersion("2.1.0.0")]
[assembly: AssemblyInformationalVersion("2.1.0+a6432e10395b947dccd01f14c65e0154edf3f185")]
[assembly: AssemblyProduct("LCFairCompany")]
[assembly: AssemblyTitle("LCFairCompany")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.1.0.0")]
[module: UnverifiableCode]
namespace LCFairCompany
{
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	internal struct EntitiesName
	{
		public const string SnareFlea = "Centipede";

		public const string BunkerSpider = "Bunker Spider";

		public const string HoardingBug = "Hoarding Bug";

		public const string Bracken = "Flowerman";

		public const string Thumper = "Crawler";

		public const string Hydrogene = "Blob";

		public const string GhostGirl = "Girl";

		public const string SporeLizard = "Puffer";

		public const string Nutcracker = "Nutcracker";

		public const string Coilhead = "Spring";

		public const string Jester = "Jester";

		public const string Masked = "Masked";

		public const string EyelessDog = "MouthDog";

		public const string ForestKeeper = "ForestGiant";

		public const string EarthLeviathan = "Earth Leviathan";

		public const string BaboonHawk = "Baboon hawk";

		public const string CircuitBees = "Red Locust Bees";

		public const string Manticoil = "Manticoil";

		public const string RoamingLocusts = "Docile Locust Bees";

		public const string LassoMan = "Lasso";
	}
	internal static class EnemyHelpers
	{
		public static bool IsMatchingName(this EnemyType enemyType, string enemyName)
		{
			return enemyType.enemyName.Equals(enemyName, StringComparison.OrdinalIgnoreCase);
		}

		public static void SetEnemyPowerLevel(this EnemyType enemyType, float powerLevel)
		{
			if (Mathf.Approximately(enemyType.PowerLevel, powerLevel))
			{
				ManualLogSource logger = Plugin.Logger;
				if (logger != null)
				{
					logger.LogDebug((object)$"\"{enemyType.enemyName}\" PowerLevel is already {powerLevel}, nothing to change");
				}
				return;
			}
			ManualLogSource logger2 = Plugin.Logger;
			if (logger2 != null)
			{
				logger2.LogInfo((object)$"Changing \"{enemyType.enemyName}\" PowerLevel ({enemyType.PowerLevel} => {powerLevel})");
			}
			enemyType.PowerLevel = powerLevel;
		}

		public static void SetEnemyMaxCount(this EnemyType enemyType, int maxCount)
		{
			if (enemyType.MaxCount == maxCount)
			{
				ManualLogSource logger = Plugin.Logger;
				if (logger != null)
				{
					logger.LogDebug((object)$"\"{enemyType.enemyName}\" MaxCount is already {maxCount}, nothing to change");
				}
				return;
			}
			ManualLogSource logger2 = Plugin.Logger;
			if (logger2 != null)
			{
				logger2.LogInfo((object)$"Changing \"{enemyType.enemyName}\" MaxCount ({enemyType.MaxCount} => {maxCount})");
			}
			enemyType.MaxCount = maxCount;
		}

		public static void SetEnemyHP(this EnemyAI enemyAI, int enemyHP)
		{
			if (enemyAI.enemyHP == enemyHP)
			{
				ManualLogSource logger = Plugin.Logger;
				if (logger != null)
				{
					logger.LogDebug((object)$"\"{enemyAI.enemyType.enemyName}\" EnemyHP is already {enemyHP}, nothing to change");
				}
				return;
			}
			ManualLogSource logger2 = Plugin.Logger;
			if (logger2 != null)
			{
				logger2.LogInfo((object)$"Changing \"{enemyAI.enemyType.enemyName}\" EnemyHP ({enemyAI.enemyHP} => {enemyHP})");
			}
			enemyAI.enemyHP = enemyHP;
		}
	}
	internal static class AudioHelpers
	{
		public static int PlayRandomOneShot(this AudioSource audioSource, AudioClip[] clipsArray, float volume = 1f, float? minDistance = null, float? maxDistance = null, bool bTransmitToWalkieTalkie = true, int timesPlayedInSameSpot = 0)
		{
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)audioSource == (Object)null || clipsArray == null || clipsArray.Length == 0)
			{
				return -1;
			}
			float pitch = audioSource.pitch;
			float minDistance2 = audioSource.minDistance;
			float maxDistance2 = audioSource.maxDistance;
			audioSource.pitch = Random.Range(0.94f, 1.06f);
			if (minDistance.HasValue)
			{
				audioSource.minDistance = minDistance.Value;
			}
			if (maxDistance.HasValue)
			{
				audioSource.maxDistance = maxDistance.Value;
			}
			int num = Random.Range(0, clipsArray.Length);
			audioSource.PlayOneShot(clipsArray[num], volume);
			if (bTransmitToWalkieTalkie)
			{
				WalkieTalkie.TransmitOneShotAudio(audioSource, clipsArray[num], 0.85f * volume);
			}
			if (audioSource.spatialBlend > 0f)
			{
				RoundManager.Instance.PlayAudibleNoise(((Component)audioSource).transform.position, 4f * volume, volume / 2f, timesPlayedInSameSpot, false, 0);
			}
			audioSource.pitch = pitch;
			audioSource.minDistance = minDistance2;
			audioSource.maxDistance = maxDistance2;
			return num;
		}
	}
	[BepInPlugin("LCFairCompany", "LCFairCompany", "2.1.0")]
	internal class Plugin : BaseUnityPlugin
	{
		private readonly Harmony _harmony = null;

		private readonly ConfigManager _configManager = null;

		internal static ManualLogSource Logger { get; private set; }

		protected Plugin()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			_harmony = new Harmony("LCFairCompany");
			_configManager = new ConfigManager(((BaseUnityPlugin)this).Config);
		}

		protected void Awake()
		{
			ManualLogSource logger = Logger;
			if (logger != null)
			{
				logger.LogInfo((object)"Plugin LCFairCompany is loaded!");
			}
			ManualLogSource logger2 = Logger;
			if (logger2 != null)
			{
				logger2.LogDebug((object)"Patching harmony...");
			}
			_harmony.PatchAll(Assembly.GetExecutingAssembly());
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "LCFairCompany";

		public const string PLUGIN_NAME = "LCFairCompany";

		public const string PLUGIN_VERSION = "2.1.0";
	}
}
namespace LCFairCompany.Patches
{
	[HarmonyPatch(typeof(CentipedeAI))]
	internal class CentipedeAIPatch : MonoBehaviour
	{
		private CentipedeAI _centipedeAI = null;

		private int _damageSinceClingingToPlayer = 0;

		private int _timesPlayedInSameSpot = 0;

		private float? _delayUntilNextAudioCue = null;

		private bool LimitDamagePerClinging => SyncedInstance<ConfigManager>.Instance.Centipede.LimitDamagePerClinging.Value;

		private int MaxDamagePerClinging => SyncedInstance<ConfigManager>.Instance.Centipede.MaxDamagePerClinging.Value;

		private bool PlayAudioShriekOnCeiling => SyncedInstance<ConfigManager>.Default.Centipede.PlayAudioShriekOnCeiling.Value;

		private int AudioShriekMinFrequency => SyncedInstance<ConfigManager>.Default.Centipede.AudioShriekMinFrequency.Value;

		private int AudioShriekMaxFrequency => SyncedInstance<ConfigManager>.Default.Centipede.AudioShriekMaxFrequency.Value;

		protected void Start()
		{
			ManualLogSource logger = Plugin.Logger;
			if (logger != null)
			{
				logger.LogDebug((object)"\"Centipede\" applies \"CentipedeAIPatch\"");
			}
			_centipedeAI = ((Component)this).gameObject.GetComponent<CentipedeAI>();
		}

		protected void LateUpdate()
		{
			if (PlayAudioShriekOnCeiling)
			{
				UpdateDelayUntilNextAudioCue(Time.deltaTime);
			}
			else
			{
				_delayUntilNextAudioCue = null;
			}
		}

		public void OnPlayerDamaged(int damage)
		{
			if (_centipedeAI.inDroppingOffPlayerAnim)
			{
				return;
			}
			ManualLogSource logger = Plugin.Logger;
			if (logger != null)
			{
				logger.LogDebug((object)string.Format("Updating \"{0}\" DamageSinceClingingToPlayer ({1} => {2})", "Centipede", _damageSinceClingingToPlayer, _damageSinceClingingToPlayer + damage));
			}
			_damageSinceClingingToPlayer += damage;
			bool flag = false;
			if (StartOfRound.Instance.connectedPlayersAmount > 0 && StartOfRound.Instance.livingPlayers == 1 && _centipedeAI.clingingToPlayer.health <= 15 && !StartOfRoundPatch.LastSurvivorSecondChanceGiven)
			{
				ManualLogSource logger2 = Plugin.Logger;
				if (logger2 != null)
				{
					logger2.LogInfo((object)"\"Centipede\" is attempting to kill the last survivor");
				}
				StartOfRoundPatch.LastSurvivorSecondChanceGiven = true;
				flag = true;
			}
			else if (LimitDamagePerClinging && _damageSinceClingingToPlayer >= MaxDamagePerClinging)
			{
				ManualLogSource logger3 = Plugin.Logger;
				if (logger3 != null)
				{
					logger3.LogInfo((object)string.Format("\"{0}\" reached MaxDamagePerClinging ({1}/{2})", "Centipede", _damageSinceClingingToPlayer, MaxDamagePerClinging));
				}
				flag = true;
			}
			if (flag)
			{
				_centipedeAI.inDroppingOffPlayerAnim = true;
				_centipedeAI.StopClingingServerRpc(false);
			}
		}

		public void OnStopClingingToPlayer()
		{
			ManualLogSource logger = Plugin.Logger;
			if (logger != null)
			{
				logger.LogDebug((object)string.Format("Resetting \"{0}\" DamageSinceClingingToPlayer ({1} => 0)", "Centipede", _damageSinceClingingToPlayer));
			}
			_damageSinceClingingToPlayer = 0;
		}

		private void PlayRandomShriekSFX()
		{
			if (!((Object)(object)_centipedeAI == (Object)null))
			{
				ManualLogSource logger = Plugin.Logger;
				if (logger != null)
				{
					logger.LogDebug((object)string.Format("Playing \"{0}\" RandomShriekSFX ({1}={2})", "Centipede", "_timesPlayedInSameSpot", _timesPlayedInSameSpot));
				}
				((EnemyAI)_centipedeAI).creatureSFX.PlayRandomOneShot(_centipedeAI.shriekClips, 0.1f, 10f, 35f, bTransmitToWalkieTalkie: false, _timesPlayedInSameSpot);
			}
		}

		private void UpdateDelayUntilNextAudioCue(float deltaTime)
		{
			if ((Object)(object)_centipedeAI == (Object)null || !((NetworkBehaviour)_centipedeAI).IsClient || !_centipedeAI.clingingToCeiling || _centipedeAI.ceilingAnimationCoroutine != null)
			{
				_delayUntilNextAudioCue = null;
				_timesPlayedInSameSpot = 0;
				return;
			}
			if (!_delayUntilNextAudioCue.HasValue)
			{
				float num = 60f / (float)Mathf.Max(AudioShriekMaxFrequency, 1);
				float num2 = 60f / (float)Mathf.Max(AudioShriekMinFrequency, 1);
				if (num <= num2)
				{
					_delayUntilNextAudioCue = Random.Range(num, num2);
				}
				else
				{
					_delayUntilNextAudioCue = Random.Range(num2, num);
				}
			}
			_delayUntilNextAudioCue -= deltaTime;
			if (_delayUntilNextAudioCue <= 0f)
			{
				PlayRandomShriekSFX();
				_delayUntilNextAudioCue = null;
				_timesPlayedInSameSpot++;
			}
		}

		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void StartPostfix(CentipedeAI __instance)
		{
			((Component)__instance).gameObject.AddComponent<CentipedeAIPatch>();
		}

		[HarmonyPatch("DamagePlayerOnIntervals")]
		[HarmonyPrefix]
		private static void DamagePlayerOnIntervalsPrefix(CentipedeAI __instance, out int __state)
		{
			__state = __instance.clingingToPlayer?.health ?? 0;
		}

		[HarmonyPatch("DamagePlayerOnIntervals")]
		[HarmonyPostfix]
		private static void DamagePlayerOnIntervalsPostfix(CentipedeAI __instance, int __state)
		{
			int valueOrDefault = (__state - __instance.clingingToPlayer?.health).GetValueOrDefault();
			CentipedeAIPatch centipedeAIPatch = default(CentipedeAIPatch);
			if (valueOrDefault > 0 && ((Component)__instance).gameObject.TryGetComponent<CentipedeAIPatch>(ref centipedeAIPatch))
			{
				centipedeAIPatch.OnPlayerDamaged(valueOrDefault);
			}
		}

		[HarmonyPatch("ClingToPlayer")]
		[HarmonyPostfix]
		private static void ClingToPlayerPostfix(CentipedeAI __instance, PlayerControllerB playerScript)
		{
			PlayerControllerBPatch playerControllerBPatch = default(PlayerControllerBPatch);
			if (((Component)playerScript).TryGetComponent<PlayerControllerBPatch>(ref playerControllerBPatch))
			{
				playerControllerBPatch.OnClingToPlayer(__instance);
			}
		}

		[HarmonyPatch("StopClingingToPlayer")]
		[HarmonyPrefix]
		private static void StopClingingToPlayerPrefix(CentipedeAI __instance)
		{
			PlayerControllerBPatch playerControllerBPatch = default(PlayerControllerBPatch);
			if (((Component)__instance.clingingToPlayer).TryGetComponent<PlayerControllerBPatch>(ref playerControllerBPatch))
			{
				playerControllerBPatch.OnStopClingingToPlayer();
			}
		}

		[HarmonyPatch("StopClingingToPlayer")]
		[HarmonyPostfix]
		private static void StopClingingToPlayerPostfix(CentipedeAI __instance)
		{
			CentipedeAIPatch centipedeAIPatch = default(CentipedeAIPatch);
			if (((Component)__instance).gameObject.TryGetComponent<CentipedeAIPatch>(ref centipedeAIPatch))
			{
				centipedeAIPatch.OnStopClingingToPlayer();
			}
		}
	}
	[HarmonyPatch(typeof(EnemyAI))]
	internal static class EnemyAIPatch
	{
		[HarmonyPatch("PlayerIsTargetable")]
		[HarmonyPostfix]
		private static void PlayerIsTargetablePostfix(ref bool __result, EnemyAI __instance, PlayerControllerB playerScript)
		{
			PlayerControllerBPatch playerControllerBPatch = default(PlayerControllerBPatch);
			if (__result && __instance is CentipedeAI && ((Component)playerScript).TryGetComponent<PlayerControllerBPatch>(ref playerControllerBPatch) && playerControllerBPatch.IsClingingToPlayer())
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch(typeof(GameNetworkManager))]
	internal class GameNetworkManagerPatch
	{
		[HarmonyPatch("SteamMatchmaking_OnLobbyMemberJoined")]
		[HarmonyPostfix]
		private static void SteamMatchmaking_OnLobbyMemberJoinedPostfix()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			if (SyncedInstance<ConfigManager>.IsHost)
			{
				SyncedInstance<ConfigManager>.MessageManager.RegisterNamedMessageHandler("LCFairCompany_OnRequestConfigSync", new HandleNamedMessageDelegate(ConfigManager.OnRequestSync));
				SyncedInstance<ConfigManager>.Synced = true;
			}
			else
			{
				SyncedInstance<ConfigManager>.Synced = false;
				SyncedInstance<ConfigManager>.MessageManager.RegisterNamedMessageHandler("LCFairCompany_OnReceiveConfigSync", new HandleNamedMessageDelegate(ConfigManager.OnReceiveSync));
				ConfigManager.RequestSync();
			}
		}

		[HarmonyPatch("StartDisconnect")]
		[HarmonyPostfix]
		public static void StartDisconnectPostfix()
		{
			SyncedInstance<ConfigManager>.RevertSync();
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB))]
	internal class PlayerControllerBPatch : MonoBehaviour
	{
		private PlayerControllerB _playerController = null;

		private CentipedeAI _clingingToPlayer = null;

		protected void Start()
		{
			_playerController = ((Component)this).gameObject.GetComponent<PlayerControllerB>();
			ManualLogSource logger = Plugin.Logger;
			if (logger != null)
			{
				logger.LogDebug((object)("\"" + _playerController.playerUsername + "\" applies \"PlayerControllerBPatch\""));
			}
		}

		public void OnClingToPlayer(CentipedeAI centipedeAI)
		{
			ManualLogSource logger = Plugin.Logger;
			if (logger != null)
			{
				logger.LogDebug((object)("\"Centipede\" has latched on player \"" + _playerController?.playerUsername + "\""));
			}
			_clingingToPlayer = centipedeAI;
		}

		public void OnStopClingingToPlayer()
		{
			ManualLogSource logger = Plugin.Logger;
			if (logger != null)
			{
				logger.LogDebug((object)("\"Centipede\" has dropped from player \"" + _playerController?.playerUsername + "\""));
			}
			_clingingToPlayer = null;
		}

		public bool IsClingingToPlayer()
		{
			return (Object)(object)_clingingToPlayer != (Object)null && !((EnemyAI)_clingingToPlayer).isEnemyDead;
		}

		[HarmonyPatch("Awake")]
		[HarmonyPostfix]
		private static void PlayerControllerBAwakePostfix(PlayerControllerB __instance)
		{
			((Component)__instance).gameObject.AddComponent<PlayerControllerBPatch>();
		}
	}
	[HarmonyPatch(typeof(SandSpiderAI))]
	internal static class SandSpiderAIPatch
	{
		private static int Health => SyncedInstance<ConfigManager>.Instance.Spider.Health.Value;

		private static int Damage => SyncedInstance<ConfigManager>.Instance.Spider.Damage.Value;

		private static int ScaleDPS => SyncedInstance<ConfigManager>.Instance.Spider.ScaleDPS.Value;

		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void StartPostfix(SandSpiderAI __instance)
		{
			((EnemyAI)(object)__instance).SetEnemyHP(Health);
		}

		[HarmonyPatch("OnCollideWithPlayer")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> OnCollideWithPlayerTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			bool flag = false;
			float num = (float)Damage / 1f;
			float num2 = num * (float)ScaleDPS / 100f;
			float num3 = (float)Damage / num2;
			FieldInfo fieldInfo = AccessTools.Field(typeof(SandSpiderAI), "timeSinceHittingPlayer");
			bool flag2 = false;
			ManualLogSource logger = Plugin.Logger;
			if (logger != null)
			{
				logger.LogDebug((object)string.Format("Enumerating code instructions in \"{0}\" until we find the hardcoded damage ({1}) and cooldown ({2})...", "OnCollideWithPlayer", 90, 1f));
			}
			for (int i = 0; i < list.Count; i++)
			{
				if (CodeInstructionExtensions.LoadsConstant(list[i], 90L))
				{
					ManualLogSource logger2 = Plugin.Logger;
					if (logger2 != null)
					{
						logger2.LogInfo((object)string.Format("Changing \"{0}\" Damage ({1} => {2})", "Bunker Spider", 90, Damage));
					}
					list[i].operand = Damage;
					flag = true;
				}
				if (CodeInstructionExtensions.LoadsField(list[i], fieldInfo, false) && i + 1 < list.Count && CodeInstructionExtensions.LoadsConstant(list[i + 1], 1.0))
				{
					ManualLogSource logger3 = Plugin.Logger;
					if (logger3 != null)
					{
						logger3.LogInfo((object)string.Format("Changing \"{0}\" HitCooldown ({1} => {2})", "Bunker Spider", 1f, num3));
					}
					list[i + 1].operand = num3;
					flag2 = true;
				}
				if (flag && flag2)
				{
					break;
				}
			}
			if (!flag)
			{
				ManualLogSource logger4 = Plugin.Logger;
				if (logger4 != null)
				{
					logger4.LogError((object)string.Format("[{0}] Cannot find hardcoded damage ({1})", "OnCollideWithPlayer", 90));
				}
			}
			if (!flag2)
			{
				ManualLogSource logger5 = Plugin.Logger;
				if (logger5 != null)
				{
					logger5.LogError((object)string.Format("[{0}] Cannot find \"{1}\" or hardcoded cooldown ({2})", "OnCollideWithPlayer", fieldInfo.Name, 1f));
				}
			}
			return list;
		}
	}
	[HarmonyPatch(typeof(StartOfRound))]
	internal static class StartOfRoundPatch
	{
		public static bool LastSurvivorSecondChanceGiven;

		private static bool BunkerSpiderChangeMaxCount => SyncedInstance<ConfigManager>.Instance.Enemy.BunkerSpiderChangeMaxCount.Value;

		private static bool CoilheadChangePowerLevel => SyncedInstance<ConfigManager>.Instance.Enemy.CoilheadChangePowerLevel.Value;

		private static bool CoilheadChangeMaxCount => SyncedInstance<ConfigManager>.Instance.Enemy.CoilheadChangeMaxCount.Value;

		private static bool GhostGirlChangePowerLevel => SyncedInstance<ConfigManager>.Instance.Enemy.GhostGirlChangePowerLevel.Value;

		private static bool JesterChangePowerLevel => SyncedInstance<ConfigManager>.Instance.Enemy.JesterChangePowerLevel.Value;

		[HarmonyPatch("StartGame")]
		[HarmonyPostfix]
		private static void StartGamePostfix()
		{
			LastSurvivorSecondChanceGiven = false;
			if (StartOfRound.Instance == null || !((NetworkBehaviour)StartOfRound.Instance).IsServer)
			{
				return;
			}
			if (StartOfRound.Instance.currentLevel == null)
			{
				ManualLogSource logger = Plugin.Logger;
				if (logger != null)
				{
					logger.LogError((object)"currentLevel is null!");
				}
				return;
			}
			ManualLogSource logger2 = Plugin.Logger;
			if (logger2 != null)
			{
				logger2.LogDebug((object)"Enumerating all spawnable enemies...");
			}
			foreach (SpawnableEnemyWithRarity enemy in StartOfRound.Instance.currentLevel.Enemies)
			{
				if (enemy == null || enemy.enemyType == null)
				{
					continue;
				}
				EnemyType enemyType = enemy.enemyType;
				ManualLogSource logger3 = Plugin.Logger;
				if (logger3 != null)
				{
					logger3.LogDebug((object)("Found spawnable enemy: \"" + enemyType.enemyName + "\""));
				}
				if (enemyType.IsMatchingName("Bunker Spider"))
				{
					if (BunkerSpiderChangeMaxCount)
					{
						enemyType.SetEnemyMaxCount(2);
					}
				}
				else if (enemyType.IsMatchingName("Spring"))
				{
					if (CoilheadChangePowerLevel)
					{
						enemyType.SetEnemyPowerLevel(1.5f);
					}
					if (CoilheadChangeMaxCount)
					{
						enemyType.SetEnemyMaxCount(4);
					}
				}
				else if (enemyType.IsMatchingName("Girl"))
				{
					if (GhostGirlChangePowerLevel)
					{
						enemyType.SetEnemyPowerLevel(3f);
					}
				}
				else if (enemyType.IsMatchingName("Jester") && JesterChangePowerLevel)
				{
					enemyType.SetEnemyPowerLevel(2f);
				}
			}
		}
	}
}
namespace LCFairCompany.Configs
{
	internal class CentipedeConfig
	{
		public ConfigEntry<bool> LimitDamagePerClinging { get; private set; } = null;


		public ConfigEntry<int> MaxDamagePerClinging { get; private set; } = null;


		public ConfigEntry<bool> PlayAudioShriekOnCeiling { get; private set; } = null;


		public ConfigEntry<int> AudioShriekMinFrequency { get; private set; } = null;


		public ConfigEntry<int> AudioShriekMaxFrequency { get; private set; } = null;


		public CentipedeConfig(ConfigFile config)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Expected O, but got Unknown
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: 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
			if (config == null)
			{
				throw new ArgumentNullException("config");
			}
			LimitDamagePerClinging = config.Bind<bool>("Snare Flea Settings", "Limit Damage Per Clinging", true, new ConfigDescription("Limit how much damage Snare Fleas can inflict per clinging to any player (i.e. prevents getting oneshot if a player doesn't find a shovel or the exit in time).", (AcceptableValueBase)null, Array.Empty<object>()));
			MaxDamagePerClinging = config.Bind<int>("Snare Flea Settings", "Max Damage Per Clinging", 60, new ConfigDescription("If limit is applied, Snare Fleas stop clinging from any player after inflicting that much damage.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(50, 100), Array.Empty<object>()));
			PlayAudioShriekOnCeiling = config.Bind<bool>("Snare Flea Settings (client only)", "Play Audio Shriek On Ceiling", true, new ConfigDescription("Add a quiet audio shriek (triggering 3 to 4 times per minute by default) when a Snare Flea is on a ceiling.", (AcceptableValueBase)null, Array.Empty<object>()));
			AudioShriekMinFrequency = config.Bind<int>("Snare Flea Settings (client only)", "Audio Shriek Min Frequency", 3, new ConfigDescription("Snare Fleas will play the audio shriek at least these many times per minute.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 5), Array.Empty<object>()));
			AudioShriekMaxFrequency = config.Bind<int>("Snare Flea Settings (client only)", "Audio Shriek Max Frequency", 4, new ConfigDescription("Snare Fleas will play the audio shriek at most these many times per minute.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 5), Array.Empty<object>()));
		}

		~CentipedeConfig()
		{
			if (LimitDamagePerClinging != null)
			{
				((ConfigEntryBase)LimitDamagePerClinging).ConfigFile.Remove(((ConfigEntryBase)LimitDamagePerClinging).Definition);
				LimitDamagePerClinging = null;
			}
			if (MaxDamagePerClinging != null)
			{
				((ConfigEntryBase)MaxDamagePerClinging).ConfigFile.Remove(((ConfigEntryBase)MaxDamagePerClinging).Definition);
				MaxDamagePerClinging = null;
			}
			if (PlayAudioShriekOnCeiling != null)
			{
				((ConfigEntryBase)PlayAudioShriekOnCeiling).ConfigFile.Remove(((ConfigEntryBase)PlayAudioShriekOnCeiling).Definition);
				PlayAudioShriekOnCeiling = null;
			}
			if (AudioShriekMinFrequency != null)
			{
				((ConfigEntryBase)AudioShriekMinFrequency).ConfigFile.Remove(((ConfigEntryBase)AudioShriekMinFrequency).Definition);
				AudioShriekMinFrequency = null;
			}
			if (AudioShriekMaxFrequency != null)
			{
				((ConfigEntryBase)AudioShriekMaxFrequency).ConfigFile.Remove(((ConfigEntryBase)AudioShriekMaxFrequency).Definition);
				AudioShriekMaxFrequency = null;
			}
		}
	}
	[Serializable]
	internal class ConfigManager : SyncedInstance<ConfigManager>
	{
		private ConfigFile _config = null;

		public EnemyConfig Enemy { get; private set; } = null;


		public SandSpiderConfig Spider { get; private set; } = null;


		public CentipedeConfig Centipede { get; private set; } = null;


		public ConfigFile Config
		{
			get
			{
				return _config;
			}
			set
			{
				if (_config != null || value == null)
				{
					Enemy = null;
					Spider = null;
					Centipede = null;
				}
				_config = value;
				if (_config != null)
				{
					ManualLogSource logger = Plugin.Logger;
					if (logger != null)
					{
						logger.LogDebug((object)"Binding config...");
					}
					_config.SaveOnConfigSet = false;
					Enemy = new EnemyConfig(_config);
					Spider = new SandSpiderConfig(_config);
					Centipede = new CentipedeConfig(_config);
					ClearOrphanedEntries(_config);
					_config.Save();
					_config.SaveOnConfigSet = true;
				}
			}
		}

		public ConfigManager(ConfigFile config)
		{
			InitInstance(this);
			Config = config;
		}

		public static void RequestSync()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (!SyncedInstance<ConfigManager>.IsClient)
			{
				return;
			}
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(SyncedInstance<ConfigManager>.IntSize, (Allocator)2, -1);
			try
			{
				SyncedInstance<ConfigManager>.MessageManager.SendNamedMessage("LCFairCompany_OnRequestConfigSync", 0uL, val, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(FastBufferWriter)(ref val)).Dispose();
			}
		}

		public static void OnRequestSync(ulong clientId, FastBufferReader _)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			if (!SyncedInstance<ConfigManager>.IsHost)
			{
				return;
			}
			ManualLogSource logger = Plugin.Logger;
			if (logger != null)
			{
				logger.LogInfo((object)$"Config sync request received from client: {clientId}");
			}
			byte[] array = SyncedInstance<ConfigManager>.SerializeToBytes(SyncedInstance<ConfigManager>.Instance);
			int num = array.Length;
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(num + SyncedInstance<ConfigManager>.IntSize, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
				((FastBufferWriter)(ref val)).WriteBytesSafe(array, -1, 0);
				SyncedInstance<ConfigManager>.MessageManager.SendNamedMessage("LCFairCompany_OnReceiveConfigSync", clientId, val, (NetworkDelivery)3);
			}
			catch (Exception arg)
			{
				ManualLogSource logger2 = Plugin.Logger;
				if (logger2 != null)
				{
					logger2.LogError((object)$"Error occurred syncing config with client: {clientId}\n{arg}");
				}
			}
			finally
			{
				((IDisposable)(FastBufferWriter)(ref val)).Dispose();
			}
		}

		public static void OnReceiveSync(ulong _, FastBufferReader reader)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if (!((FastBufferReader)(ref reader)).TryBeginRead(SyncedInstance<ConfigManager>.IntSize))
			{
				ManualLogSource logger = Plugin.Logger;
				if (logger != null)
				{
					logger.LogError((object)"Config sync error: Could not begin reading buffer.");
				}
				return;
			}
			int num = default(int);
			((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
			if (!((FastBufferReader)(ref reader)).TryBeginRead(num))
			{
				ManualLogSource logger2 = Plugin.Logger;
				if (logger2 != null)
				{
					logger2.LogError((object)"Config sync error: Host could not sync.");
				}
				return;
			}
			byte[] data = new byte[num];
			((FastBufferReader)(ref reader)).ReadBytesSafe(ref data, num, 0);
			SyncedInstance<ConfigManager>.SyncInstance(data);
			ManualLogSource logger3 = Plugin.Logger;
			if (logger3 != null)
			{
				logger3.LogInfo((object)"Successfully synced config with host.");
			}
		}

		private static void ClearOrphanedEntries(ConfigFile config)
		{
			PropertyInfo propertyInfo = AccessTools.Property(typeof(ConfigFile), "OrphanedEntries");
			Dictionary<ConfigDefinition, string> dictionary = (Dictionary<ConfigDefinition, string>)propertyInfo.GetValue(config);
			dictionary.Clear();
		}
	}
	internal class EnemyConfig
	{
		public ConfigEntry<bool> BunkerSpiderChangeMaxCount { get; private set; } = null;


		public ConfigEntry<bool> CoilheadChangePowerLevel { get; private set; } = null;


		public ConfigEntry<bool> CoilheadChangeMaxCount { get; private set; } = null;


		public ConfigEntry<bool> GhostGirlChangePowerLevel { get; private set; } = null;


		public ConfigEntry<bool> JesterChangePowerLevel { get; private set; } = null;


		public EnemyConfig(ConfigFile config)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Expected O, but got Unknown
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Expected O, but got Unknown
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Expected O, but got Unknown
			if (config == null)
			{
				throw new ArgumentNullException("config");
			}
			BunkerSpiderChangeMaxCount = config.Bind<bool>("Bunker Spider Settings", "Change Max Count", true, new ConfigDescription("If enabled, there can be at most 2 spiders spawned on the map (instead of 1). Do you prefer potentially having 2 spiders or other monsters? That's up to you.", (AcceptableValueBase)null, Array.Empty<object>()));
			CoilheadChangePowerLevel = config.Bind<bool>("Coilhead Settings", "Change Power Level", true, new ConfigDescription("If enabled, makes it less likely to spawn (e.g. more than the Bracken but less than Hoarding Bugs).", (AcceptableValueBase)null, Array.Empty<object>()));
			CoilheadChangeMaxCount = config.Bind<bool>("Coilhead Settings", "Change Max Count", true, new ConfigDescription("If enabled, there can be at most 4 coilheads spawned on the map (instead of 5).", (AcceptableValueBase)null, Array.Empty<object>()));
			GhostGirlChangePowerLevel = config.Bind<bool>("Ghost Girl Settings", "Change Power Level", true, new ConfigDescription("If enabled, makes it less likely to spawn (e.g. same as the Bracken).", (AcceptableValueBase)null, Array.Empty<object>()));
			JesterChangePowerLevel = config.Bind<bool>("Jester Settings", "Change Power Level", true, new ConfigDescription("If enabled, makes it more likely to spawn (e.g. more than the Bracken but less than Hoarding Bugs).", (AcceptableValueBase)null, Array.Empty<object>()));
		}

		~EnemyConfig()
		{
			if (BunkerSpiderChangeMaxCount != null)
			{
				((ConfigEntryBase)BunkerSpiderChangeMaxCount).ConfigFile.Remove(((ConfigEntryBase)BunkerSpiderChangeMaxCount).Definition);
				BunkerSpiderChangeMaxCount = null;
			}
			if (CoilheadChangePowerLevel != null)
			{
				((ConfigEntryBase)CoilheadChangePowerLevel).ConfigFile.Remove(((ConfigEntryBase)CoilheadChangePowerLevel).Definition);
				CoilheadChangePowerLevel = null;
			}
			if (CoilheadChangeMaxCount != null)
			{
				((ConfigEntryBase)CoilheadChangeMaxCount).ConfigFile.Remove(((ConfigEntryBase)CoilheadChangeMaxCount).Definition);
				CoilheadChangeMaxCount = null;
			}
			if (GhostGirlChangePowerLevel != null)
			{
				((ConfigEntryBase)GhostGirlChangePowerLevel).ConfigFile.Remove(((ConfigEntryBase)GhostGirlChangePowerLevel).Definition);
				GhostGirlChangePowerLevel = null;
			}
			if (JesterChangePowerLevel != null)
			{
				((ConfigEntryBase)JesterChangePowerLevel).ConfigFile.Remove(((ConfigEntryBase)JesterChangePowerLevel).Definition);
				JesterChangePowerLevel = null;
			}
		}
	}
	internal class SandSpiderConfig
	{
		public ConfigEntry<int> Health { get; private set; } = null;


		public ConfigEntry<int> Damage { get; private set; } = null;


		public ConfigEntry<int> ScaleDPS { get; private set; } = null;


		public SandSpiderConfig(ConfigFile config)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			if (config == null)
			{
				throw new ArgumentNullException("config");
			}
			Health = config.Bind<int>("Bunker Spider Settings", "Health", 4, new ConfigDescription("Changes how much health the spider has. Game default: 5", (AcceptableValueBase)(object)new AcceptableValueRange<int>(3, 5), Array.Empty<object>()));
			Damage = config.Bind<int>("Bunker Spider Settings", "Damage", 60, new ConfigDescription("Changes how much damage the spider does per hit. Game default: 90", (AcceptableValueBase)(object)new AcceptableValueRange<int>(45, 90), Array.Empty<object>()));
			ScaleDPS = config.Bind<int>("Bunker Spider Settings", "Scale DPS (%)", 75, new ConfigDescription("Allows to reduce the damage per second (i.e. how fast the spider can chain hits). Game default: 100%", (AcceptableValueBase)(object)new AcceptableValueRange<int>(50, 100), Array.Empty<object>()));
		}

		~SandSpiderConfig()
		{
			if (Health != null)
			{
				((ConfigEntryBase)Health).ConfigFile.Remove(((ConfigEntryBase)Health).Definition);
				Health = null;
			}
			if (Damage != null)
			{
				((ConfigEntryBase)Damage).ConfigFile.Remove(((ConfigEntryBase)Damage).Definition);
				Damage = null;
			}
			if (ScaleDPS != null)
			{
				((ConfigEntryBase)ScaleDPS).ConfigFile.Remove(((ConfigEntryBase)ScaleDPS).Definition);
				ScaleDPS = null;
			}
		}
	}
	[Serializable]
	public class SyncedInstance<T>
	{
		[NonSerialized]
		protected static int IntSize = 4;

		internal static CustomMessagingManager MessageManager => NetworkManager.Singleton.CustomMessagingManager;

		internal static bool IsClient => NetworkManager.Singleton.IsClient;

		internal static bool IsHost => NetworkManager.Singleton.IsHost;

		public static T Default { get; private set; }

		public static T Instance { get; private set; }

		public static bool Synced { get; internal set; }

		protected void InitInstance(T instance)
		{
			Default = instance;
			Instance = instance;
			IntSize = 4;
		}

		internal static void SyncInstance(byte[] data)
		{
			Instance = DeserializeFromBytes(data);
			Synced = true;
		}

		internal static void RevertSync()
		{
			Instance = Default;
			Synced = false;
		}

		public static byte[] SerializeToBytes(T val)
		{
			BinaryFormatter binaryFormatter = new BinaryFormatter();
			using MemoryStream memoryStream = new MemoryStream();
			try
			{
				binaryFormatter.Serialize(memoryStream, val);
				return memoryStream.ToArray();
			}
			catch (Exception arg)
			{
				ManualLogSource logger = Plugin.Logger;
				if (logger != null)
				{
					logger.LogError((object)$"Error serializing instance: {arg}");
				}
				return null;
			}
		}

		public static T DeserializeFromBytes(byte[] data)
		{
			BinaryFormatter binaryFormatter = new BinaryFormatter();
			using MemoryStream serializationStream = new MemoryStream(data);
			try
			{
				return (T)binaryFormatter.Deserialize(serializationStream);
			}
			catch (Exception arg)
			{
				ManualLogSource logger = Plugin.Logger;
				if (logger != null)
				{
					logger.LogError((object)$"Error deserializing instance: {arg}");
				}
				return default(T);
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}