Decompiled source of LethalQuantities v1.2.9

LethalQuantities.dll

Decompiled 8 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using DunGen;
using DunGen.Graph;
using HarmonyLib;
using LethalQuantities.Json;
using LethalQuantities.Objects;
using LethalQuantities.Patches;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("LethalQuantities")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Customization of Lethal Company variables")]
[assembly: AssemblyFileVersion("1.2.9.0")]
[assembly: AssemblyInformationalVersion("1.2.9+441cf1985e503c07b4da78cbab67073a81676572")]
[assembly: AssemblyProduct("LethalQuantities")]
[assembly: AssemblyTitle("LethalQuantities")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.9.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LethalQuantities
{
	[BepInPlugin("LethalQuantities", "LethalQuantities", "1.2.9")]
	public class Plugin : BaseUnityPlugin
	{
		internal static readonly string EXPORT_DIRECTORY = Path.Combine(Paths.ConfigPath, "LethalQuantities", "Advanced");

		internal static readonly string GLOBAL_SAVE_DIR = Path.Combine(Paths.ConfigPath, "LethalQuantities", "Global");

		internal static readonly string LEVEL_SAVE_DIR = Path.Combine(Paths.ConfigPath, "LethalQuantities", "Moons");

		internal static readonly string PRESET_FILE_NAME = "Presets.json";

		internal static readonly string PRESET_FILE = Path.Combine(Paths.ConfigPath, EXPORT_DIRECTORY, PRESET_FILE_NAME);

		internal GlobalConfiguration configuration;

		private Harmony _harmony;

		internal bool configInitialized;

		internal ExportData defaultInformation;

		internal Dictionary<Guid, LevelPreset> presets = new Dictionary<Guid, LevelPreset>();

		internal GlobalInformation globalInfo;

		internal FileSystemWatcher watcher;

		internal int ignoreCount;

		public static Plugin INSTANCE { get; private set; }

		private void Awake()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			if ((Object)(object)INSTANCE != (Object)null && (Object)(object)INSTANCE != (Object)(object)this)
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			INSTANCE = this;
			MiniLogger.LogInfo("Registering custom TomlTypeConverter for AnimationCurve");
			TomlTypeConverter.AddConverter(typeof(AnimationCurve), (TypeConverter)(object)new AnimationCurveTypeConverter());
			MiniLogger.LogInfo("Registering patches...");
			_harmony = new Harmony("LethalQuantities");
			_harmony.PatchAll(typeof(RoundManagerPatch));
			MiniLogger.LogInfo("Registered RoundManager patch");
			_harmony.PatchAll(typeof(ObjectPatch));
			MiniLogger.LogInfo("Registered Object patch");
			_harmony.PatchAll(typeof(DungeonPatch));
			MiniLogger.LogInfo("Registered RuntimeDungeon patch");
			_harmony.PatchAll(typeof(StartOfRoundPatch));
			MiniLogger.LogInfo("Registered StartOfRound patch");
			_harmony.PatchAll(typeof(ConfigEntryBasePatch));
			MiniLogger.LogInfo("Registered ConfigEntryBase patch");
			_harmony.PatchAll(typeof(TerminalPatch));
			MiniLogger.LogInfo("Registered Terminal patch");
			SceneManager.sceneLoaded += OnSceneLoaded;
			MiniLogger.LogInfo("Added sceneLoaded delegate");
			string text = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Editor.html");
			string text2 = Path.Combine(Paths.ConfigPath, EXPORT_DIRECTORY, "Editor.html");
			if (File.Exists(text) && !File.Exists(text2))
			{
				MiniLogger.LogInfo("Copying editor webpage to the advanced config folder");
				Directory.CreateDirectory(EXPORT_DIRECTORY);
				File.Copy(text, text2);
			}
			Directory.CreateDirectory(EXPORT_DIRECTORY);
			watcher = new FileSystemWatcher();
			watcher.Path = EXPORT_DIRECTORY;
			watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite;
			watcher.Filter = "*.json";
			watcher.Changed += onPresetChanged;
			watcher.Deleted += onPresetDeleted;
			watcher.Renamed += onPresetRenamed;
			watcher.EnableRaisingEvents = true;
		}

		private void onPresetChanged(object source, FileSystemEventArgs ev)
		{
			if (ev.Name == PRESET_FILE_NAME)
			{
				if (ignoreCount > 0)
				{
					ignoreCount--;
					return;
				}
				MiniLogger.LogInfo("The preset file has been changed, updating...");
				loadData(globalInfo, PRESET_FILE);
			}
		}

		private void onPresetDeleted(object source, FileSystemEventArgs ev)
		{
			if (ev.Name == PRESET_FILE_NAME)
			{
				MiniLogger.LogInfo("The preset file has been deleted, saving defaults...");
				exportData();
			}
		}

		private void onPresetRenamed(object source, RenamedEventArgs ev)
		{
			if (ev.OldName == PRESET_FILE_NAME)
			{
				MiniLogger.LogInfo("The preset file has been renamed, saving defaults...");
				exportData();
			}
			else if (ev.Name == PRESET_FILE_NAME)
			{
				MiniLogger.LogInfo("The preset file has been changed, updating...");
				loadData(globalInfo, PRESET_FILE);
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Expected O, but got Unknown
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			MiniLogger.LogInfo("Checking scene " + ((Scene)(ref scene)).name + " for a valid level");
			if (!((Object)(object)RoundManager.Instance != (Object)null))
			{
				return;
			}
			SelectableLevel currentLevel = RoundManager.Instance.currentLevel;
			if (!((Object)(object)currentLevel != (Object)null))
			{
				return;
			}
			Guid guid = RoundManager.Instance.currentLevel.getGuid();
			if (presets.TryGetValue(guid, out var _))
			{
				RoundState[] array = Object.FindObjectsOfType<RoundState>();
				foreach (RoundState roundState in array)
				{
					MiniLogger.LogWarning("Found stale RoundState for level " + ((Object)roundState.level).name);
					Object.Destroy((Object)(object)((Component)roundState).gameObject);
				}
				MiniLogger.LogInfo("Found a valid configuration for " + currentLevel.PlanetName + "(" + ((Object)currentLevel).name + ")");
				GameObject val = new GameObject("LevelModifier");
				SceneManager.MoveGameObjectToScene(val, scene);
				RoundState roundState2 = val.AddComponent<RoundState>();
				roundState2.plugin = this;
				roundState2.setData(scene, guid);
				MiniLogger.LogInfo("Initializing round information");
				roundState2.initialize(currentLevel);
			}
			else
			{
				MiniLogger.LogWarning("No preset found for level " + ((Object)currentLevel).name);
			}
		}

		internal void exportData()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Expected O, but got Unknown
			if (defaultInformation == null)
			{
				return;
			}
			MiniLogger.LogInfo("Exporting default data");
			Directory.CreateDirectory(EXPORT_DIRECTORY);
			string pRESET_FILE = PRESET_FILE;
			JsonSerializer val = new JsonSerializer();
			val.NullValueHandling = (NullValueHandling)1;
			((Collection<JsonConverter>)(object)val.Converters).Add((JsonConverter)(object)new AnimationCurveJsonConverter());
			JObject val2;
			if (File.Exists(pRESET_FILE))
			{
				val2 = JObject.Parse(File.ReadAllText(pRESET_FILE));
				if (val2.ContainsKey("presets"))
				{
					Dictionary<string, Preset> dictionary = val2["presets"].ToObject<Dictionary<string, Preset>>(val);
					foreach (Preset value in dictionary.Values)
					{
						value.update(defaultInformation);
					}
					val2["presets"] = (JToken)(object)JObject.FromObject((object)dictionary, val);
				}
				if (configuration != null && configuration.isAnySet())
				{
					MiniLogger.LogInfo($"Using legacy configuration: {configuration.useLegacy.Value}");
					exportLegacy(val2, configuration.useLegacy.Value);
				}
			}
			else
			{
				MiniLogger.LogInfo("No data file found, exporting global values");
				val2 = new JObject();
				exportLegacy(val2);
			}
			val2["defaults"] = (JToken)(object)JObject.FromObject((object)defaultInformation, val);
			MiniLogger.LogInfo("Writing data to the advanced config folder");
			File.WriteAllText(pRESET_FILE, JsonConvert.SerializeObject((object)val2));
		}

		internal void exportLegacy(JObject jObj, bool replace = false)
		{
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Expected O, but got Unknown
			Dictionary<string, Preset> dictionary = new Dictionary<string, Preset>();
			Preset preset = null;
			if (configuration.isSet())
			{
				preset = new Preset(configuration);
				preset.name = "Exported Global";
				preset.id = "exported-Global";
				MiniLogger.LogInfo("Created global preset " + preset.id);
				dictionary.Add(preset.id, preset);
			}
			Dictionary<string, string> dictionary2 = new Dictionary<string, string>();
			if (jObj.ContainsKey("levels"))
			{
				dictionary2 = jObj["levels"].ToObject<Dictionary<string, string>>();
			}
			foreach (KeyValuePair<Guid, LevelConfiguration> levelConfig in configuration.levelConfigs)
			{
				if (levelConfig.Value.isSet())
				{
					Preset preset2 = new Preset(levelConfig.Value);
					preset2.name = "Exported " + levelConfig.Key.getLevel().PlanetName;
					preset2.id = "exported-" + levelConfig.Key.getLevelName();
					preset2.parent = ((preset == null) ? "" : preset.id);
					dictionary.TryAdd(preset2.id, preset2);
					dictionary2.TryAdd(levelConfig.Key.getLevelName(), preset2.id);
					MiniLogger.LogInfo("Created level preset " + preset2.id + " for " + levelConfig.Key.getLevelName());
				}
				else if (preset != null)
				{
					MiniLogger.LogInfo("No configuration found for " + levelConfig.Key.getLevel().PlanetName + ", defaulting to global");
					dictionary2.TryAdd(levelConfig.Key.getLevelName(), preset.id);
				}
			}
			JsonSerializer val = new JsonSerializer();
			((Collection<JsonConverter>)(object)val.Converters).Add((JsonConverter)(object)new AnimationCurveJsonConverter());
			if (!jObj.ContainsKey("presets"))
			{
				jObj["presets"] = (JToken)(object)JObject.FromObject((object)dictionary, val);
			}
			else
			{
				JToken val2 = jObj["presets"];
				if (val2 is JObject)
				{
					JObject val3 = (JObject)(object)((val2 is JObject) ? val2 : null);
					foreach (KeyValuePair<string, Preset> item in dictionary)
					{
						if (!val3.ContainsKey(item.Key) || replace)
						{
							val3[item.Key] = (JToken)(object)JObject.FromObject((object)item.Value, val);
						}
					}
				}
				else
				{
					MiniLogger.LogError("Found an invalid presets node, replacing");
					jObj["presets"] = (JToken)(object)JObject.FromObject((object)dictionary, val);
				}
			}
			jObj["levels"] = (JToken)(object)JObject.FromObject((object)dictionary2, val);
		}

		public void loadData(GlobalInformation info, string path = null)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Expected O, but got Unknown
			globalInfo = info;
			if (path == null)
			{
				path = PRESET_FILE;
			}
			if (File.Exists(path))
			{
				MiniLogger.LogInfo("Importing data");
				JsonSerializerSettings val = new JsonSerializerSettings();
				val.NullValueHandling = (NullValueHandling)1;
				val.Converters.Add((JsonConverter)(object)new AnimationCurveJsonConverter());
				val.Converters.Add((JsonConverter)(object)new DirectionalSpawnableMapObjectJsonConverter());
				val.Converters.Add((JsonConverter)(object)new EnemyTypeJsonConverter());
				val.Converters.Add((JsonConverter)(object)new ItemJsonConverter());
				val.Converters.Add((JsonConverter)(object)new SelectableLevelGuidJsonConverter());
				ImportData importData = JsonConvert.DeserializeObject<ImportData>(File.ReadAllText(path), val);
				MiniLogger.LogInfo("Generating level presets");
				presets = importData.generate(info);
				JObject val2 = new JObject();
				if (File.Exists(PRESET_FILE))
				{
					val2 = JObject.Parse(File.ReadAllText(PRESET_FILE));
				}
				JsonSerializer val3 = new JsonSerializer();
				((Collection<JsonConverter>)(object)val3.Converters).Add((JsonConverter)(object)new AnimationCurveJsonConverter());
				((Collection<JsonConverter>)(object)val3.Converters).Add((JsonConverter)(object)new DeepDictionaryConverter(val));
				val2["results"] = (JToken)(object)JObject.FromObject((object)presets, val3);
				MiniLogger.LogInfo("Saving level presets");
				ignoreCount++;
				File.WriteAllText(PRESET_FILE, JsonConvert.SerializeObject((object)val2));
				MiniLogger.LogInfo("Done loading data");
			}
		}

		internal static RoundState getRoundState(SelectableLevel level)
		{
			RoundState[] array = Object.FindObjectsOfType<RoundState>();
			foreach (RoundState roundState in array)
			{
				if ((Object)(object)roundState.level == (Object)(object)level)
				{
					return roundState;
				}
			}
			return null;
		}
	}
	public static class MiniLogger
	{
		private static ManualLogSource logger = Logger.CreateLogSource("LethalQuantities");

		public static void LogInfo(string message)
		{
			logger.LogInfo((object)message);
		}

		public static void LogWarning(string message)
		{
			logger.LogWarning((object)message);
		}

		public static void LogError(string message)
		{
			logger.LogError((object)message);
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "LethalQuantities";

		public const string PLUGIN_NAME = "LethalQuantities";

		public const string PLUGIN_VERSION = "1.2.9";
	}
}
namespace LethalQuantities.Patches
{
	internal class ConfigEntryBasePatch
	{
		public static ConditionalWeakTable<ConfigEntryBase, BaseEntry> entries { get; } = new ConditionalWeakTable<ConfigEntryBase, BaseEntry>();


		[HarmonyPatch(typeof(ConfigEntryBase), "WriteDescription")]
		[HarmonyPrefix]
		private static bool onWriteDescriptionPrefix(ConfigEntryBase __instance, ref StreamWriter writer)
		{
			if (entries.TryGetValue(__instance, out var value))
			{
				if (!string.IsNullOrEmpty(__instance.Description.Description))
				{
					writer.WriteLine("## " + __instance.Description.Description.Replace("\n", "\n## "));
				}
				else
				{
					writer.WriteLine("## No description: " + __instance.Description.Description.Replace("\n", "\n## "));
				}
				writer.WriteLine("# Type of setting: " + value.SettingType().Name);
				if (value.hasDefault())
				{
					writer.WriteLine("# Default value: " + value.DefaultString());
				}
				if (__instance.Description.AcceptableValues != null)
				{
					writer.WriteLine(__instance.Description.AcceptableValues.ToDescriptionString());
				}
				else if (value.SettingType().IsEnum)
				{
					writer.WriteLine("# Acceptable values: " + string.Join(", ", Enum.GetNames(value.SettingType())));
					if (value.SettingType().GetCustomAttributes(typeof(FlagsAttribute), inherit: true).Any())
					{
						writer.WriteLine("# Multiple values can be set at the same time by separating them with , (e.g. Debug, Warning)");
					}
				}
				return false;
			}
			return true;
		}
	}
	internal class DungeonPatch
	{
		[HarmonyPatch(typeof(RuntimeDungeon), "Generate")]
		[HarmonyPriority(300)]
		[HarmonyPrefix]
		private static void onDungeonGenerate(RuntimeDungeon __instance)
		{
			RoundState roundState = Plugin.getRoundState(RoundManager.Instance.currentLevel);
			if ((Object)(object)roundState != (Object)null)
			{
				string name = ((Object)__instance.Generator.DungeonFlow).name;
				LevelPreset preset = roundState.getPreset();
				if (preset.dungeonFlows.isSet() && preset.dungeonFlows.value.TryGetValue(name, out var value))
				{
					value.factorySizeMultiplier.update(ref RoundManager.Instance.mapSizeMultiplier);
					__instance.Generator.LengthMultiplier = RoundManager.Instance.mapSizeMultiplier * RoundManager.Instance.currentLevel.factorySizeMultiplier;
					MiniLogger.LogInfo($"Found dungeon flow {name}, using a length multiplier of {__instance.Generator.LengthMultiplier}");
				}
			}
		}
	}
	internal class ObjectPatch
	{
		[HarmonyPatch(typeof(Object), "Instantiate", new Type[]
		{
			typeof(GameObject),
			typeof(Vector3),
			typeof(Quaternion)
		})]
		[HarmonyPriority(50)]
		[HarmonyPrefix]
		private static void onInstantiatePrefix(GameObject original)
		{
			if ((Object)(object)RoundManager.Instance != (Object)null && (Object)(object)RoundManager.Instance.currentLevel != (Object)null)
			{
				RoundState roundState = Plugin.getRoundState(RoundManager.Instance.currentLevel);
				if ((Object)(object)roundState != (Object)null && roundState.modifiedEnemyTypes.Contains(original) && !original.activeSelf)
				{
					((Object)original).hideFlags = (HideFlags)0;
					original.SetActive(true);
				}
			}
		}

		[HarmonyPatch(typeof(Object), "Instantiate", new Type[]
		{
			typeof(GameObject),
			typeof(Vector3),
			typeof(Quaternion)
		})]
		[HarmonyPriority(800)]
		[HarmonyPostfix]
		private static void onInstantiatePostfix(GameObject original)
		{
			if ((Object)(object)RoundManager.Instance != (Object)null && (Object)(object)RoundManager.Instance.currentLevel != (Object)null)
			{
				RoundState roundState = Plugin.getRoundState(RoundManager.Instance.currentLevel);
				if ((Object)(object)roundState != (Object)null && roundState.modifiedEnemyTypes.Contains(original) && original.activeSelf)
				{
					((Object)original).hideFlags = (HideFlags)61;
					original.SetActive(false);
				}
			}
		}
	}
	internal class RoundManagerPatch
	{
		[HarmonyPatch(typeof(RoundManager), "Awake")]
		[HarmonyPriority(250)]
		[HarmonyPostfix]
		private static void onStartPrefix(RoundManager __instance)
		{
			if (Plugin.INSTANCE.configInitialized)
			{
				return;
			}
			try
			{
				NetworkManager manager = Object.FindObjectOfType<NetworkManager>();
				GlobalInformation globalInformation = new GlobalInformation(Plugin.GLOBAL_SAVE_DIR, Plugin.LEVEL_SAVE_DIR);
				MiniLogger.LogInfo("Fetching all enemy types");
				HashSet<string> addedEnemyTypes = new HashSet<string>();
				globalInformation.allEnemyTypes.AddRange(Resources.FindObjectsOfTypeAll<EnemyType>().Where(delegate(EnemyType type)
				{
					if (!((Object)(object)type.enemyPrefab == (Object)null) && manager.NetworkConfig.Prefabs.Contains(type.enemyPrefab) && !addedEnemyTypes.Contains(((Object)type).name))
					{
						addedEnemyTypes.Add(((Object)type).name);
						return true;
					}
					return false;
				}));
				MiniLogger.LogInfo("Fetching all items");
				HashSet<string> addedItems = new HashSet<string>();
				globalInformation.allItems.AddRange(Resources.FindObjectsOfTypeAll<Item>().Where(delegate(Item type)
				{
					if (!((Object)(object)type.spawnPrefab == (Object)null) && manager.NetworkConfig.Prefabs.Contains(type.spawnPrefab) && !addedItems.Contains(((Object)type).name))
					{
						addedItems.Add(((Object)type).name);
						return true;
					}
					return false;
				}));
				MiniLogger.LogInfo("Fetching all moon prices");
				CompatibleNoun[] array = ((IEnumerable<TerminalKeyword>)Resources.FindObjectsOfTypeAll<TerminalKeyword>()).FirstOrDefault((Func<TerminalKeyword, bool>)((TerminalKeyword w) => ((Object)w).name == "Route"))?.compatibleNouns;
				SelectableLevel[] array2 = Resources.FindObjectsOfTypeAll<SelectableLevel>();
				foreach (SelectableLevel val in array2)
				{
					GenericLevelInformation genericLevelInformation = new GenericLevelInformation();
					if (array != null)
					{
						bool flag = false;
						CompatibleNoun[] array3 = array;
						for (int j = 0; j < array3.Length; j++)
						{
							TerminalNode result = array3[j].result;
							if (result.terminalOptions == null)
							{
								MiniLogger.LogError("Route subcommand " + ((Object)result).name + " does not have any valid terminal options!");
								continue;
							}
							CompatibleNoun val2 = ((IEnumerable<CompatibleNoun>)result.terminalOptions).FirstOrDefault((Func<CompatibleNoun, bool>)((CompatibleNoun n) => ((Object)n.noun).name == "Confirm"));
							if (val2 == null)
							{
								MiniLogger.LogError("Unable to find a confirm option for route command " + ((Object)result).name);
								continue;
							}
							TerminalNode result2 = val2.result;
							if ((Object)(object)result2 == (Object)null)
							{
								MiniLogger.LogError("Found a confirm option for route command " + ((Object)result).name + ", but it has no result node!");
								continue;
							}
							_ = result2.buyRerouteToMoon;
							if (val.levelID == result2.buyRerouteToMoon)
							{
								MiniLogger.LogInfo($"Found the price {result2.itemCost} for {((Object)val).name}");
								genericLevelInformation.price = result2.itemCost;
								flag = true;
								break;
							}
						}
						if (!flag)
						{
							MiniLogger.LogWarning("Unable to find price of " + ((Object)val).name + "(" + val.PlanetName + ")");
						}
					}
					else
					{
						MiniLogger.LogError("Unable to find Route TerminalKeyword! Cannot fetch moon prices");
					}
					if (!globalInformation.allSelectableLevels.TryAdd(val.getGuid(), genericLevelInformation))
					{
						MiniLogger.LogWarning($"Attempted to set the price for {val} with the price {genericLevelInformation.price} again");
					}
				}
				MiniLogger.LogInfo("Fetching all traps");
				Dictionary<GameObject, DirectionalSpawnableMapObject> dictionary = new Dictionary<GameObject, DirectionalSpawnableMapObject>();
				HashSet<string> hashSet = new HashSet<string>();
				foreach (Guid key in globalInformation.allSelectableLevels.Keys)
				{
					SpawnableMapObject[] spawnableMapObjects = key.getLevel().spawnableMapObjects;
					foreach (SpawnableMapObject val3 in spawnableMapObjects)
					{
						GameObject prefabToSpawn = val3.prefabToSpawn;
						if (!hashSet.Contains(((Object)prefabToSpawn).name) && manager.NetworkConfig.Prefabs.Contains(prefabToSpawn))
						{
							hashSet.Add(((Object)prefabToSpawn).name);
							dictionary.TryAdd(prefabToSpawn, new DirectionalSpawnableMapObject(prefabToSpawn, val3.spawnFacingAwayFromWall));
						}
					}
				}
				globalInformation.allSpawnableMapObjects.AddRange(dictionary.Values);
				MiniLogger.LogInfo("Fetching all dungeon flows");
				globalInformation.allDungeonFlows.AddRange(Resources.FindObjectsOfTypeAll<DungeonFlow>());
				globalInformation.manager = __instance;
				globalInformation.sortData();
				GlobalConfiguration globalConfiguration;
				if (!Plugin.INSTANCE.configInitialized)
				{
					MiniLogger.LogInfo("Loading global configuration");
					globalConfiguration = new GlobalConfiguration(globalInformation);
					Plugin.INSTANCE.configuration = globalConfiguration;
					Plugin.INSTANCE.configInitialized = true;
					MiniLogger.LogInfo("Done configuring LethalQuantities");
				}
				else
				{
					globalConfiguration = Plugin.INSTANCE.configuration;
				}
				if (globalConfiguration.scrapConfiguration.enabled.Value)
				{
					MiniLogger.LogInfo("Setting custom item weight values");
					foreach (Item allItem in globalInformation.allItems)
					{
						ItemConfiguration itemConfiguration = globalConfiguration.scrapConfiguration.items[allItem];
						if (itemConfiguration is IWeightConfigurable)
						{
							(itemConfiguration as IWeightConfigurable).weight.Set(ref allItem.weight);
						}
					}
				}
				Plugin.INSTANCE.defaultInformation = new ExportData(__instance, globalInformation);
				Plugin.INSTANCE.exportData();
				Plugin.INSTANCE.loadData(globalInformation);
			}
			catch (Exception arg)
			{
				MiniLogger.LogError("Encountered an error while trying to load the configuration");
				MiniLogger.LogError($"Please report this error to the LethalQuantities mod developers: {arg}");
			}
		}

		[HarmonyPatch(typeof(RoundManager), "Start")]
		[HarmonyPostfix]
		private static void onStartPostfix(RoundManager __instance)
		{
			StartOfRoundPatch.updateMoonPrices(StartOfRound.Instance.currentLevel);
			SelectableLevelCache.cleanIdentifiers();
		}

		[HarmonyPatch(typeof(RoundManager), "LoadNewLevel")]
		[HarmonyPriority(800)]
		[HarmonyPrefix]
		private static void onLoadNewLevelPrefix(RoundManager __instance, ref SelectableLevel newLevel)
		{
			//IL_04fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0503: Unknown result type (might be due to invalid IL or missing references)
			//IL_0508: Unknown result type (might be due to invalid IL or missing references)
			//IL_0512: Expected O, but got Unknown
			//IL_0523: Unknown result type (might be due to invalid IL or missing references)
			//IL_052a: Expected O, but got Unknown
			//IL_0331: Unknown result type (might be due to invalid IL or missing references)
			//IL_0338: Expected O, but got Unknown
			try
			{
				RoundState roundState = Plugin.getRoundState(newLevel);
				if (!((Object)(object)roundState != (Object)null))
				{
					return;
				}
				LevelPreset preset = roundState.getPreset();
				MiniLogger.LogInfo("RoundState found for level " + ((Object)roundState.level).name + ", modifying level before loading");
				int num = (int)Math.Ceiling((double)Math.Abs(TimeOfDay.Instance.daysUntilDeadline - 3) / 3.2);
				MiniLogger.LogInfo("Changing inside enemy values");
				preset.maxPowerCount.update(ref newLevel.maxEnemyPowerCount);
				preset.spawnCurve.update(ref newLevel.enemySpawnChanceThroughoutDay);
				preset.spawnProbabilityRange.update(ref newLevel.spawnProbabilityRange);
				if (newLevel.spawnProbabilityRange < (float)num)
				{
					MiniLogger.LogWarning($"Interior enemy spawn amount range is too small({newLevel.spawnProbabilityRange}), setting to {num}");
					newLevel.spawnProbabilityRange = num;
				}
				if (preset.enemies.set)
				{
					newLevel.Enemies.Clear();
					newLevel.Enemies.AddRange(roundState.enemies);
				}
				MiniLogger.LogInfo("Changing daytime enemy values");
				preset.maxDaytimePowerCount.update(ref newLevel.maxDaytimeEnemyPowerCount);
				preset.daytimeSpawnCurve.update(ref newLevel.daytimeEnemySpawnChanceThroughDay);
				preset.daytimeSpawnProbabilityRange.update(ref newLevel.daytimeEnemiesProbabilityRange);
				if (newLevel.daytimeEnemiesProbabilityRange < (float)num)
				{
					MiniLogger.LogWarning($"Daytime enemy spawn amount range is too small({newLevel.daytimeEnemiesProbabilityRange}), setting to {num}");
					newLevel.daytimeEnemiesProbabilityRange = num;
				}
				if (preset.daytimeEnemies.set)
				{
					newLevel.DaytimeEnemies.Clear();
					newLevel.DaytimeEnemies.AddRange(roundState.daytimeEnemies);
				}
				MiniLogger.LogInfo("Changing outside enemy values");
				preset.maxOutsidePowerCount.update(ref newLevel.maxOutsideEnemyPowerCount);
				preset.outsideSpawnCurve.update(ref newLevel.outsideEnemySpawnChanceThroughDay);
				if (preset.outsideEnemies.set)
				{
					newLevel.OutsideEnemies.Clear();
					newLevel.OutsideEnemies.AddRange(roundState.outsideEnemies);
				}
				MiniLogger.LogInfo("Changing scrap values");
				preset.minScrap.update(ref newLevel.minScrap);
				preset.maxScrap.update(ref newLevel.maxScrap);
				preset.scrapAmountMultiplier.update(ref __instance.scrapAmountMultiplier);
				preset.scrapValueMultiplier.update(ref __instance.scrapValueMultiplier);
				if (preset.scrap.isSet())
				{
					Dictionary<Item, int> dictionary = new Dictionary<Item, int>();
					foreach (SpawnableItemWithRarity item in newLevel.spawnableScrap)
					{
						if (!dictionary.TryAdd(item.spawnableItem, item.rarity))
						{
							MiniLogger.LogWarning(((Object)newLevel).name + " has a duplicate spawnable scrap item: " + ((Object)item.spawnableItem).name);
							dictionary[item.spawnableItem] += item.rarity;
						}
					}
					List<SpawnableItemWithRarity> list = new List<SpawnableItemWithRarity>();
					foreach (KeyValuePair<Item, LevelPresetItem> item2 in preset.scrap.value)
					{
						Item key = item2.Key;
						LevelPresetItem value = item2.Value;
						SpawnableItemWithRarity val = new SpawnableItemWithRarity();
						val.spawnableItem = key;
						val.rarity = dictionary.GetValueOrDefault(key, 0);
						value.rarity.update(ref val.rarity);
						if (val.rarity > 0)
						{
							value.conductive.update(ref key.isConductiveMetal);
							value.weight.update(ref key.weight);
							int variable = key.minValue;
							int variable2 = key.maxValue;
							value.minValue.update(ref variable);
							value.maxValue.update(ref variable2);
							key.minValue = Math.Min(variable, variable2);
							key.maxValue = Math.Max(variable, variable2);
							list.Add(val);
						}
					}
					if (list.Count > 0)
					{
						newLevel.spawnableScrap.Clear();
						newLevel.spawnableScrap.AddRange(list);
					}
					else
					{
						MiniLogger.LogWarning("Preset for level " + ((Object)newLevel).name + " has no scrap assigned! No changes have been applied.");
					}
				}
				if (preset.traps.isSet())
				{
					MiniLogger.LogInfo("Changing interior trap spawn amounts");
					Dictionary<GameObject, AnimationCurve> dictionary2 = new Dictionary<GameObject, AnimationCurve>();
					SpawnableMapObject[] spawnableMapObjects = newLevel.spawnableMapObjects;
					foreach (SpawnableMapObject val2 in spawnableMapObjects)
					{
						dictionary2.TryAdd(val2.prefabToSpawn, val2.numberToSpawn);
					}
					List<SpawnableMapObject> list2 = new List<SpawnableMapObject>();
					foreach (KeyValuePair<DirectionalSpawnableMapObject, LevelPresetTrap> item3 in preset.traps.value)
					{
						DirectionalSpawnableMapObject key2 = item3.Key;
						LevelPresetTrap value2 = item3.Value;
						AnimationCurve variable3 = dictionary2.GetValueOrDefault(key2.obj, new AnimationCurve((Keyframe[])(object)new Keyframe[1]
						{
							new Keyframe(0f, 0f)
						}));
						value2.spawnCurve.update(ref variable3);
						SpawnableMapObject val3 = new SpawnableMapObject();
						val3.prefabToSpawn = key2.obj;
						val3.numberToSpawn = variable3;
						val3.spawnFacingAwayFromWall = key2.faceAwayFromWall;
						list2.Add(val3);
					}
					newLevel.spawnableMapObjects = list2.ToArray();
				}
				preset.mapSizeMultiplier.update(ref newLevel.factorySizeMultiplier);
			}
			catch (Exception arg)
			{
				MiniLogger.LogError("Encountered an error while trying to modify the level");
				MiniLogger.LogError($"Please report this error to the LethalQuantities mod developers: {arg}");
			}
		}

		[HarmonyPatch(typeof(RoundManager), "GenerateNewFloor")]
		[HarmonyPriority(200)]
		[HarmonyPrefix]
		private static void onGenerateNewFloorPrefix(RoundManager __instance)
		{
			DungeonFlow[] array = Resources.FindObjectsOfTypeAll<DungeonFlow>();
			try
			{
				MiniLogger.LogInfo("Inserting missing dungeon flows into the RoundManager");
				List<IndoorMapType> list = __instance.dungeonFlowTypes.ToList();
				DungeonFlow[] array2 = array;
				foreach (DungeonFlow val in array2)
				{
					int num = -1;
					for (int j = 0; j < list.Count; j++)
					{
						if ((Object)(object)list[j].dungeonFlow == (Object)(object)val)
						{
							num = j;
							break;
						}
					}
					bool flag = false;
					foreach (LevelPreset value2 in Plugin.INSTANCE.presets.Values)
					{
						if (!value2.dungeonFlows.isSet())
						{
							continue;
						}
						foreach (string key2 in value2.dungeonFlows.value.Keys)
						{
							if (key2 == ((Object)val).name)
							{
								flag = true;
								goto end_IL_00dd;
							}
						}
						continue;
						end_IL_00dd:
						break;
					}
					if (num == -1 && flag)
					{
						MiniLogger.LogWarning("Did not find dungeon flow " + ((Object)val).name + " in the global list of dungeon flows. Adding it now.");
						list.Add(list[num]);
					}
				}
				__instance.dungeonFlowTypes = list.ToArray();
			}
			catch (Exception arg)
			{
				MiniLogger.LogError("Encountered an error while trying to insert missing dungeonflows");
				MiniLogger.LogError($"Please report this error to the LethalQuantities mod developers: {arg}");
			}
			try
			{
				SelectableLevel currentLevel = __instance.currentLevel;
				RoundState roundState = Plugin.getRoundState(currentLevel);
				if (!((Object)(object)roundState != (Object)null))
				{
					return;
				}
				LevelPreset preset = roundState.getPreset();
				if (!preset.dungeonFlows.isSet())
				{
					return;
				}
				MiniLogger.LogInfo("Changing dungeon flow values");
				Dictionary<string, int> dictionary = new Dictionary<string, int>();
				IntWithRarity[] dungeonFlowTypes = currentLevel.dungeonFlowTypes;
				foreach (IntWithRarity val2 in dungeonFlowTypes)
				{
					dictionary.TryAdd(((Object)__instance.dungeonFlowTypes[val2.id].dungeonFlow).name, val2.rarity);
				}
				Dictionary<string, int> dictionary2 = new Dictionary<string, int>();
				foreach (KeyValuePair<string, LevelPresetDungeonFlow> item in preset.dungeonFlows.value)
				{
					string key = item.Key;
					LevelPresetDungeonFlow value = item.Value;
					int variable = dictionary.GetValueOrDefault(key, 0);
					value.rarity.update(ref variable);
					dictionary2.TryAdd(key, variable);
					MiniLogger.LogInfo($"Set dungeon flow rarity for {key} to {variable}");
				}
				currentLevel.dungeonFlowTypes = __instance.ConvertToDungeonFlowArray(dictionary2);
				preset.mapSizeMultiplier.update(ref currentLevel.factorySizeMultiplier);
			}
			catch (Exception arg2)
			{
				MiniLogger.LogError("Encountered an error while trying to update level dungeonflows");
				MiniLogger.LogError($"Please report this error to the LethalQuantities mod developers: {arg2}");
			}
		}
	}
	public static class RoundManagerExtensions
	{
		public static IntWithRarity[] ConvertToDungeonFlowArray(this RoundManager manager, Dictionary<string, int> entries)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			List<IntWithRarity> list = new List<IntWithRarity>();
			foreach (KeyValuePair<string, int> entry in entries)
			{
				if (entry.Value <= 0)
				{
					continue;
				}
				int num = -1;
				for (int i = 0; i < manager.dungeonFlowTypes.Length; i++)
				{
					if (num >= 0)
					{
						break;
					}
					if (((Object)manager.dungeonFlowTypes[i].dungeonFlow).name == entry.Key)
					{
						num = i;
					}
				}
				if (num != -1)
				{
					IntWithRarity val = new IntWithRarity();
					val.id = num;
					val.rarity = entry.Value;
					list.Add(val);
				}
				else
				{
					MiniLogger.LogWarning("Could not find dungeon flow " + entry.Key + "!");
				}
			}
			return list.ToArray();
		}
	}
	internal class StartOfRoundPatch
	{
		private class LevelCosmeticSettings
		{
			private Guid guid;

			private string description;

			private string riskLevel;

			internal LevelCosmeticSettings(SelectableLevel level)
			{
				guid = level.getGuid();
				riskLevel = level.riskLevel;
				description = level.LevelDescription;
			}

			internal void reset()
			{
				SelectableLevel level = guid.getLevel();
				level.LevelDescription = description;
				level.riskLevel = riskLevel;
			}
		}

		private static Dictionary<int, int> defaultPrices = new Dictionary<int, int>();

		private static Optional<LevelCosmeticSettings> previousLevelSettings = Optional<LevelCosmeticSettings>.Empty();

		[HarmonyPatch(typeof(StartOfRound), "ChangeLevel")]
		[HarmonyPriority(200)]
		[HarmonyPrefix]
		private static void onPlanetChange(StartOfRound __instance, int levelID)
		{
			SelectableLevel val = __instance.levels[levelID];
			updateMoonPrices(val);
			try
			{
				if (previousLevelSettings.get(out var val2))
				{
					MiniLogger.LogInfo("Resetting previous level's risk level and description");
					val2.reset();
				}
				if (Plugin.INSTANCE.presets.TryGetValue(val.getGuid(), out var value))
				{
					previousLevelSettings = new Optional<LevelCosmeticSettings>(new LevelCosmeticSettings(val));
					value.riskLevel.update(ref val.riskLevel);
					value.levelDescription.update(ref val.LevelDescription);
				}
			}
			catch (Exception arg)
			{
				MiniLogger.LogError("Encountered an error while trying to set the moon risk level and description");
				MiniLogger.LogError($"Please report this error to the mod developers: {arg}");
			}
		}

		public static void updateMoonPrices(SelectableLevel level)
		{
			try
			{
				TerminalKeyword val = ((IEnumerable<TerminalKeyword>)Object.FindFirstObjectByType<Terminal>().terminalNodes.allKeywords).FirstOrDefault((Func<TerminalKeyword, bool>)((TerminalKeyword w) => ((Object)w).name == "Route"));
				if ((Object)(object)val != (Object)null)
				{
					List<PriceConfiguration> list = new List<PriceConfiguration>();
					GlobalConfiguration configuration = Plugin.INSTANCE.configuration;
					if (configuration != null && configuration.priceConfiguration.enabled.Value)
					{
						list.Add(configuration.priceConfiguration);
						foreach (LevelConfiguration value4 in configuration.levelConfigs.Values)
						{
							if (value4.price.enabled.Value)
							{
								list.Add(value4.price);
							}
						}
					}
					bool flag = defaultPrices.Count() == 0;
					if (Plugin.INSTANCE.presets.TryGetValue(level.getGuid(), out var value) && value.price.isSet())
					{
						bool flag2 = false;
						bool flag3 = false;
						MiniLogger.LogInfo("Modifying moon prices");
						CompatibleNoun[] compatibleNouns = val.compatibleNouns;
						for (int i = 0; i < compatibleNouns.Length; i++)
						{
							TerminalNode result = compatibleNouns[i].result;
							if (result.terminalOptions == null)
							{
								MiniLogger.LogError("Route subcommand " + ((Object)result).name + " does not have any valid terminal options!");
								continue;
							}
							CompatibleNoun val2 = ((IEnumerable<CompatibleNoun>)result.terminalOptions).FirstOrDefault((Func<CompatibleNoun, bool>)((CompatibleNoun n) => ((Object)n.noun).name == "Confirm"));
							if (val2 == null)
							{
								MiniLogger.LogError("Unable to find a confirm option for route command " + ((Object)result).name);
								continue;
							}
							TerminalNode result2 = val2.result;
							if ((Object)(object)result2 == (Object)null)
							{
								MiniLogger.LogError("Found a confirm option for route command " + ((Object)result).name + ", but it has no result node!");
								continue;
							}
							int buyRerouteToMoon = result2.buyRerouteToMoon;
							if (StartOfRound.Instance.getLevelById(buyRerouteToMoon, out var level2))
							{
								Guid guid = level2.getGuid();
								if (flag && !defaultPrices.TryAdd(buyRerouteToMoon, result.itemCost))
								{
									MiniLogger.LogError($"Already changed price for TerminalNode {((Object)result).name} with level id {buyRerouteToMoon}. Perhaps another mod has added it in twice??");
								}
								if (list.Count > 0)
								{
									bool flag4 = false;
									foreach (PriceConfiguration item in list)
									{
										if (!item.moons.TryGetValue(guid, out var _))
										{
											MiniLogger.LogError("Unable to find a price config option for " + ((Object)level2).name);
										}
										else if (item.moons[guid].price.DefaultValue() == -1)
										{
											flag2 = (flag4 = true);
											item.file.SaveOnConfigSet = false;
											item.moons[guid].price.setDefaultValue(result.itemCost);
										}
									}
									if (flag4)
									{
										MiniLogger.LogInfo("Updated price configs with a new default price for level " + ((Object)level2).name);
									}
								}
								if (value.price.value.TryGetValue(guid, out var value3))
								{
									int variable = defaultPrices.GetValueOrDefault(buyRerouteToMoon, result.itemCost);
									value3.price.update(ref variable);
									result.itemCost = variable;
									result2.itemCost = variable;
								}
								flag3 |= Plugin.INSTANCE.defaultInformation.updatePrice(level2, result.itemCost);
							}
							else
							{
								MiniLogger.LogWarning($"Unable to find moon for level {buyRerouteToMoon} on CompatibleNoun {((Object)result).name}");
							}
						}
						if (flag2)
						{
							foreach (PriceConfiguration item2 in list)
							{
								item2.file.Save();
								item2.file.SaveOnConfigSet = true;
							}
						}
						if (flag3)
						{
							Plugin.INSTANCE.exportData();
						}
					}
					else
					{
						if (flag)
						{
							return;
						}
						MiniLogger.LogInfo("Resetting moon prices back to the original values");
						CompatibleNoun[] compatibleNouns = val.compatibleNouns;
						for (int i = 0; i < compatibleNouns.Length; i++)
						{
							TerminalNode result3 = compatibleNouns[i].result;
							if (result3.terminalOptions == null)
							{
								MiniLogger.LogError("Route subcommand " + ((Object)result3).name + " does not have any valid terminal options!");
								continue;
							}
							CompatibleNoun val3 = ((IEnumerable<CompatibleNoun>)result3.terminalOptions).FirstOrDefault((Func<CompatibleNoun, bool>)((CompatibleNoun n) => ((Object)n.noun).name == "Confirm"));
							if (val3 == null)
							{
								MiniLogger.LogError("Unable to find a confirm option for route command " + ((Object)result3).name);
								continue;
							}
							TerminalNode result4 = val3.result;
							if ((Object)(object)result4 == (Object)null)
							{
								MiniLogger.LogError("Found a confirm option for route command " + ((Object)result3).name + ", but it has no result node!");
								continue;
							}
							int buyRerouteToMoon2 = result4.buyRerouteToMoon;
							result4.itemCost = (result3.itemCost = defaultPrices.GetValueOrDefault(buyRerouteToMoon2, result3.itemCost));
						}
						defaultPrices.Clear();
					}
				}
				else
				{
					MiniLogger.LogError("Unable to find Route TerminalKeyword! Cannot change moon prices");
				}
			}
			catch (Exception arg)
			{
				MiniLogger.LogError("Encountered an error while trying to update the moon prices");
				MiniLogger.LogError($"Please report this error to the mod developers: {arg}");
			}
		}
	}
	public static class StartOfRoundExtension
	{
		public static bool getLevelById(this StartOfRound round, int id, out SelectableLevel level)
		{
			SelectableLevel[] levels = round.levels;
			foreach (SelectableLevel val in levels)
			{
				if (val.levelID == id)
				{
					level = val;
					return true;
				}
			}
			level = null;
			return false;
		}
	}
	internal class TerminalPatch
	{
		[HarmonyPatch(typeof(Terminal), "Start")]
		[HarmonyPriority(700)]
		[HarmonyPostfix]
		private static void onTerminalStartPrefix(Terminal __instance)
		{
			if (((NetworkBehaviour)RoundManager.Instance).IsServer)
			{
				StartOfRoundPatch.updateMoonPrices(StartOfRound.Instance.currentLevel);
			}
		}
	}
}
namespace LethalQuantities.Objects
{
	internal class AnimationCurveTypeConverter : TypeConverter
	{
		public AnimationCurveTypeConverter()
		{
			((TypeConverter)this).ConvertToObject = delegate(string input, Type type)
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Expected O, but got Unknown
				//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c7: Expected O, but got Unknown
				//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c1: Expected O, but got Unknown
				//IL_0072: Unknown result type (might be due to invalid IL or missing references)
				//IL_0077: Unknown result type (might be due to invalid IL or missing references)
				//IL_0087: Unknown result type (might be due to invalid IL or missing references)
				//IL_008d: Expected O, but got Unknown
				if (!(type != typeof(AnimationCurve)))
				{
					string[] array = Regex.Replace(input, "\\s+", "").Split(",");
					if (array.Length <= 1)
					{
						if (string.IsNullOrEmpty(array[0]))
						{
							return (object)new AnimationCurve();
						}
						return (object)new AnimationCurve((Keyframe[])(object)new Keyframe[1]
						{
							new Keyframe(0f, float.Parse(array[0], CultureInfo.InvariantCulture))
						});
					}
					Keyframe[] array2 = (Keyframe[])(object)new Keyframe[array.Length];
					for (int j = 0; j < array.Length; j++)
					{
						string[] array3 = array[j].Split(":");
						array2[j] = new Keyframe(float.Parse(array3[0], CultureInfo.InvariantCulture), float.Parse(array3[1], CultureInfo.InvariantCulture));
					}
					return (object)new AnimationCurve(array2);
				}
				return (object)new AnimationCurve();
			};
			((TypeConverter)this).ConvertToString = delegate(object input, Type type)
			{
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_005a: Unknown result type (might be due to invalid IL or missing references)
				//IL_005f: Unknown result type (might be due to invalid IL or missing references)
				if (type != typeof(AnimationCurve))
				{
					return "";
				}
				Keyframe[] keys = ((AnimationCurve)input).GetKeys();
				if (keys.Length == 0)
				{
					return "0";
				}
				if (keys.Length == 1)
				{
					return ((Keyframe)(ref keys[0])).value.ToString(CultureInfo.InvariantCulture);
				}
				StringBuilder stringBuilder = new StringBuilder();
				for (int i = 0; i < keys.Length; i++)
				{
					Keyframe val = keys[i];
					stringBuilder.Append(((Keyframe)(ref val)).time.ToString(CultureInfo.InvariantCulture));
					stringBuilder.Append(":");
					stringBuilder.Append(((Keyframe)(ref val)).value.ToString(CultureInfo.InvariantCulture));
					if (i < keys.Length - 1)
					{
						stringBuilder.Append(", ");
					}
				}
				return stringBuilder.ToString();
			};
		}
	}
	public abstract class BaseEntry
	{
		public abstract Type SettingType();

		public virtual bool hasDefault()
		{
			return false;
		}

		public virtual string DefaultString()
		{
			throw new NotImplementedException();
		}
	}
	public abstract class CustomEntry<T> : BaseEntry, IDefaultable
	{
		public abstract T Value(T value);

		public virtual T localValue(T value)
		{
			return Value(value);
		}

		public abstract bool isDefault();

		public virtual bool isUnset()
		{
			return isDefault();
		}

		public virtual bool isLocallySet()
		{
			return !isDefault();
		}

		public abstract bool Set(ref T value);

		public override Type SettingType()
		{
			return typeof(T);
		}

		public virtual void setDefaultValue(T value)
		{
			throw new NotImplementedException();
		}

		public virtual T DefaultValue()
		{
			throw new NotImplementedException();
		}
	}
	public class EmptyEntry<T> : CustomEntry<T>
	{
		private Func<T, T> defaultValue;

		public EmptyEntry(Func<T, T> defaultValue)
		{
			this.defaultValue = defaultValue;
		}

		public EmptyEntry(T defaultValue)
		{
			this.defaultValue = (T v) => defaultValue;
		}

		public EmptyEntry()
		{
			defaultValue = (T v) => v;
		}

		public override T Value(T value)
		{
			return defaultValue(value);
		}

		public override bool isDefault()
		{
			return true;
		}

		public override bool Set(ref T value)
		{
			return true;
		}

		public override void setDefaultValue(T value)
		{
			defaultValue = (T v) => value;
		}

		public override T DefaultValue()
		{
			return defaultValue(default(T));
		}
	}
	public class GlobalConfigEntry<T> : CustomEntry<T>
	{
		public static readonly string DEFAULT_OPTION = "DEFAULT";

		public static readonly string GLOBAL_OPTION = "GLOBAL";

		private CustomEntry<T> parentEntry;

		private ConfigEntry<string> entry;

		private TypeConverter converter;

		private T defaultValue;

		public GlobalConfigEntry(CustomEntry<T> globalEntry, ConfigEntry<string> entry, T defaultValue, TypeConverter converter)
		{
			parentEntry = globalEntry;
			this.entry = entry;
			this.defaultValue = defaultValue;
			this.converter = converter;
			if (isGlobal())
			{
				entry.Value = "";
			}
		}

		public override T localValue(T value)
		{
			string value2 = entry.Value;
			if (!isLocallySet())
			{
				return defaultValue;
			}
			return (T)converter.ConvertToObject(value2, typeof(T));
		}

		public override T Value(T value)
		{
			string value2 = entry.Value;
			if (value2.ToUpper() == DEFAULT_OPTION)
			{
				return defaultValue;
			}
			if (value2.ToUpper() == GLOBAL_OPTION || Utility.IsNullOrWhiteSpace(entry.Value))
			{
				return parentEntry.Value(defaultValue);
			}
			return (T)converter.ConvertToObject(value2, typeof(T));
		}

		public override bool isDefault()
		{
			return entry.Value.ToUpper() == DEFAULT_OPTION;
		}

		public virtual bool isGlobal()
		{
			if (!(entry.Value.ToUpper() == GLOBAL_OPTION))
			{
				return Utility.IsNullOrWhiteSpace(entry.Value);
			}
			return true;
		}

		public override bool isUnset()
		{
			if (!isDefault())
			{
				if (isGlobal())
				{
					if (!parentEntry.isDefault())
					{
						if (parentEntry is GlobalConfigEntry<T>)
						{
							return (parentEntry as GlobalConfigEntry<T>).isUnset();
						}
						return false;
					}
					return true;
				}
				return false;
			}
			return true;
		}

		public override bool isLocallySet()
		{
			if (!isDefault())
			{
				return !isGlobal();
			}
			return false;
		}

		public override bool Set(ref T value)
		{
			T val = Value(value);
			bool result = value.Equals(val);
			if (!isDefault())
			{
				value = val;
			}
			return result;
		}

		public override bool hasDefault()
		{
			return true;
		}

		public override string DefaultString()
		{
			return converter.ConvertToString(defaultValue, typeof(T));
		}

		public override void setDefaultValue(T value)
		{
			defaultValue = value;
		}

		public override T DefaultValue()
		{
			return defaultValue;
		}
	}
	public class DefaultableConfigEntry<T> : CustomEntry<T>
	{
		public static readonly string DEFAULT_OPTION = "DEFAULT";

		private ConfigEntry<string> entry;

		private T defaultValue;

		private TypeConverter converter;

		public DefaultableConfigEntry(ConfigEntry<string> entry, T defaultValue, TypeConverter converter)
		{
			this.entry = entry;
			this.defaultValue = defaultValue;
			this.converter = converter;
			if (isDefault())
			{
				entry.Value = "";
			}
		}

		public override T Value(T value)
		{
			string value2 = entry.Value;
			if (value2.ToUpper() == DEFAULT_OPTION || Utility.IsNullOrWhiteSpace(value2))
			{
				return defaultValue;
			}
			return (T)converter.ConvertToObject(value2, typeof(T));
		}

		public override bool isDefault()
		{
			if (!(entry.Value.ToUpper() == DEFAULT_OPTION))
			{
				return Utility.IsNullOrWhiteSpace(entry.Value);
			}
			return true;
		}

		public override bool Set(ref T value)
		{
			T val = Value(value);
			bool result = value.Equals(val);
			if (!isDefault())
			{
				value = val;
			}
			return result;
		}

		public override bool hasDefault()
		{
			return true;
		}

		public override string DefaultString()
		{
			return converter.ConvertToString(defaultValue, typeof(T));
		}

		public override void setDefaultValue(T value)
		{
			defaultValue = value;
		}

		public override T DefaultValue()
		{
			return defaultValue;
		}
	}
	public class NonDefaultableConfigEntry<T> : CustomEntry<T>
	{
		public static readonly string DEFAULT_OPTION = "DEFAULT";

		private ConfigEntry<string> entry;

		private TypeConverter converter;

		public NonDefaultableConfigEntry(ConfigEntry<string> entry, TypeConverter converter)
		{
			this.entry = entry;
			this.converter = converter;
			if (isDefault())
			{
				entry.Value = "";
			}
		}

		public override T Value(T defaultValue)
		{
			string value = entry.Value;
			if (value.ToUpper() == DEFAULT_OPTION || Utility.IsNullOrWhiteSpace(value))
			{
				return defaultValue;
			}
			return (T)converter.ConvertToObject(value, typeof(T));
		}

		public override bool isDefault()
		{
			if (!(entry.Value.ToUpper() == DEFAULT_OPTION))
			{
				return Utility.IsNullOrWhiteSpace(entry.Value);
			}
			return true;
		}

		public override bool Set(ref T value)
		{
			value = Value(value);
			return isDefault();
		}
	}
	public static class SelectableLevelCache
	{
		internal class SelectableLevelIdentifier
		{
			internal static HashSet<Guid> usedGuids = new HashSet<Guid>();

			internal WeakReference level { get; set; }

			internal string name { get; set; }

			internal Guid guid { get; set; }

			internal SelectableLevelIdentifier(SelectableLevel level)
			{
				this.level = new WeakReference(level);
				name = ((Object)level).name;
				do
				{
					guid = Guid.NewGuid();
				}
				while (usedGuids.Contains(guid));
				usedGuids.Add(guid);
			}

			~SelectableLevelIdentifier()
			{
				usedGuids.Remove(guid);
			}
		}

		private static List<SelectableLevelIdentifier> levels = new List<SelectableLevelIdentifier>();

		public static Guid getGuid(this SelectableLevel level)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			foreach (SelectableLevelIdentifier level2 in levels)
			{
				SelectableLevel val = (SelectableLevel)level2.level.Target;
				if ((Object)(object)val == (Object)(object)level)
				{
					return level2.guid;
				}
				if (level2.name == ((Object)level).name)
				{
					if ((Object)(object)val == (Object)null)
					{
						level2.level = new WeakReference(level);
					}
					return level2.guid;
				}
			}
			SelectableLevelIdentifier selectableLevelIdentifier = new SelectableLevelIdentifier(level);
			levels.Add(selectableLevelIdentifier);
			return selectableLevelIdentifier.guid;
		}

		internal static void cleanIdentifiers()
		{
			levels.RemoveAll((SelectableLevelIdentifier id) => !id.level.IsAlive);
		}

		internal static SelectableLevel getLevel(this Guid guid)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			return (SelectableLevel)levels.Find((SelectableLevelIdentifier id) => id.guid == guid).level.Target;
		}

		internal static string getLevelName(this Guid guid)
		{
			return levels.Find((SelectableLevelIdentifier id) => id.guid == guid).name;
		}

		internal static string getOriginalLevelName(this SelectableLevel level)
		{
			return level.getGuid().getLevelName();
		}

		internal static Optional<Guid> getGuid(string name)
		{
			foreach (SelectableLevelIdentifier level in levels)
			{
				if (level.name == name)
				{
					return new Optional<Guid>(level.guid);
				}
			}
			return Optional<Guid>.Empty();
		}
	}
	public interface IWeightConfigurable
	{
		CustomEntry<float> weight { get; set; }
	}
	public class GlobalItemScrapConfiguration : GlobalItemConfiguration, IScrappableConfiguration
	{
		public CustomEntry<int> minValue { get; set; } = new EmptyEntry<int>();


		public CustomEntry<int> maxValue { get; set; } = new EmptyEntry<int>();


		public GlobalItemScrapConfiguration(Item item)
			: base(item)
		{
		}

		public override bool isDefault()
		{
			if (base.isDefault() && minValue.isDefault())
			{
				return maxValue.isDefault();
			}
			return false;
		}

		public override bool isSet()
		{
			if (!base.isSet() && !minValue.isLocallySet())
			{
				return maxValue.isLocallySet();
			}
			return true;
		}
	}
	public class GlobalItemConfiguration : ItemConfiguration, IWeightConfigurable
	{
		public CustomEntry<float> weight { get; set; } = new EmptyEntry<float>();


		public GlobalItemConfiguration(Item item)
			: base(item)
		{
			base.item = item;
		}

		public override bool isDefault()
		{
			if (base.isDefault())
			{
				return weight.isDefault();
			}
			return false;
		}

		public override bool isSet()
		{
			if (!base.isSet())
			{
				return weight.isLocallySet();
			}
			return true;
		}
	}
	public class GlobalConfiguration : ISettable, IDefaultable
	{
		public static readonly string ENEMY_CFG_NAME = "Enemies.cfg";

		public static readonly string DAYTIME_ENEMY_CFG_NAME = "DaytimeEnemies.cfg";

		public static readonly string OUTSIDE_ENEMY_CFG_NAME = "OutsideEnemies.cfg";

		public static readonly string SCRAP_CFG_NAME = "Scrap.cfg";

		public static readonly string DUNGEON_GENERATION_CFG_NAME = "DungeonGeneration.cfg";

		public static readonly string TRAP_CFG_NAME = "Traps.cfg";

		public static readonly string PRICES_CFG_NAME = "Prices.cfg";

		public static readonly string FILES_CFG_NAME = "Configuration.cfg";

		public ConfigEntry<bool> useLegacy;

		public EnemyConfiguration<EnemyTypeConfiguration> enemyConfiguration { get; private set; } = new EnemyConfiguration<EnemyTypeConfiguration>();


		public EnemyConfiguration<DaytimeEnemyTypeConfiguration> daytimeEnemyConfiguration { get; private set; } = new EnemyConfiguration<DaytimeEnemyTypeConfiguration>();


		public OutsideEnemyConfiguration<EnemyTypeConfiguration> outsideEnemyConfiguration { get; private set; } = new OutsideEnemyConfiguration<EnemyTypeConfiguration>();


		public ScrapConfiguration scrapConfiguration { get; private set; } = new ScrapConfiguration();


		public DungeonGenerationConfiguration dungeonConfiguration { get; private set; } = new DungeonGenerationConfiguration();


		public TrapConfiguration trapConfiguration { get; private set; } = new TrapConfiguration();


		public PriceConfiguration priceConfiguration { get; private set; } = new PriceConfiguration();


		public Dictionary<Guid, LevelConfiguration> levelConfigs { get; } = new Dictionary<Guid, LevelConfiguration>();


		public virtual bool isDefault()
		{
			if (enemyConfiguration.isDefault() && daytimeEnemyConfiguration.isDefault() && outsideEnemyConfiguration.isDefault() && scrapConfiguration.isDefault() && dungeonConfiguration.isDefault() && trapConfiguration.isDefault())
			{
				return priceConfiguration.isDefault();
			}
			return false;
		}

		public virtual bool isSet()
		{
			if (!enemyConfiguration.isSet() && !daytimeEnemyConfiguration.isSet() && !outsideEnemyConfiguration.isSet() && !scrapConfiguration.isSet() && !dungeonConfiguration.isSet() && !trapConfiguration.isSet())
			{
				return priceConfiguration.isSet();
			}
			return true;
		}

		public virtual bool isAnySet()
		{
			if (!levelConfigs.isSet())
			{
				return isSet();
			}
			return true;
		}

		public GlobalConfiguration(GlobalInformation globalInfo)
		{
			instantiateConfigs(globalInfo);
		}

		private void instantiateConfigs(GlobalInformation globalInfo)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			ConfigFile val = new ConfigFile(Path.Combine(globalInfo.configSaveDir, FILES_CFG_NAME), true);
			val.SaveOnConfigSet = false;
			useLegacy = val.Bind<bool>("Advanced", "UseLegacy", false, "Whether or not to use the old configuration handling system. This is for if you do not want to use the web UI. If you choose to use the web UI, then you should not enable any of the configuration files below.");
			instantiateEnemyConfigs(globalInfo, val);
			instantiateScrapConfigs(globalInfo, val);
			instantiateDungeonConfigs(globalInfo, val);
			instantiateTrapConfigs(globalInfo, val);
			instantiatePriceConfigs(globalInfo, val);
			instantiateMoonConfig(globalInfo, val);
			val.SaveOnConfigSet = true;
			val.Save();
		}

		private void instantiateMoonConfig(GlobalInformation globalInfo, ConfigFile fileConfigFile)
		{
			foreach (Guid key in globalInfo.allSelectableLevels.Keys)
			{
				SelectableLevel level = key.getLevel();
				string levelSaveDir = Path.Combine(globalInfo.moonSaveDir, ((Object)level).name.getFileFriendlyName());
				LevelInformation levelInfo = new LevelInformation(this, globalInfo, level, levelSaveDir, fileConfigFile);
				levelConfigs.Add(key, new LevelConfiguration(levelInfo));
			}
		}

		private void instantiateEnemyConfigs(GlobalInformation globalInfo, ConfigFile fileConfigFile)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			//IL_0402: Unknown result type (might be due to invalid IL or missing references)
			//IL_0409: Expected O, but got Unknown
			//IL_077b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0782: Expected O, but got Unknown
			enemyConfiguration.enabled = fileConfigFile.Bind<bool>("Global", "EnemiesEnabled", false, "Whether or not to enable the global config for all inside enemies");
			ConfigFile val = null;
			if (enemyConfiguration.enabled.Value)
			{
				val = new ConfigFile(Path.Combine(globalInfo.configSaveDir, ENEMY_CFG_NAME), true);
				val.SaveOnConfigSet = false;
			}
			enemyConfiguration.maxPowerCount = BindEmptyOrNonDefaultable<int>(val, "General", "MaxPowerCount", "Maximum total power level allowed for inside enemies.\nLeave blank or DEFAULT to use the moon's default rarity.");
			enemyConfiguration.spawnAmountCurve = BindEmptyOrNonDefaultable<AnimationCurve>(val, "General", "SpawnAmountCurve", "How many enemies can spawn enemy as the day progresses. (Key ranges from 0-1 ).\nLeave blank or DEFAULT to use the moon's default rarity.");
			enemyConfiguration.spawnAmountRange = BindEmptyOrNonDefaultable<float>(val, "General", "SpawnAmountRange", "How many more/less enemies can spawn. A spawn range of 3 means there can be -/+3 enemies. This value cannot be less than half the total amount of days for the quota rounded down, otherwise the game will throw an error and not spawn any enemies.\nLeave blank or DEFAULT to use the moon's default rarity.");
			foreach (EnemyType allEnemyType in globalInfo.allEnemyTypes)
			{
				EnemyTypeConfiguration enemyTypeConfiguration = new EnemyTypeConfiguration(allEnemyType);
				string tableName = "EnemyTypes." + ((Object)allEnemyType).name.getTomlFriendlyName();
				enemyTypeConfiguration.rarity = BindEmptyOrNonDefaultable<int>(val, "Rarity", ((Object)allEnemyType).name.getTomlFriendlyName(), "Rarity of a(n) " + allEnemyType.enemyName + " spawning relative to the total rarity of all other enemy types combined. A higher rarity increases the chance that the enemy will spawn.\nLeave blank or DEFAULT to use the moon's default rarity.");
				enemyTypeConfiguration.maxEnemyCount = BindEmptyOrDefaultable(val, tableName, "MaxEnemyCount", allEnemyType.MaxCount, "Maximum amount of " + allEnemyType.enemyName + "s allowed at once.\nAlternate values: DEFAULT");
				enemyTypeConfiguration.powerLevel = BindEmptyOrDefaultable(val, tableName, "PowerLevel", allEnemyType.PowerLevel, "How much a single " + allEnemyType.enemyName + " contributes to the maximum power level\nAlternate values: DEFAULT");
				enemyTypeConfiguration.spawnCurve = BindEmptyOrDefaultable<AnimationCurve>(val, tableName, "SpawnChanceCurve", allEnemyType.probabilityCurve, "How likely a(n) " + allEnemyType.enemyName + " is to spawn as the day progresses. (Key ranges from 0-1 )\nAlternate values: DEFAULT");
				enemyTypeConfiguration.stunTimeMultiplier = BindEmptyOrDefaultable(val, tableName, "StunTimeMultiplier", allEnemyType.stunTimeMultiplier, "The multiplier for how long a(n) " + allEnemyType.enemyName + " can be stunned\nAlternate values: DEFAULT");
				enemyTypeConfiguration.doorSpeedMultiplier = BindEmptyOrDefaultable(val, tableName, "DoorSpeedMultiplier", allEnemyType.doorSpeedMultiplier, "The multiplier for how long it takes a(n) " + allEnemyType.enemyName + " to open a door\nAlternate values: DEFAULT");
				enemyTypeConfiguration.stunGameDifficultyMultiplier = BindEmptyOrDefaultable(val, tableName, "StunGameDifficultyMultiplier", allEnemyType.stunGameDifficultyMultiplier, "I don't know what this does\nAlternate values: DEFAULT");
				enemyTypeConfiguration.stunnable = BindEmptyOrDefaultable(val, tableName, "Stunnable", allEnemyType.canBeStunned, "Whether or not a(n) " + allEnemyType.enemyName + " can be stunned\nAlternate values: DEFAULT");
				enemyTypeConfiguration.killable = BindEmptyOrDefaultable(val, tableName, "Killable", allEnemyType.canDie, "Whether or not a(n) " + allEnemyType.enemyName + " can die\nAlternate values: DEFAULT");
				enemyTypeConfiguration.enemyHp = BindEmptyOrDefaultable(val, tableName, "EnemyHp", ((Object)(object)allEnemyType.enemyPrefab != (Object)null) ? allEnemyType.enemyPrefab.GetComponent<EnemyAI>().enemyHP : 3, "The initial amount of health a(n) " + allEnemyType.enemyName + " has\nAlternate values: DEFAULT");
				enemyTypeConfiguration.spawnGroupCount = BindEmptyOrDefaultable(val, tableName, "SpawnInGroupsOf", allEnemyType.spawnInGroupsOf, "How many " + allEnemyType.enemyName + "s this tries to spawn at once\nAlternate values: DEFAULT");
				enemyTypeConfiguration.spawnFalloffCurve = BindEmptyOrDefaultable<AnimationCurve>(val, tableName, "SpawnFalloffCurve", allEnemyType.numberSpawnedFalloff, "The spawning curve multiplier of how less/more likely a(n) " + allEnemyType.enemyName + " is to spawn based on how many already have been spawned. (Key is number of " + allEnemyType.enemyName + "s/10).\nAlternate values: DEFAULT");
				enemyTypeConfiguration.useSpawnFalloff = BindEmptyOrDefaultable(val, tableName, "UseSpawnFalloff", allEnemyType.useNumberSpawnedFalloff, "Whether or not to modify spawn rates based on how many existing " + allEnemyType.enemyName + "s there are inside.\nAlternate values: DEFAULT");
				enemyConfiguration.enemyTypes.Add(allEnemyType, enemyTypeConfiguration);
			}
			if (enemyConfiguration.enabled.Value)
			{
				val.SaveOnConfigSet = true;
				val.Save();
			}
			daytimeEnemyConfiguration.enabled = fileConfigFile.Bind<bool>("Global", "DaytimeEnemiesEnabled", false, "Whether or not to enable the global config for all daytime enemies. Typically enemies like manticoils, locusts, etc.");
			ConfigFile val2 = null;
			if (daytimeEnemyConfiguration.enabled.Value)
			{
				val2 = new ConfigFile(Path.Combine(globalInfo.configSaveDir, DAYTIME_ENEMY_CFG_NAME), true);
				val2.SaveOnConfigSet = false;
			}
			daytimeEnemyConfiguration.maxPowerCount = BindEmptyOrNonDefaultable<int>(val2, "General", "MaxPowerCount", "Maximum total power level allowed for inside enemies.\nLeave blank or DEFAULT to use the moon's default rarity.");
			daytimeEnemyConfiguration.spawnAmountCurve = BindEmptyOrNonDefaultable<AnimationCurve>(val2, "General", "SpawnAmountCurve", "How many enemies can spawn enemy as the day progresses. (Key ranges from 0-1 ).\nLeave blank or DEFAULT to use the moon's default rarity.");
			daytimeEnemyConfiguration.spawnAmountRange = BindEmptyOrNonDefaultable<float>(val2, "General", "SpawnAmountRange", "How many more/less enemies can spawn. A spawn range of 3 means there can be -/+3 enemies. This value cannot be less than half the total amount of days for the quota rounded down, otherwise the game will throw an error and not spawn any enemies.\nLeave blank or DEFAULT to use the moon's default rarity.");
			foreach (EnemyType allEnemyType2 in globalInfo.allEnemyTypes)
			{
				DaytimeEnemyTypeConfiguration daytimeEnemyTypeConfiguration = new DaytimeEnemyTypeConfiguration(allEnemyType2);
				string tableName2 = "EnemyTypes." + ((Object)allEnemyType2).name.getTomlFriendlyName();
				daytimeEnemyTypeConfiguration.rarity = BindEmptyOrNonDefaultable<int>(val2, "Rarity", ((Object)allEnemyType2).name.getTomlFriendlyName(), "Rarity of a(n) " + allEnemyType2.enemyName + " spawning relative to the total rarity of all other enemy types combined. A higher rarity increases the chance that the enemy will spawn.\nLeave blank or DEFAULT to use the moon's default rarity.");
				daytimeEnemyTypeConfiguration.maxEnemyCount = BindEmptyOrDefaultable(val2, tableName2, "MaxEnemyCount", allEnemyType2.MaxCount, "Maximum amount of " + allEnemyType2.enemyName + "s allowed at once\nAlternate values: DEFAULT");
				daytimeEnemyTypeConfiguration.powerLevel = BindEmptyOrDefaultable(val2, tableName2, "PowerLevel", allEnemyType2.PowerLevel, "How much a(n) " + allEnemyType2.enemyName + " contributes to the maximum power level\nAlternate values: DEFAULT");
				daytimeEnemyTypeConfiguration.spawnCurve = BindEmptyOrDefaultable<AnimationCurve>(val2, tableName2, "SpawnChanceCurve", allEnemyType2.probabilityCurve, "How likely a(n) " + allEnemyType2.enemyName + " is to spawn as the day progresses. (Key ranges from 0-1 )\nAlternate values: DEFAULT");
				daytimeEnemyTypeConfiguration.stunTimeMultiplier = BindEmptyOrDefaultable(val2, tableName2, "StunTimeMultiplier", allEnemyType2.stunTimeMultiplier, "The multiplier for how long a(n) " + allEnemyType2.enemyName + " can be stunned\nAlternate values: DEFAULT");
				daytimeEnemyTypeConfiguration.doorSpeedMultiplier = BindEmptyOrDefaultable(val2, tableName2, "DoorSpeedMultiplier", allEnemyType2.doorSpeedMultiplier, "The multiplier for how long it takes a(n) " + allEnemyType2.enemyName + " to open a door\nAlternate values: DEFAULT");
				daytimeEnemyTypeConfiguration.stunGameDifficultyMultiplier = BindEmptyOrDefaultable(val2, tableName2, "StunGameDifficultyMultiplier", allEnemyType2.stunGameDifficultyMultiplier, "I don't know what this does\nAlternate values: DEFAULT");
				daytimeEnemyTypeConfiguration.stunnable = BindEmptyOrDefaultable(val2, tableName2, "Stunnable", allEnemyType2.canBeStunned, "Whether or not a(n) " + allEnemyType2.enemyName + " can be stunned\nAlternate values: DEFAULT");
				daytimeEnemyTypeConfiguration.killable = BindEmptyOrDefaultable(val2, tableName2, "Killable", allEnemyType2.canDie, "Whether or not a(n) " + allEnemyType2.enemyName + " can die\nAlternate values: DEFAULT");
				daytimeEnemyTypeConfiguration.enemyHp = BindEmptyOrDefaultable(val2, tableName2, "EnemyHp", ((Object)(object)allEnemyType2.enemyPrefab != (Object)null) ? allEnemyType2.enemyPrefab.GetComponent<EnemyAI>().enemyHP : 3, "The initial amount of health a(n) " + allEnemyType2.enemyName + " has\nAlternate values: DEFAULT");
				daytimeEnemyTypeConfiguration.spawnGroupCount = BindEmptyOrDefaultable(val2, tableName2, "SpawnInGroupsOf", allEnemyType2.spawnInGroupsOf, "How many " + allEnemyType2.enemyName + "s this tries to spawn at once\nAlternate values: DEFAULT");
				daytimeEnemyConfiguration.enemyTypes.Add(allEnemyType2, daytimeEnemyTypeConfiguration);
			}
			if (daytimeEnemyConfiguration.enabled.Value)
			{
				val2.SaveOnConfigSet = true;
				val2.Save();
			}
			outsideEnemyConfiguration.enabled = fileConfigFile.Bind<bool>("Global", "OutsideEnemiesEnabled", false, "Whether or not to enable the global config for all outside enemies. Typically eyeless dogs, forest giants, etc.");
			ConfigFile val3 = null;
			if (outsideEnemyConfiguration.enabled.Value)
			{
				val3 = new ConfigFile(Path.Combine(globalInfo.configSaveDir, OUTSIDE_ENEMY_CFG_NAME), true);
				val3.SaveOnConfigSet = false;
			}
			outsideEnemyConfiguration.maxPowerCount = BindEmptyOrNonDefaultable<int>(val3, "General", "MaxPowerCount", "Maximum total power level allowed for inside enemies.\nLeave blank or DEFAULT to use the moon's default rarity.");
			outsideEnemyConfiguration.spawnAmountCurve = BindEmptyOrNonDefaultable<AnimationCurve>(val3, "General", "SpawnAmountCurve", "How many enemies can spawn enemy as the day progresses. (Key ranges from 0-1 ).\nLeave blank or DEFAULT to use the moon's default rarity.");
			foreach (EnemyType allEnemyType3 in globalInfo.allEnemyTypes)
			{
				EnemyTypeConfiguration enemyTypeConfiguration2 = new EnemyTypeConfiguration(allEnemyType3);
				string tableName3 = "EnemyTypes." + ((Object)allEnemyType3).name.getTomlFriendlyName();
				enemyTypeConfiguration2.rarity = BindEmptyOrNonDefaultable<int>(val3, "Rarity", ((Object)allEnemyType3).name.getTomlFriendlyName(), "Rarity of a(n) " + allEnemyType3.enemyName + " spawning relative to the total rarity of all other enemy types combined. A higher rarity increases the chance that the enemy will spawn.\nLeave blank or DEFAULT to use the moon's default rarity.");
				enemyTypeConfiguration2.maxEnemyCount = BindEmptyOrDefaultable(val3, tableName3, "MaxEnemyCount", allEnemyType3.MaxCount, "Maximum amount of " + allEnemyType3.enemyName + "s allowed at once\nAlternate values: DEFAULT");
				enemyTypeConfiguration2.powerLevel = BindEmptyOrDefaultable(val3, tableName3, "PowerLevel", allEnemyType3.PowerLevel, "How much a(n) " + allEnemyType3.enemyName + " contributes to the maximum power level\nAlternate values: DEFAULT");
				enemyTypeConfiguration2.spawnCurve = BindEmptyOrDefaultable<AnimationCurve>(val3, tableName3, "SpawnChanceCurve", allEnemyType3.probabilityCurve, "How likely a(n) " + allEnemyType3.enemyName + " is to spawn as the day progresses, (Key ranges from 0-1)\nAlternate values: DEFAULT");
				enemyTypeConfiguration2.stunTimeMultiplier = BindEmptyOrDefaultable(val3, tableName3, "StunTimeMultiplier", allEnemyType3.stunTimeMultiplier, "The multiplier for how long a(n) " + allEnemyType3.enemyName + " can be stunned\nAlternate values: DEFAULT");
				enemyTypeConfiguration2.doorSpeedMultiplier = BindEmptyOrDefaultable(val3, tableName3, "DoorSpeedMultiplier", allEnemyType3.doorSpeedMultiplier, "The multiplier for how long it takes a(n) " + allEnemyType3.enemyName + " to open a door\nAlternate values: DEFAULT");
				enemyTypeConfiguration2.stunGameDifficultyMultiplier = BindEmptyOrDefaultable(val3, tableName3, "StunGameDifficultyMultiplier", allEnemyType3.stunGameDifficultyMultiplier, "I don't know what this does\nAlternate values: DEFAULT");
				enemyTypeConfiguration2.stunnable = BindEmptyOrDefaultable(val3, tableName3, "Stunnable", allEnemyType3.canBeStunned, "Whether or not a(n) " + allEnemyType3.enemyName + " can be stunned\nAlternate values: DEFAULT");
				enemyTypeConfiguration2.killable = BindEmptyOrDefaultable(val3, tableName3, "Killable", allEnemyType3.canDie, "Whether or not a(n) " + allEnemyType3.enemyName + " can die\nAlternate values: DEFAULT");
				enemyTypeConfiguration2.enemyHp = BindEmptyOrDefaultable(val3, tableName3, "EnemyHp", ((Object)(object)allEnemyType3.enemyPrefab != (Object)null) ? allEnemyType3.enemyPrefab.GetComponent<EnemyAI>().enemyHP : 3, "The initial amount of health a(n) " + allEnemyType3.enemyName + " has\nAlternate values: DEFAULT");
				enemyTypeConfiguration2.spawnGroupCount = BindEmptyOrDefaultable(val3, tableName3, "SpawnInGroupsOf", allEnemyType3.spawnInGroupsOf, "How many " + allEnemyType3.enemyName + "s this tries to spawn at once\nAlternate values: DEFAULT");
				enemyTypeConfiguration2.spawnFalloffCurve = BindEmptyOrDefaultable<AnimationCurve>(val3, tableName3, "SpawnFalloffCurve", allEnemyType3.numberSpawnedFalloff, "The spawning curve multiplier of how less/more likely a(n) " + allEnemyType3.enemyName + " is to spawn based on how many have already been spawned. (Key is number of " + allEnemyType3.enemyName + "s/10)\nAlternate values: DEFAULT");
				enemyTypeConfiguration2.useSpawnFalloff = BindEmptyOrDefaultable(val3, tableName3, "UseSpawnFalloff", allEnemyType3.useNumberSpawnedFalloff, "Whether or not to modify spawn rates based on how many existing " + allEnemyType3.enemyName + "s there are\nAlternate values: DEFAULT");
				outsideEnemyConfiguration.enemyTypes.Add(allEnemyType3, enemyTypeConfiguration2);
			}
			if (outsideEnemyConfiguration.enabled.Value)
			{
				val3.SaveOnConfigSet = true;
				val3.Save();
			}
		}

		private void instantiateScrapConfigs(GlobalInformation globalInfo, ConfigFile fileConfigFile)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			scrapConfiguration.enabled = fileConfigFile.Bind<bool>("Global", "ScrapEnabled", false, "Whether or not to enable the global config for all scrap generation.");
			ConfigFile val = null;
			if (scrapConfiguration.enabled.Value)
			{
				val = new ConfigFile(Path.Combine(globalInfo.configSaveDir, SCRAP_CFG_NAME), true);
				val.SaveOnConfigSet = false;
			}
			scrapConfiguration.minScrap = BindEmptyOrNonDefaultable<int>(val, "General", "MinScrapCount", "Minimum total number of scrap generated in the level, inclusive.\nLeave blank or DEFAULT to use the moon's default min scrap count.");
			scrapConfiguration.maxScrap = BindEmptyOrNonDefaultable<int>(val, "General", "MaxScrapCount", "Maximum total number of scrap generated in the level, exclusive.\nLeave blank or DEFAULT to use the moon's default max scrap count.");
			scrapConfiguration.scrapAmountMultiplier = BindEmptyOrDefaultable(val, "General", "ScrapAmountMultiplier", globalInfo.manager.scrapAmountMultiplier, "Modifier to the total amount of scrap generated in the level.\nAlternate values: DEFAULT");
			scrapConfiguration.scrapValueMultiplier = BindEmptyOrDefaultable(val, "General", "ScrapValueMultiplier", globalInfo.manager.scrapValueMultiplier, "Modifier to the total value of scrap generated in the level.\nAlternate values: DEFAULT");
			foreach (Item allItem in globalInfo.allItems)
			{
				string tableName = "ItemType." + ((Object)allItem).name.getTomlFriendlyName();
				GlobalItemConfiguration globalItemConfiguration;
				if (allItem.isScrap)
				{
					GlobalItemConfiguration globalItemConfiguration2 = (globalItemConfiguration = new GlobalItemScrapConfiguration(allItem));
					((GlobalItemScrapConfiguration)globalItemConfiguration2).minValue = BindEmptyOrDefaultable(val, tableName, "MinValue", Math.Min(allItem.minValue, allItem.maxValue), "Minimum value of a " + allItem.itemName + ", inclusive.\nAlternate values: DEFAULT");
					((GlobalItemScrapConfiguration)globalItemConfiguration2).maxValue = BindEmptyOrDefaultable(val, tableName, "MaxValue", Math.Max(allItem.minValue, allItem.maxValue), "Maximum value of a " + allItem.itemName + ", exclusive.\nAlternate values: DEFAULT");
				}
				else
				{
					globalItemConfiguration = new GlobalItemConfiguration(allItem);
				}
				globalItemConfiguration.rarity = BindEmptyOrNonDefaultable<int>(val, "Rarity", ((Object)allItem).name.getTomlFriendlyName(), "Rarity of a(n) " + allItem.itemName + " relative to the total rarity of all other item types combined. A higher rarity increases the chance that the item will spawn.\nLeave blank or DEFAULT to use the moon's default rarity.");
				globalItemConfiguration.weight = BindEmptyOrDefaultable(val, tableName, "Weight", allItem.weight, "The weight of a(n) " + allItem.itemName + ". The in-game weight can be found by the formula: pounds = (value - 1) * 100. For example, a value of 1.18 means the object weighs 18lbs. This option can only be set in the global config.\nAlternate values: DEFAULT");
				globalItemConfiguration.conductive = BindEmptyOrDefaultable(val, tableName, "Conductive", allItem.isConductiveMetal, "Whether or not " + allItem.itemName + " is conductive(can be struck by lightning).\nAlternate values: DEFAULT");
				scrapConfiguration.items.Add(allItem, globalItemConfiguration);
			}
			if (scrapConfiguration.enabled.Value)
			{
				val.SaveOnConfigSet = true;
				val.Save();
			}
		}

		private void instantiateDungeonConfigs(GlobalInformation globalInfo, ConfigFile fileConfigFile)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			dungeonConfiguration.enabled = fileConfigFile.Bind<bool>("Global", "DungeonGenerationEnabled", false, "Whether or not to enable the global config for all dungeon generation.");
			ConfigFile val = null;
			if (dungeonConfiguration.enabled.Value)
			{
				val = new ConfigFile(Path.Combine(globalInfo.configSaveDir, DUNGEON_GENERATION_CFG_NAME), true);
				val.SaveOnConfigSet = false;
			}
			dungeonConfiguration.mapSizeMultiplier = BindEmptyOrNonDefaultable<float>(val, "General", "MapSizeMultiplier", "The multiplier to use for determining the size of the dungeon.\nAlternate values: DEFAULT");
			foreach (DungeonFlow allDungeonFlow in globalInfo.allDungeonFlows)
			{
				DungeonFlowConfiguration dungeonFlowConfiguration = new DungeonFlowConfiguration();
				dungeonFlowConfiguration.rarity = BindEmptyOrNonDefaultable<int>(val, "Rarity", ((Object)allDungeonFlow).name.getTomlFriendlyName(), "Rarity of a moon using a " + ((Object)allDungeonFlow).name + " dungeon generator as the interior. A higher rarity increases the chance that the moon will use this dungeon flow.\nLeave blank or DEFAULT to use the moon's default rarity.");
				string tableName = "DungeonFlow." + ((Object)allDungeonFlow).name.getTomlFriendlyName();
				dungeonFlowConfiguration.factorySizeMultiplier = BindEmptyOrDefaultable(val, tableName, "FactorySizeMultiplier", globalInfo.manager.mapSizeMultiplier, "Size of the dungeon when using this dungeon flow.\nLeave blank or DEFAULT to use the moon's default factory size multiplier.\nAlternate values: DEFAULT");
				dungeonConfiguration.dungeonFlowConfigurations.Add(((Object)allDungeonFlow).name, dungeonFlowConfiguration);
			}
			if (dungeonConfiguration.enabled.Value)
			{
				val.SaveOnConfigSet = true;
				val.Save();
			}
		}

		private void instantiateTrapConfigs(GlobalInformation globalInfo, ConfigFile fileConfigFile)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			trapConfiguration.enabled = fileConfigFile.Bind<bool>("Global", "TrapEnabled", false, "Whether or not to enable the global config for all trap generation");
			ConfigFile val = null;
			if (trapConfiguration.enabled.Value)
			{
				val = new ConfigFile(Path.Combine(globalInfo.configSaveDir, TRAP_CFG_NAME), true);
				val.SaveOnConfigSet = false;
			}
			foreach (DirectionalSpawnableMapObject allSpawnableMapObject in globalInfo.allSpawnableMapObjects)
			{
				SpawnableMapObjectConfiguration spawnableMapObjectConfiguration = new SpawnableMapObjectConfiguration(allSpawnableMapObject);
				string tableName = "Trap." + ((Object)allSpawnableMapObject.obj).name.getTomlFriendlyName();
				string name = allSpawnableMapObject.getName();
				spawnableMapObjectConfiguration.numberToSpawn = BindEmptyOrNonDefaultable<AnimationCurve>(val, tableName, "SpawnAmount", "The amount of " + name + " to spawn. 'Y Axis is the amount to be spawned; X axis should be from 0 to 1 and is randomly picked from.'\nAlternate values: DEFAULT");
				trapConfiguration.traps.Add(allSpawnableMapObject.obj, spawnableMapObjectConfiguration);
			}
			if (trapConfiguration.enabled.Value)
			{
				val.SaveOnConfigSet = true;
				val.Save();
			}
		}

		private void instantiatePriceConfigs(GlobalInformation globalInfo, ConfigFile fileConfigFile)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			priceConfiguration.enabled = fileConfigFile.Bind<bool>("Global", "PriceEnabled", false, "Whether or not to enable the global config for all moon pricing");
			ConfigFile val = null;
			if (priceConfiguration.enabled.Value)
			{
				val = new ConfigFile(Path.Combine(globalInfo.configSaveDir, PRICES_CFG_NAME), true);
				priceConfiguration.file = val;
				val.SaveOnConfigSet = false;
			}
			List<Guid> list = globalInfo.allSelectableLevels.Keys.ToList();
			list.Sort(GlobalInformation.GUID_LEVEL_SORTER);
			foreach (Guid item in list)
			{
				if (globalInfo.allSelectableLevels.TryGetValue(item, out var value))
				{
					SelectableLevel level = item.getLevel();
					MoonPriceConfiguration moonPriceConfiguration = new MoonPriceConfiguration(item);
					string tableName = "Level." + ((Object)level).name.getTomlFriendlyName();
					moonPriceConfiguration.price = BindEmptyOrDefaultable(val, tableName, "TravelCost", value.price, "How many credits it costs to travel to " + ((Object)level).name + "(" + level.PlanetName + ").\nAlternate values: DEFAULT");
					priceConfiguration.moons.Add(item, moonPriceConfiguration);
				}
			}
			if (priceConfiguration.enabled.Value)
			{
				val.SaveOnConfigSet = true;
				val.Save();
			}
		}

		private static CustomEntry<T> BindEmptyOrDefaultable<T>(ConfigFile file, string tableName, string name, T defaultValue, string desc)
		{
			if (file == null)
			{
				return new EmptyEntry<T>(defaultValue);
			}
			return file.BindDefaultable(tableName, name, defaultValue, desc);
		}

		private static CustomEntry<T> BindEmptyOrNonDefaultable<T>(ConfigFile file, string tableName, string name, string desc)
		{
			if (file == null)
			{
				return new EmptyEntry<T>();
			}
			return file.BindNonDefaultable<T>(tableName, name, desc);
		}
	}
	public static class ConfigEntryExtension
	{
		public static GlobalConfigEntry<T> BindGlobal<T>(this ConfigFile file, CustomEntry<T> parent, string tablename, string name, T defaultValue, string description)
		{
			TypeConverter converter = TomlTypeConverter.GetConverter(typeof(T));
			ConfigEntry<string> val = file.Bind<string>(tablename, name, GlobalConfigEntry<T>.GLOBAL_OPTION, description);
			GlobalConfigEntry<T> globalConfigEntry = new GlobalConfigEntry<T>(parent, val, defaultValue, converter);
			ConfigEntryBasePatch.entries.Add((ConfigEntryBase)(object)val, globalConfigEntry);
			return globalConfigEntry;
		}

		public static DefaultableConfigEntry<T> BindDefaultable<T>(this ConfigFile file, string tablename, string name, T defaultValue, string description)
		{
			TypeConverter converter = TomlTypeConverter.GetConverter(typeof(T));
			ConfigEntry<string> val = file.Bind<string>(tablename, name, DefaultableConfigEntry<T>.DEFAULT_OPTION, description);
			DefaultableConfigEntry<T> defaultableConfigEntry = new DefaultableConfigEntry<T>(val, defaultValue, converter);
			ConfigEntryBasePatch.entries.Add((ConfigEntryBase)(object)val, defaultableConfigEntry);
			return defaultableConfigEntry;
		}

		public static NonDefaultableConfigEntry<T> BindNonDefaultable<T>(this ConfigFile file, string tablename, string name, string description)
		{
			TypeConverter converter = TomlTypeConverter.GetConverter(typeof(T));
			ConfigEntry<string> val = file.Bind<string>(tablename, name, NonDefaultableConfigEntry<T>.DEFAULT_OPTION, description);
			NonDefaultableConfigEntry<T> nonDefaultableConfigEntry = new NonDefaultableConfigEntry<T>(val, converter);
			ConfigEntryBasePatch.entries.Add((ConfigEntryBase)(object)val, nonDefaultableConfigEntry);
			return nonDefaultableConfigEntry;
		}
	}
	public class DirectionalSpawnableMapObject
	{
		public GameObject obj;

		public bool faceAwayFromWall;

		public DirectionalSpawnableMapObject(GameObject obj, bool faceAwayFromWall)
		{
			this.obj = obj;
			this.faceAwayFromWall = faceAwayFromWall;
		}

		public string getName()
		{
			ScanNodeProperties componentInChildren = obj.GetComponentInChildren<ScanNodeProperties>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				return componentInChildren.headerText;
			}
			return ((Object)obj).name;
		}

		public string getDescription()
		{
			ScanNodeProperties componentInChildren = obj.GetComponentInChildren<ScanNodeProperties>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				return componentInChildren.subText;
			}
			return "";
		}
	}
	public class GenericLevelInformation
	{
		public int price { get; set; } = -1;

	}
	public class GlobalInformation
	{
		public static readonly Comparison<string> STRING_SORTER = (string a, string b) => (a.ToUpper() == b.ToUpper()) ? a.CompareTo(b) : a.ToUpper().CompareTo(b.ToUpper());

		public static readonly Comparison<ScriptableObject> SCRIPTABLE_OBJECT_SORTER = (ScriptableObject a, ScriptableObject b) => STRING_SORTER(((Object)a).name, ((Object)b).name);

		public static readonly Comparison<Guid> GUID_LEVEL_SORTER = delegate(Guid a, Guid b)
		{
			string levelName = a.getLevelName();
			string levelName2 = b.getLevelName();
			return STRING_SORTER(levelName, levelName2);
		};

		public RoundManager manager;

		public List<EnemyType> allEnemyTypes { get; } = new List<EnemyType>();


		public List<Item> allItems { get; } = new List<Item>();


		public List<DungeonFlow> allDungeonFlows { get; } = new List<DungeonFlow>();


		public Dictionary<Guid, GenericLevelInformation> allSelectableLevels { get; } = new Dictionary<Guid, GenericLevelInformation>();


		public List<DirectionalSpawnableMapObject> allSpawnableMapObjects { get; } = new List<DirectionalSpawnableMapObject>();


		public string configSaveDir { get; private set; }

		public string moonSaveDir { get; private set; }

		public GlobalInformation(string globalConfigSaveDir, string moonSaveDir)
		{
			configSaveDir = globalConfigSaveDir;
			this.moonSaveDir = moonSaveDir;
		}

		public void sortData()
		{
			allEnemyTypes.Sort((Comparison<EnemyType>)SCRIPTABLE_OBJECT_SORTER);
			allItems.Sort((Comparison<Item>)SCRIPTABLE_OBJECT_SORTER);
			allDungeonFlows.Sort((Comparison<DungeonFlow>)SCRIPTABLE_OBJECT_SORTER);
			allSpawnableMapObjects.Sort((DirectionalSpawnableMapObject a, DirectionalSpawnableMapObject b) => STRING_SORTER(((Object)a.obj).name, ((Object)b.obj).name));
		}
	}
	public class LevelInformation
	{
		public GlobalConfiguration masterConfig { get; private set; }

		public GlobalInformation globalInfo { get; private set; }

		public SelectableLevel level { get; private set; }

		public string levelSaveDir { get; private set; }

		public ConfigFile mainConfigFile { get; private set; }

		public LevelInformation(GlobalConfiguration config, GlobalInformation globalInfo, SelectableLevel level, string levelSaveDir, ConfigFile mainConfigFile)
		{
			masterConfig = config;
			this.globalInfo = globalInfo;
			this.level = level;
			this.levelSaveDir = levelSaveDir;
			this.mainConfigFile = mainConfigFile;
		}
	}
	public static class EnemyTypeExtension
	{
		private static Dictionary<int, TerminalNode> enemyFiles;

		static EnemyTypeExtension()
		{
			enemyFiles = new Dictionary<int, TerminalNode>();
			TerminalNode[] array = Resources.FindObjectsOfTypeAll<TerminalNode>();
			foreach (TerminalNode val in array)
			{
				enemyFiles.TryAdd(val.creatureFileID, val);
			}
		}

		public static string getFriendlyName(this EnemyType type)
		{
			GameObject enemyPrefab = type.enemyPrefab;
			if ((Object)(object)enemyPrefab != (Object)null)
			{
				ScanNodeProperties componentInChildren = enemyPrefab.GetComponentInChildren<ScanNodeProperties>();
				if ((Object)(object)componentInChildren != (Object)null && enemyFiles.TryGetValue(componentInChildren.creatureScanID, out var value))
				{
					return value.creatureName;
				}
			}
			return type.enemyName;
		}
	}
	public class ItemInformation
	{
		public int maxValue { get; set; }

		public int minValue { get; set; }

		public bool conductive { get; set; }

		public ItemInformation(int min, int max, bool conductive)
		{
			maxValue = max;
			minValue = min;
			this.conductive = conductive;
		}
	}
	public interface IEnableConfigurable
	{
		ConfigEntry<bool> enabled { get; set; }
	}
	public interface IDefaultable
	{
		bool isDefault();
	}
	public interface IValidatableConfiguration : IEnableConfigurable, ISettable, IDefaultable
	{
		bool isValid()
		{
			if (enabled.Value)
			{
				return !isDefault();
			}
			return false;
		}
	}
	public interface ISettable : IDefaultable
	{
		bool isSet()
		{
			return !isDefault();
		}
	}
	public class OutsideEnemyConfiguration<T> : IValidatableConfiguration, IEnableConfigurable, ISettable, IDefaultable where T : DaytimeEnemyTypeConfiguration
	{
		public ConfigEntry<bool> enabled { get; set; }

		public CustomEntry<int> maxPowerCount { get; set; } = new EmptyEntry<int>();


		public CustomEntry<AnimationCurve> spawnAmountCurve { get; set; } = new EmptyEntry<AnimationCurve>();


		public Dictionary<EnemyType, T> enemyTypes { get; } = new Dictionary<EnemyType, T>();


		public virtual bool isDefault()
		{
			if (enemyTypes.isDefault() && maxPowerCount.isDefault())
			{
				return spawnAmountCurve.isDefault();
			}
			return false;
		}

		public virtual bool isSet()
		{
			if (enabled.Value)
			{
				if (!enemyTypes.isSet() && !maxPowerCount.isLocallySet())
				{
					return spawnAmountCurve.isLocallySet();
				}
				return true;
			}
			return false;
		}
	}
	public class EnemyConfiguration<T> : OutsideEnemyConfiguration<T> where T : DaytimeEnemyTypeConfiguration
	{
		public CustomEntry<float> spawnAmountRange { get; set; } = new EmptyEntry<float>();


		public override bool isDefault()
		{
			if (base.isDefault())
			{
				return spawnAmountRange.isDefault();
			}
			return false;
		}

		public override bool isSet()
		{
			if (base.enabled.Value)
			{
				if (!base.isSet())
				{
					return spawnAmountRange.isLocallySet();
				}
				return true;
			}
			return false;
		}
	}
	public class DaytimeEnemyTypeConfiguration : ISettable, IDefaultable
	{
		public EnemyType type { get; protected set; }

		public CustomEntry<int> rarity { get; set; } = new EmptyEntry<int>();


		public CustomEntry<int> maxEnemyCount { get; set; } = new EmptyEntry<int>();


		public CustomEntry<float> powerLevel { get; set; } = new EmptyEntry<float>();


		public CustomEntry<int> spawnGroupCount { get; set; } = new EmptyEntry<int>();


		public CustomEntry<AnimationCurve> spawnCurve { get; set; } = new EmptyEntry<AnimationCurve>();


		public CustomEntry<float> stunTimeMultiplier { get; set; } = new EmptyEntry<float>();


		public CustomEntry<float> doorSpeedMultiplier { get; set; } = new EmptyEntry<float>();


		public CustomEntry<float> stunGameDifficultyMultiplier { get; set; } = new EmptyEntry<float>();


		public CustomEntry<bool> stunnable { get; set; } = new EmptyEntry<bool>();


		public CustomEntry<bool> killable { get; set; } = new EmptyEntry<bool>();


		public CustomEntry<int> enemyHp { get; set; } = new EmptyEntry<int>();


		public DaytimeEnemyTypeConfiguration(EnemyType type)
		{
			this.type = type;
		}

		public virtual bool isDefault()
		{
			if (rarity.isDefault() && maxEnemyCount.isDefault() && powerLevel.isDefault() && spawnCurve.isDefault() && stunTimeMultiplier.isDefault() && doorSpeedMultiplier.isDefault() && stunGameDifficultyMultiplier.isDefault() && stunnable.isDefault() && killable.isDefault())
			{
				return enemyHp.isDefault();
			}
			return false;
		}

		public virtual bool isSet()
		{
			if (!rarity.isLocallySet() && !maxEnemyCount.isLocallySet() && !powerLevel.isLocallySet() && !spawnCurve.isLocallySet() && !stunTimeMultiplier.isLocallySet() && !doorSpeedMultiplier.isLocallySet() && !stunGameDifficultyMultiplier.isLocallySet() && !stunnable.isLocallySet() && !killable.isLocallySet())
			{
				return enemyHp.isLocallySet();
			}
			return true;
		}
	}
	public class EnemyTypeConfiguration : DaytimeEnemyTypeConfiguration
	{
		public CustomEntry<AnimationCurve> spawnFalloffCurve { get; set; } = new EmptyEntry<AnimationCurve>();


		public CustomEntry<bool> useSpawnFalloff { get; set; } = new EmptyEntry<bool>();


		public EnemyTypeConfiguration(EnemyType type)
			: base(type)
		{
		}

		public override bool isDefault()
		{
			if (base.isDefault() && spawnFalloffCurve.isDefault())
			{
				return useSpawnFalloff.isDefault();
			}
			return false;
		}

		public override bool isSet()
		{
			if (!base.isSet() && !spawnFalloffCurve.isLocallySet())
			{
				return useSpawnFalloff.isLocallySet();
			}
			return true;
		}
	}
	public class ScrapConfiguration : IValidatableConfiguration, IEnableConfigurable, ISettable, IDefaultable
	{
		public ConfigEntry<bool> enabled { get; set; }

		public CustomEntry<int> minScrap { get; set; } = new EmptyEntry<int>();


		public CustomEntry<int> maxScrap { get; set; } = new EmptyEntry<int>();


		public CustomEntry<float> scrapValueMultiplier { get; set; } = new EmptyEntry<float>();


		public CustomEntry<float> scrapAmountMultiplier { get; set; } = new EmptyEntry<float>();


		public Dictionary<Item, ItemConfiguration> items { get; } = new Dictionary<Item, ItemConfiguration>();


		public virtual bool isDefault()
		{
			if (items.isDefault() && minScrap.isDefault() && maxScrap.isDefault() && scrapAmountMultiplier.isDefault())
			{
				return scrapValueMultiplier.isDefault();
			}
			return false;
		}

		public virtual bool isSet()
		{
			if (enabled.Value)
			{
				if (!minScrap.isLocallySet() && !maxScrap.isLocallySet() && !scrapAmountMultiplier.isLocallySet() && !scrapValueMultiplier.isLocallySet())
				{
					return items.isSet();
				}
				return true;
			}
			return false;
		}
	}
	public class ItemConfiguration : ISettable, IDefaultable
	{
		public Item item { get; protected set; }

		public CustomEntry<int> rarity { get; set; } = new EmptyEntry<int>();


		public CustomEntry<bool> conductive { get; set; } = new EmptyEntry<bool>();


		internal ItemConfiguration(Item item)
		{
			this.item = item;
		}

		public virtual bool isDefault()
		{
			if (rarity.isDefault())
			{
				return conductive.isDefault();
			}
			return false;
		}

		public virtual bool isSet()
		{
			if (!rarity.isLocallySet())
			{
				return conductive.isLocallySet();
			}
			return true;
		}
	}
	public interface IScrappableConfiguration
	{
		CustomEntry<int> minValue { get; set; }

		CustomEntry<int> maxValue { get; set; }
	}
	public class ScrapItemConfiguration : ItemConfiguration, IScrappableConfiguration, ISettable, IDefaultable
	{
		public CustomEntry<int> maxValue { get; set; } = new EmptyEntry<int>();


		public CustomEntry<int> minValue { get; set; } = new EmptyEntry<int>();


		internal ScrapItemConfiguration(Item item)
			: base(item)
		{
		}

		public override bool isDefault()
		{
			if (base.isDefault() && maxValue.isDefault())
			{
				return minValue.isDefault();
			}
			return false;
		}

		public override bool isSet()
		{
			if (!base.isSet() && !minValue.isLocallySet())
			{
				return maxValue.isLocallySet();
			}
			return true;
		}
	}
	public class DungeonGenerationConfiguration : IValidatableConfiguration, IEnableConfigurable, ISettable, IDefaultable
	{
		public ConfigEntry<bool> enabled { get; set; }

		public CustomEntry<float> mapSizeMultiplier { get; set; } = new EmptyEntry<float>();


		public Dictionary<string, DungeonFlowConfiguration> dungeonFlowConfigurations { get; private set; } = new Dictionary<string, DungeonFlowConfiguration>();


		public virtual bool isDefault()
		{
			if (dungeonFlowConfigurations.isDefault())
			{
				return mapSizeMultiplier.isDefault();
			}
			return false;
		}

		public virtual bool isSet()
		{
			if (enabled.Value)
			{
				if (!mapSizeMultiplier.isLocallySet())
				{
					return dungeonFlowConfigurations.isSet();
				}
				return true;
			}
			return false;
		}
	}
	public class DungeonFlowConfiguration : ISettable, IDefaultable
	{
		public CustomEntry<int> rarity { get; set; } = new EmptyEntry<int>();


		public CustomEntry<float> factorySizeMultiplier { get; set; } = new EmptyEntry<float>();


		public virtual bool isDefault()
		{
			return rarity.isDefault();
		}

		public virtual bool isSet()
		{
			if (!rarity.isLocallySet())
			{
				return factorySizeMultiplier.isLocallySet();
			}
			return true;
		}
	}
	public class TrapConfiguration : IValidatableConfiguration, IEnableConfigurable, ISettable, IDefaultable
	{
		public ConfigEntry<bool> enabled { get; set; }

		public Dictionary<GameObject, SpawnableMapObjectConfiguration> traps { get; private set; } = new Dictionary<GameObject, SpawnableMapObjectConfiguration>();


		public virtual bool isDefault()
		{
			return traps.isDefault();
		}

		public virtual bool isSet()
		{
			if (enabled.Value)
			{
				return traps.isSet();
			}
			return false;
		}
	}
	public class SpawnableMapObjectConfiguration : ISettable, IDefaultable
	{
		public DirectionalSpawnableMapObject spawnableObject { get; }

		public CustomEntry<AnimationCurve> numberToSpawn { get; set; } = new EmptyEntry<AnimationCurve>();


		public SpawnableMapObjectConfiguration(DirectionalSpawnableMapObject obj)
		{
			spawnableObject = obj;
		}

		public virtual bool isDefault()
		{
			return numberToSpawn.isDefault();
		}

		public virtual bool isSet()
		{
			return numberToSpawn.isLocallySet();
		}
	}
	public class PriceConfiguration : ISettable, IDefaultable
	{
		internal ConfigFile file { get; set; }

		public ConfigEntry<bool> enabled { get; set; }

		public Dictionary<Guid, MoonPriceConfiguration> moons { get; } = new Dictionary<Guid, MoonPriceConfiguration>();


		public virtual bool isDefault()
		{
			return moons.isDefault();
		}

		public virtual bool isSet()
		{
			if (enabled.Value)
			{
				return moons.isSet();
			}
			return false;
		}
	}
	public class MoonPriceConfiguration : ISettable, IDefaultable
	{
		public Guid guid { get; protected set; }

		public CustomEntry<int> price { get; set; } = new EmptyEntry<int>();


		public MoonPriceConfiguration(Guid name)
		{
			guid = name;
		}

		public virtual bool isDefault()
		{
			return price.isDefault();
		}

		public virtual bool isSet()
		{
			return price.isLocallySet();
		}
	}
	public class LevelConfiguration : ISettable, IDefaultable
	{
		public Guid levelGuid { get; }

		public EnemyConfiguration<EnemyTypeConfiguration> enemies { get; } = new EnemyConfiguration<EnemyTypeConfiguration>();


		public EnemyConfiguration<DaytimeEnemyTypeConfiguration> daytimeEnemies { get; } = new EnemyConfig