Decompiled source of CommunityPatchExtras v0.1.1

plugins/CommunityPatchExtras.dll

Decompiled 3 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using CommunityPatchExtras.Common;
using CommunityPatchExtras.Patches;
using HarmonyLib;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using SimpleJson;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("CommunityPatchExtras")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CommunityPatchExtras")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("0.1.1")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.1.0")]
namespace CommunityPatchExtras
{
	internal static class ConfigFileWatcher
	{
		private class WatchEntry
		{
			internal DateTime LastWriteUTC;

			internal long FileLength;

			internal Action<string> Callback;
		}

		internal class ConfigFileWatcherBehaviour : MonoBehaviour
		{
			private float nextPollTime;

			public void Update()
			{
				if (!(Time.unscaledTime < nextPollTime))
				{
					nextPollTime = Time.unscaledTime + PollInterval();
					Poll();
				}
			}

			private static float PollInterval()
			{
				if (ValConfig.ConfigPollIntervalSeconds == null)
				{
					return 30f;
				}
				return ValConfig.ConfigPollIntervalSeconds.Value;
			}

			private static void Poll()
			{
				if (WatchedFiles.Count == 0)
				{
					return;
				}
				string[] array = WatchedFiles.Keys.ToArray();
				foreach (string text in array)
				{
					if (!WatchedFiles.TryGetValue(text, out var value) || !File.Exists(text))
					{
						continue;
					}
					FileInfo fileInfo = new FileInfo(text);
					DateTime lastWriteTimeUtc = fileInfo.LastWriteTimeUtc;
					long length = fileInfo.Length;
					if (!(lastWriteTimeUtc == value.LastWriteUTC) || length != value.FileLength)
					{
						value.LastWriteUTC = lastWriteTimeUtc;
						value.FileLength = length;
						try
						{
							value.Callback?.Invoke(text);
						}
						catch (Exception ex)
						{
							Logger.LogWarning("ConfigFileWatcher callback for " + text + " threw: " + ex.Message);
						}
					}
				}
			}
		}

		private const float FallbackPollSeconds = 30f;

		private static readonly Dictionary<string, WatchEntry> WatchedFiles = new Dictionary<string, WatchEntry>(StringComparer.OrdinalIgnoreCase);

		private static ConfigFileWatcherBehaviour watchProcess;

		internal static void Initialize()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)watchProcess != (Object)null))
			{
				GameObject val = new GameObject("ValheimCommunityPatchExtras_ConfigFileWatcher");
				Object.DontDestroyOnLoad((Object)val);
				((Object)val).hideFlags = (HideFlags)61;
				watchProcess = val.AddComponent<ConfigFileWatcherBehaviour>();
				Logger.LogDebug("ConfigFileWatcher initialized.");
			}
		}

		internal static void Register(string fullPath, Action<string> onChanged)
		{
			if (!string.IsNullOrEmpty(fullPath))
			{
				DateTime lastWriteUTC = DateTime.MinValue;
				long fileLength = 0L;
				if (File.Exists(fullPath))
				{
					FileInfo fileInfo = new FileInfo(fullPath);
					lastWriteUTC = fileInfo.LastWriteTimeUtc;
					fileLength = fileInfo.Length;
				}
				WatchedFiles[fullPath] = new WatchEntry
				{
					LastWriteUTC = lastWriteUTC,
					FileLength = fileLength,
					Callback = onChanged
				};
				Logger.LogDebug("ConfigFileWatcher watching " + fullPath);
			}
		}

		internal static void RefreshStamp(string fullPath)
		{
			if (string.IsNullOrEmpty(fullPath) || !WatchedFiles.TryGetValue(fullPath, out var value))
			{
				return;
			}
			try
			{
				FileInfo fileInfo = new FileInfo(fullPath);
				value.LastWriteUTC = fileInfo.LastWriteTimeUtc;
				value.FileLength = fileInfo.Length;
			}
			catch (Exception)
			{
				value.LastWriteUTC = DateTime.MinValue;
				value.FileLength = 0L;
			}
		}
	}
	internal static class ConfigNetwork
	{
		private static bool initialized;

		private static Harmony harmony;

		private static readonly HashSet<string> usedRpcNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private const byte EditProtocolVersion = 1;

		internal static bool ServerConfigsSynced { get; private set; }

		internal static event Action<YamlConfigFile, bool, string> EditResult;

		internal static void Init()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			if (initialized)
			{
				return;
			}
			initialized = true;
			SynchronizationManager.OnConfigurationSynchronized += OnConfigurationSynchronized;
			try
			{
				harmony = new Harmony("MidnightsFX.ValheimCommunityPatchExtras.config");
				harmony.Patch((MethodBase)AccessTools.Method(typeof(ZNet), "Shutdown", (Type[])null, (Type[])null), new HarmonyMethod(typeof(ConfigNetwork), "ResetOnWorldUnload", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			catch (Exception ex)
			{
				Logger.LogWarning("Could not patch ZNet.Shutdown for config sync teardown: " + ex.Message);
			}
		}

		internal static void RegisterFile(YamlConfigFile file)
		{
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Expected O, but got Unknown
			//IL_00ea: Expected O, but got Unknown
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Expected O, but got Unknown
			//IL_01a5: Expected O, but got Unknown
			if (file == null || file.Sync == ConfigSyncMode.LocalOnly)
			{
				return;
			}
			if (string.IsNullOrEmpty(file.RpcName))
			{
				file.RpcName = "ValheimCommunityPatchExtras_" + Path.GetFileNameWithoutExtension(file.FileName);
			}
			if (!usedRpcNames.Add(file.RpcName))
			{
				Logger.LogError("Config RPC name '" + file.RpcName + "' is already in use; " + file.FileName + " will not be synced. Give it an explicit RpcName.");
				return;
			}
			file.Rpc = NetworkManager.Instance.AddRPC(file.RpcName, (CoroutineHandler)((long sender, ZPackage package) => OnServerReceive(file, sender, package)), (CoroutineHandler)((long sender, ZPackage package) => OnClientReceive(file, sender, package)));
			SynchronizationManager.Instance.AddInitialSynchronization(file.Rpc, (Func<ZPackage>)(() => SendFileAsZPackage(file)));
			if (!file.AllowAdminEdit)
			{
				return;
			}
			string text = file.RpcName + "_Edit";
			if (!usedRpcNames.Add(text))
			{
				Logger.LogError("Config RPC name '" + text + "' is already in use; " + file.FileName + " will not accept admin edits.");
			}
			else
			{
				file.EditRpc = NetworkManager.Instance.AddRPC(text, (CoroutineHandler)((long sender, ZPackage package) => OnServerReceiveEdit(file, sender, package)), (CoroutineHandler)((long sender, ZPackage package) => OnClientReceiveEditResult(file, sender, package)));
			}
		}

		internal static bool RequestEdit(YamlConfigFile file, string yaml, out string refusal)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			refusal = "";
			if (file == null || file.EditRpc == null)
			{
				refusal = "this config cannot be edited remotely.";
				return false;
			}
			if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer())
			{
				refusal = "not connected to a server as a client.";
				return false;
			}
			if (SynchronizationManager.Instance != null && !SynchronizationManager.Instance.PlayerIsAdmin)
			{
				refusal = "only server admins can change this.";
				return false;
			}
			ZPackage val = new ZPackage();
			val.Write((byte)1);
			val.Write(yaml);
			file.EditRpc.SendPackage(ZRoutedRpc.instance.GetServerPeerID(), val);
			return true;
		}

		private static IEnumerator OnServerReceiveEdit(YamlConfigFile file, long sender, ZPackage package)
		{
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				yield break;
			}
			byte b = package.ReadByte();
			if (b != 1)
			{
				SendEditResult(sender, file, accepted: false, $"This server expects edit protocol v{(byte)1}, " + $"the sender used v{b}. Update so both sides match.");
				yield break;
			}
			string yaml = package.ReadString();
			string message;
			if (!SenderIsAdmin(sender))
			{
				Logger.LogWarning($"Rejecting an edit of {file.FileName} from non-admin peer {sender}.");
				SendEditResult(sender, file, accepted: false, "Only server admins can change " + file.FileName + ".");
			}
			else if (!YamlConfigManager.ApplyEdited(file, yaml, out message))
			{
				Logger.LogWarning($"Admin peer {sender} sent a {file.FileName} that was rejected: {message}");
				SendEditResult(sender, file, accepted: false, message);
			}
			else
			{
				Logger.LogInfo($"{file.FileName} was replaced by admin peer {sender}.");
				SendEditResult(sender, file, accepted: true, message);
				yield return null;
			}
		}

		private static IEnumerator OnClientReceiveEditResult(YamlConfigFile file, long sender, ZPackage package)
		{
			if (package.ReadByte() != 1)
			{
				ConfigNetwork.EditResult?.Invoke(file, arg2: false, "The server answered with an edit protocol this build does not understand.");
				yield break;
			}
			bool arg = package.ReadBool();
			string arg2 = package.ReadString();
			ConfigNetwork.EditResult?.Invoke(file, arg, arg2);
			yield return null;
		}

		private static void SendEditResult(long peer, YamlConfigFile file, bool accepted, string message)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			if (file.EditRpc != null)
			{
				ZPackage val = new ZPackage();
				val.Write((byte)1);
				val.Write(accepted);
				val.Write(message ?? "");
				file.EditRpc.SendPackage(peer, val);
			}
		}

		internal static void Broadcast(YamlConfigFile file)
		{
			if (file != null && file.Rpc != null && !((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
			{
				file.Rpc.SendPackage(ZNet.instance.m_peers, SendFileAsZPackage(file));
			}
		}

		internal static void ResetServerSyncState()
		{
			ServerConfigsSynced = false;
		}

		private static void OnConfigurationSynchronized(object sender, EventArgs e)
		{
			ServerConfigsSynced = true;
		}

		private static void ResetOnWorldUnload()
		{
			ResetServerSyncState();
		}

		private static IEnumerator OnServerReceive(YamlConfigFile file, long sender, ZPackage package)
		{
			Logger.LogDebug($"Peer {sender} sent {file.FileName}; this config is server-authoritative, ignoring.");
			yield break;
		}

		private static IEnumerator OnClientReceive(YamlConfigFile file, long sender, ZPackage package)
		{
			string text = package.ReadString();
			file.LoadFrom(text, ConfigOrigin.ServerSync);
			if (file.ClientWritesToDisk)
			{
				YamlConfigManager.WriteRawToDisk(file, text);
			}
			yield return null;
		}

		private static ZPackage SendFileAsZPackage(YamlConfigFile file)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			try
			{
				val.Write(File.Exists(file.Path) ? File.ReadAllText(file.Path) : file.SerializeCurrent());
			}
			catch (Exception ex)
			{
				Logger.LogError("Could not read " + file.FileName + " to send to peers: " + ex.Message);
				val.Write("");
			}
			return val;
		}

		internal static bool SenderIsAdmin(long sender)
		{
			ZNet instance = ZNet.instance;
			ZNetPeer val = ((instance != null) ? instance.GetPeer(sender) : null);
			if (val == null || val.m_socket == null)
			{
				return false;
			}
			return ZNet.instance.IsAdmin(val.m_socket.GetHostName());
		}
	}
	internal class ValidationReport
	{
		internal readonly List<string> Warnings = new List<string>();

		internal readonly List<string> Errors = new List<string>();

		internal bool HasErrors => Errors.Count > 0;

		internal ValidationReport Warn(string message)
		{
			Warnings.Add(message);
			return this;
		}

		internal ValidationReport Error(string message)
		{
			Errors.Add(message);
			return this;
		}

		internal ValidationReport Absorb(ValidationReport other)
		{
			if (other == null)
			{
				return this;
			}
			Warnings.AddRange(other.Warnings);
			Errors.AddRange(other.Errors);
			return this;
		}
	}
	internal static class ConfigValidation
	{
		internal static float Prefer(float bepInExValue, float yamlValue, float sentinel = 0f)
		{
			if (bepInExValue != sentinel)
			{
				return bepInExValue;
			}
			return yamlValue;
		}

		internal static string SuggestKey(string unknownKey, IEnumerable<string> knownKeys)
		{
			if (string.IsNullOrEmpty(unknownKey) || knownKeys == null)
			{
				return "";
			}
			int num = Math.Max(1, unknownKey.Length / 4);
			string text = null;
			int num2 = int.MaxValue;
			foreach (string knownKey in knownKeys)
			{
				if (!string.IsNullOrEmpty(knownKey))
				{
					int num3 = Distance(unknownKey, knownKey);
					if (num3 < num2)
					{
						num2 = num3;
						text = knownKey;
					}
				}
			}
			if (text == null || num2 > num)
			{
				return "";
			}
			return " Did you mean '" + text + "'?";
		}

		private static int Distance(string a, string b)
		{
			a = a.ToLowerInvariant();
			b = b.ToLowerInvariant();
			if (a == b)
			{
				return 0;
			}
			if (a.Length == 0)
			{
				return b.Length;
			}
			if (b.Length == 0)
			{
				return a.Length;
			}
			int[] array = new int[b.Length + 1];
			int[] array2 = new int[b.Length + 1];
			for (int i = 0; i <= b.Length; i++)
			{
				array[i] = i;
			}
			for (int j = 1; j <= a.Length; j++)
			{
				array2[0] = j;
				for (int k = 1; k <= b.Length; k++)
				{
					int num = ((a[j - 1] != b[k - 1]) ? 1 : 0);
					array2[k] = Math.Min(Math.Min(array2[k - 1] + 1, array[k] + 1), array[k - 1] + num);
				}
				int[] array3 = array;
				array = array2;
				array2 = array3;
			}
			return array[b.Length];
		}
	}
	internal static class YamlConfigManager
	{
		internal static YamlConfigFile<ExampleSettings> ExampleFile;

		internal static YamlConfigFile<Dictionary<string, int>> ExampleSavedDataFile;

		private const string ExampleHeader = "#################################################\n# CommunityPatchExtras - Example settings\n#\n# Entries is a map of <key>: <entry>. The key is the identity used elsewhere in this mod, so\n# renaming one is a breaking change; DisplayName is only a label and is safe to change.\n#\n#   DisplayName  string   Shown to the player.\n#   Multiplier   float    Scales the thing. 1.0 is unchanged. Range 0.1 - 10.\n#   Mode         enum     Off | Add | Multiply\n#   Prefabs      list     Prefab names this entry applies to. Unknown names are warned about\n#                         and skipped, they do not break the file.\n#\n# A typo in a key or an enum value costs you that one setting and logs a warning naming the\n# line; the rest of the file still loads.\n#################################################";

		private static bool initialized;

		private static readonly List<YamlConfigFile> Files = new List<YamlConfigFile>();

		private static readonly Dictionary<string, YamlConfigFile> ByPath = new Dictionary<string, YamlConfigFile>(StringComparer.OrdinalIgnoreCase);

		internal static IEnumerable<YamlConfigFile> All => Files;

		private static void RegisterConfigFiles()
		{
			RegisterExampleConfigs();
		}

		private static void RegisterExampleConfigs()
		{
			ExampleFile = Register(new YamlConfigFile<ExampleSettings>("ExampleSettings.yaml")
			{
				Header = "#################################################\n# CommunityPatchExtras - Example settings\n#\n# Entries is a map of <key>: <entry>. The key is the identity used elsewhere in this mod, so\n# renaming one is a breaking change; DisplayName is only a label and is safe to change.\n#\n#   DisplayName  string   Shown to the player.\n#   Multiplier   float    Scales the thing. 1.0 is unchanged. Range 0.1 - 10.\n#   Mode         enum     Off | Add | Multiply\n#   Prefabs      list     Prefab names this entry applies to. Unknown names are warned about\n#                         and skipped, they do not break the file.\n#\n# A typo in a key or an enum value costs you that one setting and logs a warning naming the\n# line; the rest of the file still loads.\n#################################################",
				Defaults = () => ExampleData.BuildDefaults(),
				Apply = delegate(ExampleSettings parsed)
				{
					ExampleData.Current = parsed;
				},
				Validate = ExampleData.Validate,
				NeedsPrefabs = true,
				SchemaVersion = 1,
				GetSchemaVersion = (ExampleSettings settings) => settings.Version,
				SetSchemaVersion = delegate(ExampleSettings settings, int version)
				{
					settings.Version = version;
				}
			});
			ExampleSavedDataFile = Register(new YamlConfigFile<Dictionary<string, int>>("ExampleSavedData.yaml")
			{
				SubFolder = "SavedData",
				Header = "# Save data written by this mod. Edit it with the game closed.",
				Defaults = () => new Dictionary<string, int>(),
				Apply = delegate(Dictionary<string, int> parsed)
				{
					ExampleData.SavedCounters = parsed;
				},
				Sync = ConfigSyncMode.LocalOnly,
				Watch = false
			});
			Register(new YamlConfigFile<Dictionary<string, ExampleEntry>>("ExampleLegacyFormat.yaml")
			{
				Header = "# A config kept in its original camelCase form for backwards compatibility.",
				Format = YamlFormat.CamelCase,
				Defaults = () => new Dictionary<string, ExampleEntry>(),
				Apply = delegate(Dictionary<string, ExampleEntry> parsed)
				{
					ExampleData.LegacyEntries = parsed;
				},
				ClientWritesToDisk = true
			});
		}

		internal static void Init()
		{
			if (!initialized)
			{
				initialized = true;
				ConfigNetwork.Init();
				YamlFormat.AddTypeConverter((IYamlTypeConverter)(object)new TolerantEnumConverter());
				RegisterConfigFiles();
				ConfigFileWatcher.Initialize();
				Logger.LogDebug($"Registered {Files.Count} yaml config files.");
			}
		}

		internal static TFile Register<TFile>(TFile file) where TFile : YamlConfigFile
		{
			if (file == null)
			{
				return null;
			}
			Files.Add(file);
			if (initialized)
			{
				Prepare(file);
			}
			return file;
		}

		internal static YamlConfigFile Find(string fileNameOrPath)
		{
			if (string.IsNullOrEmpty(fileNameOrPath))
			{
				return null;
			}
			if (ByPath.TryGetValue(fileNameOrPath, out var value))
			{
				return value;
			}
			for (int i = 0; i < Files.Count; i++)
			{
				if (string.Equals(Files[i].FileName, fileNameOrPath, StringComparison.OrdinalIgnoreCase))
				{
					return Files[i];
				}
			}
			return null;
		}

		internal static string ConfigDirectory(string subFolder = null)
		{
			string text = Path.Combine(Paths.ConfigPath, ValConfig.cfgFolder);
			if (!string.IsNullOrEmpty(subFolder))
			{
				text = Path.Combine(text, subFolder);
			}
			return Directory.CreateDirectory(text).FullName;
		}

		internal static void ReloadFromDisk(YamlConfigFile file, bool broadcast = true)
		{
			if (file == null)
			{
				return;
			}
			try
			{
				if (!File.Exists(file.Path))
				{
					Logger.LogWarning(file.FileName + " is no longer on disk; rewriting it with this mod's built-in defaults.");
					RestoreDefaults(file);
				}
				if (file.LoadFrom(File.ReadAllText(file.Path), ConfigOrigin.LocalFile) && broadcast)
				{
					ConfigNetwork.Broadcast(file);
				}
			}
			catch (Exception ex)
			{
				Logger.LogError("Could not reload " + file.FileName + ": " + ex.Message);
			}
		}

		internal static bool ApplyEdited(YamlConfigFile file, string yaml, out string message)
		{
			message = "";
			if (file == null)
			{
				message = "no config file was named";
				return false;
			}
			if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer())
			{
				message = file.FileName + " belongs to the server; changes have to be sent to it.";
				return false;
			}
			string parseError;
			ValidationReport validationReport = file.DryRun(yaml, out parseError);
			if (parseError != null)
			{
				message = file.FileName + " was rejected because " + parseError + ".";
				return false;
			}
			if (validationReport.HasErrors)
			{
				message = string.Join(" ", validationReport.Errors.ToArray());
				return false;
			}
			if (!file.LoadFrom(yaml, ConfigOrigin.Api))
			{
				message = file.LastError ?? (file.FileName + " could not be applied.");
				return false;
			}
			WriteRawToDisk(file, yaml);
			ConfigNetwork.Broadcast(file);
			message = ((validationReport.Warnings.Count == 0) ? "" : string.Join(" ", validationReport.Warnings.ToArray()));
			return true;
		}

		internal static string SerializeForEdit<T>(YamlConfigFile<T> file, T value) where T : class
		{
			if (file == null || value == null)
			{
				return "";
			}
			return file.EffectiveFormat.Serializer.Serialize((object)value);
		}

		internal static void RestoreDefaults(YamlConfigFile file)
		{
			WriteRawToDisk(file, file?.SerializeDefaults());
		}

		internal static void WriteCurrentToDisk(YamlConfigFile file)
		{
			WriteRawToDisk(file, file?.SerializeCurrent());
		}

		internal static void WriteRawToDisk(YamlConfigFile file, string serializedYaml)
		{
			if (file == null || string.IsNullOrEmpty(file.Path))
			{
				return;
			}
			try
			{
				Directory.CreateDirectory(Path.GetDirectoryName(file.Path));
				using (StreamWriter streamWriter = new StreamWriter(file.Path))
				{
					if (!string.IsNullOrEmpty(file.Header))
					{
						streamWriter.WriteLine(file.Header);
					}
					streamWriter.WriteLine(serializedYaml);
				}
				ConfigFileWatcher.RefreshStamp(file.Path);
			}
			catch (Exception ex)
			{
				Logger.LogError("Could not write " + file.FileName + ": " + ex.Message);
			}
		}

		internal static void RevalidateAll()
		{
			for (int i = 0; i < Files.Count; i++)
			{
				try
				{
					Files[i].Revalidate();
				}
				catch (Exception ex)
				{
					Logger.LogError("Revalidating " + Files[i].FileName + " threw: " + ex.Message);
				}
			}
		}

		internal static bool HasNoUsableConfig(string yamlText)
		{
			if (string.IsNullOrWhiteSpace(yamlText))
			{
				return true;
			}
			string[] array = yamlText.Split(new char[1] { '\n' });
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length != 0 && !text.StartsWith("#") && !(text == "---") && !(text == "..."))
				{
					return false;
				}
			}
			return true;
		}

		private static void Prepare(YamlConfigFile file)
		{
			try
			{
				file.Path = Path.Combine(ConfigDirectory(file.SubFolder), file.FileName);
				ByPath[file.Path] = file;
				if (!File.Exists(file.Path))
				{
					Logger.LogDebug(file.FileName + " missing, writing this mod's built-in defaults.");
					RestoreDefaults(file);
				}
				else if (HasNoUsableConfig(File.ReadAllText(file.Path)))
				{
					Logger.LogWarning(file.FileName + " was empty and has been overwritten with this mod's built-in defaults. File: " + file.Path);
					RestoreDefaults(file);
				}
				file.LoadFrom(File.Exists(file.Path) ? File.ReadAllText(file.Path) : "", ConfigOrigin.Startup);
				ConfigNetwork.RegisterFile(file);
				if (file.Watch)
				{
					ConfigFileWatcher.Register(file.Path, OnWatchedFileChanged);
				}
			}
			catch (Exception arg)
			{
				Logger.LogError($"Could not prepare {file.FileName}: {arg}");
			}
		}

		private static void OnWatchedFileChanged(string path)
		{
			if (ByPath.TryGetValue(path, out var file))
			{
				ConfigChangeDebouncer.Schedule(file, delegate
				{
					ReloadFromDisk(file);
				});
			}
		}
	}
	public enum ExampleMode
	{
		Off,
		Add,
		Multiply
	}
	public class ExampleEntry
	{
		public string DisplayName { get; set; }

		[DefaultValue(1f)]
		public float Multiplier { get; set; } = 1f;

		public ExampleMode Mode { get; set; }

		public List<string> Prefabs { get; set; } = new List<string>();
	}
	public class ExampleSettings
	{
		public int Version { get; set; } = 1;

		public Dictionary<string, ExampleEntry> Entries { get; set; } = new Dictionary<string, ExampleEntry>();
	}
	internal static class ExampleData
	{
		internal static ExampleSettings Current = new ExampleSettings();

		internal static Dictionary<string, int> SavedCounters = new Dictionary<string, int>();

		internal static Dictionary<string, ExampleEntry> LegacyEntries = new Dictionary<string, ExampleEntry>();

		internal static ExampleSettings BuildDefaults()
		{
			return new ExampleSettings
			{
				Version = 1,
				Entries = new Dictionary<string, ExampleEntry> { 
				{
					"Example",
					new ExampleEntry
					{
						DisplayName = "An example",
						Multiplier = 1.5f,
						Mode = ExampleMode.Multiply
					}
				} }
			};
		}

		internal static ValidationReport Validate(ExampleSettings next, ExampleSettings previous)
		{
			ValidationReport validationReport = new ValidationReport();
			if (next.Entries == null || next.Entries.Count == 0)
			{
				return validationReport.Error("it defines no entries");
			}
			foreach (KeyValuePair<string, ExampleEntry> entry in next.Entries)
			{
				if (entry.Value == null)
				{
					validationReport.Error("entry '" + entry.Key + "' has no settings under it");
					continue;
				}
				if (entry.Value.Multiplier < 0.1f || entry.Value.Multiplier > 10f)
				{
					validationReport.Warn($"entry '{entry.Key}' has Multiplier {entry.Value.Multiplier}, outside the " + "supported range of 0.1 - 10. It will be used as written.");
				}
				if (entry.Value.Prefabs == null)
				{
					continue;
				}
				foreach (string prefab in entry.Value.Prefabs)
				{
					if (PrefabManager.Instance != null && (Object)(object)PrefabManager.Instance.GetPrefab(prefab) == (Object)null)
					{
						validationReport.Warn("entry '" + entry.Key + "' names prefab '" + prefab + "', which does not exist. That prefab will be skipped.");
					}
				}
			}
			if (previous != null && previous.Entries != null)
			{
				foreach (string key in previous.Entries.Keys)
				{
					if (!next.Entries.ContainsKey(key))
					{
						validationReport.Warn("entry '" + key + "' was removed. Anything still referring to it will fall back.");
					}
				}
			}
			return validationReport;
		}
	}
	internal class TolerantEnumConverter : IYamlTypeConverter
	{
		private static readonly Dictionary<Type, object> fallbacks = new Dictionary<Type, object>();

		internal static void SetFallback(Type enumType, object fallback)
		{
			if (!(enumType == null) && enumType.IsEnum)
			{
				fallbacks[enumType] = fallback;
			}
		}

		public bool Accepts(Type type)
		{
			if (type != null)
			{
				return type.IsEnum;
			}
			return false;
		}

		public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			Scalar val = ParserExtensions.Consume<Scalar>(parser);
			string value = val.Value;
			if (!string.IsNullOrWhiteSpace(value))
			{
				try
				{
					return Enum.Parse(type, value.Trim(), ignoreCase: true);
				}
				catch (Exception)
				{
				}
			}
			object obj = FallbackFor(type);
			object[] array = new object[4];
			Mark start = ((ParsingEvent)val).Start;
			array[0] = ((Mark)(ref start)).Line;
			array[1] = value;
			array[2] = type.Name;
			array[3] = obj;
			Logger.LogWarning(string.Format("line {0}: '{1}' is not a valid {2}. Using {3}. ", array) + "Valid values: " + string.Join(", ", Enum.GetNames(type)) + ".");
			return obj;
		}

		public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer serializer)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			emitter.Emit((ParsingEvent)new Scalar((value == null) ? "" : value.ToString()));
		}

		private static object FallbackFor(Type type)
		{
			if (fallbacks.TryGetValue(type, out var value))
			{
				return value;
			}
			return Activator.CreateInstance(type);
		}
	}
	internal static class ConfigUI
	{
		internal class ConfigUIInputGuard : MonoBehaviour
		{
			private bool held;

			internal void Hold()
			{
				if (!held)
				{
					held = true;
					PushInputBlock();
				}
			}

			public void OnDestroy()
			{
				if (held)
				{
					held = false;
					PopInputBlock();
				}
			}
		}

		internal const float RowHeight = 34f;

		internal const float SubRowHeight = 26f;

		internal const float RowGap = 4f;

		internal const float CloseXSize = 28f;

		private static int inputBlockDepth;

		internal static void PushInputBlock()
		{
			if (!((Object)(object)Player.m_localPlayer == (Object)null))
			{
				inputBlockDepth++;
				if (inputBlockDepth == 1)
				{
					GUIManager.BlockInput(true);
				}
			}
		}

		internal static void PopInputBlock()
		{
			if (inputBlockDepth > 0)
			{
				inputBlockDepth--;
				if (inputBlockDepth == 0)
				{
					GUIManager.BlockInput(false);
				}
			}
		}

		internal static GameObject NewUI(string name, Transform parent, params Type[] components)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			GameObject val = new GameObject(name, components)
			{
				layer = 5
			};
			if ((Object)(object)val.GetComponent<RectTransform>() == (Object)null)
			{
				val.AddComponent<RectTransform>();
			}
			val.transform.SetParent(parent, false);
			return val;
		}

		internal static GameObject NewRect(string name, Transform parent, float x, float y, float w, float h)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = NewUI(name, parent, typeof(RectTransform));
			RectTransform val = (RectTransform)obj.transform;
			val.anchorMin = new Vector2(0f, 1f);
			val.anchorMax = new Vector2(0f, 1f);
			val.pivot = new Vector2(0f, 1f);
			val.sizeDelta = new Vector2(w, h);
			val.anchoredPosition = new Vector2(x, 0f - y);
			return obj;
		}

		internal static GameObject NewRow(Transform parent, float width, float height)
		{
			return NewRect("Row", parent, 0f, 0f, width, height);
		}

		internal static GameObject NewLayoutRow(Transform content, float width, float height)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = NewUI("LayoutRow", content, typeof(RectTransform), typeof(LayoutElement));
			RectTransform val = (RectTransform)obj.transform;
			val.anchorMin = new Vector2(0f, 1f);
			val.anchorMax = new Vector2(0f, 1f);
			val.pivot = new Vector2(0f, 1f);
			val.sizeDelta = new Vector2(width, height);
			LayoutElement component = obj.GetComponent<LayoutElement>();
			component.minHeight = height;
			component.preferredHeight = height;
			component.minWidth = width;
			component.preferredWidth = width;
			return obj;
		}

		internal static void LayoutColumn(List<GameObject> rows, float x, float startY, float gap = 4f)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			float num = startY;
			foreach (GameObject row in rows)
			{
				if (!((Object)(object)row == (Object)null) && row.activeSelf)
				{
					RectTransform val = (RectTransform)row.transform;
					val.anchoredPosition = new Vector2(x, 0f - num);
					num += val.sizeDelta.y + gap;
				}
			}
		}

		internal static void PositionRow(GameObject row, float x, float y)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)row == (Object)null))
			{
				((RectTransform)row.transform).anchoredPosition = new Vector2(x, 0f - y);
			}
		}

		internal static GameObject CreatePanel(string title, float w, float h, out Transform body)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = GUIManager.Instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 0f), w, h, true);
			val.AddComponent<ConfigUIInputGuard>().Hold();
			AddText(val.transform, 0f, 16f, w, 34f, title, 22, (TextAnchor)4, GUIManager.Instance.ValheimYellow);
			body = val.transform;
			return val;
		}

		internal static GameObject CreateScroll(Transform parent, float x, float y, float w, float h, out Transform content, out float contentWidth)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = NewRect("ScrollHolder", parent, x, y, w, h);
			GameObject val2 = GUIManager.Instance.CreateScrollView(val.transform, false, true, 8f, 4f, GUIManager.Instance.ValheimScrollbarHandleColorBlock, new Color(0f, 0f, 0f, 0.5f), w, h);
			content = val2.transform.Find("Scroll View/Viewport/Content");
			contentWidth = w - 16f;
			ScrollRect componentInChildren = val2.GetComponentInChildren<ScrollRect>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.scrollSensitivity = 200f;
			}
			return val2;
		}

		internal static string L(string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				return "";
			}
			if (Localization.instance == null)
			{
				return text;
			}
			return Localization.instance.Localize(text);
		}

		internal static Text AddText(Transform parent, float x, float y, float w, float h, string text, int fontSize, TextAnchor anchor, Color? color = null)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: 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)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = GUIManager.Instance.CreateText(L(text), parent, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(x, 0f - y), GUIManager.Instance.AveriaSerifBold, fontSize, (Color)(((??)color) ?? GUIManager.Instance.ValheimBeige), true, Color.black, w, h, false);
			RectTransform val = (RectTransform)obj.transform;
			val.pivot = new Vector2(0f, 1f);
			val.anchoredPosition = new Vector2(x, 0f - y);
			Text component = obj.GetComponent<Text>();
			component.alignment = anchor;
			component.horizontalOverflow = (HorizontalWrapMode)0;
			component.verticalOverflow = (VerticalWrapMode)0;
			return component;
		}

		internal static GameObject AddHeaderRow(Transform parent, float colWidth, string text, TextAnchor anchor = (TextAnchor)3)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = NewRow(parent, colWidth, 34f);
			AddText(obj.transform, 0f, 0f, colWidth, 34f, text, 18, anchor, GUIManager.Instance.ValheimYellow);
			return obj;
		}

		internal static GameObject AddTextRow(Transform parent, float colWidth, float height, string text, int fontSize, Color color, TextAnchor anchor = (TextAnchor)0)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = NewRow(parent, colWidth, height);
			AddText(obj.transform, 0f, 0f, colWidth, height, text, fontSize, anchor, color);
			return obj;
		}

		internal static GameObject AddSpacerRow(Transform parent, float colWidth, float height)
		{
			return NewRow(parent, colWidth, height);
		}

		internal static GameObject AddDividerRow(Transform parent, float colWidth, float height = 12f)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = NewRow(parent, colWidth, height);
			GameObject obj = NewUI("Divider", val.transform, typeof(Image));
			RectTransform val2 = (RectTransform)obj.transform;
			val2.anchorMin = new Vector2(0f, 1f);
			val2.anchorMax = new Vector2(0f, 1f);
			val2.pivot = new Vector2(0f, 1f);
			val2.sizeDelta = new Vector2(colWidth, 2f);
			val2.anchoredPosition = new Vector2(0f, 0f - height * 0.5f);
			Image component = obj.GetComponent<Image>();
			((Graphic)component).color = new Color(0.6f, 0.5f, 0.35f, 0.6f);
			((Graphic)component).raycastTarget = false;
			return val;
		}

		internal static void SetMessages(Text target, IList<string> errors, IList<string> warnings)
		{
			if ((Object)(object)target == (Object)null)
			{
				return;
			}
			List<string> list = new List<string>();
			if (errors != null)
			{
				foreach (string error in errors)
				{
					list.Add("<color=#F87171>" + error + "</color>");
				}
			}
			if (warnings != null)
			{
				foreach (string warning in warnings)
				{
					list.Add("<color=#FBBF24>" + warning + "</color>");
				}
			}
			target.text = string.Join("\n", list.ToArray());
		}

		internal static GameObject AddButton(Transform parent, float x, float y, float w, string text, UnityAction onClick, float h = 40f)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: 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)
			GameObject val = GUIManager.Instance.CreateButton(L(text), parent, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(x, 0f - y), w, h);
			RectTransform val2 = (RectTransform)val.transform;
			val2.pivot = new Vector2(0f, 1f);
			val2.anchoredPosition = new Vector2(x, 0f - y);
			if (onClick != null)
			{
				((UnityEvent)val.GetComponent<Button>().onClick).AddListener(onClick);
			}
			return val;
		}

		internal static GameObject AddCloseX(Transform panel, float panelWidth, UnityAction onClick)
		{
			return AddButton(panel, panelWidth - 28f - 16f, 12f, 28f, "X", onClick, 28f);
		}

		internal static Toggle AddToggle(Transform parent, float x, float y, float size, bool value, Action<bool> onChange)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = GUIManager.Instance.CreateToggle(parent, size, size);
			obj.transform.SetParent(parent, false);
			RectTransform val = (RectTransform)obj.transform;
			((Transform)val).localScale = Vector3.one;
			val.anchorMin = new Vector2(0f, 1f);
			val.anchorMax = new Vector2(0f, 1f);
			val.pivot = new Vector2(0f, 1f);
			val.anchoredPosition = new Vector2(x, 0f - y);
			Toggle component = obj.GetComponent<Toggle>();
			component.isOn = value;
			if (onChange != null)
			{
				((UnityEvent<bool>)(object)component.onValueChanged).AddListener((UnityAction<bool>)delegate(bool b)
				{
					onChange(b);
				});
			}
			return component;
		}

		internal static GameObject AddToggleRow(Transform parent, float colWidth, float labelW, string label, bool value, Action<bool> onChange, bool toggleOnLeft = false)
		{
			GameObject obj = NewRow(parent, colWidth, 34f);
			float x = (toggleOnLeft ? 0f : (labelW + 6f));
			float x2 = (toggleOnLeft ? 34f : 0f);
			AddText(obj.transform, x2, 0f, labelW, 34f, label, 15, (TextAnchor)3);
			AddToggle(obj.transform, x, 3f, 26f, value, onChange);
			return obj;
		}

		internal static string Fmt(float v, bool whole)
		{
			if (!whole)
			{
				return v.ToString("0.00");
			}
			return ((int)Mathf.Round(v)).ToString();
		}

		internal static Slider BuildSlider(Transform parent, float x, float y, float width, float min, float max, float value, bool wholeNumbers)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Expected O, but got Unknown
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Expected O, but got Unknown
			//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = NewUI("Slider", parent, typeof(RectTransform), typeof(Slider));
			RectTransform val2 = (RectTransform)val.transform;
			val2.anchorMin = new Vector2(0f, 1f);
			val2.anchorMax = new Vector2(0f, 1f);
			val2.pivot = new Vector2(0f, 1f);
			val2.sizeDelta = new Vector2(width, 20f);
			val2.anchoredPosition = new Vector2(x, 0f - y);
			GameObject obj = NewUI("Background", val.transform, typeof(Image));
			RectTransform val3 = (RectTransform)obj.transform;
			val3.anchorMin = new Vector2(0f, 0.25f);
			val3.anchorMax = new Vector2(1f, 0.75f);
			val3.sizeDelta = Vector2.zero;
			val3.anchoredPosition = Vector2.zero;
			((Graphic)obj.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.6f);
			GameObject val4 = NewUI("Fill Area", val.transform, typeof(RectTransform));
			RectTransform val5 = (RectTransform)val4.transform;
			val5.anchorMin = new Vector2(0f, 0.25f);
			val5.anchorMax = new Vector2(1f, 0.75f);
			val5.sizeDelta = new Vector2(-20f, 0f);
			val5.anchoredPosition = Vector2.zero;
			GameObject obj2 = NewUI("Fill", val4.transform, typeof(Image));
			RectTransform val6 = (RectTransform)obj2.transform;
			val6.sizeDelta = new Vector2(10f, 0f);
			((Graphic)obj2.GetComponent<Image>()).color = new Color(0.7f, 0.6f, 0.4f, 0.9f);
			GameObject val7 = NewUI("Handle Slide Area", val.transform, typeof(RectTransform));
			RectTransform val8 = (RectTransform)val7.transform;
			val8.anchorMin = Vector2.zero;
			val8.anchorMax = Vector2.one;
			val8.sizeDelta = new Vector2(-20f, 0f);
			val8.anchoredPosition = Vector2.zero;
			GameObject obj3 = NewUI("Handle", val7.transform, typeof(Image));
			RectTransform val9 = (RectTransform)obj3.transform;
			val9.sizeDelta = new Vector2(20f, 0f);
			Image component = obj3.GetComponent<Image>();
			component.sprite = GUIManager.Instance.GetSprite("checkbox_marker");
			component.type = (Type)1;
			Slider component2 = val.GetComponent<Slider>();
			component2.fillRect = val6;
			component2.handleRect = val9;
			((Selectable)component2).targetGraphic = (Graphic)(object)component;
			component2.direction = (Direction)0;
			component2.minValue = min;
			component2.maxValue = max;
			component2.wholeNumbers = wholeNumbers;
			component2.value = Mathf.Clamp(value, min, max);
			GUIManager.Instance.ApplySliderStyle(component2);
			return component2;
		}

		internal static GameObject AddSliderRow(Transform parent, float colWidth, float labelW, float sliderW, float valueW, string label, float min, float max, float value, bool wholeNumbers, Action<float> onChange)
		{
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = NewRow(parent, colWidth, 34f);
			AddText(val.transform, 0f, 0f, labelW, 34f, label, 15, (TextAnchor)3);
			Slider slider = BuildSlider(val.transform, labelW, 7f, sliderW, min, max, value, wholeNumbers);
			float num = labelW + sliderW + 10f;
			GameObject val2 = GUIManager.Instance.CreateInputField(val.transform, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(num, -3f), (ContentType)(wholeNumbers ? 2 : 3), (string)null, 15, valueW, 28f);
			RectTransform val3 = (RectTransform)val2.transform;
			val3.pivot = new Vector2(0f, 1f);
			val3.anchoredPosition = new Vector2(num, -3f);
			InputField box = val2.GetComponent<InputField>();
			box.SetTextWithoutNotify(Fmt(slider.value, wholeNumbers));
			((UnityEvent<float>)(object)slider.onValueChanged).AddListener((UnityAction<float>)delegate(float v)
			{
				if (wholeNumbers)
				{
					v = Mathf.Round(v);
				}
				box.SetTextWithoutNotify(Fmt(v, wholeNumbers));
				onChange?.Invoke(v);
			});
			((UnityEvent<string>)(object)box.onEndEdit).AddListener((UnityAction<string>)delegate(string str)
			{
				if (!float.TryParse(str, out var result))
				{
					result = slider.value;
				}
				result = Mathf.Clamp(result, min, max);
				if (wholeNumbers)
				{
					result = Mathf.Round(result);
				}
				box.SetTextWithoutNotify(Fmt(result, wholeNumbers));
				if (slider.value != result)
				{
					slider.value = result;
				}
				else
				{
					onChange?.Invoke(result);
				}
			});
			return val;
		}

		internal static InputField AddTextField(Transform parent, float x, float y, float w, string value, Action<string> onCommit, ContentType contentType = (ContentType)0, string placeholder = null, int charLimit = 0)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = GUIManager.Instance.CreateInputField(parent, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(x, 0f - y), contentType, placeholder, 15, w, 28f);
			RectTransform val = (RectTransform)obj.transform;
			val.pivot = new Vector2(0f, 1f);
			val.anchoredPosition = new Vector2(x, 0f - y);
			InputField component = obj.GetComponent<InputField>();
			if (charLimit > 0)
			{
				component.characterLimit = charLimit;
			}
			component.SetTextWithoutNotify(value ?? "");
			if (onCommit != null)
			{
				((UnityEvent<string>)(object)component.onEndEdit).AddListener((UnityAction<string>)delegate(string s)
				{
					onCommit(s);
				});
			}
			return component;
		}

		internal static GameObject AddTextFieldRow(Transform parent, float colWidth, float labelW, float fieldW, string label, string value, Action<string> onCommit, string placeholder = null, int charLimit = 0)
		{
			GameObject obj = NewRow(parent, colWidth, 34f);
			AddText(obj.transform, 0f, 0f, labelW, 34f, label, 15, (TextAnchor)3);
			AddTextField(obj.transform, labelW + 6f, 3f, fieldW, value, onCommit, (ContentType)0, placeholder, charLimit);
			return obj;
		}

		internal static GameObject AddEnumCycleRow(Transform parent, float colWidth, float labelW, float ctrlW, string label, string[] options, int currentIndex, Action<int> onChange)
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Expected O, but got Unknown
			GameObject val = NewRow(parent, colWidth, 34f);
			AddText(val.transform, 0f, 0f, labelW, 34f, label, 15, (TextAnchor)3);
			int idx = Mathf.Clamp(currentIndex, 0, Math.Max(0, options.Length - 1));
			GameObject val2 = GUIManager.Instance.CreateButton((options.Length != 0) ? options[idx] : "", val.transform, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(labelW + 6f, -2f), ctrlW, 28f);
			RectTransform val3 = (RectTransform)val2.transform;
			val3.pivot = new Vector2(0f, 1f);
			val3.anchoredPosition = new Vector2(labelW + 6f, -2f);
			Text caption = val2.GetComponentInChildren<Text>();
			((UnityEvent)val2.GetComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				if (options.Length != 0)
				{
					idx = (idx + 1) % options.Length;
					caption.text = options[idx];
					onChange?.Invoke(idx);
				}
			});
			return val;
		}

		internal static GameObject AddEnumFlagsRow(Transform parent, float colWidth, float labelW, string label, string[] names, Func<int, bool> isOn, Action<int, bool> set)
		{
			GameObject val = NewRow(parent, colWidth, 34f);
			AddText(val.transform, 0f, 0f, labelW, 34f, label, 15, (TextAnchor)3);
			float num = labelW + 6f;
			for (int i = 0; i < names.Length; i++)
			{
				int index = i;
				AddToggle(val.transform, num, 4f, 22f, isOn(index), delegate(bool on)
				{
					set(index, on);
				});
				AddText(val.transform, num + 26f, 0f, 90f, 34f, names[index], 13, (TextAnchor)3);
				num += 120f;
			}
			return val;
		}

		internal static GameObject AddPickerRow(Transform parent, float colWidth, float labelW, float ctrlW, string label, string current, Func<IList<string>> options, Action<string> onPick, Func<string, bool> isKnown = null)
		{
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Expected O, but got Unknown
			GameObject val = NewRow(parent, colWidth, 34f);
			AddText(val.transform, 0f, 0f, labelW, 34f, label, 15, (TextAnchor)3);
			float num = ctrlW - 40f;
			InputField field = AddTextField(val.transform, labelW + 6f, 3f, num, current, delegate(string s)
			{
				onPick?.Invoke(s);
			}, (ContentType)0);
			Text marker = AddText(val.transform, labelW + 6f + num + 44f, 0f, 20f, 34f, "", 15, (TextAnchor)3, (Color?)new Color(0.98f, 0.75f, 0.14f));
			Action refreshMarker = delegate
			{
				bool flag = isKnown != null && !string.IsNullOrEmpty(field.text) && !isKnown(field.text);
				marker.text = (flag ? "!" : "");
			};
			refreshMarker();
			((UnityEvent<string>)(object)field.onEndEdit).AddListener((UnityAction<string>)delegate
			{
				refreshMarker();
			});
			AddButton(val.transform, labelW + 6f + num + 4f, 3f, 34f, "...", (UnityAction)delegate
			{
				string title = label;
				IList<string> options2;
				if (options == null)
				{
					IList<string> list = new List<string>();
					options2 = list;
				}
				else
				{
					options2 = options();
				}
				ConfigUIPicker.ShowPicker(title, options2, field.text, delegate(string picked)
				{
					field.SetTextWithoutNotify(picked);
					refreshMarker();
					onPick?.Invoke(picked);
				});
			}, 28f);
			return val;
		}

		internal static GameObject AddStringListEditor(Transform content, float width, string label, List<string> items, Action onChanged, Func<IList<string>> options = null, Func<string, bool> isKnown = null)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected O, but got Unknown
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Expected O, but got Unknown
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Expected O, but got Unknown
			GameObject val = NewLayoutRow(content, width, 26f);
			AddText(val.transform, 0f, 0f, width - 90f, 26f, label, 14, (TextAnchor)3, GUIManager.Instance.ValheimOrange);
			AddButton(val.transform, width - 84f, 0f, 80f, "Add", (UnityAction)delegate
			{
				items.Add("");
				onChanged?.Invoke();
			}, 24f);
			for (int num = 0; num < items.Count; num++)
			{
				int index = num;
				GameObject val2 = NewLayoutRow(content, width, 26f);
				InputField field = AddTextField(val2.transform, 12f, 0f, width - 92f, items[index], delegate(string s)
				{
					items[index] = s;
				}, (ContentType)0);
				Text marker = AddText(val2.transform, width - 74f, 0f, 16f, 26f, "", 14, (TextAnchor)3, (Color?)new Color(0.98f, 0.75f, 0.14f));
				Action refreshMarker = delegate
				{
					bool flag = isKnown != null && !string.IsNullOrEmpty(field.text) && !isKnown(field.text);
					marker.text = (flag ? "!" : "");
				};
				refreshMarker();
				((UnityEvent<string>)(object)field.onEndEdit).AddListener((UnityAction<string>)delegate
				{
					refreshMarker();
				});
				if (options != null)
				{
					AddButton(val2.transform, width - 56f, 0f, 26f, "...", (UnityAction)delegate
					{
						ConfigUIPicker.ShowPicker(label, options(), field.text, delegate(string picked)
						{
							field.SetTextWithoutNotify(picked);
							items[index] = picked;
							refreshMarker();
						});
					}, 24f);
				}
				AddButton(val2.transform, width - 26f, 0f, 24f, "x", (UnityAction)delegate
				{
					items.RemoveAt(index);
					onChanged?.Invoke();
				}, 24f);
			}
			return val;
		}
	}
	internal static class ConfigUILauncher
	{
		private static Component cachedBroker;

		private static MethodInfo cachedRegister;

		private static MethodInfo cachedUnregister;

		private static bool loggedOwner;

		internal static bool IsAvailable => (Object)(object)Resolve() != (Object)null;

		internal static void Init()
		{
			Resolve();
		}

		internal static bool Register(string displayName, Action openPanel)
		{
			if (string.IsNullOrEmpty(displayName) || openPanel == null)
			{
				return false;
			}
			Component val = Resolve();
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			if (cachedRegister == null)
			{
				Logger.LogError("The QuickConfig launcher on this machine has no compatible Register method; '" + displayName + "' will not appear in it.");
				return false;
			}
			try
			{
				cachedRegister.Invoke(val, new object[2] { displayName, openPanel });
				return true;
			}
			catch (Exception ex)
			{
				Logger.LogError("Could not register '" + displayName + "' with the QuickConfig launcher: " + ex.Message);
				return false;
			}
		}

		internal static void Unregister(string displayName)
		{
			if (string.IsNullOrEmpty(displayName))
			{
				return;
			}
			Component val = Resolve();
			if ((Object)(object)val == (Object)null || cachedUnregister == null)
			{
				return;
			}
			try
			{
				cachedUnregister.Invoke(val, new object[1] { displayName });
			}
			catch (Exception ex)
			{
				Logger.LogWarning("Could not unregister '" + displayName + "' from the QuickConfig launcher: " + ex.Message);
			}
		}

		private static Component Resolve()
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			if ((Object)(object)cachedBroker != (Object)null)
			{
				return cachedBroker;
			}
			cachedRegister = null;
			cachedUnregister = null;
			GameObject val = null;
			try
			{
				val = GameObject.Find("ModQuickConfigLauncher");
			}
			catch (Exception)
			{
			}
			if ((Object)(object)val == (Object)null)
			{
				try
				{
					val = new GameObject("ModQuickConfigLauncher");
					Object.DontDestroyOnLoad((Object)(object)val);
					val.AddComponent<QuickConfigBroker>();
				}
				catch (Exception ex2)
				{
					Logger.LogError("Could not create the QuickConfig launcher: " + ex2.Message);
					return null;
				}
			}
			Component val2 = null;
			Component[] components = val.GetComponents<Component>();
			foreach (Component val3 in components)
			{
				if ((Object)(object)val3 != (Object)null && ((object)val3).GetType().Name == "QuickConfigBroker")
				{
					val2 = val3;
					break;
				}
			}
			if ((Object)(object)val2 == (Object)null)
			{
				return null;
			}
			Type type = ((object)val2).GetType();
			cachedRegister = type.GetMethod("Register", BindingFlags.Instance | BindingFlags.Public, null, new Type[2]
			{
				typeof(string),
				typeof(Action)
			}, null);
			cachedUnregister = type.GetMethod("Unregister", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(string) }, null);
			if (!loggedOwner)
			{
				loggedOwner = true;
				int num = 1;
				try
				{
					PropertyInfo property = type.GetProperty("BrokerVersion", BindingFlags.Instance | BindingFlags.Public);
					if (property != null)
					{
						num = (int)property.GetValue(val2, null);
					}
				}
				catch (Exception)
				{
				}
				Logger.LogInfo($"QuickConfig launcher v{num} owned by " + $"{type.Assembly.GetName().Name}; this mod carries v{2}.");
				if (num < 2)
				{
					Logger.LogInfo("That copy is older than this one. Registration still works; the launcher UI is whatever the owning mod shipped.");
				}
			}
			cachedBroker = val2;
			return cachedBroker;
		}
	}
	internal static class ConfigUIPicker
	{
		private const float PanelW = 420f;

		private const float PanelH = 520f;

		private const float RowH = 30f;

		private const int MaxRows = 400;

		private static GameObject overlay;

		internal static bool IsOpen => (Object)(object)overlay != (Object)null;

		internal static void ShowPicker(string title, IList<string> options, string current, Action<string> onPick)
		{
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Expected O, but got Unknown
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Expected O, but got Unknown
			Close();
			if (GUIManager.Instance == null || (Object)(object)GUIManager.CustomGUIFront == (Object)null)
			{
				return;
			}
			List<string> all = new List<string>();
			if (options != null)
			{
				foreach (string option in options)
				{
					if (!string.IsNullOrEmpty(option))
					{
						all.Add(option);
					}
				}
			}
			all.Sort(StringComparer.OrdinalIgnoreCase);
			overlay = ConfigUI.NewUI("ConfigUIPickerOverlay", GUIManager.CustomGUIFront.transform, typeof(Image));
			RectTransform val = (RectTransform)overlay.transform;
			val.anchorMin = Vector2.zero;
			val.anchorMax = Vector2.one;
			val.offsetMin = Vector2.zero;
			val.offsetMax = Vector2.zero;
			((Graphic)overlay.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.35f);
			Button obj = overlay.AddComponent<Button>();
			((Selectable)obj).transition = (Transition)0;
			((UnityEvent)obj.onClick).AddListener(new UnityAction(Close));
			overlay.AddComponent<ConfigUI.ConfigUIInputGuard>().Hold();
			GameObject obj2 = GUIManager.Instance.CreateWoodpanel(overlay.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 0f), 420f, 520f, true);
			ConfigUI.AddText(obj2.transform, 0f, 14f, 420f, 30f, title, 18, (TextAnchor)4, GUIManager.Instance.ValheimYellow);
			InputField val2 = ConfigUI.AddTextField(obj2.transform, 16f, 52f, 320f, "", null, (ContentType)0, "Filter...");
			ConfigUI.AddButton(obj2.transform, 344f, 52f, 60f, "Close", new UnityAction(Close), 28f);
			ConfigUI.CreateScroll(obj2.transform, 16f, 92f, 388f, 404f, out var content, out var contentW);
			if ((Object)(object)content == (Object)null)
			{
				return;
			}
			Action<string> rebuild = null;
			rebuild = delegate(string needle)
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
				//IL_00dd: Expected O, but got Unknown
				foreach (Transform item in content)
				{
					Object.Destroy((Object)(object)((Component)item).gameObject);
				}
				int num = 0;
				foreach (string item2 in all)
				{
					if (string.IsNullOrEmpty(needle) || item2.IndexOf(needle, StringComparison.OrdinalIgnoreCase) >= 0)
					{
						if (num >= 400)
						{
							break;
						}
						num++;
						string picked = item2;
						ConfigUI.AddButton(ConfigUI.NewLayoutRow(content, contentW, 30f).transform, 0f, 0f, contentW, picked, (UnityAction)delegate
						{
							Close();
							onPick?.Invoke(picked);
						}, 28f);
					}
				}
				if (num == 0)
				{
					ConfigUI.AddText(ConfigUI.NewLayoutRow(content, contentW, 30f).transform, 4f, 0f, contentW, 30f, "No matches", 14, (TextAnchor)3);
				}
				else if (num >= 400)
				{
					ConfigUI.AddText(ConfigUI.NewLayoutRow(content, contentW, 30f).transform, 4f, 0f, contentW, 30f, $"... {all.Count - num} more, type to narrow", 13, (TextAnchor)3);
				}
			};
			((UnityEvent<string>)(object)val2.onValueChanged).AddListener((UnityAction<string>)delegate(string needle)
			{
				rebuild(needle);
			});
			rebuild("");
		}

		internal static void Close()
		{
			if (!((Object)(object)overlay == (Object)null))
			{
				Object.Destroy((Object)(object)overlay);
				overlay = null;
			}
		}
	}
	internal static class ConfigUIPrompt
	{
		private const float PanelW = 460f;

		private static GameObject overlay;

		internal static void Show(string title, string label, string initial, string warning, Action<string> onAccept)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Expected O, but got Unknown
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Expected O, but got Unknown
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			Close();
			if (GUIManager.Instance != null && !((Object)(object)GUIManager.CustomGUIFront == (Object)null))
			{
				bool flag = !string.IsNullOrEmpty(warning);
				float num = (flag ? 96f : 0f);
				float num2 = 190f + num;
				overlay = ConfigUI.NewUI("ConfigUIPromptOverlay", GUIManager.CustomGUIFront.transform, typeof(Image));
				RectTransform val = (RectTransform)overlay.transform;
				val.anchorMin = Vector2.zero;
				val.anchorMax = Vector2.one;
				val.offsetMin = Vector2.zero;
				val.offsetMax = Vector2.zero;
				((Graphic)overlay.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.45f);
				overlay.AddComponent<ConfigUI.ConfigUIInputGuard>().Hold();
				GameObject val2 = GUIManager.Instance.CreateWoodpanel(overlay.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 0f), 460f, num2, true);
				ConfigUI.AddText(val2.transform, 0f, 14f, 460f, 30f, title, 18, (TextAnchor)4, GUIManager.Instance.ValheimYellow);
				float num3 = 56f;
				if (flag)
				{
					ConfigUI.AddText(val2.transform, 20f, num3, 420f, num - 8f, warning, 13, (TextAnchor)0, (Color?)new Color(0.98f, 0.75f, 0.14f));
					num3 += num;
				}
				ConfigUI.AddText(val2.transform, 20f, num3, 120f, 28f, label, 15, (TextAnchor)3);
				InputField field = ConfigUI.AddTextField(val2.transform, 140f, num3, 300f, initial, null, (ContentType)0, null, 64);
				num3 += 46f;
				ConfigUI.AddButton(val2.transform, 20f, num3, 190f, "Cancel", new UnityAction(Close), 34f);
				ConfigUI.AddButton(val2.transform, 250f, num3, 190f, "OK", (UnityAction)delegate
				{
					string text = field.text;
					Close();
					onAccept?.Invoke(text);
				}, 34f);
				((Selectable)field).Select();
				field.ActivateInputField();
			}
		}

		internal static void Close()
		{
			if (!((Object)(object)overlay == (Object)null))
			{
				Object.Destroy((Object)(object)overlay);
				overlay = null;
			}
		}
	}
	internal static class ExampleConfigPanel
	{
		private const string EntryName = "CommunityPatchExtras";

		private const float PanelW = 620f;

		private const float PanelH = 520f;

		private const float LabelW = 190f;

		private static GameObject panel;

		private static ExampleSettings staged;

		private static Text messages;

		internal static void Init()
		{
			ConfigUILauncher.Init();
			ApplyRegistration();
		}

		internal static void ApplyRegistration()
		{
			if (ValConfig.ShowQuickConfigButton == null || ValConfig.ShowQuickConfigButton.Value)
			{
				ConfigUILauncher.Register("CommunityPatchExtras", OpenPanel);
			}
			else
			{
				ConfigUILauncher.Unregister("CommunityPatchExtras");
			}
		}

		internal static void OpenPanel()
		{
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c2: Expected O, but got Unknown
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Expected O, but got Unknown
			//IL_030b: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: Expected O, but got Unknown
			ClosePanel();
			YamlConfigFile<ExampleSettings> exampleFile = YamlConfigManager.ExampleFile;
			if (exampleFile == null)
			{
				return;
			}
			staged = exampleFile.EffectiveFormat.Deserializer.Deserialize<ExampleSettings>(exampleFile.EffectiveFormat.Serializer.Serialize((object)exampleFile.Value));
			if (staged == null)
			{
				staged = ExampleData.BuildDefaults();
			}
			panel = ConfigUI.CreatePanel("Example settings", 620f, 520f, out var body);
			List<GameObject> list = new List<GameObject>();
			list.Add(ConfigUI.AddHeaderRow(body, 580f, "Entries", (TextAnchor)3));
			foreach (KeyValuePair<string, ExampleEntry> entry2 in staged.Entries)
			{
				ExampleEntry entry = entry2.Value;
				list.Add(ConfigUI.AddTextRow(body, 580f, 26f, entry2.Key, 15, GUIManager.Instance.ValheimOrange, (TextAnchor)0));
				list.Add(ConfigUI.AddTextFieldRow(body, 580f, 190f, 240f, "Display name", entry.DisplayName, delegate(string s)
				{
					entry.DisplayName = s;
				}, null, 64));
				list.Add(ConfigUI.AddSliderRow(body, 580f, 190f, 200f, 60f, "Multiplier", 0.1f, 10f, entry.Multiplier, wholeNumbers: false, delegate(float v)
				{
					entry.Multiplier = v;
				}));
				list.Add(ConfigUI.AddEnumCycleRow(body, 580f, 190f, 150f, "Mode", Enum.GetNames(typeof(ExampleMode)), (int)entry.Mode, delegate(int i)
				{
					entry.Mode = (ExampleMode)i;
				}));
				list.Add(ConfigUI.AddPickerRow(body, 580f, 190f, 260f, "First prefab", (entry.Prefabs.Count > 0) ? entry.Prefabs[0] : "", PrefabNames, delegate(string s)
				{
					if (entry.Prefabs.Count > 0)
					{
						entry.Prefabs[0] = s;
					}
					else
					{
						entry.Prefabs.Add(s);
					}
				}, IsKnownPrefab));
				list.Add(ConfigUI.AddDividerRow(body, 580f));
			}
			ConfigUI.LayoutColumn(list, 20f, 60f);
			messages = ConfigUI.AddText(body, 20f, 412f, 580f, 46f, "", 13, (TextAnchor)0);
			ConfigUI.AddButton(body, 20f, 464f, 130f, "Validate", new UnityAction(Validate));
			ConfigUI.AddButton(body, 300f, 464f, 130f, "Cancel", new UnityAction(ClosePanel));
			ConfigUI.AddButton(body, 450f, 464f, 150f, "Apply & Save", new UnityAction(ApplyAndSave));
		}

		private static void Validate()
		{
			YamlConfigFile<ExampleSettings> exampleFile = YamlConfigManager.ExampleFile;
			if (exampleFile != null && staged != null)
			{
				string parseError;
				ValidationReport validationReport = exampleFile.DryRun(YamlConfigManager.SerializeForEdit(exampleFile, staged), out parseError);
				if (parseError != null)
				{
					ConfigUI.SetMessages(messages, new List<string> { parseError }, null);
				}
				else if (validationReport.Errors.Count == 0 && validationReport.Warnings.Count == 0)
				{
					messages.text = "Looks good.";
				}
				else
				{
					ConfigUI.SetMessages(messages, validationReport.Errors, validationReport.Warnings);
				}
			}
		}

		private static void ApplyAndSave()
		{
			YamlConfigFile<ExampleSettings> exampleFile = YamlConfigManager.ExampleFile;
			if (exampleFile == null || staged == null)
			{
				return;
			}
			try
			{
				string yaml = YamlConfigManager.SerializeForEdit(exampleFile, staged);
				if (!YamlConfigManager.ApplyEdited(exampleFile, yaml, out var message))
				{
					ConfigUI.SetMessages(messages, new List<string> { message }, null);
				}
				else
				{
					ClosePanel();
				}
			}
			catch (Exception ex)
			{
				Logger.LogError($"Example config panel failed to apply: {ex}");
				ConfigUI.SetMessages(messages, new List<string> { ex.Message }, null);
			}
		}

		private static void ClosePanel()
		{
			if (!((Object)(object)panel == (Object)null))
			{
				Object.Destroy((Object)(object)panel);
				panel = null;
				messages = null;
			}
		}

		private static IList<string> PrefabNames()
		{
			List<string> list = new List<string>();
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				return list;
			}
			foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
			{
				if ((Object)(object)prefab != (Object)null)
				{
					list.Add(((Object)prefab).name);
				}
			}
			return list;
		}

		private static bool IsKnownPrefab(string name)
		{
			if (PrefabManager.Instance == null)
			{
				return true;
			}
			return (Object)(object)PrefabManager.Instance.GetPrefab(name) != (Object)null;
		}
	}
	internal class QuickConfigBroker : MonoBehaviour
	{
		internal const string BrokerObjectName = "ModQuickConfigLauncher";

		internal const string BrokerTypeName = "QuickConfigBroker";

		internal const string ButtonObjectName = "ModQuickConfigButton";

		internal const int ContractVersion = 2;

		private const float ButtonW = 150f;

		private const float ButtonH = 38f;

		private const float PanelW = 320f;

		private static QuickConfigBroker Instance;

		private static Harmony harmony;

		private readonly Dictionary<string, Action> entries = new Dictionary<string, Action>(StringComparer.Ordinal);

		private readonly List<string> order = new List<string>();

		private GameObject mainMenuButton;

		private GameObject pauseButton;

		private GameObject listPanel;

		public int BrokerVersion => 2;

		public void Register(string modName, Action openPanel)
		{
			if (!string.IsNullOrEmpty(modName) && openPanel != null)
			{
				if (!entries.ContainsKey(modName))
				{
					order.Add(modName);
				}
				entries[modName] = openPanel;
				RefreshVisibility();
			}
		}

		public void Unregister(string modName)
		{
			if (!string.IsNullOrEmpty(modName))
			{
				if (entries.Remove(modName))
				{
					order.Remove(modName);
				}
				if ((Object)(object)listPanel != (Object)null)
				{
					CloseList();
				}
				RefreshVisibility();
			}
		}

		public bool IsRegistered(string modName)
		{
			if (!string.IsNullOrEmpty(modName))
			{
				return entries.ContainsKey(modName);
			}
			return false;
		}

		public void Awake()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Expected O, but got Unknown
			Instance = this;
			GUIManager.OnCustomGUIAvailable += OnCustomGUIAvailable;
			SynchronizationManager.OnAdminStatusChanged += OnAdminStatusChanged;
			SynchronizationManager.OnConfigurationSynchronized += OnConfigurationSynchronized;
			try
			{
				if (harmony == null)
				{
					harmony = new Harmony("ModQuickConfigLauncher.broker");
					harmony.Patch((MethodBase)AccessTools.Method(typeof(Menu), "Start", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(QuickConfigBroker), "OnMenuStart", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					harmony.Patch((MethodBase)AccessTools.Method(typeof(Menu), "Update", (Type[])null, (Type[])null), new HarmonyMethod(typeof(QuickConfigBroker), "OnMenuUpdate", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			catch (Exception ex)
			{
				Logger.LogWarning("QuickConfig launcher could not patch Menu: " + ex.Message);
			}
			TryBuildButtons();
		}

		public void OnDestroy()
		{
			GUIManager.OnCustomGUIAvailable -= OnCustomGUIAvailable;
			SynchronizationManager.OnAdminStatusChanged -= OnAdminStatusChanged;
			SynchronizationManager.OnConfigurationSynchronized -= OnConfigurationSynchronized;
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		private void OnAdminStatusChanged()
		{
			RefreshVisibility();
		}

		private void OnConfigurationSynchronized(object sender, EventArgs e)
		{
			RefreshVisibility();
		}

		private static void OnMenuStart(Menu __instance)
		{
			if (!((Object)(object)Instance == (Object)null))
			{
				Instance.EnsurePauseButton(__instance);
			}
		}

		private static bool OnMenuUpdate()
		{
			if ((Object)(object)Instance == (Object)null || (Object)(object)Instance.listPanel == (Object)null)
			{
				return true;
			}
			if (!ZInput.GetKeyDown((KeyCode)27, true))
			{
				return true;
			}
			Instance.CloseList();
			return false;
		}

		public void Update()
		{
			if (!((Object)(object)listPanel == (Object)null) && !((Object)(object)Menu.instance != (Object)null) && Input.GetKeyDown((KeyCode)27))
			{
				CloseList();
			}
		}

		private void OnCustomGUIAvailable()
		{
			TryBuildButtons();
		}

		private void TryBuildButtons()
		{
			if (!GUIManager.IsHeadless() && GUIManager.Instance != null)
			{
				if ((Object)(object)FejdStartup.instance != (Object)null && (Object)(object)GUIManager.CustomGUIFront != (Object)null)
				{
					mainMenuButton = EnsureCornerButton(mainMenuButton, GUIManager.CustomGUIFront.transform);
				}
				if ((Object)(object)Menu.instance != (Object)null)
				{
					EnsurePauseButton(Menu.instance);
				}
				RefreshVisibility();
			}
		}

		private void EnsurePauseButton(Menu menu)
		{
			if (!((Object)(object)menu == (Object)null) && !((Object)(object)menu.m_root == (Object)null))
			{
				pauseButton = EnsureCornerButton(pauseButton, menu.m_root);
				RefreshVisibility();
			}
		}

		private GameObject EnsureCornerButton(GameObject existing, Transform parent)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Expected O, but got Unknown
			if (GUIManager.IsHeadless() || GUIManager.Instance == null || (Object)(object)parent == (Object)null)
			{
				return existing;
			}
			if ((Object)(object)existing != (Object)null && (Object)(object)existing.transform.parent == (Object)(object)parent)
			{
				return existing;
			}
			Transform val = parent.Find("ModQuickConfigButton");
			if ((Object)(object)val != (Object)null)
			{
				return ((Component)val).gameObject;
			}
			GameObject obj = GUIManager.Instance.CreateButton(ConfigUI.L("Mod Config"), parent, new Vector2(1f, 0f), new Vector2(1f, 0f), new Vector2(-20f, 20f), 150f, 38f);
			((Object)obj).name = "ModQuickConfigButton";
			RectTransform val2 = (RectTransform)obj.transform;
			val2.pivot = new Vector2(1f, 0f);
			val2.anchoredPosition = new Vector2(-20f, 20f);
			((UnityEvent)obj.GetComponent<Button>().onClick).AddListener(new UnityAction(OpenList));
			return obj;
		}

		private static bool CanConfigure()
		{
			if (GUIManager.IsHeadless() || GUIManager.Instance == null)
			{
				return false;
			}
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return true;
			}
			if (ZNet.instance.IsServer())
			{
				return true;
			}
			if (SynchronizationManager.Instance != null)
			{
				return SynchronizationManager.Instance.PlayerIsAdmin;
			}
			return false;
		}

		private void RefreshVisibility()
		{
			bool flag = entries.Count > 0 && CanConfigure();
			if ((Object)(object)mainMenuButton != (Object)null)
			{
				mainMenuButton.SetActive(flag && (Object)(object)FejdStartup.instance != (Object)null);
			}
			if ((Object)(object)pauseButton != (Object)null)
			{
				pauseButton.SetActive(flag);
			}
			if (!flag && (Object)(object)listPanel != (Object)null)
			{
				CloseList();
			}
		}

		private void OpenList()
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Expected O, but got Unknown
			CloseList();
			if (!CanConfigure())
			{
				return;
			}
			if (order.Count == 1)
			{
				Invoke(order[0]);
				return;
			}
			float h = Mathf.Clamp(80f + 42f * (float)order.Count, 122f, 560f);
			listPanel = ConfigUI.CreatePanel("Configure a mod", 320f, h, out var body);
			ConfigUI.AddCloseX(body, 320f, new UnityAction(CloseList));
			float num = 64f;
			foreach (string item in order)
			{
				string entry = item;
				ConfigUI.AddButton(body, 20f, num, 280f, entry, (UnityAction)delegate
				{
					CloseList();
					Invoke(entry);
				});
				num += 42f;
			}
		}

		private void CloseList()
		{
			if (!((Object)(object)listPanel == (Object)null))
			{
				Object.Destroy((Object)(object)listPanel);
				listPanel = null;
			}
		}

		private void Invoke(string modName)
		{
			if (!entries.TryGetValue(modName, out var value) || value == null)
			{
				return;
			}
			try
			{
				value();
			}
			catch (Exception arg)
			{
				Logger.LogError($"The config panel for '{modName}' failed to open: {arg}");
			}
		}
	}
	internal enum ConfigOrigin
	{
		Startup,
		LocalFile,
		ServerSync,
		Api
	}
	internal enum ConfigFailurePolicy
	{
		KeepLastGood,
		RevertToDefaults,
		RestoreFileOnDisk
	}
	internal enum ConfigSyncMode
	{
		ServerAuthoritative,
		LocalOnly
	}
	internal enum UnknownKeyPolicy
	{
		WarnAndContinue,
		Strict,
		Silent
	}
	internal abstract class YamlConfigFile
	{
		internal string FileName { get; set; }

		internal string SubFolder { get; set; }

		internal string Header { get; set; }

		internal string RpcName { get; set; }

		internal YamlFormat Format { get; set; }

		internal ConfigFailurePolicy OnFailure { get; set; }

		internal ConfigSyncMode Sync { get; set; }

		internal UnknownKeyPolicy UnknownKeys { get; set; }

		internal bool ClientWritesToDisk { get; set; }

		internal bool Watch { get; set; } = true;

		internal bool NeedsPrefabs { get; set; }

		internal int SchemaVersion { get; set; }

		internal bool AllowAdminEdit { get; set; }

		internal string Path { get; set; }

		internal CustomRPC Rpc { get; set; }

		internal CustomRPC EditRpc { get; set; }

		internal bool LastLoadFailed { get; set; }

		internal string LastError { get; set; }

		internal DateTime LastLoadedUtc { get; set; }

		internal ValidationReport LastReport { get; set; }

		internal YamlFormat EffectiveFormat => Format ?? YamlFormat.Default;

		internal abstract Type ValueType { get; }

		internal abstract string SerializeDefaults();

		internal abstract string SerializeCurrent();

		internal abstract bool LoadFrom(string yaml, ConfigOrigin origin);

		internal abstract ValidationReport Revalidate();

		internal abstract ValidationReport DryRun(string yaml, out string parseError);
	}
	internal sealed class YamlConfigFile<T> : YamlConfigFile where T : class
	{
		internal Func<T> Defaults { get; set; }

		internal Action<T> Apply { get; set; }

		internal Func<T, T, ValidationReport> Validate { get; set; }

		internal Func<T, T> Migrate { get; set; }

		internal Func<T, int> GetSchemaVersion { get; set; }

		internal Action<T, int> SetSchemaVersion { get; set; }

		internal Func<T, bool> MigrateInPlace { get; set; }

		internal T Value { get; private set; }

		internal override Type ValueType => typeof(T);

		internal YamlConfigFile(string fileName)
		{
			base.FileName = fileName;
		}

		internal override string SerializeDefaults()
		{
			T val = BuildDefaults();
			if (val != null)
			{
				return base.EffectiveFormat.Serializer.Serialize((object)val);
			}
			return "";
		}

		internal override string SerializeCurrent()
		{
			if (Value != null)
			{
				return base.EffectiveFormat.Serializer.Serialize((object)Value);
			}
			return SerializeDefaults();
		}

		internal override ValidationReport DryRun(string yaml, out string parseError)
		{
			parseError = null;
			if (YamlConfigManager.HasNoUsableConfig(yaml))
			{
				parseError = "it is empty or contains only comments";
				return new ValidationReport();
			}
			string reason;
			T val = Deserialize(yaml, out reason);
			if (val == null)
			{
				parseError = reason ?? "it could not be parsed";
				return new ValidationReport();
			}
			if (MigrateInPlace != null)
			{
				try
				{
					MigrateInPlace(val);
				}
				catch (Exception ex)
				{
					Logger.LogWarning(base.FileName + " migration threw during a dry run: " + ex.Message);
				}
			}
			if (Validate == null)
			{
				return new ValidationReport();
			}
			try
			{
				return Validate(val, Value) ?? new ValidationReport();
			}
			catch (Exception ex2)
			{
				return new ValidationReport().Error("the validator threw: " + ex2.Message);
			}
		}

		internal override ValidationReport Revalidate()
		{
			if (Validate == null || Value == null)
			{
				return new ValidationReport();
			}
			ValidationReport validationReport;
			try
			{
				validationReport = Validate(Value, Value) ?? new ValidationReport();
			}
			catch (Exception ex)
			{
				validationReport = new ValidationReport().Error("the validator threw: " + ex.Message);
			}
			base.LastReport = validationReport;
			LogReport(validationReport);
			return validationReport;
		}

		internal override bool LoadFrom(string yaml, ConfigOrigin origin)
		{
			T parsed = null;
			string reason;
			if (YamlConfigManager.HasNoUsableConfig(yaml))
			{
				reason = "it is empty or contains only comments";
			}
			else
			{
				parsed = Deserialize(yaml, out reason);
			}
			if (parsed == null)
			{
				return Fail(reason, origin);
			}
			bool changed = false;
			if (base.SchemaVersion > 0 && GetSchemaVersion != null && !ApplySchemaVersion(ref parsed, out var problem, out changed))
			{
				return Fail(problem, origin);
			}
			if (MigrateInPlace != null)
			{
				try
				{
					if (MigrateInPlace(parsed))
					{
						changed = true;
					}
				}
				catch (Exception ex)
				{
					Logger.LogWarning(base.FileName + " migration threw, the file was left as it is: " + ex.Message);
				}
			}
			ValidationReport validationReport = new ValidationReport();
			if (Validate != null)
			{
				try
				{
					validationReport = Validate(parsed, Value) ?? new ValidationReport();
				}
				catch (Exception ex2)
				{
					validationReport = new ValidationReport().Error("the validator threw: " + ex2.Message);
				}
			}
			base.LastReport = validationReport;
			LogReport(validationReport);
			if (validationReport.HasErrors)
			{
				return Fail(string.Join(" ", validationReport.Errors.ToArray()), origin);
			}
			Value = parsed;
			base.LastLoadFailed = false;
			base.LastError = null;
			base.LastLoadedUtc = DateTime.UtcNow;
			Publish();
			if (changed && origin != ConfigOrigin.ServerSync && ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer()))
			{
				Logger.LogInfo(base.FileName + " was migrated to the current format; rewriting it.");
				YamlConfigManager.WriteCurrentToDisk(this);
			}
			return true;
		}

		private T Deserialize(string yaml, out string reason)
		{
			//IL_00a6: Expected O, but got Unknown
			//IL_002c: Expected O, but got Unknown
			reason = null;
			YamlFormat effectiveFormat = base.EffectiveFormat;
			try
			{
				T val = effectiveFormat.Deserializer.Deserialize<T>(yaml);
				if (val == null)
				{
					reason = "it is empty or contains only comments";
				}
				return val;
			}
			catch (YamlException ex)
			{
				YamlException e = ex;
				if (base.UnknownKeys == UnknownKeyPolicy.Strict)
				{
					reason = Describe(e);
					return null;
				}
				try
				{
					T val2 = effectiveFormat.TolerantDeserializer.Deserialize<T>(yaml);
					if (val2 == null)
					{
						reason = "it is empty or contains only comments";
						return null;
					}
					if (base.UnknownKeys == UnknownKeyPolicy.WarnAndContinue)
					{
						Logger.LogWarning(base.FileName + " " + Describe(e) + " That setting was ignored; the rest of the file loaded normally.");
					}
					return val2;
				}
				catch (YamlException ex2)
				{
					YamlException e2 = ex2;
					reason = Describe(e2);
					return null;
				}
			}
			catch (Exception ex3)
			{
				reason = ex3.Message;
				return null;
			}
		}

		private bool ApplySchemaVersion(ref T parsed, out string problem, out bool changed)
		{
			problem = null;
			changed = false;
			int num;
			try
			{
				num = GetSchemaVersion(parsed);
			}
			catch (Exception ex)
			{
				problem = "the schema version could not be read: " + ex.Message;
				return false;
			}
			if (num == base.SchemaVersion)
			{
				return true;
			}
			if (Migrate == null)
			{
				problem = $"it is schema version {num} but this mod expects {base.SchemaVersion}, and there is no migration for it";
				return false;
			}
			T val;
			try
			{
				val = Migrate(parsed);
			}
			catch (Exception ex2)
			{
				problem = $"migrating from schema version {num} to {base.SchemaVersion} threw: {ex2.Message}";
				return false;
			}
			if (val == null)
			{
				problem = $"migrating from schema version {num} to {base.SchemaVersion} produced nothing";
				return false;
			}
			parsed = val;
			SetSchemaVersion?.Invoke(parsed, base.SchemaVersion);
			changed = true;
			Logger.LogInfo($"{base.FileName} migrated from schema version {num} to {base.SchemaVersion}.");
			return true;
		}

		private bool Fail(string reason, ConfigOrigin origin)
		{
			base.LastLoadFailed = true;
			base.LastError = reason;
			switch (base.OnFailure)
			{
			case ConfigFailurePolicy.RevertToDefaults:
				PublishDefaults();
				Logger.LogError(base.FileName + " could not be loaded because " + reason + ". This mod's built-in defaults are in use; your file was left alone.");
				break;
			case ConfigFailurePolicy.RestoreFileOnDisk:
				PublishDefaults();
				if (origin != ConfigOrigin.ServerSync && ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer()))
				{
					YamlConfigManager.RestoreDefaults(this);
					Logger.LogError(base.FileName + " could not be loaded because " + reason + ". It has been overwritten with this mod's built-in defaults.");
				}
				else
				{
					Logger.LogError(base.FileName + " could not be loaded because " + reason + ". This mod's built-in defaults are in use; the file was left alone because this machine does not own it.");
				}
				break;
			default:
				if (Value == null)
				{
					PublishDefaults();
					Logger.LogError(base.FileName + " could not be loaded because " + reason + ". Nothing had loaded successfully yet, so this mod's built-in defaults are in use; your file was left alone.");
				}
				else
				{
					Logger.LogError(base.FileName + " could not be loaded because " + reason + ". The values that last loaded cleanly are still in use; your file was left alone.");
				}
				break;
			}
			return false;
		}

		private void PublishDefaults()
		{
			T val = BuildDefaults();
			if (val != null)
			{
				Value = val;
				Publish();
			}
		}

		private void Publish()
		{
			try
			{
				Apply?.Invoke(Value);
			}
			catch (Exception arg)
			{
				Logger.LogError($"{base.FileName} apply hook threw, the mod may be in a half-configured state: {arg}");
			}
		}

		private T BuildDefaults()
		{
			if (Defaults == null)
			{
				return null;
			}
			try
			{
				return Defaults();
			}
			catch (Exception arg)
			{
				Logger.LogError($"{base.FileName} default factory threw: {arg}");
				return null;
			}
		}

		private void LogReport(ValidationReport report)
		{
			if (report != null)
			{
				for (int i = 0; i < report.Warnings.Count; i++)
				{
					Logger.LogWarning(base.FileName + ": " + report.Warnings[i]);
				}
			}
		}

		private static string Describe(YamlException e)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			string arg = ((((Exception)(object)e).InnerException != null) ? ((Exception)(object)e).InnerException.Message : ((Exception)(object)e).Message);
			Mark start = e.Start;
			return $"line {((Mark)(ref start)).Line}: {arg}";
		}
	}
	internal sealed class YamlFormat
	{
		private readonly Action<SerializerBuilder> configureSerializer;

		private readonly Action<DeserializerBuilder> configureDeserializer;

		private static readonly List<YamlFormat> built;

		private static readonly List<IYamlTypeConverter> converters;

		internal ISerializer Serializer { get; private set; }

		internal IDeserializer Deserializer { get; private set; }

		internal IDeserializer TolerantDeserializer { get; private set; }

		internal static YamlFormat Default { get; private set; }

		internal static YamlFormat CamelCase { get; private set; }

		internal static YamlFormat JsonCompat { get; private set; }

		static YamlFormat()
		{
			built = new List<YamlFormat>();
			converters = new List<IYamlTypeConverter>();
			Default = Build(delegate(SerializerBuilder s)
			{
				((BuilderSkeleton<SerializerBuilder>)(object)s).WithNamingConvention(PascalCaseNamingConvention.Instance);
			}, null);
			CamelCase = Build(delegate(SerializerBuilder s)
			{
				((BuilderSkeleton<SerializerBuilder>)(object)s).WithNamingConvention(CamelCaseNamingConvention.Instance);
			}, null);
			JsonCompat = Build(delegate(SerializerBuilder s)
			{
				((BuilderSkeleton<SerializerBuilder>)(object)s).WithNamingConvention(PascalCaseNamingConvention.Instance).JsonCompatible();
			}, null);
		}

		private YamlFormat(Action<SerializerBuilder> serializerSetup, Action<DeserializerBuilder> deserializerSetup)
		{
			configureSerializer = serializerSetup;
			configureDeserializer = deserializerSetup;
			Rebuild();
		}

		internal static YamlFormat Build(Action<SerializerBuilder> configureSerializer, Action<DeserializerBuilder> configureDeserializer)
		{
			YamlFormat yamlFormat = new YamlFormat(configureSerializer, configureDeserializer);
			built.Add(yamlFormat);
			return yamlFormat;
		}

		internal static void AddTypeConverter(IYamlTypeConverter converter)
		{
			if (converter != null)
			{
				converters.Add(converter);
				for (int i = 0; i < built.Count; i++)
				{
					built[i].Rebuild();
				}
			}
		}

		private void Rebuild()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			SerializerBuilder val = new SerializerBuilder().DisableAliases().ConfigureDefaultValuesHandling((DefaultValuesHandling)2);
			configureSerializer?.Invoke(val);
			for (int i = 0; i < converters.Count; i++)
			{
				((BuilderSkeleton<SerializerBuilder>)(object)val).WithTypeConverter(converters[i]);
			}
			Serializer = val.Build();
			Deserializer = BuildDeserializer(tolerant: false);
			TolerantDeserializer = BuildDeserializ