Decompiled source of ModMenu v0.2.0

patchers/ModMenu/ModMenu.Patcher.dll

Decompiled 20 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mono.Cecil;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("ModMenu.Patcher")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Preloader part of ModMenu")]
[assembly: AssemblyFileVersion("0.2.0.0")]
[assembly: AssemblyInformationalVersion("0.2.0+118507c856dd0bcaa86de9a6f1234131721214f8")]
[assembly: AssemblyProduct("ModMenu.Patcher")]
[assembly: AssemblyTitle("ModMenu.Patcher")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.2.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ModMenu.Patcher
{
	internal static class ChainloaderFilter
	{
		private static PropertyInfo _locationProperty;

		private static readonly List<PluginInfo> _seen = new List<PluginInfo>();

		public static void Install()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			Harmony val = new Harmony("com.damia.modmenu.patcher");
			MethodInfo methodInfo = AccessTools.Method(typeof(TypeLoader), "FindPluginTypes", (Type[])null, (Type[])null).MakeGenericMethod(typeof(PluginInfo));
			val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(ChainloaderFilter), "FindPluginTypesPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static void FindPluginTypesPostfix(string cacheName, Dictionary<string, List<PluginInfo>> __result)
		{
			if (cacheName != "chainloader" || __result == null)
			{
				return;
			}
			object data = AppDomain.CurrentDomain.GetData("ModMenu.Discovering");
			bool flag = default(bool);
			int num;
			if (data is bool)
			{
				flag = (bool)data;
				num = 1;
			}
			else
			{
				num = 0;
			}
			if (((uint)num & (flag ? 1u : 0u)) != 0)
			{
				return;
			}
			try
			{
				HashSet<string> hashSet = Patcher.ReadDisabled(Patcher.DisabledFile);
				_seen.AddRange(__result.Values.SelectMany((List<PluginInfo> result) => result));
				List<PluginInfo> seen = _seen;
				if (hashSet.Count > 0 && !seen.Any((PluginInfo i) => string.Equals(i.Metadata.GUID, "com.damia.modmenu", StringComparison.OrdinalIgnoreCase)))
				{
					Patcher.Log.LogWarning((object)"ModMenu plugin not found; ignoring disabled.txt and loading every mod.");
					return;
				}
				HashSet<string> hashSet2 = ProtectedGuids(seen);
				List<PluginInfo> list = (AppDomain.CurrentDomain.GetData("ModMenu.Patcher.Skipped") as List<PluginInfo>) ?? new List<PluginInfo>();
				foreach (string item in __result.Keys.ToList())
				{
					List<PluginInfo> list2 = __result[item];
					foreach (PluginInfo item2 in list2.ToList())
					{
						string gUID = item2.Metadata.GUID;
						if (hashSet.Contains(gUID) && !hashSet2.Contains(gUID))
						{
							if (_locationProperty == null)
							{
								_locationProperty = AccessTools.Property(typeof(PluginInfo), "Location");
							}
							_locationProperty.SetValue(item2, item, null);
							list2.Remove(item2);
							list.Add(item2);
							Patcher.Log.LogMessage((object)$"Disabled in ModMenu, not loading [{item2}]");
						}
					}
					if (list2.Count == 0)
					{
						__result.Remove(item);
					}
				}
				AppDomain.CurrentDomain.SetData("ModMenu.Patcher.Skipped", list);
				AppDomain.CurrentDomain.SetData("ModMenu.Patcher.Protected", hashSet2.ToArray());
			}
			catch (Exception arg)
			{
				Patcher.Log.LogError((object)$"Could not filter disabled mods, every mod will load: {arg}");
			}
		}

		private static HashSet<string> ProtectedGuids(List<PluginInfo> all)
		{
			//IL_0095: 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)
			Dictionary<string, PluginInfo> dictionary = new Dictionary<string, PluginInfo>(StringComparer.OrdinalIgnoreCase);
			foreach (PluginInfo item in all)
			{
				dictionary[item.Metadata.GUID] = item;
			}
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "com.damia.modmenu" };
			Queue<string> queue = new Queue<string>(hashSet);
			while (queue.Count > 0)
			{
				if (!dictionary.TryGetValue(queue.Dequeue(), out var value))
				{
					continue;
				}
				foreach (BepInDependency dependency in value.Dependencies)
				{
					if ((dependency.Flags & 1) != 0 && hashSet.Add(dependency.DependencyGUID))
					{
						queue.Enqueue(dependency.DependencyGUID);
					}
				}
			}
			return hashSet;
		}
	}
	public static class Patcher
	{
		public const string ModMenuGuid = "com.damia.modmenu";

		public const string DataSkipped = "ModMenu.Patcher.Skipped";

		public const string DataProtected = "ModMenu.Patcher.Protected";

		public const string DataDisabledFile = "ModMenu.Patcher.DisabledFile";

		public const string DataDiscovering = "ModMenu.Discovering";

		internal static readonly ManualLogSource Log = Logger.CreateLogSource("ModMenu.Patcher");

		public static IEnumerable<string> TargetDLLs { get; } = new string[0];

		public static string DisabledFile => Path.Combine(Path.Combine(Paths.ConfigPath, "ModMenu"), "disabled.txt");

		public static void Patch(AssemblyDefinition assembly)
		{
		}

		public static void Finish()
		{
			try
			{
				ChainloaderFilter.Install();
				AppDomain.CurrentDomain.SetData("ModMenu.Patcher.DisabledFile", DisabledFile);
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Could not hook the chainloader, every mod will load: {arg}");
			}
		}

		public static HashSet<string> ReadDisabled(string file)
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			if (!File.Exists(file))
			{
				return hashSet;
			}
			string[] array = File.ReadAllLines(file);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0 && !text.StartsWith("#"))
				{
					hashSet.Add(text);
				}
			}
			return hashSet;
		}
	}
	internal static class PluginInfo
	{
		public const string Guid = "com.damia.modmenu.patcher";

		public const string Name = "ModMenu.Patcher";

		public const string Version = "0.2.0";
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}

plugins/ModMenu/ModMenu.dll

Decompiled 20 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using ModMenu.UI;
using Mono.Cecil;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("ModMenu")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Main-menu mod manager: switch mods on/off, edit their settings, profiles, update check (Nexus, Thunderstore)")]
[assembly: AssemblyFileVersion("0.2.0.0")]
[assembly: AssemblyInformationalVersion("0.2.0+118507c856dd0bcaa86de9a6f1234131721214f8")]
[assembly: AssemblyProduct("ModMenu")]
[assembly: AssemblyTitle("ModMenu")]
[assembly: InternalsVisibleTo("ModMenu.Tests")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.2.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ModMenu
{
	internal static class ConfigSources
	{
		private const BindingFlags InstanceFields = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private const BindingFlags StaticFields = BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly Dictionary<BaseUnityPlugin, List<ConfigFile>> Cache = new Dictionary<BaseUnityPlugin, List<ConfigFile>>();

		public static List<ConfigFile> For(BaseUnityPlugin plugin)
		{
			if ((Object)(object)plugin == (Object)null)
			{
				return new List<ConfigFile>();
			}
			if (Cache.TryGetValue(plugin, out var value))
			{
				return value;
			}
			List<ConfigFile> list = new List<ConfigFile>();
			Add(list, plugin.Config);
			try
			{
				Type type = ((object)plugin).GetType();
				while (type != null && type != typeof(BaseUnityPlugin))
				{
					FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (FieldInfo field in fields)
					{
						AddFromValue(list, field.FieldType, () => field.GetValue(plugin));
					}
					type = type.BaseType;
				}
				foreach (Type item in LoadableTypes(((object)plugin).GetType().Assembly))
				{
					if (item.ContainsGenericParameters || item.TypeInitializer != null)
					{
						continue;
					}
					FieldInfo[] fields = item.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (FieldInfo field2 in fields)
					{
						if (!field2.IsLiteral)
						{
							AddFromValue(list, field2.FieldType, () => field2.GetValue(null));
						}
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				PluginInfo info = plugin.Info;
				object obj;
				if (info == null)
				{
					obj = null;
				}
				else
				{
					BepInPlugin metadata = info.Metadata;
					obj = ((metadata != null) ? metadata.Name : null);
				}
				log.LogWarning((object)("Could not look for extra config files of " + (string?)obj + ": " + ex.Message));
			}
			Cache[plugin] = list;
			return list;
		}

		private static void AddFromValue(List<ConfigFile> files, Type fieldType, Func<object> read)
		{
			if (!typeof(ConfigFile).IsAssignableFrom(fieldType) && !typeof(ConfigEntryBase).IsAssignableFrom(fieldType))
			{
				return;
			}
			try
			{
				object obj = read();
				object obj2 = ((obj is ConfigFile) ? obj : null);
				if (obj2 == null)
				{
					object obj3 = ((obj is ConfigEntryBase) ? obj : null);
					obj2 = ((obj3 != null) ? ((ConfigEntryBase)obj3).ConfigFile : null);
				}
				Add(files, (ConfigFile)obj2);
			}
			catch (Exception)
			{
			}
		}

		private static void Add(List<ConfigFile> files, ConfigFile file)
		{
			if (file != null && !files.Contains(file) && !string.Equals(file.ConfigFilePath, Paths.BepInExConfigPath, StringComparison.OrdinalIgnoreCase))
			{
				files.Add(file);
			}
		}

		private static IEnumerable<Type> LoadableTypes(Assembly assembly)
		{
			try
			{
				return assembly.GetTypes();
			}
			catch (ReflectionTypeLoadException ex)
			{
				return ex.Types.Where((Type t) => t != null);
			}
		}
	}
	internal static class GameRestart
	{
		private const string SteamAppId = "892970";

		private static ProcessStartInfo UnixRestart(int pid, bool steam, string exe)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			string text = (((int)Application.platform == 1) ? "open" : "xdg-open");
			string arg = (steam ? (text + " steam://rungameid/892970") : ("\"" + exe.Replace("\"", "") + "\""));
			return new ProcessStartInfo
			{
				FileName = "/bin/sh",
				Arguments = $"-c 'while kill -0 {pid} 2>/dev/null; do sleep 1; done; {arg} >/dev/null 2>&1 &'",
				UseShellExecute = false,
				CreateNoWindow = true
			};
		}

		public static void Restart()
		{
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Invalid comparison between Unknown and I4
			try
			{
				Process currentProcess = Process.GetCurrentProcess();
				int id = currentProcess.Id;
				string text = currentProcess.MainModule?.FileName ?? "";
				bool flag = text.IndexOf("steamapps", StringComparison.OrdinalIgnoreCase) >= 0;
				string[] commandLineArgs = Environment.GetCommandLineArgs();
				string text2 = string.Join(",", (from a in commandLineArgs.Skip(1)
					select "'" + a.Replace("\"", "").Replace("'", "''") + "'").ToArray());
				string arg = (flag ? "Start-Process 'steam://rungameid/892970'" : ("Start-Process -FilePath '" + text.Replace("'", "''") + "'" + ((text2.Length > 0) ? (" -ArgumentList " + text2) : "")));
				Process.Start(((int)Application.platform == 2) ? new ProcessStartInfo
				{
					FileName = "powershell.exe",
					Arguments = $"-NoProfile -WindowStyle Hidden -Command \"Wait-Process -Id {id} -ErrorAction SilentlyContinue; {arg}\"",
					UseShellExecute = false,
					CreateNoWindow = true
				} : UnixRestart(id, flag, text));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Could not schedule the restart, the game will only quit: " + ex.Message));
			}
			Application.Quit();
		}
	}
	internal enum ModState
	{
		Loaded,
		Disabled,
		Failed
	}
	internal sealed class ModEntry
	{
		public string Guid;

		public string Name;

		public string Version;

		public string Location;

		public ModState State;

		public string Error;

		public string OnlyFor;

		public BaseUnityPlugin Instance;

		public string[] HardDependencies = new string[0];

		public bool Protected;

		public ModSource Source;

		public string LatestVersion;

		public bool UpdateAvailable;
	}
	internal static class ModCatalog
	{
		private const string DataSkipped = "ModMenu.Patcher.Skipped";

		private const string DataProtected = "ModMenu.Patcher.Protected";

		private const string DataDisabledFile = "ModMenu.Patcher.DisabledFile";

		private const string DataDiscovering = "ModMenu.Discovering";

		private static List<ModEntry> _mods;

		private static HashSet<string> _disabledAtStart;

		private static HashSet<string> _wanted;

		public static string Folder => Path.Combine(Paths.ConfigPath, "ModMenu");

		public static string DisabledFile => Path.Combine(Folder, "disabled.txt");

		public static string ProfilesFolder => Path.Combine(Folder, "profiles");

		public static bool PatcherActive => AppDomain.CurrentDomain.GetData("ModMenu.Patcher.DisabledFile") != null;

		public static List<ModEntry> Mods
		{
			get
			{
				if (_mods == null)
				{
					Build();
				}
				return _mods;
			}
		}

		public static HashSet<string> WantedDisabled
		{
			get
			{
				_ = Mods;
				return new HashSet<string>(_wanted, StringComparer.OrdinalIgnoreCase);
			}
		}

		public static bool RestartNeeded
		{
			get
			{
				_ = Mods;
				return _mods.Any((ModEntry m) => _wanted.Contains(m.Guid) != _disabledAtStart.Contains(m.Guid));
			}
		}

		public static bool IsWantedDisabled(string guid)
		{
			_ = Mods;
			return _wanted.Contains(guid);
		}

		public static void SetWantedDisabled(string guid, bool disabled)
		{
			_ = Mods;
			ModEntry modEntry = _mods.FirstOrDefault((ModEntry m) => m.Guid == guid);
			if ((modEntry == null || !modEntry.Protected) && (disabled ? _wanted.Add(guid) : _wanted.Remove(guid)))
			{
				SaveWanted();
			}
		}

		public static void ReplaceWanted(IEnumerable<string> guids)
		{
			_ = Mods;
			HashSet<string> protectedGuids = new HashSet<string>(from m in _mods
				where m.Protected
				select m.Guid, StringComparer.OrdinalIgnoreCase);
			_wanted = new HashSet<string>(guids.Where((string g) => !protectedGuids.Contains(g)), StringComparer.OrdinalIgnoreCase);
			SaveWanted();
		}

		public static List<ModEntry> Dependents(string guid)
		{
			return Mods.Where((ModEntry m) => m.HardDependencies.Contains<string>(guid, StringComparer.OrdinalIgnoreCase)).ToList();
		}

		public static List<string> MissingDependencies(ModEntry mod)
		{
			List<string> list = new List<string>();
			string[] hardDependencies = mod.HardDependencies;
			foreach (string dependency in hardDependencies)
			{
				ModEntry modEntry = Mods.FirstOrDefault((ModEntry m) => string.Equals(m.Guid, dependency, StringComparison.OrdinalIgnoreCase));
				if (modEntry == null || _wanted.Contains(modEntry.Guid))
				{
					list.Add(modEntry?.Name ?? dependency);
				}
			}
			return list;
		}

		private static void Build()
		{
			Dictionary<string, ModEntry> dictionary = new Dictionary<string, ModEntry>(StringComparer.OrdinalIgnoreCase);
			string[] source = (AppDomain.CurrentDomain.GetData("ModMenu.Patcher.Protected") as string[]) ?? new string[1] { "com.damia.modmenu" };
			foreach (PluginInfo value in Chainloader.PluginInfos.Values)
			{
				dictionary[value.Metadata.GUID] = FromInfo(value, (!((Object)(object)value.Instance != (Object)null)) ? ModState.Failed : ModState.Loaded);
			}
			_disabledAtStart = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			if (AppDomain.CurrentDomain.GetData("ModMenu.Patcher.Skipped") is List<PluginInfo> list)
			{
				foreach (PluginInfo item in list)
				{
					dictionary[item.Metadata.GUID] = FromInfo(item, ModState.Disabled);
					_disabledAtStart.Add(item.Metadata.GUID);
				}
			}
			foreach (PluginInfo info in DiscoverAll())
			{
				if (!dictionary.ContainsKey(info.Metadata.GUID))
				{
					ModEntry modEntry = FromInfo(info, ModState.Failed);
					modEntry.Error = Chainloader.DependencyErrors.FirstOrDefault((string e) => e.Contains("[" + ((object)info)?.ToString() + "]"));
					List<string> list2 = info.Processes.Select((BepInProcess p) => p.ProcessName).ToList();
					if (list2.Count > 0 && !list2.Any((string p) => string.Equals(p.Replace(".exe", ""), Paths.ProcessName, StringComparison.OrdinalIgnoreCase)))
					{
						modEntry.OnlyFor = string.Join(", ", list2.ToArray());
					}
					dictionary[info.Metadata.GUID] = modEntry;
				}
			}
			foreach (ModEntry value2 in dictionary.Values)
			{
				value2.Protected = source.Contains<string>(value2.Guid, StringComparer.OrdinalIgnoreCase);
			}
			_mods = dictionary.Values.OrderBy<ModEntry, string>((ModEntry m) => m.Name, StringComparer.OrdinalIgnoreCase).ToList();
			_wanted = ReadGuidFile(DisabledFile);
			_wanted.RemoveWhere((string g) => _mods.Any((ModEntry m) => m.Protected && string.Equals(m.Guid, g, StringComparison.OrdinalIgnoreCase)));
			ModSources.Detect(_mods);
			Plugin.Log.LogInfo((object)($"Found {_mods.Count} mods: {_mods.Count((ModEntry m) => m.State == ModState.Loaded)} loaded, " + $"{_mods.Count((ModEntry m) => m.State == ModState.Disabled)} switched off, {_mods.Count((ModEntry m) => m.State == ModState.Failed)} not loaded; " + $"sources: {_mods.Count((ModEntry m) => m.Source.Kind == SourceKind.Nexus)} Nexus, {_mods.Count((ModEntry m) => m.Source.Kind == SourceKind.Thunderstore)} Thunderstore"));
		}

		private static IEnumerable<PluginInfo> DiscoverAll()
		{
			AppDomain.CurrentDomain.SetData("ModMenu.Discovering", true);
			Dictionary<string, List<PluginInfo>> dictionary;
			try
			{
				dictionary = TypeLoader.FindPluginTypes<PluginInfo>(Paths.PluginPath, (Func<TypeDefinition, PluginInfo>)Chainloader.ToPluginInfo, (Func<AssemblyDefinition, bool>)null, "chainloader");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not list the plugins folder: " + ex.Message));
				yield break;
			}
			finally
			{
				AppDomain.CurrentDomain.SetData("ModMenu.Discovering", false);
			}
			foreach (KeyValuePair<string, List<PluginInfo>> pair in dictionary)
			{
				foreach (PluginInfo item in pair.Value)
				{
					if (string.IsNullOrEmpty(item.Location))
					{
						AccessLocation(item, pair.Key);
					}
					yield return item;
				}
			}
		}

		private static void AccessLocation(PluginInfo info, string location)
		{
			AccessTools.Property(typeof(PluginInfo), "Location").SetValue(info, location, null);
		}

		private static ModEntry FromInfo(PluginInfo info, ModState state)
		{
			return new ModEntry
			{
				Guid = info.Metadata.GUID,
				Name = info.Metadata.Name,
				Version = (info.Metadata.Version?.ToString() ?? "?"),
				Location = info.Location,
				State = state,
				Instance = info.Instance,
				HardDependencies = (from d in info.Dependencies
					where (d.Flags & 1) > 0
					select d.DependencyGUID).ToArray()
			};
		}

		private static void SaveWanted()
		{
			try
			{
				Directory.CreateDirectory(Folder);
				List<string> list = new List<string> { "# Mods switched off by ModMenu (one plugin GUID per line). Delete a line, or this file, to switch a mod back on." };
				list.AddRange(_wanted.OrderBy<string, string>((string g) => g, StringComparer.OrdinalIgnoreCase));
				File.WriteAllLines(DisabledFile, list.ToArray());
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Could not save " + DisabledFile + ": " + ex.Message));
			}
		}

		internal static HashSet<string> ReadGuidFile(string file)
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			try
			{
				if (File.Exists(file))
				{
					string[] array = File.ReadAllLines(file);
					for (int i = 0; i < array.Length; i++)
					{
						string text = array[i].Trim();
						if (text.Length > 0 && !text.StartsWith("#"))
						{
							hashSet.Add(text);
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not read " + file + ": " + ex.Message));
			}
			return hashSet;
		}
	}
	internal enum SourceKind
	{
		Unknown,
		Nexus,
		Thunderstore
	}
	internal sealed class ModSource
	{
		public SourceKind Kind;

		public int NexusId;

		public string ThunderstoreNamespace;

		public string ThunderstoreName;

		public string InstalledVersion;

		public bool Guessed;

		public string PageUrl
		{
			get
			{
				if (Kind != SourceKind.Nexus)
				{
					if (Kind != SourceKind.Thunderstore || ThunderstoreNamespace == null)
					{
						return null;
					}
					return "https://thunderstore.io/c/valheim/p/" + ThunderstoreNamespace + "/" + ThunderstoreName + "/";
				}
				return $"https://www.nexusmods.com/valheim/mods/{NexusId}";
			}
		}
	}
	internal static class ModSources
	{
		private static readonly Regex VortexNew = new Regex("^(?<name>.+?) (?<id>\\d+) (?<ver>\\S+) \\d{4}-\\d{2}-\\d{2}T", RegexOptions.Compiled);

		private static readonly Regex VortexOld = new Regex("^(?<name>.+?)-(?<id>\\d+)-(?<ver>\\d+(?:-\\d+)*?)-\\d{9,}$", RegexOptions.Compiled);

		private static readonly Regex Dependency = new Regex("^(?<ns>[^-]+)-(?<name>.+)-\\d+\\.\\d+\\.\\d+$", RegexOptions.Compiled);

		public static void Detect(List<ModEntry> mods)
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, string> vortex = ReadVortexManifests();
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			Dictionary<ModEntry, JObject> dictionary2 = new Dictionary<ModEntry, JObject>();
			foreach (ModEntry mod in mods)
			{
				if (string.IsNullOrEmpty(mod.Location))
				{
					mod.Source = new ModSource();
					continue;
				}
				mod.Source = FromVortex(mod, vortex) ?? new ModSource();
				if (mod.Source.Kind != SourceKind.Unknown)
				{
					continue;
				}
				JObject val = FindManifest(mod.Location);
				if (val == null)
				{
					continue;
				}
				dictionary2[mod] = val;
				JToken obj = val["dependencies"];
				foreach (JToken item in (JArray)(((object)((obj is JArray) ? obj : null)) ?? ((object)new JArray())))
				{
					Match match = Dependency.Match(((string)item) ?? "");
					if (match.Success)
					{
						dictionary[match.Groups["name"].Value] = match.Groups["ns"].Value;
					}
				}
			}
			foreach (KeyValuePair<ModEntry, JObject> item2 in dictionary2)
			{
				string text = (string)item2.Value["name"];
				if (!string.IsNullOrEmpty(text))
				{
					string name = new DirectoryInfo(Path.GetDirectoryName(item2.Key.Location)).Name;
					string value;
					string thunderstoreNamespace = (name.EndsWith("-" + text, StringComparison.OrdinalIgnoreCase) ? name.Substring(0, name.Length - text.Length - 1) : (dictionary.TryGetValue(text, out value) ? value : null));
					item2.Key.Source = new ModSource
					{
						Kind = SourceKind.Thunderstore,
						ThunderstoreName = text,
						ThunderstoreNamespace = thunderstoreNamespace,
						InstalledVersion = (string)item2.Value["version_number"]
					};
				}
			}
			foreach (ModEntry item3 in mods.Where((ModEntry m) => m.Source.Kind == SourceKind.Unknown && !string.IsNullOrEmpty(m.Location)))
			{
				item3.Source = new ModSource
				{
					Kind = SourceKind.Thunderstore,
					ThunderstoreName = item3.Name.Replace(" ", ""),
					Guessed = true
				};
			}
		}

		private static ModSource FromVortex(ModEntry mod, Dictionary<string, string> vortex)
		{
			if (!vortex.TryGetValue(Normalize(mod.Location), out var value) || !ParseVortexArchive(value, out var id, out var version))
			{
				return null;
			}
			return new ModSource
			{
				Kind = SourceKind.Nexus,
				NexusId = id,
				InstalledVersion = version
			};
		}

		internal static bool ParseVortexArchive(string archive, out int id, out string version)
		{
			id = 0;
			version = null;
			Match match = VortexNew.Match(archive ?? "");
			if (match.Success)
			{
				version = match.Groups["ver"].Value;
			}
			else
			{
				match = VortexOld.Match(archive ?? "");
				if (!match.Success)
				{
					return false;
				}
				version = match.Groups["ver"].Value.Replace('-', '.');
			}
			return int.TryParse(match.Groups["id"].Value, out id);
		}

		private static Dictionary<string, string> ReadVortexManifests()
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			try
			{
				string[] files = Directory.GetFiles(Paths.PluginPath, "vortex.deployment*.json");
				for (int i = 0; i < files.Length; i++)
				{
					JObject obj = JObject.Parse(File.ReadAllText(files[i]));
					string path = ((string)obj["targetPath"]) ?? Paths.PluginPath;
					JToken obj2 = obj["files"];
					foreach (JToken item in (JArray)(((object)((obj2 is JArray) ? obj2 : null)) ?? ((object)new JArray())))
					{
						string text = (string)item[(object)"relPath"];
						string value = (string)item[(object)"source"];
						if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(value))
						{
							dictionary[Normalize(Path.Combine(path, text))] = value;
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not read the Vortex deployment manifest: " + ex.Message));
			}
			return dictionary;
		}

		private static JObject FindManifest(string dll)
		{
			string text = Normalize(Paths.PluginPath);
			string directoryName = Path.GetDirectoryName(dll);
			while (!string.IsNullOrEmpty(directoryName) && Normalize(directoryName).StartsWith(text) && Normalize(directoryName) != text)
			{
				string text2 = Path.Combine(directoryName, "manifest.json");
				if (File.Exists(text2))
				{
					try
					{
						return JObject.Parse(File.ReadAllText(text2));
					}
					catch (Exception ex)
					{
						Plugin.Log.LogWarning((object)("Could not read " + text2 + ": " + ex.Message));
						return null;
					}
				}
				directoryName = Path.GetDirectoryName(directoryName);
			}
			return null;
		}

		private static string Normalize(string path)
		{
			return Path.GetFullPath(path).TrimEnd('\\', '/').ToLowerInvariant();
		}

		public static int[] ParseVersion(string version)
		{
			if (string.IsNullOrEmpty(version))
			{
				return null;
			}
			int result;
			int[] array = (from Match m in Regex.Matches(version, "\\d+")
				select int.TryParse(m.Value, out result) ? result : 0).ToArray();
			if (array.Length != 0)
			{
				return array;
			}
			return null;
		}

		public static bool IsNewer(string latest, string installed)
		{
			int[] array = ParseVersion(latest);
			int[] array2 = ParseVersion(installed);
			if (array == null || array2 == null)
			{
				return false;
			}
			for (int i = 0; i < Math.Max(array.Length, array2.Length); i++)
			{
				int num = ((i < array.Length) ? array[i] : 0);
				int num2 = ((i < array2.Length) ? array2[i] : 0);
				if (num != num2)
				{
					return num > num2;
				}
			}
			return false;
		}
	}
	[BepInPlugin("com.damia.modmenu", "Mod Menu", "0.2.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		internal static Plugin Instance;

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> CheckUpdatesOnOpen;

		internal static ConfigEntry<KeyboardShortcut> OpenKey;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0051: 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_0075: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			CheckUpdatesOnOpen = ((BaseUnityPlugin)this).Config.Bind<bool>("Updates", "CheckOnOpen", true, "Check Nexus Mods and Thunderstore for newer versions the first time the menu is opened in a session.");
			OpenKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "OpenKey", new KeyboardShortcut((KeyCode)109, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Opens the Mods window in the main menu - also when another mod reworks the menu and hides the button.");
			_harmony = new Harmony("com.damia.modmenu");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			Log.LogInfo((object)"ModMenu 0.2.0 loaded");
		}

		private void Update()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			FejdStartup instance = FejdStartup.instance;
			if ((Object)(object)instance != (Object)null && !ModMenuWindow.IsOpen && (Object)(object)instance.m_menuList != (Object)null && instance.m_menuList.activeInHierarchy)
			{
				KeyboardShortcut value = OpenKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					MainMenuButton.OpenWindow(instance);
				}
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal static class Profiles
	{
		public static List<string> Names()
		{
			try
			{
				if (!Directory.Exists(ModCatalog.ProfilesFolder))
				{
					return new List<string>();
				}
				return Directory.GetFiles(ModCatalog.ProfilesFolder, "*.txt").Select(Path.GetFileNameWithoutExtension).OrderBy<string, string>((string n) => n, StringComparer.OrdinalIgnoreCase)
					.ToList();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not list profiles: " + ex.Message));
				return new List<string>();
			}
		}

		public static HashSet<string> Read(string name)
		{
			return ModCatalog.ReadGuidFile(PathOf(name));
		}

		public static string Matching(HashSet<string> disabled)
		{
			return Names().FirstOrDefault((string n) => Read(n).SetEquals(disabled));
		}

		public static string Save(string name, IEnumerable<string> disabledGuids)
		{
			name = Clean(name);
			if (name.Length == 0)
			{
				return null;
			}
			try
			{
				Directory.CreateDirectory(ModCatalog.ProfilesFolder);
				List<string> list = new List<string> { "# ModMenu profile: mods switched off (one plugin GUID per line)." };
				list.AddRange(disabledGuids.OrderBy<string, string>((string g) => g, StringComparer.OrdinalIgnoreCase));
				File.WriteAllLines(PathOf(name), list.ToArray());
				return name;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Could not save profile " + name + ": " + ex.Message));
				return null;
			}
		}

		public static void Delete(string name)
		{
			try
			{
				File.Delete(PathOf(name));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Could not delete profile " + name + ": " + ex.Message));
			}
		}

		private static string PathOf(string name)
		{
			return Path.Combine(ModCatalog.ProfilesFolder, Clean(name) + ".txt");
		}

		private static string Clean(string name)
		{
			char[] invalid = Path.GetInvalidFileNameChars();
			return new string((name ?? "").Where((char c) => !invalid.Contains(c)).ToArray()).Trim();
		}
	}
	internal static class T
	{
		private static readonly Dictionary<string, (string en, string pl)> Strings = new Dictionary<string, (string, string)>
		{
			["menu_button"] = ("Mods", "Mody"),
			["title"] = ("Mods ({0})", "Mody ({0})"),
			["close"] = ("Close", "Zamknij"),
			["back"] = ("Back", "Wróć"),
			["profiles"] = ("Profiles", "Profile"),
			["check_updates"] = ("Check updates", "Sprawdź aktualizacje"),
			["checking"] = ("Checking... {0}/{1}", "Sprawdzam... {0}/{1}"),
			["restart"] = ("Restart game", "Uruchom ponownie"),
			["restart_needed"] = ("Changes apply after a restart.", "Zmiany zadziałają po ponownym uruchomieniu gry."),
			["no_patcher"] = ("ModMenu.Patcher is missing from BepInEx/patchers - switching mods off will not work.", "Brak ModMenu.Patcher w BepInEx/patchers - wyłączanie modów nie zadziała."),
			["search"] = ("Search...", "Szukaj..."),
			["settings"] = ("Settings", "Ustawienia"),
			["page"] = ("Page", "Strona"),
			["state_loaded"] = ("Loaded", "Działa"),
			["state_disabled"] = ("Switched off", "Wyłączony"),
			["only_for"] = ("Not for this program (only {0})", "Nie dla tego programu (tylko {0})"),
			["state_failed"] = ("Failed to load", "Błąd ładowania"),
			["state_off_next"] = ("Off after restart", "Wyłączy się po restarcie"),
			["state_on_next"] = ("On after restart", "Włączy się po restarcie"),
			["protected"] = ("Required by Mod Menu", "Wymagany przez Mod Menu"),
			["update"] = ("Update: {0}", "Aktualizacja: {0}"),
			["up_to_date"] = ("Up to date", "Aktualny"),
			["needs"] = ("Needs: {0}", "Wymaga: {0}"),
			["also_stops"] = ("Also stops: {0}", "Przestaną działać też: {0}"),
			["update_error"] = ("Update check failed: {0}", "Nie udało się sprawdzić aktualizacji: {0}"),
			["updates_found"] = ("Updates available: {0}", "Dostępne aktualizacje: {0}"),
			["no_updates"] = ("All checked mods are up to date.", "Wszystkie sprawdzone mody są aktualne."),
			["config_title"] = ("{0} - settings", "{0} - ustawienia"),
			["config_none"] = ("This mod has no settings.", "Ten mod nie ma ustawień."),
			["config_off"] = ("Switch the mod on and restart the game to edit its settings.", "Włącz moda i uruchom ponownie grę, żeby zmienić jego ustawienia."),
			["config_hint"] = ("Saved at once. Some mods read a setting only at startup.", "Zapisuje się od razu. Niektóre mody czytają ustawienie tylko przy starcie gry."),
			["advanced"] = ("advanced", "zaawansowane"),
			["config_search"] = ("Search settings...", "Szukaj ustawień..."),
			["config_no_match"] = ("No setting matches the search.", "Żadne ustawienie nie pasuje do wyszukiwania."),
			["reset"] = ("Default", "Domyślne"),
			["invalid"] = ("Invalid value", "Nieprawidłowa wartość"),
			["profile_name"] = ("New profile name...", "Nazwa nowego profilu..."),
			["profile_save"] = ("Save current", "Zapisz obecny"),
			["profile_load"] = ("Load", "Wczytaj"),
			["profile_overwrite"] = ("Overwrite", "Nadpisz"),
			["profile_delete"] = ("Delete", "Usuń"),
			["profile_active"] = ("(current)", "(obecny)"),
			["profile_none"] = ("No profiles yet. A profile remembers which mods are switched off.", "Brak profili. Profil zapamiętuje, które mody są wyłączone."),
			["profile_count"] = ("{0} off", "wyłączonych: {0}"),
			["all_on"] = ("Switch all on", "Włącz wszystkie")
		};

		public static string Get(string key, params object[] args)
		{
			if (!Strings.TryGetValue(key, out (string, string) value))
			{
				return key;
			}
			string text;
			if (Localization.instance == null || !(Localization.instance.GetSelectedLanguage() == "Polish"))
			{
				(text, _) = value;
			}
			else
			{
				text = value.Item2;
			}
			string text2 = text;
			if (args.Length == 0)
			{
				return text2;
			}
			return string.Format(text2, args);
		}
	}
	internal static class UpdateChecker
	{
		private const string NexusApi = "https://api.nexusmods.com/v2/graphql";

		private const string ThunderstorePackage = "https://thunderstore.io/api/experimental/package/{0}/{1}/";

		private const string ThunderstoreSearch = "https://thunderstore.io/api/cyberstorm/listing/valheim/?q={0}";

		private const int ParallelRequests = 6;

		private const int NexusBatch = 50;

		private const int NameBatch = 20;

		public static bool Running { get; private set; }

		public static bool Done { get; private set; }

		public static int Progress { get; private set; }

		public static int Total { get; private set; }

		public static string LastError { get; private set; }

		public static IEnumerator Run(List<ModEntry> mods, Action onChanged)
		{
			List<ModEntry> thunderstore;
			int next;
			int workers;
			if (!Running)
			{
				Running = true;
				LastError = null;
				List<ModEntry> nexus = mods.Where(delegate(ModEntry m)
				{
					ModSource source = m.Source;
					return source != null && source.Kind == SourceKind.Nexus;
				}).ToList();
				thunderstore = mods.Where(delegate(ModEntry m)
				{
					ModSource source = m.Source;
					return source != null && source.Kind == SourceKind.Thunderstore;
				}).ToList();
				Total = (nexus.Count + 50 - 1) / 50 + thunderstore.Count + 1;
				Progress = 0;
				onChanged();
				for (int i = 0; i < nexus.Count; i += 50)
				{
					yield return CheckNexus(nexus.Skip(i).Take(50).ToList());
					Progress++;
					onChanged();
				}
				next = 0;
				workers = 0;
				for (int num = 0; num < 6; num++)
				{
					workers++;
					((MonoBehaviour)Plugin.Instance).StartCoroutine(Worker());
				}
				float deadline = Time.realtimeSinceStartup + 180f;
				while (workers > 0 && Time.realtimeSinceStartup < deadline)
				{
					yield return null;
				}
				List<ModEntry> unknown = thunderstore.Where((ModEntry m) => m.Source.Guessed && m.Source.ThunderstoreNamespace == null).ToList();
				for (int i = 0; i < unknown.Count; i += 20)
				{
					yield return SearchNexusByName(unknown.Skip(i).Take(20).ToList());
				}
				Progress++;
				Running = false;
				Done = true;
				List<ModEntry> list = mods.Where((ModEntry m) => m.UpdateAvailable).ToList();
				Plugin.Log.LogInfo((object)($"Update check done: {mods.Count((ModEntry m) => m.LatestVersion != null)} mods checked, {list.Count} updates" + ((list.Count > 0) ? (": " + string.Join(", ", list.Select((ModEntry m) => m.Name + " " + (m.Source.InstalledVersion ?? m.Version) + " -> " + m.LatestVersion).ToArray())) : "")));
				onChanged();
			}
			IEnumerator Worker()
			{
				while (next < thunderstore.Count)
				{
					ModEntry mod = thunderstore[next++];
					yield return CheckThunderstore(mod);
					Progress++;
					onChanged();
				}
				workers--;
			}
		}

		private static IEnumerator CheckNexus(List<ModEntry> mods)
		{
			string text = string.Join(", ", (from id in mods.Select((ModEntry m) => m.Source.NexusId).Distinct()
				select $"{{gameDomain: \"valheim\", modId: {id}}}").ToArray());
			yield return PostGraphQL("{ legacyModsByDomain(ids: [" + text + "]) { nodes { modId version } } }", delegate(JObject result)
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				Dictionary<int, string> dictionary = new Dictionary<int, string>();
				JToken obj = ((JToken)result).SelectToken("data.legacyModsByDomain.nodes");
				foreach (JToken item in (JArray)(((object)((obj is JArray) ? obj : null)) ?? ((object)new JArray())))
				{
					dictionary[(int)item[(object)"modId"]] = (string)item[(object)"version"];
				}
				foreach (ModEntry mod in mods)
				{
					if (dictionary.TryGetValue(mod.Source.NexusId, out var value))
					{
						SetLatest(mod, value);
					}
				}
			});
		}

		private static IEnumerator SearchNexusByName(List<ModEntry> mods)
		{
			List<string> list = new List<string>();
			for (int i = 0; i < mods.Count; i++)
			{
				list.Add($"m{i}: mods(filter: {{ gameDomainName: [{{value: \"valheim\"}}], name: [{{value: {JsonConvert.ToString(mods[i].Name)}, op: EQUALS}}] }}) {{ nodes {{ modId version author }} }}");
			}
			yield return PostGraphQL("{ " + string.Join(" ", list.ToArray()) + " }", delegate(JObject result)
			{
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				for (int j = 0; j < mods.Count; j++)
				{
					JToken obj = ((JToken)result).SelectToken($"data.m{j}.nodes");
					List<JToken> list2 = ((IEnumerable<JToken>)(((object)((obj is JArray) ? obj : null)) ?? ((object)new JArray()))).ToList();
					string[] guidParts = mods[j].Guid.ToLowerInvariant().Split('.', '_', '-');
					List<JToken> list3 = list2.Where((JToken n) => guidParts.Contains((((string)n[(object)"author"]) ?? "").Replace(" ", "").ToLowerInvariant())).ToList();
					JToken val = ((list3.Count == 1) ? list3[0] : ((list2.Count == 1) ? list2[0] : null));
					if (val != null)
					{
						mods[j].Source = new ModSource
						{
							Kind = SourceKind.Nexus,
							NexusId = (int)val[(object)"modId"]
						};
						SetLatest(mods[j], (string)val[(object)"version"]);
					}
				}
			});
		}

		private static IEnumerator PostGraphQL(string query, Action<JObject> onResult)
		{
			string s = JsonConvert.SerializeObject((object)new { query });
			UnityWebRequest request = new UnityWebRequest("https://api.nexusmods.com/v2/graphql", "POST");
			try
			{
				request.uploadHandler = (UploadHandler)new UploadHandlerRaw(Encoding.UTF8.GetBytes(s));
				request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
				request.SetRequestHeader("Content-Type", "application/json");
				request.timeout = 20;
				yield return request.SendWebRequest();
				if ((int)request.result != 1)
				{
					Fail("Nexus: " + request.error);
					yield break;
				}
				try
				{
					onResult(JObject.Parse(request.downloadHandler.text));
				}
				catch (Exception ex)
				{
					Fail("Nexus: " + ex.Message);
				}
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private static IEnumerator CheckThunderstore(ModEntry mod)
		{
			ModSource source = mod.Source;
			if (source.ThunderstoreNamespace == null)
			{
				string found = null;
				yield return Get($"https://thunderstore.io/api/cyberstorm/listing/valheim/?q={Uri.EscapeDataString(source.ThunderstoreName)}", delegate(string text)
				{
					found = PickNamespace(mod, text);
				});
				if (found == null)
				{
					yield break;
				}
				source.ThunderstoreNamespace = found;
			}
			yield return Get($"https://thunderstore.io/api/experimental/package/{source.ThunderstoreNamespace}/{source.ThunderstoreName}/", delegate(string text)
			{
				SetLatest(mod, (string)((JToken)JObject.Parse(text)).SelectToken("latest.version_number"));
			});
		}

		private static string PickNamespace(ModEntry mod, string json)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			ModSource source = mod.Source;
			JToken obj = JObject.Parse(json)["results"];
			IEnumerable<JToken> source2 = ((IEnumerable<JToken>)(((object)((obj is JArray) ? obj : null)) ?? ((object)new JArray()))).Where((JToken r) => string.Equals((string)r[(object)"name"], source.ThunderstoreName, StringComparison.OrdinalIgnoreCase));
			if (source.Guessed)
			{
				List<JToken> list = source2.ToList();
				string[] guidParts = mod.Guid.Split('.', '_', '-');
				List<JToken> list2 = list.Where((JToken r) => guidParts.Contains<string>((string)r[(object)"namespace"], StringComparer.OrdinalIgnoreCase)).ToList();
				source2 = ((list2.Count > 0) ? list2 : ((list.Count == 1) ? list : new List<JToken>()));
			}
			JToken val = source2.OrderByDescending((JToken r) => ((long?)r[(object)"download_count"]).GetValueOrDefault()).FirstOrDefault();
			if (val == null)
			{
				return null;
			}
			source.ThunderstoreName = (string)val[(object)"name"];
			return (string)val[(object)"namespace"];
		}

		private static IEnumerator Get(string url, Action<string> onText)
		{
			UnityWebRequest request = UnityWebRequest.Get(url);
			try
			{
				request.timeout = 15;
				yield return request.SendWebRequest();
				if ((int)request.result != 1)
				{
					if (request.responseCode != 404)
					{
						Fail("Thunderstore: " + request.error);
					}
					yield break;
				}
				try
				{
					onText(request.downloadHandler.text);
				}
				catch (Exception ex)
				{
					Fail("Thunderstore: " + ex.Message);
				}
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private static void SetLatest(ModEntry mod, string latest)
		{
			if (!string.IsNullOrEmpty(latest))
			{
				mod.LatestVersion = latest;
				mod.UpdateAvailable = ModSources.IsNewer(latest, mod.Version) && (mod.Source.InstalledVersion == null || ModSources.IsNewer(latest, mod.Source.InstalledVersion));
			}
		}

		private static void Fail(string error)
		{
			LastError = error;
			Plugin.Log.LogWarning((object)("Update check: " + error));
		}
	}
	internal static class PluginInfo
	{
		public const string Guid = "com.damia.modmenu";

		public const string Name = "ModMenu";

		public const string Version = "0.2.0";
	}
}
namespace ModMenu.UI
{
	internal static class ConfigEditors
	{
		private const float EditorWidth = 300f;

		private const float ResetWidth = 100f;

		private const int MaxDropdownOptions = 60;

		public static List<ConfigEntryBase> Visible(ConfigFile config)
		{
			List<ConfigEntryBase> list = new List<ConfigEntryBase>();
			foreach (ConfigDefinition item in config.Keys.ToList())
			{
				ConfigEntryBase val = config[item];
				if (val != null && Attribute<bool?>(val, "Browsable") != false)
				{
					list.Add(val);
				}
			}
			return list.OrderBy<ConfigEntryBase, string>(Category, StringComparer.OrdinalIgnoreCase).ThenByDescending((ConfigEntryBase e) => Attribute<int?>(e, "Order").GetValueOrDefault()).ThenBy<ConfigEntryBase, string>((ConfigEntryBase e) => e.Definition.Key, StringComparer.OrdinalIgnoreCase)
				.ToList();
		}

		public static string Category(ConfigEntryBase entry)
		{
			return Attribute<string>(entry, "Category") ?? entry.Definition.Section;
		}

		public static string DisplayName(ConfigEntryBase entry)
		{
			return Attribute<string>(entry, "DispName") ?? entry.Definition.Key;
		}

		public static bool Matches(ConfigEntryBase entry, string filter)
		{
			if (!string.IsNullOrEmpty(filter) && DisplayName(entry).IndexOf(filter, StringComparison.OrdinalIgnoreCase) < 0 && entry.Definition.Key.IndexOf(filter, StringComparison.OrdinalIgnoreCase) < 0 && entry.Definition.Section.IndexOf(filter, StringComparison.OrdinalIgnoreCase) < 0)
			{
				ConfigDescription description = entry.Description;
				return (((description != null) ? description.Description : null) ?? "").IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}

		public static void Row(Transform content, ConfigEntryBase entry, float rowWidth, Action onReset)
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Expected O, but got Unknown
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			GUIManager instance = GUIManager.Instance;
			float num = rowWidth - 300f - 100f - 50f;
			GameObject val = UiKit.Row(content, 50f, shaded: true);
			string text = DisplayName(entry);
			if (Attribute<bool?>(entry, "IsAdvanced") == true)
			{
				text = text + "  <size=13><color=#a89a80>(" + T.Get("advanced") + ")</color></size>";
			}
			Text obj = UiKit.Label(val.transform, text, 17, instance.ValheimBeige, bold: true, (TextAnchor)3);
			obj.supportRichText = true;
			UiKit.Place(((Component)obj).gameObject, 12f, 8f, num, 24f);
			float num2 = 50f;
			ConfigDescription description = entry.Description;
			string text2 = ((description != null) ? description.Description : null);
			if (!string.IsNullOrEmpty(text2))
			{
				Text obj2 = UiKit.Label(val.transform, text2.Trim(), 14, new Color(0.72f, 0.68f, 0.6f), bold: false, (TextAnchor)0);
				obj2.verticalOverflow = (VerticalWrapMode)1;
				UiKit.Place(((Component)obj2).gameObject, 12f, 32f, num, 20f);
				float num3 = Mathf.Ceil(obj2.preferredHeight) + 2f;
				((Graphic)obj2).rectTransform.sizeDelta = new Vector2(num, num3);
				num2 = Mathf.Max(num2, 32f + num3 + 8f);
			}
			val.GetComponent<LayoutElement>().preferredHeight = num2;
			val.GetComponent<LayoutElement>().minHeight = num2;
			GameObject val2 = new GameObject("Editor", new Type[1] { typeof(RectTransform) });
			val2.transform.SetParent(val.transform, false);
			UiKit.PlaceRight(val2, 120f, 300f, 34f);
			bool readOnly = Attribute<bool?>(entry, "ReadOnly") == true;
			Button reset = UiKit.Button(val.transform, T.Get("reset"), delegate
			{
				Set(entry, entry.DefaultValue);
				onReset();
			}, 14);
			UiKit.PlaceRight(((Component)reset).gameObject, 10f, 100f, 32f);
			((Component)reset).gameObject.SetActive(Attribute<bool?>(entry, "HideDefaultButton") != true);
			Action changed = delegate
			{
				UiKit.SetEnabled(reset, !readOnly && !object.Equals(entry.BoxedValue, entry.DefaultValue));
			};
			changed();
			BuildEditor(val2.transform, entry, readOnly, delegate(object value)
			{
				Set(entry, value);
				changed();
			});
		}

		private static void BuildEditor(Transform parent, ConfigEntryBase entry, bool readOnly, Action<object> set)
		{
			//IL_027a: Unknown result type (might be due to invalid IL or missing references)
			Type type = entry.SettingType;
			ConfigDescription description = entry.Description;
			AcceptableValueBase acceptable = ((description != null) ? description.AcceptableValues : null);
			Type type2 = ((object)acceptable)?.GetType();
			bool flag = type2 != null && type2.IsGenericType && type2.GetGenericTypeDefinition() == typeof(AcceptableValueList<>);
			bool flag2 = type2 != null && type2.IsGenericType && type2.GetGenericTypeDefinition() == typeof(AcceptableValueRange<>);
			if (type == typeof(bool))
			{
				Toggle obj = UiKit.Toggle(parent, (bool)entry.BoxedValue, delegate(bool v)
				{
					set(v);
				});
				UiKit.PlaceLeft(((Component)obj).gameObject, 0f, 28f, 28f);
				((Selectable)obj).interactable = !readOnly;
				return;
			}
			bool flag3 = type.IsEnum && !type.IsDefined(typeof(FlagsAttribute), inherit: false) && Enum.GetValues(type).Length <= 60;
			object[] array = (flag ? ((Array)type2.GetProperty("AcceptableValues").GetValue(acceptable, null)).Cast<object>().ToArray() : null);
			if ((flag && array.Length <= 60) || (!flag && flag3))
			{
				object[] values = array ?? Enum.GetValues(type).Cast<object>().ToArray();
				string[] options = values.Select((object v) => ToText(v, type)).ToArray();
				int val = Array.FindIndex(values, (object v) => object.Equals(v, entry.BoxedValue));
				Dropdown obj2 = UiKit.Dropdown(parent, options, Math.Max(0, val), delegate(int i)
				{
					set(values[i]);
				});
				UiKit.Stretch(((Component)obj2).gameObject);
				((Selectable)obj2).interactable = !readOnly;
				return;
			}
			if (!TomlTypeConverter.CanConvert(type))
			{
				UiKit.Stretch(((Component)UiKit.Label(parent, entry.BoxedValue?.ToString() ?? "", 15, GUIManager.Instance.ValheimBeige, bold: false, (TextAnchor)3)).gameObject);
				return;
			}
			InputField field = UiKit.Input(parent, "");
			field.SetTextWithoutNotify(ToText(entry.BoxedValue, type));
			((Selectable)field).interactable = !readOnly;
			if (flag2 && IsNumber(type))
			{
				float min = Convert.ToSingle(type2.GetProperty("MinValue").GetValue(acceptable, null));
				float max = Convert.ToSingle(type2.GetProperty("MaxValue").GetValue(acceptable, null));
				bool whole = type != typeof(float) && type != typeof(double) && type != typeof(decimal);
				Slider slider = UiKit.Slider(parent, min, max, Convert.ToSingle(entry.BoxedValue), whole, delegate(float v)
				{
					try
					{
						set(Convert.ChangeType(whole ? Math.Round(v) : Math.Round(v, 3), type));
					}
					catch (OverflowException)
					{
					}
					field.SetTextWithoutNotify(ToText(entry.BoxedValue, type));
				});
				UiKit.PlaceLeft(((Component)slider).gameObject, 0f, 200f, 24f);
				((Selectable)slider).interactable = !readOnly;
				UiKit.PlaceRight(((Component)field).gameObject, 0f, 90f, 34f);
				((UnityEvent<string>)(object)field.onEndEdit).AddListener((UnityAction<string>)delegate(string text)
				{
					if (TryParse(text, type, acceptable, out var value))
					{
						set(value);
					}
					field.SetTextWithoutNotify(ToText(entry.BoxedValue, type));
					slider.SetValueWithoutNotify(Convert.ToSingle(entry.BoxedValue));
				});
				return;
			}
			UiKit.Stretch(((Component)field).gameObject);
			((UnityEvent<string>)(object)field.onEndEdit).AddListener((UnityAction<string>)delegate(string text)
			{
				if (TryParse(text, type, acceptable, out var value))
				{
					set(value);
				}
				field.SetTextWithoutNotify(ToText(entry.BoxedValue, type));
			});
		}

		private static void Set(ConfigEntryBase entry, object value)
		{
			try
			{
				entry.BoxedValue = value;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)$"Setting {entry.Definition} raised an error in its mod: {ex.Message}");
			}
			try
			{
				if (entry.ConfigFile != null && !entry.ConfigFile.SaveOnConfigSet)
				{
					entry.ConfigFile.Save();
				}
			}
			catch (Exception ex2)
			{
				ManualLogSource log = Plugin.Log;
				ConfigFile configFile = entry.ConfigFile;
				log.LogWarning((object)("Could not save " + ((configFile != null) ? configFile.ConfigFilePath : null) + ": " + ex2.Message));
			}
		}

		internal static bool TryParse(string text, Type type, AcceptableValueBase acceptable, out object value)
		{
			try
			{
				if (IsNumber(type))
				{
					text = text.Trim().Replace(',', '.');
				}
				value = TomlTypeConverter.ConvertToValue(text, type);
				bool flag = acceptable != null && ((object)acceptable).GetType().IsGenericType && ((object)acceptable).GetType().GetGenericTypeDefinition() == typeof(AcceptableValueRange<>);
				return acceptable == null || flag || acceptable.IsValid(value);
			}
			catch (Exception)
			{
				value = null;
				return false;
			}
		}

		private static string ToText(object value, Type type)
		{
			try
			{
				return TomlTypeConverter.ConvertToString(value, type);
			}
			catch (Exception)
			{
				return value?.ToString() ?? "";
			}
		}

		private static bool IsNumber(Type type)
		{
			if (!(type == typeof(int)) && !(type == typeof(float)) && !(type == typeof(double)) && !(type == typeof(long)) && !(type == typeof(short)) && !(type == typeof(byte)) && !(type == typeof(uint)) && !(type == typeof(ulong)) && !(type == typeof(ushort)) && !(type == typeof(sbyte)))
			{
				return type == typeof(decimal);
			}
			return true;
		}

		private static TValue Attribute<TValue>(ConfigEntryBase entry, string field)
		{
			ConfigDescription description = entry.Description;
			object[] array = ((description != null) ? description.Tags : null);
			if (array == null)
			{
				return default(TValue);
			}
			object[] array2 = array;
			foreach (object obj in array2)
			{
				if (obj != null && !(obj.GetType().Name != "ConfigurationManagerAttributes"))
				{
					object obj2 = obj.GetType().GetField(field, BindingFlags.Instance | BindingFlags.Public)?.GetValue(obj) ?? obj.GetType().GetProperty(field, BindingFlags.Instance | BindingFlags.Public)?.GetValue(obj, null);
					if (obj2 is TValue)
					{
						return (TValue)obj2;
					}
				}
			}
			return default(TValue);
		}
	}
	[HarmonyPatch(typeof(FejdStartup), "Start")]
	internal static class MainMenuButton
	{
		private const string ButtonName = "ModMenuButton";

		private static void Postfix(FejdStartup __instance)
		{
			try
			{
				Add(__instance);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Could not add the main menu button: {arg}");
			}
		}

		private static void Add(FejdStartup startup)
		{
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Expected O, but got Unknown
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Expected O, but got Unknown
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Expected O, but got Unknown
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Expected O, but got Unknown
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			GameObject menuList = startup.m_menuList;
			if ((Object)(object)menuList == (Object)null || menuList.GetComponentsInChildren<Transform>(true).Any((Transform t) => ((Object)t).name == "ModMenuButton"))
			{
				return;
			}
			Button[] componentsInChildren = menuList.GetComponentsInChildren<Button>(true);
			Button val = ((IEnumerable<Button>)componentsInChildren).FirstOrDefault((Func<Button, bool>)((Button b) => Calls(b, "OnButtonSettings"))) ?? componentsInChildren.LastOrDefault();
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Main menu has no buttons to copy; the Mods button was not added.");
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Component)val).transform.parent);
			((Object)val2).name = "ModMenuButton";
			MonoBehaviour[] componentsInChildren2 = val2.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val3 in componentsInChildren2)
			{
				if (((object)val3).GetType().Name == "Localize")
				{
					Object.Destroy((Object)(object)val3);
				}
			}
			UIGamePad[] componentsInChildren3 = val2.GetComponentsInChildren<UIGamePad>(true);
			foreach (UIGamePad val4 in componentsInChildren3)
			{
				if ((Object)(object)val4.m_hint != (Object)null)
				{
					Object.Destroy((Object)(object)val4.m_hint);
				}
				Object.Destroy((Object)(object)val4);
			}
			SetLabel(val2, T.Get("menu_button"));
			Button component = val2.GetComponent<Button>();
			component.onClick = new ButtonClickedEvent();
			((UnityEvent)component.onClick).AddListener((UnityAction)delegate
			{
				OpenWindow(startup);
			});
			if ((Object)(object)((Component)val2.transform.parent).GetComponent<LayoutGroup>() != (Object)null)
			{
				val2.transform.SetSiblingIndex(((Component)val).transform.GetSiblingIndex() + 1);
			}
			else
			{
				Button[] array = componentsInChildren.OrderByDescending((Button b) => ((RectTransform)((Component)b).transform).anchoredPosition.y).ToArray();
				if (array.Length >= 2)
				{
					RectTransform val5 = (RectTransform)((Component)array[^1]).transform;
					RectTransform val6 = (RectTransform)((Component)array[^2]).transform;
					((RectTransform)val2.transform).anchoredPosition = val5.anchoredPosition + (val5.anchoredPosition - val6.anchoredPosition);
				}
			}
			startup.m_menuButtons = menuList.GetComponentsInChildren<Button>();
			Plugin.Log.LogInfo((object)("Main menu button added after \"" + ((Object)val).name + "\""));
		}

		internal static void OpenWindow(FejdStartup startup)
		{
			startup.m_menuList.SetActive(false);
			ModMenuWindow.Open(delegate
			{
				if ((Object)(object)startup != (Object)null)
				{
					startup.m_menuList.SetActive(true);
				}
			});
		}

		private static bool Calls(Button button, string method)
		{
			for (int i = 0; i < ((UnityEventBase)button.onClick).GetPersistentEventCount(); i++)
			{
				if (((UnityEventBase)button.onClick).GetPersistentMethodName(i) == method)
				{
					return true;
				}
			}
			return false;
		}

		private static void SetLabel(GameObject button, string text)
		{
			TMP_Text componentInChildren = button.GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.text = text;
				return;
			}
			Text componentInChildren2 = button.GetComponentInChildren<Text>(true);
			if ((Object)(object)componentInChildren2 != (Object)null)
			{
				componentInChildren2.text = text;
			}
		}
	}
	internal sealed class ModMenuWindow : MonoBehaviour
	{
		private enum View
		{
			Mods,
			Config,
			Profiles
		}

		private const float Width = 1060f;

		private const float Height = 740f;

		private const float Margin = 30f;

		private const float ListTop = 158f;

		private const float RowWidth = 974f;

		private static ModMenuWindow _instance;

		private static bool _checkedThisSession;

		private View _view;

		private ModEntry _configMod;

		private Action _onClosed;

		private bool _dirty;

		private bool _typingLastFrame;

		private Text _title;

		private Text _status;

		private Button _back;

		private Button _profilesButton;

		private Button _updatesButton;

		private Text _updatesLabel;

		private Button _restartButton;

		private InputField _search;

		private Button _allOnButton;

		private InputField _profileName;

		private Button _profileSave;

		private InputField _configSearch;

		private readonly HashSet<string> _collapsed = new HashSet<string>();

		private ModEntry _collapsedFor;

		private const int ExpandedLimit = 40;

		private RectTransform _list;

		public static bool IsOpen
		{
			get
			{
				if ((Object)(object)_instance != (Object)null)
				{
					return ((Component)_instance).gameObject.activeSelf;
				}
				return false;
			}
		}

		public static void Open(Action onClosed)
		{
			if ((Object)(object)_instance == (Object)null)
			{
				if (GUIManager.Instance == null || (Object)(object)GUIManager.CustomGUIFront == (Object)null)
				{
					Plugin.Log.LogWarning((object)"Jotunn GUI is not ready yet; the Mods window cannot open now.");
					onClosed?.Invoke();
					return;
				}
				try
				{
					_instance = Create();
				}
				catch (Exception arg)
				{
					Plugin.Log.LogError((object)$"Could not build the Mods window: {arg}");
					onClosed?.Invoke();
					return;
				}
			}
			_instance._onClosed = onClosed;
			_instance._view = View.Mods;
			((Component)_instance).gameObject.SetActive(true);
			((Component)_instance).transform.SetAsLastSibling();
			_instance.FitToScreen();
			_instance.Rebuild();
			if (!_checkedThisSession && Plugin.CheckUpdatesOnOpen.Value)
			{
				_checkedThisSession = true;
				_instance.StartUpdateCheck();
			}
		}

		private void FitToScreen()
		{
			//IL_0028: 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_0040: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: 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)
			RectTransform val = (((Object)(object)GUIManager.CustomGUIFront != (Object)null) ? GUIManager.CustomGUIFront.GetComponent<RectTransform>() : null);
			if (!((Object)(object)val != (Object)null))
			{
				return;
			}
			Rect rect = val.rect;
			if (((Rect)(ref rect)).width > 0f)
			{
				rect = val.rect;
				if (((Rect)(ref rect)).height > 0f)
				{
					float[] obj = new float[3] { 1f, 0f, 0f };
					rect = val.rect;
					obj[1] = (((Rect)(ref rect)).width - 40f) / 1060f;
					rect = val.rect;
					obj[2] = (((Rect)(ref rect)).height - 40f) / 740f;
					float num = Mathf.Min(obj);
					((Component)this).transform.localScale = Vector3.one * Mathf.Max(0.5f, num);
				}
			}
		}

		public void Close()
		{
			((Component)this).gameObject.SetActive(false);
			Action onClosed = _onClosed;
			_onClosed = null;
			onClosed?.Invoke();
		}

		private void Update()
		{
			if (_dirty)
			{
				_dirty = false;
				Rebuild();
			}
			EventSystem current = EventSystem.current;
			GameObject val = ((current != null) ? current.currentSelectedGameObject : null);
			InputField val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<InputField>() : null);
			bool flag = (Object)(object)val2 != (Object)null && val2.isFocused;
			bool typingLastFrame = _typingLastFrame;
			_typingLastFrame = flag;
			if ((ZInput.GetKeyDown((KeyCode)27, true) || ZInput.GetButtonDown("JoyButtonB")) && !flag && !typingLastFrame)
			{
				if (_view == View.Mods)
				{
					Close();
				}
				else
				{
					ShowView(View.Mods);
				}
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)_instance == (Object)(object)this)
			{
				_instance = null;
			}
		}

		private static ModMenuWindow Create()
		{
			//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_002d: 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), Vector2.zero, 1060f, 740f, false);
			((Object)val).name = "ModMenuWindow";
			ModMenuWindow modMenuWindow = val.AddComponent<ModMenuWindow>();
			try
			{
				modMenuWindow.Build(val.transform);
				return modMenuWindow;
			}
			catch
			{
				Object.Destroy((Object)(object)val);
				throw;
			}
		}

		private void Build(Transform root)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			GUIManager instance = GUIManager.Instance;
			_back = UiKit.Button(root, "< " + T.Get("back"), delegate
			{
				ShowView(View.Mods);
			});
			UiKit.Place(((Component)_back).gameObject, 30f, 26f, 120f, 40f);
			_title = UiKit.Label(root, "", 28, instance.ValheimOrange, bold: true, (TextAnchor)3);
			UiKit.Place(((Component)_title).gameObject, 30f, 26f, 520f, 40f);
			UiKit.Place(((Component)UiKit.Button(root, T.Get("close"), Close)).gameObject, 890f, 26f, 140f, 40f);
			_updatesButton = UiKit.Button(root, T.Get("check_updates"), StartUpdateCheck);
			_updatesLabel = ((Component)_updatesButton).GetComponentInChildren<Text>();
			UiKit.Place(((Component)_updatesButton).gameObject, 640f, 26f, 240f, 40f);
			_profilesButton = UiKit.Button(root, T.Get("profiles"), delegate
			{
				ShowView(View.Profiles);
			});
			UiKit.Place(((Component)_profilesButton).gameObject, 480f, 26f, 150f, 40f);
			_status = UiKit.Label(root, "", 16, instance.ValheimBeige, bold: false, (TextAnchor)3);
			UiKit.Place(((Component)_status).gameObject, 30f, 72f, 750f, 40f);
			_restartButton = UiKit.Button(root, T.Get("restart"), GameRestart.Restart);
			UiKit.Place(((Component)_restartButton).gameObject, 800f, 72f, 230f, 40f);
			_search = UiKit.Input(root, T.Get("search"));
			UiKit.Place(((Component)_search).gameObject, 30f, 116f, 360f, 34f);
			((UnityEvent<string>)(object)_search.onValueChanged).AddListener((UnityAction<string>)delegate
			{
				RebuildList();
			});
			_allOnButton = UiKit.Button(root, T.Get("all_on"), delegate
			{
				ModCatalog.ReplaceWanted(new string[0]);
				_dirty = true;
			});
			UiKit.Place(((Component)_allOnButton).gameObject, 400f, 114f, 220f, 38f);
			_profileName = UiKit.Input(root, T.Get("profile_name"));
			UiKit.Place(((Component)_profileName).gameObject, 30f, 116f, 360f, 34f);
			_profileSave = UiKit.Button(root, T.Get("profile_save"), delegate
			{
				if (Profiles.Save(_profileName.text, ModCatalog.WantedDisabled) != null)
				{
					_profileName.text = "";
				}
				_dirty = true;
			});
			UiKit.Place(((Component)_profileSave).gameObject, 400f, 114f, 220f, 38f);
			_configSearch = UiKit.Input(root, T.Get("config_search"));
			UiKit.Place(((Component)_configSearch).gameObject, 30f, 116f, 360f, 34f);
			((UnityEvent<string>)(object)_configSearch.onValueChanged).AddListener((UnityAction<string>)delegate
			{
				_dirty = true;
			});
			_list = UiKit.ScrollList(root, 30f, 158f, 30f, 30f);
		}

		private void ShowView(View view, ModEntry configMod = null)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			_view = view;
			if (configMod != null && configMod != _configMod)
			{
				_configSearch.SetTextWithoutNotify("");
			}
			_configMod = configMod ?? _configMod;
			_list.anchoredPosition = Vector2.zero;
			_dirty = true;
		}

		private void Rebuild()
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			bool flag = _view == View.Mods;
			((Component)_back).gameObject.SetActive(!flag);
			((Graphic)_title).rectTransform.anchoredPosition = new Vector2(flag ? 30f : 165f, -26f);
			((Graphic)_title).rectTransform.sizeDelta = new Vector2(flag ? 420f : 705f, 40f);
			((Component)_profilesButton).gameObject.SetActive(flag);
			((Component)_updatesButton).gameObject.SetActive(flag);
			((Component)_search).gameObject.SetActive(flag);
			((Component)_allOnButton).gameObject.SetActive(flag && ModCatalog.PatcherActive);
			((Component)_profileName).gameObject.SetActive(_view == View.Profiles);
			((Component)_profileSave).gameObject.SetActive(_view == View.Profiles);
			((Component)_configSearch).gameObject.SetActive(_view == View.Config);
			RefreshHeader();
			RebuildList();
		}

		private void RefreshHeader()
		{
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: 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_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: 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)
			GUIManager instance = GUIManager.Instance;
			switch (_view)
			{
			case View.Mods:
				_title.text = T.Get("title", ModCatalog.Mods.Count);
				break;
			case View.Config:
				_title.text = T.Get("config_title", _configMod?.Name);
				break;
			case View.Profiles:
				_title.text = T.Get("profiles");
				break;
			}
			_updatesLabel.text = (UpdateChecker.Running ? T.Get("checking", UpdateChecker.Progress, UpdateChecker.Total) : T.Get("check_updates"));
			UiKit.SetEnabled(_updatesButton, !UpdateChecker.Running);
			bool restartNeeded = ModCatalog.RestartNeeded;
			((Component)_restartButton).gameObject.SetActive(restartNeeded);
			if (!ModCatalog.PatcherActive)
			{
				SetStatus(T.Get("no_patcher"), Color.red);
			}
			else if (restartNeeded)
			{
				SetStatus(T.Get("restart_needed"), instance.ValheimYellow);
			}
			else if (_view == View.Config)
			{
				SetStatus(T.Get("config_hint"), instance.ValheimBeige);
			}
			else if (_view != View.Mods)
			{
				SetStatus("", instance.ValheimBeige);
			}
			else if (UpdateChecker.LastError != null)
			{
				SetStatus(T.Get("update_error", UpdateChecker.LastError), new Color(1f, 0.5f, 0.4f));
			}
			else if (UpdateChecker.Done)
			{
				int num = ModCatalog.Mods.Count((ModEntry m) => m.UpdateAvailable);
				SetStatus((num > 0) ? T.Get("updates_found", num) : T.Get("no_updates"), (num > 0) ? instance.ValheimOrange : instance.ValheimBeige);
			}
			else
			{
				SetStatus("", instance.ValheimBeige);
			}
		}

		private void SetStatus(string text, Color color)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			_status.text = text;
			((Graphic)_status).color = color;
		}

		private void StartUpdateCheck()
		{
			if (UpdateChecker.Running)
			{
				return;
			}
			((MonoBehaviour)Plugin.Instance).StartCoroutine(UpdateChecker.Run(ModCatalog.Mods, delegate
			{
				if (!((Object)(object)this == (Object)null) && ((Component)this).gameObject.activeSelf)
				{
					RefreshHeader();
					if (!UpdateChecker.Running && _view == View.Mods)
					{
						RebuildList();
					}
				}
			}));
		}

		private void RebuildList()
		{
			UiKit.Clear((Transform)(object)_list);
			switch (_view)
			{
			case View.Mods:
				BuildModRows();
				break;
			case View.Config:
				BuildConfigRows();
				break;
			case View.Profiles:
				BuildProfileRows();
				break;
			}
		}

		private void BuildModRows()
		{
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_033f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			GUIManager instance = GUIManager.Instance;
			string text = _search.text.Trim();
			int num = 0;
			foreach (ModEntry mod in ModCatalog.Mods)
			{
				if (text.Length > 0 && mod.Name.IndexOf(text, StringComparison.OrdinalIgnoreCase) < 0 && mod.Guid.IndexOf(text, StringComparison.OrdinalIgnoreCase) < 0)
				{
					continue;
				}
				GameObject val = UiKit.Row((Transform)(object)_list, 60f, num++ % 2 == 0);
				bool flag = ModCatalog.IsWantedDisabled(mod.Guid);
				Toggle obj = UiKit.Toggle(val.transform, !flag, delegate(bool on)
				{
					ModCatalog.SetWantedDisabled(mod.Guid, !on);
					_dirty = true;
				});
				UiKit.PlaceLeft(((Component)obj).gameObject, 12f, 28f, 28f);
				((Selectable)obj).interactable = ModCatalog.PatcherActive && !mod.Protected;
				Text obj2 = UiKit.Label(val.transform, mod.Name + "  <size=14><color=#a89a80>v" + mod.Version + "</color></size>", 19, (Color)(flag ? new Color(0.6f, 0.6f, 0.6f) : instance.ValheimBeige), bold: true, (TextAnchor)3);
				obj2.supportRichText = true;
				UiKit.PlaceLeft(((Component)obj2).gameObject, 52f, 502f, 28f, 12f);
				Text obj3 = UiKit.Label(val.transform, "", 14, instance.ValheimBeige, bold: false, (TextAnchor)3);
				UiKit.PlaceLeft(((Component)obj3).gameObject, 52f, 502f, 24f, -14f);
				Text val2 = obj3;
				(string, Color) tuple = StateLine(mod, flag);
				val2.text = tuple.Item1;
				((Graphic)obj3).color = tuple.Item2;
				Button obj4 = UiKit.Button(val.transform, T.Get("settings"), delegate
				{
					ShowView(View.Config, mod);
				}, 15);
				UiKit.PlaceRight(((Component)obj4).gameObject, 10f, 130f, 36f);
				UiKit.SetEnabled(obj4, (Object)(object)mod.Instance != (Object)null);
				string url = mod.Source?.PageUrl;
				if (url != null)
				{
					UiKit.PlaceRight(((Component)UiKit.Button(val.transform, T.Get("page"), delegate
					{
						Application.OpenURL(url);
					}, 15)).gameObject, 150f, 100f, 36f);
				}
				if (mod.LatestVersion != null)
				{
					UiKit.PlaceRight(((Component)UiKit.Label(val.transform, mod.UpdateAvailable ? T.Get("update", mod.LatestVersion) : T.Get("up_to_date"), 15, (Color)(mod.UpdateAvailable ? instance.ValheimOrange : new Color(0.55f, 0.75f, 0.5f)), bold: true, (TextAnchor)5)).gameObject, 260f, 150f, 40f);
				}
			}
		}

		private static (string, Color) StateLine(ModEntry mod, bool wantedOff)
		{
			//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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			Color item = default(Color);
			((Color)(ref item))..ctor(0.55f, 0.75f, 0.5f);
			Color item2 = default(Color);
			((Color)(ref item2))..ctor(0.6f, 0.6f, 0.6f);
			Color valheimYellow = GUIManager.Instance.ValheimYellow;
			Color item3 = default(Color);
			((Color)(ref item3))..ctor(1f, 0.45f, 0.4f);
			if (mod.Protected)
			{
				return (T.Get("protected"), item2);
			}
			bool flag = mod.State == ModState.Disabled;
			if (wantedOff && !flag)
			{
				List<ModEntry> list = (from d in ModCatalog.Dependents(mod.Guid)
					where !ModCatalog.IsWantedDisabled(d.Guid)
					select d).ToList();
				string text = T.Get("state_off_next");
				if (list.Count > 0)
				{
					text = text + " - " + T.Get("also_stops", string.Join(", ", list.Select((ModEntry d) => d.Name).ToArray()));
				}
				return (text, valheimYellow);
			}
			if (!wantedOff && flag)
			{
				List<string> list2 = ModCatalog.MissingDependencies(mod);
				return (T.Get("state_on_next") + ((list2.Count > 0) ? (" - " + T.Get("needs", string.Join(", ", list2.ToArray()))) : ""), valheimYellow);
			}
			switch (mod.State)
			{
			case ModState.Disabled:
				return (T.Get("state_disabled"), item2);
			case ModState.Failed:
				if (mod.OnlyFor != null)
				{
					return (T.Get("only_for", mod.OnlyFor), item2);
				}
				return (T.Get("state_failed") + ((mod.Error != null) ? (": " + mod.Error) : ""), item3);
			default:
				return (T.Get("state_loaded"), item);
			}
		}

		private void BuildConfigRows()
		{
			_ = GUIManager.Instance;
			List<ConfigFile> list = (((Object)(object)_configMod?.Instance != (Object)null) ? ConfigSources.For(_configMod.Instance) : new List<ConfigFile>());
			if ((Object)(object)_configMod?.Instance == (Object)null)
			{
				Message(T.Get("config_off"));
				return;
			}
			List<(string, string, List<ConfigEntryBase>)> list2 = new List<(string, string, List<ConfigEntryBase>)>();
			foreach (ConfigFile item2 in list)
			{
				string text = ((list.Count > 1) ? (Path.GetFileNameWithoutExtension(item2.ConfigFilePath) + " / ") : "");
				foreach (IGrouping<string, ConfigEntryBase> item3 in ConfigEditors.Visible(item2).GroupBy(ConfigEditors.Category))
				{
					list2.Add((item2.ConfigFilePath + "|" + item3.Key, text + item3.Key, item3.ToList()));
				}
			}
			if (list2.Count == 0)
			{
				Message(T.Get("config_none"));
				return;
			}
			if (_collapsedFor != _configMod)
			{
				_collapsedFor = _configMod;
				_collapsed.Clear();
				if (list2.Sum<(string, string, List<ConfigEntryBase>)>(((string key, string title, List<ConfigEntryBase> entries) g) => g.entries.Count) > 40)
				{
					_collapsed.UnionWith(list2.Select<(string, string, List<ConfigEntryBase>), string>(((string key, string title, List<ConfigEntryBase> entries) g) => g.key));
				}
			}
			string filter = _configSearch.text.Trim();
			bool flag = filter.Length > 0;
			int num = 0;
			foreach (var item4 in list2)
			{
				string key = item4.Item1;
				string item = item4.Item2;
				List<ConfigEntryBase> list3 = item4.Item3.Where((ConfigEntryBase e) => ConfigEditors.Matches(e, filter)).ToList();
				if (list3.Count == 0)
				{
					continue;
				}
				bool flag2 = flag || !_collapsed.Contains(key);
				SectionHeader(item, list3.Count, flag2, flag ? null : ((Action)delegate
				{
					if (!_collapsed.Remove(key))
					{
						_collapsed.Add(key);
					}
					_dirty = true;
				}));
				if (!flag2)
				{
					continue;
				}
				foreach (ConfigEntryBase item5 in list3)
				{
					ConfigEditors.Row((Transform)(object)_list, item5, 974f, delegate
					{
						_dirty = true;
					});
					num++;
				}
			}
			if (flag && num == 0)
			{
				Message(T.Get("config_no_match"));
			}
		}

		private void SectionHeader(string title, int count, bool open, Action toggle)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Expected O, but got Unknown
			GUIManager instance = GUIManager.Instance;
			GameObject val = UiKit.Row((Transform)(object)_list, 38f, shaded: false);
			string arg = ((toggle == null) ? "" : (open ? "[-]  " : "[+]  "));
			Text obj = UiKit.Label(val.transform, $"{arg}{title}  <size=15><color=#a89a80>({count})</color></size>", 21, instance.ValheimOrange, bold: true, (TextAnchor)3);
			obj.supportRichText = true;
			UiKit.Stretch(((Component)obj).gameObject);
			((Graphic)obj).rectTransform.offsetMin = new Vector2(8f, 0f);
			if (toggle != null)
			{
				Image component = val.GetComponent<Image>();
				((Graphic)component).raycastTarget = true;
				((Graphic)component).color = new Color(0f, 0f, 0f, 0.25f);
				Button obj2 = val.AddComponent<Button>();
				((Selectable)obj2).targetGraphic = (Graphic)(object)component;
				((UnityEvent)obj2.onClick).AddListener((UnityAction)delegate
				{
					toggle();
				});
			}
		}

		private void Message(string text)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			UiKit.Stretch(((Component)UiKit.Label(UiKit.Row((Transform)(object)_list, 60f, shaded: false).transform, text, 18, GUIManager.Instance.ValheimBeige, bold: false, (TextAnchor)4)).gameObject);
		}

		private void BuildProfileRows()
		{
			//IL_00d6: 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_0138: Unknown result type (might be due to invalid IL or missing references)
			GUIManager instance = GUIManager.Instance;
			List<string> list = Profiles.Names();
			if (list.Count == 0)
			{
				Message(T.Get("profile_none"));
				return;
			}
			HashSet<string> wantedDisabled = ModCatalog.WantedDisabled;
			int num = 0;
			foreach (string profile in list)
			{
				HashSet<string> hashSet = Profiles.Read(profile);
				bool flag = hashSet.SetEquals(wantedDisabled);
				GameObject val = UiKit.Row((Transform)(object)_list, 54f, num++ % 2 == 0);
				UiKit.PlaceLeft(((Component)UiKit.Label(val.transform, profile + (flag ? ("  " + T.Get("profile_active")) : ""), 19, flag ? instance.ValheimOrange : instance.ValheimBeige, bold: true, (TextAnchor)3)).gameObject, 14f, 480f, 28f, 10f);
				UiKit.PlaceLeft(((Component)UiKit.Label(val.transform, T.Get("profile_count", hashSet.Count), 14, new Color(0.65f, 0.6f, 0.5f), bold: false, (TextAnchor)3)).gameObject, 14f, 480f, 22f, -13f);
				UiKit.PlaceRight(((Component)UiKit.Button(val.transform, T.Get("profile_delete"), delegate
				{
					Profiles.Delete(profile);
					_dirty = true;
				}, 15)).gameObject, 10f, 120f, 36f);
				UiKit.PlaceRight(((Component)UiKit.Button(val.transform, T.Get("profile_overwrite"), delegate
				{
					Profiles.Save(profile, ModCatalog.WantedDisabled);
					_dirty = true;
				}, 15)).gameObject, 140f, 140f, 36f);
				Button obj = UiKit.Button(val.transform, T.Get("profile_load"), delegate
				{
					ModCatalog.ReplaceWanted(Profiles.Read(profile));
					ShowView(View.Mods);
				}, 15);
				UiKit.PlaceRight(((Component)obj).gameObject, 290f, 140f, 36f);
				UiKit.SetEnabled(obj, ModCatalog.PatcherActive && !flag);
			}
		}
	}
	internal static class UiKit
	{
		public static GUIManager Gui => GUIManager.Instance;

		public static RectTransform Place(GameObject go, float x, float y, float width, float height)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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)
			//IL_0025: 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_0027: 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_0033: 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_0041: 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_0050: Expected O, but got Unknown
			RectTransform val = (RectTransform)go.transform;
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0f, 1f);
			val.pivot = val2;
			Vector2 anchorMin = (val.anchorMax = val2);
			val.anchorMin = anchorMin;
			val.anchoredPosition = new Vector2(x, 0f - y);
			val.sizeDelta = new Vector2(width, height);
			return val;
		}

		public static RectTransform PlaceRight(GameObject go, float right, float width, float height)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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)
			//IL_0025: 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_0027: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			RectTransform val = (RectTransform)go.transform;
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(1f, 0.5f);
			val.pivot = val2;
			Vector2 anchorMin = (val.anchorMax = val2);
			val.anchorMin = anchorMin;
			val.anchoredPosition = new Vector2(0f - right, 0f);
			val.sizeDelta = new Vector2(width, height);
			return val;
		}

		public static RectTransform PlaceLeft(GameObject go, float left, float width, float height, float y = 0f)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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)
			//IL_0025: 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_0027: 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_0033: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			RectTransform val = (RectTransform)go.transform;
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0f, 0.5f);
			val.pivot = val2;
			Vector2 anchorMin = (val.anchorMax = val2);
			val.anchorMin = anchorMin;
			val.anchoredPosition = new Vector2(left, y);
			val.sizeDelta = new Vector2(width, height);
			return val;
		}

		public static void Stretch(GameObject go)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_0028: 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)
			RectTransform val = (RectTransform)go.transform;
			val.anchorMin = Vector2.zero;
			val.anchorMax = Vector2.one;
			Vector2 offsetMin = (val.offsetMax = Vector2.zero);
			val.offsetMin = offsetMin;
		}

		public static Text Label(Transform parent, string text, int size, Color color, bool bold = true, TextAnchor alignment = (TextAnchor)3)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			Text component = Gui.CreateText(text, parent, Vector2.zero, Vector2.zero, Vector2.zero, bold ? Gui.AveriaSerifBold : Gui.AveriaSerif, size, color, true, Color.black, 100f, 30f, false).GetComponent<Text>();
			component.alignment = alignment;
			component.horizontalOverflow = (HorizontalWrapMode)0;
			component.verticalOverflow = (VerticalWrapMode)0;
			((Graphic)component).raycastTarget = false;
			return component;
		}

		public static Button Button(Transform parent, string text, Action onClick, int fontSize = 16)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			GameObject obj = Gui.CreateButton(text, parent, Vector2.zero, Vector2.zero, Vector2.zero, 0f, 0f);
			Button component = obj.GetComponent<Button>();
			Text componentInChildren = obj.GetComponentInChildren<Text>();
			componentInChildren.fontSize = fontSize;
			Stretch(((Component)componentInChildren).gameObject);
			((UnityEvent)component.onClick).AddListener((UnityAction)delegate
			{
				onClick();
			});
			return component;
		}

		public static void SetEnabled(Button button, bool enabled)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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)
			((Selectable)button).interactable = enabled;
			Text componentInChildren = ((Component)button).GetComponentInChildren<Text>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				Color color = ((Graphic)componentInChildren).color;
				color.a = (enabled ? 1f : 0.35f);
				((Graphic)componentInChildren).color = color;
			}
		}

		public static InputField Input(Transform parent, string placeholder, int fontSize = 16)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			InputField component = Gui.CreateInputField(parent, Vector2.zero, Vector2.zero, Vector2.zero, (ContentType)0, placeholder, fontSize, 0f, 0f).GetComponent<InputField>();
			Graphic[] array = (Graphic[])(object)new Graphic[2]
			{
				(Graphic)component.textComponent,
				component.placeholder
			};
			foreach (Graphic obj in array)
			{
				RectTransform rectTransform = obj.rectTransform;
				rectTransform.anchorMin = Vector2.zero;
				rectTransform.anchorMax = Vector2.one;
				rectTransform.offsetMin = new Vector2(10f, 4f);
				rectTransform.offsetMax = new Vector2(-10f, -4f);
				Text val = (Text)(object)((obj is Text) ? obj : null);
				if (val != null)
				{
					val.alignment = (TextAnchor)3;
				}
			}
			return component;
		}

		public static Toggle Toggle(Transform parent, bool value, Action<bool> onChange, float size = 28f)
		{
			//IL_0020: 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_0040: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = Gui.CreateToggle(parent, size, size);
			obj.transform.localScale = Vector3.one;
			obj.transform.localPosition = Vector3.zero;
			obj.transform.localRotation = Quaternion.identity;
			Toggle component = obj.GetComponent<Toggle>();
			component.SetIsOnWithoutNotify(value);
			((UnityEvent<bool>)(object)component.onValueChanged).AddListener((UnityAction<bool>)delegate(bool v)
			{
				onChange(v);
			});
			Transform val = obj.transform.Find("Label");
			if ((Object)(object)val != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val).gameObject);
			}
			return component;
		}

		public static Dropdown Dropdown(Transform parent, string[] options, int value, Action<int> onChange)
		{
			//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_001d: Unknown result type (might be due to invalid IL or missing references)
			Dropdown component = Gui.CreateDropDown(parent, Vector2.zero, Vector2.zero, Vector2.zero, 16, 300f, 32f).GetComponent<Dropdown>();
			component.AddOptions(new List<string>(options));
			component.SetValueWithoutNotify(value);
			((UnityEvent<int>)(object)component.onValueChanged).AddListener((UnityAction<int>)delegate(int v)
			{
				onChange(v);
			});
			return component;
		}

		public static Slider Slider(Transform parent, float min, float max, float value, bool whole, Action<float> onChange)
		{
			//IL_0013: 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)
			GameObject obj = DefaultControls.CreateSlider(Gui.ValheimControlResources);
			obj.transform.SetParent(parent, false);
			Slider component = obj.GetComponent<Slider>();
			Gui.ApplySliderStyle(component, new Vector2(16f, 24f));
			component.minValue = min;
			component.maxValue = max;
			component.wholeNumbers = whole;
			component.SetValueWithoutNotify(value);
			((UnityEvent<float>)(object)component.onValueChanged).AddListener((UnityAction<float>)delegate(float v)
			{
				onChange(v);
			});
			return component;
		}

		public static RectTransform ScrollList(Transform parent, float left, float top, float right, float bottom)
		{
			//IL_0005: 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_0032: 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_003d: 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_0048: 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_005a: 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_00d5: 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_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Expected O, but got Unknown
			GameObject obj = DefaultControls.CreateScrollView(Gui.ValheimControlResources);
			((Object)obj).name = "ModMenuList";
			obj.transform.SetParent(parent, false);
			RectTransform val = (RectTransform)obj.transform;
			val.anchorMin = Vector2.zero;
			val.anchorMax = Vector2.one;
			val.offsetMin = new Vector2(left, bottom);
			val.offsetMax = new Vector2(0f - right, 0f - top);
			ScrollRect component = obj.GetComponent<ScrollRect>();
			component.horizontal = false;
			component.movementType = (MovementType)2;
			if ((Object)(object)component.horizontalScrollbar != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)component.horizontalScrollbar).gameObject);
				component.horizontalScrollbar = null;
			}
			component.verticalScrollbarVisibility = (ScrollbarVisibility)2;
			Gui.ApplyScrollRectStyle(component);
			RectTransform content = component.content;
			content.anchorMin = new Vector2(0f, 1f);
			content.anchorMax = new Vector2(1f, 1f);
			content.pivot = new Vector2(0.5f, 1f);
			Vector2 offsetMin = (content.offsetMax = Vector2.zero);
			content.offsetMin = offsetMin;
			VerticalLayoutGroup obj2 = ((Component)content).gameObject.AddComponent<VerticalLayoutGroup>();
			((LayoutGroup)obj2).padding = new RectOffset(6, 6, 6, 6);
			((HorizontalOrVerticalLayoutGroup)obj2).spacing = 4f;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false;
			((Component)content).gameObject.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
			return content;
		}

		public static GameObject Row(Transform content, float height, bool shaded)
		{
			//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_0044: 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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			GameObject val = new GameObject("Row", new Type[3]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(LayoutElement)
			});
			val.transform.SetParent(content, false);
			val.GetComponent<LayoutElement>().preferredHeight = height;
			val.GetComponent<LayoutElement>().minHeight = height;
			Image component = val.GetComponent<Image>();
			((Graphic)component).color = (shaded ? new Color(1f, 1f, 1f, 0.05f) : new Color(0f, 0f, 0f, 0f));
			((Graphic)component).raycastTarget = false;
			return val;
		}

		public static void Clear(Transform content)
		{
			for (int num = content.childCount - 1; num >= 0; num--)
			{
				GameObject gameObject = ((Component)content.GetChild(num)).gameObject;
				gameObject.SetActive(false);
				Object.Destroy((Object)(object)gameObject);
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}