Decompiled source of LethalBestiary v1.2.1

plugins/LethalBestiary/LethalBestiary.dll

Decompiled 8 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using DunGen;
using DunGen.Graph;
using GameNetcodeStuff;
using LethalBestiary.Modules;
using LethalBestiary.NetcodePatcher;
using Microsoft.CodeAnalysis;
using Mono.Cecil.Cil;
using MonoMod.Cil;
using MonoMod.RuntimeDetour;
using On;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Audio;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("Xilef992")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Lightweight version for Lethal Lib for registering new enemies!")]
[assembly: AssemblyFileVersion("0.0.0.0")]
[assembly: AssemblyInformationalVersion("0.0.0-dev.5+1066fcad873f53ff493f6e79e46189f3bc6bf919")]
[assembly: AssemblyProduct("LethalBestiary")]
[assembly: AssemblyTitle("LethalBestiary")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/FelixAllard/Xilef-LethalBestiary-LC")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
internal class <Module>
{
	static <Module>()
	{
	}
}
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LethalBestiary
{
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "LethalBestiary";

		public const string PLUGIN_NAME = "LethalBestiary";

		public const string PLUGIN_VERSION = "1.0.0";
	}
	[BepInPlugin("Xilef.LethalBestiary", "LethalBestiary", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string ModGUID = "Xilef.LethalBestiary";

		public const string ModName = "LethalBestiary";

		public const string ModVersion = "1.0.0";

		public static AssetBundle MainAssets;

		public static ManualLogSource logger;

		public static ConfigFile config;

		public static Plugin Instance;

		public static ConfigEntry<bool> extendedLogging;

		private void Awake()
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			config = ((BaseUnityPlugin)this).Config;
			logger = ((BaseUnityPlugin)this).Logger;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"LethalBestiary Is loading ...");
			extendedLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ExtendedLogging", false, "Enable extended logging");
			new ILHook((MethodBase)typeof(StackTrace).GetMethod("AddFrames", BindingFlags.Instance | BindingFlags.NonPublic), new Manipulator(IlHook));
			Enemies.Init();
			Utilities.Init();
			NetworkPrefabs.Init();
			Utilities.Init();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"LethalBestiary Is Loaded");
		}

		private void IlHook(ILContext il)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			try
			{
				ILCursor val = new ILCursor(il);
				val.GotoNext(new Func<Instruction, bool>[1]
				{
					(Instruction x) => ILPatternMatchingExt.MatchCallvirt(x, (MethodBase)typeof(StackFrame).GetMethod("GetFileLineNumber", BindingFlags.Instance | BindingFlags.Public))
				});
				val.RemoveRange(2);
				val.EmitDelegate<Func<StackFrame, string>>((Func<StackFrame, string>)GetLineOrIL);
			}
			catch (Exception)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"ILHook already applied! LethalBestiary is skipping Method Patching!");
			}
		}

		private static string GetLineOrIL(StackFrame instance)
		{
			int fileLineNumber = instance.GetFileLineNumber();
			if (fileLineNumber == -1 || fileLineNumber == 0)
			{
				return "IL_" + instance.GetILOffset().ToString("X4");
			}
			return fileLineNumber.ToString();
		}
	}
}
namespace LethalBestiary.Modules
{
	public class Enemies
	{
		public struct EnemyAssetInfo
		{
			public EnemyType EnemyAsset;

			public TerminalKeyword keyword;
		}

		public enum SpawnType
		{
			Default,
			Daytime,
			Outside
		}

		public class SpawnableEnemy
		{
			public EnemyType enemy;

			public SpawnType spawnType;

			public TerminalNode terminalNode;

			public TerminalKeyword infoKeyword;

			public string modName;

			public int rarity;

			public Levels.LevelTypes spawnLevels;

			public string[] spawnLevelOverrides;

			public Dictionary<string, int> customLevelRarities = new Dictionary<string, int>();

			public Dictionary<Levels.LevelTypes, int> levelRarities = new Dictionary<Levels.LevelTypes, int>();

			public SpawnableEnemy(EnemyType enemy, int rarity, Levels.LevelTypes spawnLevels, SpawnType spawnType, string[] spawnLevelOverrides = null)
			{
				this.enemy = enemy;
				this.spawnLevels = spawnLevels;
				this.spawnType = spawnType;
				if (spawnLevelOverrides != null)
				{
					foreach (string levelName in spawnLevelOverrides)
					{
						customLevelRarities.Add(Levels.Compatibility.GetLLLNameOfLevel(levelName), rarity);
					}
				}
				if (spawnLevels == Levels.LevelTypes.None)
				{
					return;
				}
				foreach (Levels.LevelTypes value in Enum.GetValues(typeof(Levels.LevelTypes)))
				{
					if (spawnLevels.HasFlag(value))
					{
						levelRarities.Add(value, rarity);
					}
				}
			}

			public SpawnableEnemy(EnemyType enemy, SpawnType spawnType, Dictionary<Levels.LevelTypes, int>? levelRarities = null, Dictionary<string, int>? customLevelRarities = null)
			{
				this.enemy = enemy;
				this.spawnType = spawnType;
				if (levelRarities != null)
				{
					this.levelRarities = levelRarities;
				}
				if (customLevelRarities != null)
				{
					this.customLevelRarities = Levels.Compatibility.LLLifyLevelRarityDictionary(customLevelRarities);
				}
			}
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static hook_Awake <0>__RegisterLevelEnemies;

			public static hook_Start <1>__Terminal_Start;

			public static hook_Start <2>__QuickMenuManager_Start;

			public static hook_Start <3>__RegisterLevelEnemiesforLLL_RoundManager_Start;

			public static hook_Start <4>__RegisterLevelEnemiesforLE_Terminal_Start;
		}

		private static List<SelectableLevel> levelsAlreadyAddedTo = new List<SelectableLevel>();

		private static bool addedToDebug = false;

		public static Terminal terminal;

		public static List<EnemyAssetInfo> enemyAssetInfos = new List<EnemyAssetInfo>();

		public static List<SpawnableEnemy> spawnableEnemies = new List<SpawnableEnemy>();

		public static void Init()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_0030: 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: Expected O, but got Unknown
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			object obj = <>O.<0>__RegisterLevelEnemies;
			if (obj == null)
			{
				hook_Awake val = RegisterLevelEnemies;
				<>O.<0>__RegisterLevelEnemies = val;
				obj = (object)val;
			}
			StartOfRound.Awake += (hook_Awake)obj;
			object obj2 = <>O.<1>__Terminal_Start;
			if (obj2 == null)
			{
				hook_Start val2 = Terminal_Start;
				<>O.<1>__Terminal_Start = val2;
				obj2 = (object)val2;
			}
			Terminal.Start += (hook_Start)obj2;
			object obj3 = <>O.<2>__QuickMenuManager_Start;
			if (obj3 == null)
			{
				hook_Start val3 = QuickMenuManager_Start;
				<>O.<2>__QuickMenuManager_Start = val3;
				obj3 = (object)val3;
			}
			QuickMenuManager.Start += (hook_Start)obj3;
		}

		private static void QuickMenuManager_Start(orig_Start orig, QuickMenuManager self)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			if (addedToDebug)
			{
				orig.Invoke(self);
				return;
			}
			SelectableLevel testAllEnemiesLevel = self.testAllEnemiesLevel;
			List<SpawnableEnemyWithRarity> enemies = testAllEnemiesLevel.Enemies;
			List<SpawnableEnemyWithRarity> daytimeEnemies = testAllEnemiesLevel.DaytimeEnemies;
			List<SpawnableEnemyWithRarity> outsideEnemies = testAllEnemiesLevel.OutsideEnemies;
			foreach (SpawnableEnemy spawnableEnemy in spawnableEnemies)
			{
				if (enemies.All((SpawnableEnemyWithRarity x) => (Object)(object)x.enemyType == (Object)(object)spawnableEnemy.enemy))
				{
					continue;
				}
				SpawnableEnemyWithRarity item = new SpawnableEnemyWithRarity
				{
					enemyType = spawnableEnemy.enemy,
					rarity = spawnableEnemy.rarity
				};
				switch (spawnableEnemy.spawnType)
				{
				case SpawnType.Default:
					if (!enemies.Any((SpawnableEnemyWithRarity x) => (Object)(object)x.enemyType == (Object)(object)spawnableEnemy.enemy))
					{
						enemies.Add(item);
					}
					break;
				case SpawnType.Daytime:
					if (!daytimeEnemies.Any((SpawnableEnemyWithRarity x) => (Object)(object)x.enemyType == (Object)(object)spawnableEnemy.enemy))
					{
						daytimeEnemies.Add(item);
					}
					break;
				case SpawnType.Outside:
					if (!outsideEnemies.Any((SpawnableEnemyWithRarity x) => (Object)(object)x.enemyType == (Object)(object)spawnableEnemy.enemy))
					{
						outsideEnemies.Add(item);
					}
					break;
				}
				if (Plugin.extendedLogging.Value)
				{
					Plugin.logger.LogInfo((object)$"Added {spawnableEnemy.enemy.enemyName} to DebugList [{spawnableEnemy.spawnType}]");
				}
			}
			addedToDebug = true;
			orig.Invoke(self);
		}

		private static void Terminal_Start(orig_Start orig, Terminal self)
		{
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_027a: Expected O, but got Unknown
			terminal = self;
			TerminalKeyword val = self.terminalNodes.allKeywords.First((TerminalKeyword keyword) => keyword.word == "info");
			List<string> list = new List<string>();
			foreach (SpawnableEnemy spawnableEnemy in spawnableEnemies)
			{
				if (list.Contains(spawnableEnemy.enemy.enemyName))
				{
					Plugin.logger.LogInfo((object)("Skipping " + spawnableEnemy.enemy.enemyName + " because it was already added"));
					continue;
				}
				if ((Object)(object)spawnableEnemy.terminalNode == (Object)null)
				{
					spawnableEnemy.terminalNode = ScriptableObject.CreateInstance<TerminalNode>();
					spawnableEnemy.terminalNode.displayText = spawnableEnemy.enemy.enemyName + "\n\nDanger level: Unknown\n\n[No information about this creature was found.]\n\n";
					spawnableEnemy.terminalNode.clearPreviousText = true;
					spawnableEnemy.terminalNode.maxCharactersToType = 35;
					spawnableEnemy.terminalNode.creatureName = spawnableEnemy.enemy.enemyName;
				}
				if (self.enemyFiles.Any((TerminalNode x) => x.creatureName == spawnableEnemy.terminalNode.creatureName))
				{
					Plugin.logger.LogInfo((object)("Skipping " + spawnableEnemy.enemy.enemyName + " because it was already added"));
					continue;
				}
				TerminalKeyword keyword2 = (((Object)(object)spawnableEnemy.infoKeyword != (Object)null) ? spawnableEnemy.infoKeyword : TerminalUtils.CreateTerminalKeyword(spawnableEnemy.terminalNode.creatureName.ToLowerInvariant().Replace(" ", "-"), isVerb: false, null, null, val));
				keyword2.defaultVerb = val;
				List<TerminalKeyword> list2 = self.terminalNodes.allKeywords.ToList();
				if (!list2.Any((TerminalKeyword x) => x.word == keyword2.word))
				{
					list2.Add(keyword2);
					self.terminalNodes.allKeywords = list2.ToArray();
				}
				List<CompatibleNoun> list3 = val.compatibleNouns.ToList();
				if (!list3.Any((CompatibleNoun x) => x.noun.word == keyword2.word))
				{
					list3.Add(new CompatibleNoun
					{
						noun = keyword2,
						result = spawnableEnemy.terminalNode
					});
				}
				val.compatibleNouns = list3.ToArray();
				spawnableEnemy.terminalNode.creatureFileID = self.enemyFiles.Count;
				self.enemyFiles.Add(spawnableEnemy.terminalNode);
				ScanNodeProperties[] componentsInChildren = spawnableEnemy.enemy.enemyPrefab.GetComponentsInChildren<ScanNodeProperties>();
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					componentsInChildren[i].creatureScanID = spawnableEnemy.terminalNode.creatureFileID;
				}
				EnemyAssetInfo enemyAssetInfo = default(EnemyAssetInfo);
				enemyAssetInfo.EnemyAsset = spawnableEnemy.enemy;
				enemyAssetInfo.keyword = keyword2;
				EnemyAssetInfo item = enemyAssetInfo;
				enemyAssetInfos.Add(item);
			}
			orig.Invoke(self);
		}

		private static void RegisterLevelEnemies(orig_Awake orig, StartOfRound self)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			orig.Invoke(self);
			RegisterLethalLibEnemiesForAllLevels();
			if (Chainloader.PluginInfos.ContainsKey("imabatby.lethallevelloader") || Chainloader.PluginInfos.ContainsKey("iambatby.lethallevelloader"))
			{
				object obj = <>O.<3>__RegisterLevelEnemiesforLLL_RoundManager_Start;
				if (obj == null)
				{
					hook_Start val = RegisterLevelEnemiesforLLL_RoundManager_Start;
					<>O.<3>__RegisterLevelEnemiesforLLL_RoundManager_Start = val;
					obj = (object)val;
				}
				RoundManager.Start += (hook_Start)obj;
			}
			if (Chainloader.PluginInfos.ContainsKey("LethalExpansion"))
			{
				object obj2 = <>O.<4>__RegisterLevelEnemiesforLE_Terminal_Start;
				if (obj2 == null)
				{
					hook_Start val2 = RegisterLevelEnemiesforLE_Terminal_Start;
					<>O.<4>__RegisterLevelEnemiesforLE_Terminal_Start = val2;
					obj2 = (object)val2;
				}
				Terminal.Start += (hook_Start)obj2;
			}
		}

		private static void RegisterLevelEnemiesforLLL_RoundManager_Start(orig_Start orig, RoundManager self)
		{
			orig.Invoke(self);
			RegisterLethalLibEnemiesForAllLevels();
		}

		private static void RegisterLevelEnemiesforLE_Terminal_Start(orig_Start orig, Terminal self)
		{
			orig.Invoke(self);
			RegisterLethalLibEnemiesForAllLevels();
		}

		private static void RegisterLethalLibEnemiesForAllLevels()
		{
			SelectableLevel[] levels = StartOfRound.Instance.levels;
			foreach (SelectableLevel val in levels)
			{
				if (levelsAlreadyAddedTo.Contains(val))
				{
					continue;
				}
				foreach (SpawnableEnemy spawnableEnemy in spawnableEnemies)
				{
					AddEnemyToLevel(spawnableEnemy, val);
				}
				levelsAlreadyAddedTo.Add(val);
			}
		}

		private static void AddEnemyToLevel(SpawnableEnemy spawnableEnemy, SelectableLevel level)
		{
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Expected O, but got Unknown
			SpawnableEnemy spawnableEnemy2 = spawnableEnemy;
			string text = ((Object)level).name;
			bool flag = spawnableEnemy2.levelRarities.ContainsKey(Levels.LevelTypes.All) || (spawnableEnemy2.customLevelRarities != null && spawnableEnemy2.customLevelRarities.ContainsKey(text));
			if (spawnableEnemy2.levelRarities.ContainsKey(Levels.LevelTypes.Modded) && !Enum.IsDefined(typeof(Levels.LevelTypes), text))
			{
				flag = true;
			}
			Levels.LevelTypes levelTypes = Levels.LevelTypes.None;
			bool flag2 = false;
			if (Enum.IsDefined(typeof(Levels.LevelTypes), text))
			{
				levelTypes = (Levels.LevelTypes)Enum.Parse(typeof(Levels.LevelTypes), text);
				flag2 = true;
			}
			else
			{
				text = Levels.Compatibility.GetLLLNameOfLevel(text);
			}
			if (!(flag2 || flag))
			{
				return;
			}
			Levels.LevelTypes key = (flag ? Levels.LevelTypes.All : levelTypes);
			if (!flag && !spawnableEnemy2.levelRarities.ContainsKey(key))
			{
				return;
			}
			int num = 0;
			if (flag2 && spawnableEnemy2.levelRarities.ContainsKey(levelTypes))
			{
				num = spawnableEnemy2.levelRarities[levelTypes];
			}
			else if (!flag2 && spawnableEnemy2.customLevelRarities != null && spawnableEnemy2.customLevelRarities.ContainsKey(text))
			{
				num = spawnableEnemy2.customLevelRarities[text];
			}
			else if (!flag2 && spawnableEnemy2.levelRarities.ContainsKey(Levels.LevelTypes.Modded))
			{
				num = spawnableEnemy2.levelRarities[Levels.LevelTypes.Modded];
			}
			else if (spawnableEnemy2.levelRarities.ContainsKey(Levels.LevelTypes.All))
			{
				num = spawnableEnemy2.levelRarities[Levels.LevelTypes.All];
			}
			SpawnableEnemyWithRarity item = new SpawnableEnemyWithRarity
			{
				enemyType = spawnableEnemy2.enemy,
				rarity = num
			};
			switch (spawnableEnemy2.spawnType)
			{
			case SpawnType.Default:
				if (!level.Enemies.Any((SpawnableEnemyWithRarity x) => (Object)(object)x.enemyType == (Object)(object)spawnableEnemy2.enemy))
				{
					level.Enemies.Add(item);
					if (Plugin.extendedLogging.Value)
					{
						Plugin.logger.LogInfo((object)$"To {text} added {((Object)spawnableEnemy2.enemy).name} with weight {num} and SpawnType [Default]");
					}
				}
				break;
			case SpawnType.Daytime:
				if (!level.DaytimeEnemies.Any((SpawnableEnemyWithRarity x) => (Object)(object)x.enemyType == (Object)(object)spawnableEnemy2.enemy))
				{
					level.DaytimeEnemies.Add(item);
					if (Plugin.extendedLogging.Value)
					{
						Plugin.logger.LogInfo((object)$"To {text} added {((Object)spawnableEnemy2.enemy).name} with weight {num} andSpawnType [Daytime]");
					}
				}
				break;
			case SpawnType.Outside:
				if (!level.OutsideEnemies.Any((SpawnableEnemyWithRarity x) => (Object)(object)x.enemyType == (Object)(object)spawnableEnemy2.enemy))
				{
					level.OutsideEnemies.Add(item);
					if (Plugin.extendedLogging.Value)
					{
						Plugin.logger.LogInfo((object)$"To {text} added {((Object)spawnableEnemy2.enemy).name} with weight {num} and SpawnType [Outside]");
					}
				}
				break;
			}
		}

		public static void RegisterEnemy(EnemyType enemy, int rarity, Levels.LevelTypes levelFlags, SpawnType spawnType, TerminalNode infoNode = null, TerminalKeyword infoKeyword = null)
		{
			RegisterEnemy(enemy, rarity, levelFlags, spawnType, null, infoNode, infoKeyword);
		}

		public static void RegisterEnemy(EnemyType enemy, int rarity, Levels.LevelTypes levelFlags, SpawnType spawnType, string[] spawnLevelOverrides = null, TerminalNode infoNode = null, TerminalKeyword infoKeyword = null)
		{
			EnemyType enemy2 = enemy;
			EnemyNullCheck(enemy2);
			SpawnableEnemy spawnableEnemy = spawnableEnemies.FirstOrDefault((SpawnableEnemy x) => (Object)(object)x.enemy == (Object)(object)enemy2 && x.spawnType == spawnType);
			if (spawnableEnemy != null)
			{
				if (levelFlags != Levels.LevelTypes.None)
				{
					spawnableEnemy.levelRarities.Add(levelFlags, rarity);
				}
				if (spawnLevelOverrides != null)
				{
					foreach (string levelName in spawnLevelOverrides)
					{
						spawnableEnemy.customLevelRarities.Add(Levels.Compatibility.GetLLLNameOfLevel(levelName), rarity);
					}
				}
			}
			else
			{
				spawnableEnemy = new SpawnableEnemy(enemy2, rarity, levelFlags, spawnType, spawnLevelOverrides);
				spawnableEnemy.terminalNode = infoNode;
				spawnableEnemy.infoKeyword = infoKeyword;
				FinalizeRegisterEnemy(spawnableEnemy);
			}
		}

		public static void RegisterEnemy(EnemyType enemy, SpawnType spawnType, Dictionary<Levels.LevelTypes, int>? levelRarities = null, Dictionary<string, int>? customLevelRarities = null, TerminalNode infoNode = null, TerminalKeyword infoKeyword = null)
		{
			EnemyType enemy2 = enemy;
			EnemyNullCheck(enemy2);
			SpawnableEnemy spawnableEnemy = spawnableEnemies.FirstOrDefault((SpawnableEnemy x) => (Object)(object)x.enemy == (Object)(object)enemy2 && x.spawnType == spawnType);
			if (spawnableEnemy != null)
			{
				if (levelRarities != null)
				{
					foreach (KeyValuePair<Levels.LevelTypes, int> levelRarity in levelRarities)
					{
						spawnableEnemy.levelRarities.Add(levelRarity.Key, levelRarity.Value);
					}
				}
				if (customLevelRarities == null)
				{
					return;
				}
				{
					foreach (KeyValuePair<string, int> customLevelRarity in customLevelRarities)
					{
						spawnableEnemy.customLevelRarities.Add(Levels.Compatibility.GetLLLNameOfLevel(customLevelRarity.Key), customLevelRarity.Value);
					}
					return;
				}
			}
			spawnableEnemy = new SpawnableEnemy(enemy2, spawnType, levelRarities, customLevelRarities);
			spawnableEnemy.terminalNode = infoNode;
			spawnableEnemy.infoKeyword = infoKeyword;
			FinalizeRegisterEnemy(spawnableEnemy);
		}

		private static void FinalizeRegisterEnemy(SpawnableEnemy spawnableEnemy)
		{
			string name = Assembly.GetCallingAssembly().GetName().Name;
			spawnableEnemy.modName = name;
			if (spawnableEnemy.enemy.enemyPrefab == null)
			{
				throw new NullReferenceException("Cannot register enemy '" + spawnableEnemy.enemy.enemyName + "', because enemy.enemyPrefab is null!");
			}
			EnemyAICollisionDetect[] componentsInChildren = spawnableEnemy.enemy.enemyPrefab.GetComponentsInChildren<EnemyAICollisionDetect>();
			foreach (EnemyAICollisionDetect val in componentsInChildren)
			{
				if (val.mainScript == null)
				{
					Plugin.logger.LogWarning((object)("An Enemy AI Collision Detect Script on GameObject '" + ((Object)((Component)val).gameObject).name + "' of enemy '" + spawnableEnemy.enemy.enemyName + "' does not reference a 'Main Script', and could cause Null Reference Exceptions."));
				}
			}
			spawnableEnemies.Add(spawnableEnemy);
		}

		private static void EnemyNullCheck(EnemyType enemy)
		{
			if (enemy == null)
			{
				throw new ArgumentNullException("enemy", "The first argument of RegisterEnemy was null!");
			}
		}

		public static void RegisterEnemy(EnemyType enemy, int rarity, Levels.LevelTypes levelFlags, TerminalNode infoNode = null, TerminalKeyword infoKeyword = null)
		{
			EnemyNullCheck(enemy);
			SpawnType spawnType = (enemy.isDaytimeEnemy ? SpawnType.Daytime : (enemy.isOutsideEnemy ? SpawnType.Outside : SpawnType.Default));
			RegisterEnemy(enemy, rarity, levelFlags, spawnType, null, infoNode, infoKeyword);
		}

		public static void RegisterEnemy(EnemyType enemy, int rarity, Levels.LevelTypes levelFlags, string[] spawnLevelOverrides = null, TerminalNode infoNode = null, TerminalKeyword infoKeyword = null)
		{
			EnemyNullCheck(enemy);
			SpawnType spawnType = (enemy.isDaytimeEnemy ? SpawnType.Daytime : (enemy.isOutsideEnemy ? SpawnType.Outside : SpawnType.Default));
			RegisterEnemy(enemy, rarity, levelFlags, spawnType, spawnLevelOverrides, infoNode, infoKeyword);
		}

		public static void RegisterEnemy(EnemyType enemy, Dictionary<Levels.LevelTypes, int>? levelRarities = null, Dictionary<string, int>? customLevelRarities = null, TerminalNode infoNode = null, TerminalKeyword infoKeyword = null)
		{
			EnemyNullCheck(enemy);
			SpawnType spawnType = (enemy.isDaytimeEnemy ? SpawnType.Daytime : (enemy.isOutsideEnemy ? SpawnType.Outside : SpawnType.Default));
			RegisterEnemy(enemy, spawnType, levelRarities, customLevelRarities, infoNode, infoKeyword);
		}

		public static void RemoveEnemyFromLevels(EnemyType enemyType, Levels.LevelTypes levelFlags = Levels.LevelTypes.None, string[] levelOverrides = null)
		{
			EnemyType enemyType2 = enemyType;
			if (!((Object)(object)StartOfRound.Instance != (Object)null))
			{
				return;
			}
			SelectableLevel[] levels = StartOfRound.Instance.levels;
			foreach (SelectableLevel val in levels)
			{
				string name = ((Object)val).name;
				if (!Enum.IsDefined(typeof(Levels.LevelTypes), name))
				{
					name = Levels.Compatibility.GetLLLNameOfLevel(name);
				}
				bool flag = levelFlags.HasFlag(Levels.LevelTypes.All) || (levelOverrides?.Any((string item) => Levels.Compatibility.GetLLLNameOfLevel(item).ToLowerInvariant() == name.ToLowerInvariant()) ?? false);
				if (levelFlags.HasFlag(Levels.LevelTypes.Modded) && !Enum.IsDefined(typeof(Levels.LevelTypes), name))
				{
					flag = true;
				}
				if (!(Enum.IsDefined(typeof(Levels.LevelTypes), name) || flag))
				{
					continue;
				}
				Levels.LevelTypes levelTypes = (flag ? Levels.LevelTypes.All : ((Levels.LevelTypes)Enum.Parse(typeof(Levels.LevelTypes), name)));
				if (flag || levelFlags.HasFlag(levelTypes))
				{
					List<SpawnableEnemyWithRarity> enemies = val.Enemies;
					List<SpawnableEnemyWithRarity> daytimeEnemies = val.DaytimeEnemies;
					List<SpawnableEnemyWithRarity> outsideEnemies = val.OutsideEnemies;
					enemies.RemoveAll((SpawnableEnemyWithRarity x) => (Object)(object)x.enemyType == (Object)(object)enemyType2);
					daytimeEnemies.RemoveAll((SpawnableEnemyWithRarity x) => (Object)(object)x.enemyType == (Object)(object)enemyType2);
					outsideEnemies.RemoveAll((SpawnableEnemyWithRarity x) => (Object)(object)x.enemyType == (Object)(object)enemyType2);
					if (Plugin.extendedLogging.Value)
					{
						Plugin.logger.LogInfo((object)("Removed Enemy " + ((Object)enemyType2).name + " from Level " + name));
					}
				}
			}
		}
	}
	public class Levels
	{
		[Flags]
		public enum LevelTypes
		{
			None = 1,
			ExperimentationLevel = 4,
			AssuranceLevel = 8,
			VowLevel = 0x10,
			OffenseLevel = 0x20,
			MarchLevel = 0x40,
			RendLevel = 0x80,
			DineLevel = 0x100,
			TitanLevel = 0x200,
			Vanilla = 0x3FC,
			Modded = 0x400,
			All = -1
		}

		internal static class Compatibility
		{
			private const string illegalCharacters = ".,?!@#$%^&*()_+-=';:'\"";

			private static string GetNumberlessPlanetName(string planetName)
			{
				if (planetName != null)
				{
					return new string(planetName.SkipWhile((char c) => !char.IsLetter(c)).ToArray());
				}
				return string.Empty;
			}

			private static string StripSpecialCharacters(string input)
			{
				string text = string.Empty;
				for (int i = 0; i < input.Length; i++)
				{
					char c = input[i];
					if ((!".,?!@#$%^&*()_+-=';:'\"".ToCharArray().Contains(c) && char.IsLetterOrDigit(c)) || c.ToString() == " ")
					{
						text += c;
					}
				}
				return text;
			}

			internal static string GetLLLNameOfLevel(string levelName)
			{
				string text = StripSpecialCharacters(GetNumberlessPlanetName(levelName));
				if (!text.EndsWith("Level"))
				{
					text += "Level";
				}
				return text;
			}

			internal static Dictionary<string, int> LLLifyLevelRarityDictionary(Dictionary<string, int> keyValuePairs)
			{
				Dictionary<string, int> dictionary = new Dictionary<string, int>();
				List<string> list = keyValuePairs.Keys.ToList();
				List<int> list2 = keyValuePairs.Values.ToList();
				for (int i = 0; i < keyValuePairs.Count; i++)
				{
					dictionary.Add(GetLLLNameOfLevel(list[i]), list2[i]);
				}
				return dictionary;
			}
		}
	}
	public class NetworkPrefabs
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static hook_Start <0>__GameNetworkManager_Start;
		}

		private static List<GameObject> _networkPrefabs = new List<GameObject>();

		internal static void Init()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			object obj = <>O.<0>__GameNetworkManager_Start;
			if (obj == null)
			{
				hook_Start val = GameNetworkManager_Start;
				<>O.<0>__GameNetworkManager_Start = val;
				obj = (object)val;
			}
			GameNetworkManager.Start += (hook_Start)obj;
		}

		public static void RegisterNetworkPrefab(GameObject prefab)
		{
			if (prefab == null)
			{
				throw new ArgumentNullException("prefab", "The given argument for RegisterNetworkPrefab is null!");
			}
			if (!_networkPrefabs.Contains(prefab))
			{
				_networkPrefabs.Add(prefab);
			}
		}

		private static void GameNetworkManager_Start(orig_Start orig, GameNetworkManager self)
		{
			orig.Invoke(self);
			Debug.Log((object)"Registering All Prefabs!");
			foreach (GameObject networkPrefab in _networkPrefabs)
			{
				if (!NetworkManager.Singleton.NetworkConfig.Prefabs.Contains(networkPrefab))
				{
					NetworkManager.Singleton.AddNetworkPrefab(networkPrefab);
				}
			}
		}
	}
	public class PrefabUtils
	{
		internal static Lazy<GameObject> _prefabParent;

		internal static GameObject prefabParent => _prefabParent.Value;

		static PrefabUtils()
		{
			_prefabParent = new Lazy<GameObject>((Func<GameObject>)delegate
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_001a: Expected O, but got Unknown
				GameObject val = new GameObject("LethalLibGeneratedPrefabs")
				{
					hideFlags = (HideFlags)61
				};
				val.SetActive(false);
				return val;
			});
		}

		public static GameObject ClonePrefab(GameObject prefabToClone, string newName = null)
		{
			GameObject val = Object.Instantiate<GameObject>(prefabToClone, prefabParent.transform);
			((Object)val).hideFlags = (HideFlags)61;
			if (newName != null)
			{
				((Object)val).name = newName;
			}
			else
			{
				((Object)val).name = ((Object)prefabToClone).name;
			}
			return val;
		}

		public static GameObject CreatePrefab(string name)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			GameObject val = new GameObject(name)
			{
				hideFlags = (HideFlags)61
			};
			val.transform.SetParent(prefabParent.transform);
			return val;
		}
	}
	public class TerminalUtils
	{
		public static TerminalKeyword CreateTerminalKeyword(string word, bool isVerb = false, CompatibleNoun[] compatibleNouns = null, TerminalNode specialKeywordResult = null, TerminalKeyword defaultVerb = null, bool accessTerminalObjects = false)
		{
			TerminalKeyword obj = ScriptableObject.CreateInstance<TerminalKeyword>();
			((Object)obj).name = word;
			obj.word = word;
			obj.isVerb = isVerb;
			obj.compatibleNouns = compatibleNouns;
			obj.specialKeywordResult = specialKeywordResult;
			obj.defaultVerb = defaultVerb;
			obj.accessTerminalObjects = accessTerminalObjects;
			return obj;
		}
	}
	public class Utilities
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static hook_Start <0>__StartOfRound_Start;

			public static hook_Start <1>__MenuManager_Start;
		}

		public static List<GameObject> prefabsToFix = new List<GameObject>();

		public static List<GameObject> fixedPrefabs = new List<GameObject>();

		public static void Init()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_0030: 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: Expected O, but got Unknown
			object obj = <>O.<0>__StartOfRound_Start;
			if (obj == null)
			{
				hook_Start val = StartOfRound_Start;
				<>O.<0>__StartOfRound_Start = val;
				obj = (object)val;
			}
			StartOfRound.Start += (hook_Start)obj;
			object obj2 = <>O.<1>__MenuManager_Start;
			if (obj2 == null)
			{
				hook_Start val2 = MenuManager_Start;
				<>O.<1>__MenuManager_Start = val2;
				obj2 = (object)val2;
			}
			MenuManager.Start += (hook_Start)obj2;
		}

		private static void StartOfRound_Start(orig_Start orig, StartOfRound self)
		{
			AudioMixer diageticMixer = SoundManager.Instance.diageticMixer;
			if (Plugin.extendedLogging.Value)
			{
				Plugin.logger.LogInfo((object)("Diagetic mixer is " + ((Object)diageticMixer).name));
			}
			Plugin.logger.LogInfo((object)$"Found {prefabsToFix.Count} prefabs to fix");
			List<GameObject> list = new List<GameObject>();
			for (int num = prefabsToFix.Count - 1; num >= 0; num--)
			{
				GameObject val = prefabsToFix[num];
				AudioSource[] componentsInChildren = val.GetComponentsInChildren<AudioSource>();
				foreach (AudioSource val2 in componentsInChildren)
				{
					if ((Object)(object)val2.outputAudioMixerGroup == (Object)null || !(((Object)val2.outputAudioMixerGroup.audioMixer).name == "Diagetic"))
					{
						continue;
					}
					AudioMixerGroup val3 = diageticMixer.FindMatchingGroups(((Object)val2.outputAudioMixerGroup).name)[0];
					if ((Object)(object)val3 != (Object)null)
					{
						val2.outputAudioMixerGroup = val3;
						if (Plugin.extendedLogging.Value)
						{
							Plugin.logger.LogInfo((object)("Set mixer group for " + ((Object)val2).name + " in " + ((Object)val).name + " to Diagetic:" + ((Object)val3).name));
						}
						list.Add(val);
					}
				}
			}
			foreach (GameObject item in list)
			{
				prefabsToFix.Remove(item);
			}
			orig.Invoke(self);
		}

		private static void MenuManager_Start(orig_Start orig, MenuManager self)
		{
			orig.Invoke(self);
			if ((Object)(object)((Component)self).GetComponent<AudioSource>() == (Object)null)
			{
				return;
			}
			AudioMixer audioMixer = ((Component)self).GetComponent<AudioSource>().outputAudioMixerGroup.audioMixer;
			List<GameObject> list = new List<GameObject>();
			for (int num = prefabsToFix.Count - 1; num >= 0; num--)
			{
				GameObject val = prefabsToFix[num];
				AudioSource[] componentsInChildren = val.GetComponentsInChildren<AudioSource>();
				foreach (AudioSource val2 in componentsInChildren)
				{
					if ((Object)(object)val2.outputAudioMixerGroup == (Object)null || !(((Object)val2.outputAudioMixerGroup.audioMixer).name == "NonDiagetic"))
					{
						continue;
					}
					AudioMixerGroup val3 = audioMixer.FindMatchingGroups(((Object)val2.outputAudioMixerGroup).name)[0];
					if ((Object)(object)val3 != (Object)null)
					{
						val2.outputAudioMixerGroup = val3;
						if (Plugin.extendedLogging.Value)
						{
							Plugin.logger.LogInfo((object)("Set mixer group for " + ((Object)val2).name + " in " + ((Object)val).name + " to NonDiagetic:" + ((Object)val3).name));
						}
						list.Add(val);
					}
				}
			}
			foreach (GameObject item in list)
			{
				prefabsToFix.Remove(item);
			}
		}

		public static void FixMixerGroups(GameObject prefab)
		{
			if (!fixedPrefabs.Contains(prefab))
			{
				fixedPrefabs.Add(prefab);
				prefabsToFix.Add(prefab);
			}
		}
	}
}
namespace LethalBestiary.Extras
{
	[CreateAssetMenu(menuName = "ScriptableObjects/DungeonDef")]
	public class DungeonDef : ScriptableObject
	{
		public DungeonFlow dungeonFlow;

		[Range(0f, 300f)]
		public int rarity;

		public AudioClip firstTimeDungeonAudio;
	}
	[CreateAssetMenu(menuName = "ScriptableObjects/DungeonGraphLine")]
	public class DungeonGraphLineDef : ScriptableObject
	{
		public GraphLine graphLine;
	}
	public static class ScriptableObjectExtension
	{
		public static T Clone<T>(this T scriptableObject) where T : ScriptableObject
		{
			if ((Object)(object)scriptableObject == (Object)null)
			{
				Debug.LogError((object)$"ScriptableObject was null. Returning default {typeof(T)} object.");
				return (T)(object)ScriptableObject.CreateInstance(typeof(T));
			}
			T val = Object.Instantiate<T>(scriptableObject);
			((Object)(object)val).name = ((Object)(object)scriptableObject).name;
			return val;
		}
	}
	[CreateAssetMenu(menuName = "ScriptableObjects/GameObjectChance")]
	public class GameObjectChanceDef : ScriptableObject
	{
		public GameObjectChance gameObjectChance;
	}
	[CreateAssetMenu(menuName = "ScriptableObjects/SpawnableMapObject")]
	public class SpawnableMapObjectDef : ScriptableObject
	{
		public SpawnableMapObject spawnableMapObject;
	}
	[CreateAssetMenu(menuName = "ScriptableObjects/SpawnableOutsideObject")]
	public class SpawnableOutsideObjectDef : ScriptableObject
	{
		public SpawnableOutsideObjectWithRarity spawnableMapObject;
	}
}
namespace LethalLib
{
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "LethalBestiary";

		public const string PLUGIN_NAME = "LethalBestiary";

		public const string PLUGIN_VERSION = "1.2.1";
	}
}
namespace LethalLib.EnemyHelper
{
	public static class FlashLightEnemyHelper
	{
		public static bool CheckIfEnemyFlashed(Vector3 EnemyPosition, float angle = 20f)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: 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)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			PlayerControllerB[] allPlayerScripts = RoundManager.Instance.playersManager.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (!val.HasLineOfSightToPosition(EnemyPosition, 45f, 60, -1f))
				{
					continue;
				}
				GrabbableObject[] itemSlots = val.ItemSlots;
				foreach (GrabbableObject val2 in itemSlots)
				{
					if ((Object)(object)val2 != (Object)null && (Object)(object)((Component)val2).gameObject.GetComponent<FlashlightItem>() != (Object)null && ((GrabbableObject)((Component)val2).gameObject.GetComponent<FlashlightItem>()).isBeingUsed && Vector3.Distance(((Component)val).transform.position, EnemyPosition) < 3f && val.LineOfSightToPositionAngle(EnemyPosition, 60, -1f) < 20f)
					{
						return true;
					}
				}
			}
			return false;
		}

		public static bool CheckIfEnemyFlashedByPlayer(Vector3 EnemyPosition, PlayerControllerB PlayerToCheck, float angle = 20f)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			if (PlayerToCheck.HasLineOfSightToPosition(EnemyPosition, 45f, 60, -1f))
			{
				GrabbableObject[] itemSlots = PlayerToCheck.ItemSlots;
				foreach (GrabbableObject val in itemSlots)
				{
					if ((Object)(object)val != (Object)null && (Object)(object)((Component)val).gameObject.GetComponent<FlashlightItem>() != (Object)null && ((GrabbableObject)((Component)val).gameObject.GetComponent<FlashlightItem>()).isBeingUsed && Vector3.Distance(((Component)PlayerToCheck).transform.position, EnemyPosition) < 3f && PlayerToCheck.LineOfSightToPositionAngle(EnemyPosition, 60, -1f) < angle)
					{
						return true;
					}
				}
			}
			return false;
		}

		public static bool CheckIfPlayerHasFlashlight(PlayerControllerB PlayerToCheck, bool CheckIfOpened)
		{
			GrabbableObject[] itemSlots = PlayerToCheck.ItemSlots;
			foreach (GrabbableObject val in itemSlots)
			{
				if ((Object)(object)val != (Object)null && (Object)(object)((Component)val).gameObject.GetComponent<FlashlightItem>() != (Object)null && CheckIfOpened && ((GrabbableObject)((Component)val).gameObject.GetComponent<FlashlightItem>()).isBeingUsed)
				{
					return true;
				}
			}
			return false;
		}
	}
	public static class TeleportEnemy
	{
		public static void FindValidTeleportPositionRadius(Vector3 position, float MinRadius, float MaxRadius, bool MustHavePath = true)
		{
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}
namespace LethalBestiary.NetcodePatcher
{
	[AttributeUsage(AttributeTargets.Module)]
	internal class NetcodePatchedAssemblyAttribute : Attribute
	{
	}
}