plugins/Hex/Hex.Core.dll

Decompiled 5 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ExtraPotions")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (C) 2026 expDARE (ExtraPotions Meadworks)")]
[assembly: AssemblyFileVersion("0.1.18.0")]
[assembly: AssemblyInformationalVersion("0.1.18+da1d6644b921fba451b3511c7b98b4c9770d446f")]
[assembly: AssemblyProduct("Hex.Core")]
[assembly: AssemblyTitle("Hex.Core")]
[assembly: AssemblyVersion("0.1.18.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[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 ExtraPotions.Hex
{
	public static class HexActionKeys
	{
		public static IReadOnlyList<string> Powers { get; } = new string[8] { "GP_Eikthyr", "GP_TheElder", "GP_Bonemass", "GP_Moder", "GP_Yagluth", "GP_Queen", "GP_Ashlands", "GP_DeepNorth" };

		public static IReadOnlyList<string> Keys { get; } = new string[17]
		{
			"heal", "rested", "reveal", "poi", "estimatepoi", "seed", "reset", "reset_speeds", "spawn_protection", "GP_Eikthyr",
			"GP_TheElder", "GP_Bonemass", "GP_Moder", "GP_Yagluth", "GP_Queen", "GP_Ashlands", "GP_DeepNorth"
		};

		public static string Label(string key)
		{
			return key switch
			{
				"spawn_protection" => "spawn_protection_label", 
				"reset" => "map_reset", 
				"seed" => "seed_label", 
				"reset_speeds" => "speeds_reset_all", 
				"estimatepoi" => "poi_estimate", 
				"poi" => "poi_actual", 
				"reveal" => "map_reveal", 
				"rested" => "actions_rested", 
				"heal" => "actions_heal", 
				_ => "actions_power", 
			};
		}
	}
	public static class HexCatalog
	{
		public static IReadOnlyList<string> AgreedUnits { get; } = new string[26]
		{
			"A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "B1", "B2",
			"B3", "C1", "C2", "C3", "C4", "D1", "E1", "E2", "F1", "F2",
			"F3", "G1", "G2", "G3", "G4", "G5"
		};

		public static IReadOnlyList<string> RuntimeKeys { get; } = new string[35]
		{
			"unlimited_stamina", "unlimited_eitr", "infinite_jumps", "walk_speed", "run_speed", "swim_speed", "jump_power", "moon_gravity", "disable_durability_loss", "no_carry_limit",
			"custom_carry_weight", "disable_food_degradation", "god_mode", "ghost_mode", "fly", "noclip", "freecam", "fly_speed", "mounted_speed", "keep_items",
			"keep_food", "keep_skills", "keep_status_effects", "achievements_despite_cheats", "clear_inventory_marks", "clear_container_marks", "clear_drop_marks", "local_time_minute", "local_time_freeze", "bouncy",
			"super_knockback", "party_hits", "player_size", "debug_mode", "esp"
		};

		public static float SpeedFactor(int percent)
		{
			return (float)Math.Min(300, Math.Max(10, percent)) / 100f;
		}

		public static float SizeFactor(int percent)
		{
			return (float)Math.Min(300, Math.Max(25, percent)) / 100f;
		}

		public static float JumpFactor(int percent)
		{
			return (float)Math.Min(500, Math.Max(25, percent)) / 100f;
		}

		public static float CarryCapacity(float native, bool noLimit, int custom)
		{
			if (!noLimit)
			{
				if (custom <= 0)
				{
					return native;
				}
				return Math.Min(99999, custom);
			}
			return float.PositiveInfinity;
		}
	}
	public readonly struct OwnedScale
	{
		public readonly float Before;

		public readonly float Applied;

		public OwnedScale(float before, float factor)
		{
			Before = before;
			Applied = before * factor;
		}

		public float Restore(float current)
		{
			if (current != Applied)
			{
				return current;
			}
			return Before;
		}
	}
	public static class HexCore
	{
		public const string PluginGuid = "com.meadworks.hex";

		public const string ProductName = "Hex";

		public const string ProductVersion = "0.1.18";

		public const string Family = "Mischief";

		public const string TokenNamespace = "hex";

		public const string SupportedGameVersion = "1.0.17";

		public const string TokenPrefix = "meadworks_hex_";

		public const string DataFolder = "Meadworks/hex";
	}
	public static class HexDebugView
	{
		public const float DayPerMouse = 0.005f;

		public const float FovMin = 0.5f;

		public const float FovMax = 165f;

		public static float Day(float fraction, float mouseY)
		{
			float num = (fraction + mouseY * 0.005f) % 1f;
			if (!(num < 0f))
			{
				return num;
			}
			return num + 1f;
		}

		public static float Fov(float fov, float mouseX)
		{
			return Math.Max(0.5f, Math.Min(165f, fov + mouseX));
		}
	}
	public sealed class HexHotkeyValues
	{
		private readonly Dictionary<string, object> selected = new Dictionary<string, object>(StringComparer.Ordinal);

		public void Remember(string key, object current, object safe)
		{
			if (current is int && !object.Equals(current, safe))
			{
				selected[key] = current;
			}
		}

		public bool Next(string key, object current, object safe, out object next)
		{
			Remember(key, current, safe);
			next = safe;
			if (current is bool flag)
			{
				next = !flag;
				return true;
			}
			if (!(current is int))
			{
				return false;
			}
			if (!object.Equals(current, safe))
			{
				return true;
			}
			return selected.TryGetValue(key, out next);
		}
	}
	public readonly struct HexKillReply
	{
		public int Targets { get; }

		public int Submitted { get; }

		public int Skipped { get; }

		public HexKillReply(int targets, int submitted, int skipped)
		{
			Targets = targets;
			Submitted = submitted;
			Skipped = skipped;
		}
	}
	public readonly struct HexAreaRequest
	{
		public float Radius { get; }

		public HexAreaRequest(float radius)
		{
			Radius = radius;
		}
	}
	public static class HexKillData
	{
		public const string OperationId = "meadworks.hex.debug_kill";

		public const string DropsOperationId = "meadworks.hex.debug_drops";

		public const string TameOperationId = "meadworks.hex.debug_tame";

		public const string EventOperationId = "meadworks.hex.debug_event";

		public const int MaxTargets = 512;

		public static readonly Version Version = new Version(1, 0);

		public static byte[] EncodeRequest(HexAreaRequest request)
		{
			if (!HexOwnerData.ValidRadius(request.Radius))
			{
				throw new ArgumentException("Invalid radius.");
			}
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
			binaryWriter.Write((byte)2);
			binaryWriter.Write((byte)1);
			binaryWriter.Write(request.Radius);
			return memoryStream.ToArray();
		}

		public static HexAreaRequest DecodeRequest(byte[] bytes)
		{
			if (bytes == null || bytes.Length != 6 || bytes[0] != 2 || bytes[1] != 1)
			{
				throw new FormatException("Invalid kill request.");
			}
			using BinaryReader binaryReader = new BinaryReader(new MemoryStream(bytes, writable: false));
			binaryReader.ReadByte();
			binaryReader.ReadByte();
			float radius = binaryReader.ReadSingle();
			if (!HexOwnerData.ValidRadius(radius))
			{
				throw new FormatException("Invalid radius.");
			}
			return new HexAreaRequest(radius);
		}

		public static byte[] EncodeEvent(bool confirmed)
		{
			if (!confirmed)
			{
				throw new ArgumentException("Event confirmation required.");
			}
			return new byte[2] { 1, 1 };
		}

		public static bool DecodeEvent(byte[] bytes)
		{
			if (bytes == null || bytes.Length != 2 || bytes[0] != 1 || bytes[1] != 1)
			{
				throw new FormatException("Invalid event request.");
			}
			return true;
		}

		private static bool Valid(HexKillReply value)
		{
			if (value.Targets >= 0 && value.Targets <= 512 && value.Submitted >= 0 && value.Skipped >= 0 && value.Submitted <= value.Targets)
			{
				return value.Skipped == value.Targets - value.Submitted;
			}
			return false;
		}

		public static byte[] EncodeReply(HexKillReply value)
		{
			if (!Valid(value))
			{
				throw new ArgumentException("Invalid kill result.");
			}
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
			binaryWriter.Write((byte)1);
			binaryWriter.Write(value.Targets);
			binaryWriter.Write(value.Submitted);
			binaryWriter.Write(value.Skipped);
			return memoryStream.ToArray();
		}

		public static HexKillReply DecodeReply(byte[] bytes)
		{
			if (bytes == null || bytes.Length != 13 || bytes[0] != 1)
			{
				throw new FormatException("Invalid kill result.");
			}
			using BinaryReader binaryReader = new BinaryReader(new MemoryStream(bytes, writable: false));
			binaryReader.ReadByte();
			HexKillReply hexKillReply = new HexKillReply(binaryReader.ReadInt32(), binaryReader.ReadInt32(), binaryReader.ReadInt32());
			if (!Valid(hexKillReply))
			{
				throw new FormatException("Invalid kill counts.");
			}
			return hexKillReply;
		}
	}
	public static class HexMenu
	{
		public const float ValueX = 380f;

		public const float RowEnd = 708f;

		public static IReadOnlyList<string> Tabs { get; } = new string[7] { "cheats", "movement", "skills", "spawn", "map", "debug", "presets" };

		public static IReadOnlyList<string> Speeds { get; } = new string[5] { "walk_speed", "run_speed", "swim_speed", "fly_speed", "mounted_speed" };

		public static IReadOnlyDictionary<string, string[]> Preferences { get; } = new Dictionary<string, string[]>
		{
			["cheats"] = new string[17]
			{
				"god_mode", "ghost_mode", "fly", "noclip", "freecam", "unlimited_stamina", "unlimited_eitr", "infinite_jumps", "disable_durability_loss", "disable_food_degradation",
				"no_carry_limit", "custom_carry_weight", "keep_items", "keep_food", "keep_skills", "keep_status_effects", "quick_actions"
			},
			["movement"] = new string[11]
			{
				"moon_gravity", "bouncy", "super_knockback", "party_hits", "jump_power", "player_size", "walk_speed", "run_speed", "swim_speed", "fly_speed",
				"mounted_speed"
			},
			["skills"] = new string[1] { "skill_editor" },
			["spawn"] = new string[0],
			["map"] = new string[1] { "map_tools" },
			["debug"] = new string[5] { "debug_tools", "debug_mode", "esp", "local_time_minute", "local_time_freeze" },
			["presets"] = new string[0]
		};

		public static IReadOnlyList<string> AlmanacOnly { get; } = new string[4] { "achievements_despite_cheats", "clear_inventory_marks", "clear_container_marks", "clear_drop_marks" };

		public static IReadOnlyList<(string Id, int Minute)> TimePresets { get; } = new(string, int)[4]
		{
			("midnight", 0),
			("sunrise", 360),
			("noon", 720),
			("sunset", 1080)
		};

		public static (float X, float Width) ResetSpan(float captionWidth)
		{
			float num = Math.Min(150f, Math.Max(68f, captionWidth + 18f));
			return (X: 708f - num, Width: num);
		}

		public static float ValueWidth(float preferred, float resetX)
		{
			return Math.Max(120f, Math.Min(preferred, resetX - 10f - 380f));
		}
	}
	public enum HexOwnerAction : byte
	{
		Kill = 1,
		Drops,
		Tame
	}
	public readonly struct HexTargetId : IEquatable<HexTargetId>
	{
		public long User { get; }

		public uint Id { get; }

		public HexTargetId(long user, uint id)
		{
			User = user;
			Id = id;
		}

		public bool Equals(HexTargetId other)
		{
			if (User == other.User)
			{
				return Id == other.Id;
			}
			return false;
		}

		public override bool Equals(object? obj)
		{
			if (obj is HexTargetId other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (User.GetHashCode() * 397) ^ (int)Id;
		}

		public override string ToString()
		{
			return User + ":" + Id;
		}
	}
	public sealed class HexOwnerCommand
	{
		public HexOwnerAction Action { get; }

		public float X { get; }

		public float Y { get; }

		public float Z { get; }

		public float Radius { get; }

		public IReadOnlyList<HexTargetId> Targets { get; }

		public HexOwnerCommand(HexOwnerAction action, float x, float y, float z, float radius, IReadOnlyList<HexTargetId> targets)
		{
			Action = action;
			X = x;
			Y = y;
			Z = z;
			Radius = radius;
			Targets = targets;
		}
	}
	public readonly struct HexOwnerReply
	{
		public int Applied { get; }

		public int Skipped { get; }

		public HexOwnerReply(int applied, int skipped)
		{
			Applied = applied;
			Skipped = skipped;
		}
	}
	public static class HexOwnerData
	{
		public const string CommandId = "meadworks.hex.debug_owner";

		public const int MaxBatch = 64;

		public const float MinRadius = 5f;

		public const float MaxRadius = 1000f;

		public static readonly Version Version = new Version(2, 0);

		private static bool Finite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}

		private static bool Defined(HexOwnerAction action)
		{
			if (action != HexOwnerAction.Kill && action != HexOwnerAction.Drops)
			{
				return action == HexOwnerAction.Tame;
			}
			return true;
		}

		public static bool ValidRadius(float radius)
		{
			if (Finite(radius) && radius >= 5f)
			{
				return radius <= 1000f;
			}
			return false;
		}

		public static bool SkipCreature(HexOwnerAction action, bool player, bool tamed)
		{
			if (action != HexOwnerAction.Drops)
			{
				return player || tamed;
			}
			return false;
		}

		public static bool Within(float cx, float cy, float cz, float x, float y, float z, float radius)
		{
			if (!Finite(cx) || !Finite(cy) || !Finite(cz) || !Finite(x) || !Finite(y) || !Finite(z))
			{
				return false;
			}
			double num = x - cx;
			double num2 = y - cy;
			double num3 = z - cz;
			return num * num + num2 * num2 + num3 * num3 <= (double)radius * (double)radius;
		}

		public static byte[] Encode(HexOwnerCommand command)
		{
			if (command == null || !Defined(command.Action) || !Finite(command.X) || !Finite(command.Y) || !Finite(command.Z) || !ValidRadius(command.Radius) || command.Targets == null || command.Targets.Count < 1 || command.Targets.Count > 64 || command.Targets.Distinct().Count() != command.Targets.Count)
			{
				throw new ArgumentException("Invalid owner command.");
			}
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
			binaryWriter.Write((byte)2);
			binaryWriter.Write((byte)command.Action);
			binaryWriter.Write(command.X);
			binaryWriter.Write(command.Y);
			binaryWriter.Write(command.Z);
			binaryWriter.Write(command.Radius);
			binaryWriter.Write((ushort)command.Targets.Count);
			foreach (HexTargetId target in command.Targets)
			{
				binaryWriter.Write(target.User);
				binaryWriter.Write(target.Id);
			}
			return memoryStream.ToArray();
		}

		public static HexOwnerCommand Decode(byte[] bytes)
		{
			if (bytes == null || bytes.Length < 20 || bytes[0] != 2 || !Defined((HexOwnerAction)bytes[1]))
			{
				throw new FormatException("Invalid owner command.");
			}
			using BinaryReader binaryReader = new BinaryReader(new MemoryStream(bytes, writable: false));
			binaryReader.ReadByte();
			HexOwnerAction action = (HexOwnerAction)binaryReader.ReadByte();
			float num = binaryReader.ReadSingle();
			float num2 = binaryReader.ReadSingle();
			float num3 = binaryReader.ReadSingle();
			float radius = binaryReader.ReadSingle();
			int num4 = binaryReader.ReadUInt16();
			if (!Finite(num) || !Finite(num2) || !Finite(num3) || !ValidRadius(radius) || num4 < 1 || num4 > 64 || bytes.Length != 20 + num4 * 12)
			{
				throw new FormatException("Invalid owner command.");
			}
			List<HexTargetId> list = new List<HexTargetId>(num4);
			for (int i = 0; i < num4; i++)
			{
				list.Add(new HexTargetId(binaryReader.ReadInt64(), binaryReader.ReadUInt32()));
			}
			if (list.Distinct().Count() != num4)
			{
				throw new FormatException("Repeated owner target.");
			}
			return new HexOwnerCommand(action, num, num2, num3, radius, list);
		}

		private static bool Valid(int applied, int skipped)
		{
			if (applied >= 0 && skipped >= 0 && applied <= 64 && skipped <= 64 && applied + skipped >= 1)
			{
				return applied + skipped <= 64;
			}
			return false;
		}

		public static byte[] EncodeReply(HexOwnerReply reply)
		{
			if (!Valid(reply.Applied, reply.Skipped))
			{
				throw new ArgumentException("Invalid owner reply.");
			}
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
			binaryWriter.Write((byte)1);
			binaryWriter.Write(reply.Applied);
			binaryWriter.Write(reply.Skipped);
			return memoryStream.ToArray();
		}

		public static HexOwnerReply DecodeReply(byte[] bytes)
		{
			if (bytes == null || bytes.Length != 9 || bytes[0] != 1)
			{
				throw new FormatException("Invalid owner reply.");
			}
			using BinaryReader binaryReader = new BinaryReader(new MemoryStream(bytes, writable: false));
			binaryReader.ReadByte();
			int applied = binaryReader.ReadInt32();
			int skipped = binaryReader.ReadInt32();
			if (!Valid(applied, skipped))
			{
				throw new FormatException("Invalid owner counts.");
			}
			return new HexOwnerReply(applied, skipped);
		}
	}
	public readonly struct HexOwnedTarget
	{
		public long Owner { get; }

		public HexTargetId Id { get; }

		public HexOwnedTarget(long owner, HexTargetId id)
		{
			Owner = owner;
			Id = id;
		}
	}
	public sealed class HexOwnerBatch
	{
		public long Owner { get; }

		public IReadOnlyList<HexTargetId> Ids { get; }

		public HexOwnerBatch(long owner, IReadOnlyList<HexTargetId> ids)
		{
			Owner = owner;
			Ids = ids;
		}
	}
	public sealed class HexOwnerPlan
	{
		public IReadOnlyList<HexOwnerBatch> Batches { get; }

		public int Targets { get; }

		public int Unowned { get; }

		public bool OverLimit { get; }

		internal HexOwnerPlan(IReadOnlyList<HexOwnerBatch> batches, int targets, int unowned, bool overLimit)
		{
			Batches = batches;
			Targets = targets;
			Unowned = unowned;
			OverLimit = overLimit;
		}
	}
	public static class HexOwnerPlanner
	{
		public static HexOwnerPlan Plan(IEnumerable<HexOwnedTarget> targets, int maxTargets, int batchSize)
		{
			if (maxTargets < 1)
			{
				throw new ArgumentOutOfRangeException("maxTargets");
			}
			if (batchSize < 1)
			{
				throw new ArgumentOutOfRangeException("batchSize");
			}
			HashSet<HexTargetId> hashSet = new HashSet<HexTargetId>();
			List<long> list = new List<long>();
			Dictionary<long, List<HexTargetId>> dictionary = new Dictionary<long, List<HexTargetId>>();
			int num = 0;
			int num2 = 0;
			foreach (HexOwnedTarget target in targets)
			{
				if (!hashSet.Add(target.Id))
				{
					continue;
				}
				if (target.Owner == 0L)
				{
					num++;
					continue;
				}
				num2++;
				if (!dictionary.TryGetValue(target.Owner, out var value))
				{
					value = new List<HexTargetId>();
					dictionary.Add(target.Owner, value);
					list.Add(target.Owner);
				}
				value.Add(target.Id);
			}
			if (num2 > maxTargets)
			{
				return new HexOwnerPlan(Array.Empty<HexOwnerBatch>(), num2, num, overLimit: true);
			}
			List<HexOwnerBatch> list2 = new List<HexOwnerBatch>();
			foreach (long item in list)
			{
				for (int i = 0; i < dictionary[item].Count; i += batchSize)
				{
					list2.Add(new HexOwnerBatch(item, dictionary[item].Skip(i).Take(batchSize).ToArray()));
				}
			}
			return new HexOwnerPlan(list2, num2, num, overLimit: false);
		}
	}
	public enum HexBatchState
	{
		Applied,
		Refused,
		Unknown
	}
	public sealed class HexOwnerTally
	{
		private readonly int targets;

		private int submitted;

		private int recorded;

		public bool Uncertain { get; private set; }

		public HexKillReply Reply
		{
			get
			{
				if (!Uncertain)
				{
					return new HexKillReply(targets, submitted, targets - submitted);
				}
				throw new InvalidOperationException("Owner outcome uncertain.");
			}
		}

		public HexOwnerTally(int targets)
		{
			if (targets < 0)
			{
				throw new ArgumentOutOfRangeException("targets");
			}
			this.targets = targets;
		}

		public void Record(int batchSize, HexBatchState state, HexOwnerReply reply)
		{
			recorded += batchSize;
			if (recorded > targets || batchSize < 1)
			{
				Uncertain = true;
				return;
			}
			switch (state)
			{
			case HexBatchState.Refused:
				return;
			case HexBatchState.Unknown:
				Uncertain = true;
				return;
			}
			if (reply.Applied < 0 || reply.Skipped < 0 || reply.Applied + reply.Skipped != batchSize)
			{
				Uncertain = true;
			}
			else
			{
				submitted += reply.Applied;
			}
		}
	}
	public static class HexPoiRows
	{
		public const string CapabilityId = "meadworks.thing.poi";

		public static readonly Version Version = new Version(1, 0);

		public const int Maximum = 512;

		private static readonly Dictionary<string, string> names = new Dictionary<string, string>(StringComparer.Ordinal)
		{
			["Eikthyrnir"] = "$enemy_eikthyr",
			["GDKing"] = "$enemy_gdking",
			["Bonemass"] = "$enemy_bonemass",
			["Dragonqueen"] = "$enemy_dragon",
			["GoblinKing"] = "$enemy_goblinking",
			["Mistlands_DvergrBossEntrance1"] = "$enemy_seekerqueen",
			["FaderLocation"] = "$enemy_fader",
			["DN_Bossroom"] = "$enemy_frozenking",
			["Vendor_BlackForest"] = "$npc_haldor",
			["Hildir_camp"] = "$npc_hildir",
			["BogWitch_Camp"] = "$npc_bogwitch"
		};

		public static bool Trader(string name)
		{
			if (!(name == "Vendor_BlackForest") && !(name == "Hildir_camp"))
			{
				return name == "BogWitch_Camp";
			}
			return true;
		}

		public static string Token(string name)
		{
			if (!names.TryGetValue(name, out string value))
			{
				return name;
			}
			return value;
		}

		private static bool Coordinate(float value)
		{
			if (!float.IsNaN(value) && !float.IsInfinity(value))
			{
				return Math.Abs(value) <= 20000f;
			}
			return false;
		}

		public static IReadOnlyList<Tuple<string, float, float, float, bool>> Select(IEnumerable<Tuple<string, float, float, float, bool>> source)
		{
			List<Tuple<string, float, float, float, bool>> list = new List<Tuple<string, float, float, float, bool>>();
			foreach (Tuple<string, float, float, float, bool> item in source)
			{
				if (item != null && names.ContainsKey(item.Item1 ?? "") && Coordinate(item.Item2) && Coordinate(item.Item3) && Coordinate(item.Item4))
				{
					list.Add(item);
					if (list.Count > 512)
					{
						throw new InvalidOperationException("PoiLimit");
					}
				}
			}
			HashSet<string> confirmed = new HashSet<string>(from row in list
				where Trader(row.Item1) && row.Item5
				select row.Item1, StringComparer.Ordinal);
			return Array.AsReadOnly(list.Where((Tuple<string, float, float, float, bool> row) => !Trader(row.Item1) || row.Item5 || !confirmed.Contains(row.Item1)).Distinct().ToArray());
		}
	}
	public static class HexSourceImport
	{
		public const string VatFile = "com.icecub.valheimadmintool.cfg";

		public const string VatPresetFile = "com.icecub.valheimadmintool.cheats.cfg";

		public const string AsFile = "liveriadevs.valheim.achievementsync.cfg";

		public static IReadOnlyDictionary<string, string> ToggleKeys { get; } = new Dictionary<string, string>(StringComparer.Ordinal)
		{
			["GodMode"] = "god_mode",
			["DebugMode"] = "debug_mode",
			["UnlimitedStamina"] = "unlimited_stamina",
			["UnlimitedEitr"] = "unlimited_eitr",
			["FlyMode"] = "fly",
			["InfiniteJumps"] = "infinite_jumps",
			["NoClipMode"] = "noclip",
			["FreeCamMode"] = "freecam",
			["GhostMode"] = "ghost_mode",
			["NoCarryLimit"] = "no_carry_limit",
			["DisableFoodDegradation"] = "disable_food_degradation",
			["DisableDurabilityLoss"] = "disable_durability_loss",
			["DisableItemLoss"] = "keep_items",
			["DisableFoodLoss"] = "keep_food",
			["DisableStatusLoss"] = "keep_status_effects",
			["DisableSkillLoss"] = "keep_skills",
			["MoonGravity"] = "moon_gravity",
			["SuperKnockback"] = "super_knockback",
			["BouncyMode"] = "bouncy",
			["PartyHits"] = "party_hits"
		};

		public static IReadOnlyDictionary<string, string> Owners { get; } = new Dictionary<string, string>(StringComparer.Ordinal)
		{
			["NoBuildCost"] = "Timber",
			["BuildEverywhere"] = "Timber",
			["NoStructuralDamage"] = "Timber",
			["MapTeleport"] = "Wayfarer",
			["UnrestrictedPortals"] = "Threshold",
			["ForgeAlwaysSucceed"] = "Inscribe",
			["InstantCrafting"] = "Kindle",
			["WindInBack"] = "Keel",
			["ShipSpeed"] = "Keel",
			["WardOverride"] = "Thing",
			["RemoveDrops"] = "Thing"
		};

		public static IReadOnlyDictionary<string, string> ActionKeys { get; } = new Dictionary<string, string>(StringComparer.Ordinal)
		{
			["QuickHeal"] = "heal",
			["Rested"] = "rested",
			["ExploreMap"] = "reveal",
			["RevealPoi"] = "poi",
			["ShowWorldSeed"] = "seed",
			["ResetMap"] = "reset",
			["BossPowerEikthyr"] = "GP_Eikthyr",
			["BossPowerElder"] = "GP_TheElder",
			["BossPowerBonemass"] = "GP_Bonemass",
			["BossPowerModer"] = "GP_Moder",
			["BossPowerYagluth"] = "GP_Yagluth",
			["BossPowerQueen"] = "GP_Queen",
			["BossPowerFader"] = "GP_Ashlands"
		};

		public static IReadOnlyDictionary<string, string> AchievementKeys { get; } = new Dictionary<string, string>(StringComparer.Ordinal)
		{
			["EnableAchievements"] = "achievements_despite_cheats",
			["ClearItemCheatFlags"] = "clear_inventory_marks",
			["ClearContainerCheatFlags"] = "clear_container_marks",
			["ClearWorldDropCheatFlags"] = "clear_drop_marks"
		};

		public static string? Target(string source, string sectionKey)
		{
			if (source == "vat")
			{
				if (sectionKey == "General.Toggle menu")
				{
					return "menu";
				}
				if (sectionKey.StartsWith("Hotkeys.", StringComparison.Ordinal))
				{
					if (ToggleKeys.TryGetValue(sectionKey.Substring(8), out string value))
					{
						return "hotkey:" + value;
					}
					if (ActionKeys.TryGetValue(sectionKey.Substring(8), out string value2))
					{
						return "action:" + value2;
					}
				}
			}
			if (source == "as" && sectionKey.StartsWith("General.", StringComparison.Ordinal) && AchievementKeys.TryGetValue(sectionKey.Substring(8), out string value3))
			{
				return "preference:" + value3;
			}
			if (source == "as-guard" && (sectionKey == "General.SyncPastStats" || sectionKey == "General.ResyncKey"))
			{
				return "Achievements." + sectionKey.Substring(8);
			}
			return null;
		}

		public static string? Referral(string sectionKey)
		{
			if (sectionKey.StartsWith("Automatic resets.", StringComparison.Ordinal))
			{
				return "Delve";
			}
			if (!sectionKey.StartsWith("Hotkeys.", StringComparison.Ordinal) || !Owners.TryGetValue(sectionKey.Substring(8), out string value))
			{
				return null;
			}
			return value;
		}

		public static string? PresetKey(string sectionKey)
		{
			int num = sectionKey.LastIndexOf('.');
			string text = ((num >= 0) ? sectionKey.Substring(num + 1) : sectionKey);
			if (ToggleKeys.TryGetValue(text, out string value))
			{
				return value;
			}
			foreach (string runtimeKey in HexCatalog.RuntimeKeys)
			{
				if (runtimeKey == text)
				{
					return runtimeKey;
				}
			}
			return null;
		}
	}
	public enum HexSpawnKind : byte
	{
		Item = 1,
		Creature
	}
	public sealed class HexSpawnRequest
	{
		public HexSpawnKind Kind { get; }

		public string Prefab { get; }

		public int Amount { get; }

		public int Level { get; }

		public bool Tamed { get; }

		public bool Inventory { get; }

		public HexSpawnRequest(HexSpawnKind kind, string prefab, int amount, int level, bool tamed, bool inventory)
		{
			Kind = kind;
			Prefab = prefab;
			Amount = amount;
			Level = level;
			Tamed = tamed;
			Inventory = inventory;
		}
	}
	public sealed class HexSpawnReply
	{
		public string Receipt { get; }

		public int Created { get; }

		public bool Partial { get; }

		public HexSpawnReply(string receipt, int created, bool partial)
		{
			Receipt = receipt;
			Created = created;
			Partial = partial;
		}
	}
	public static class HexSpawnData
	{
		public const string OperationId = "meadworks.hex.spawn";

		public const string AuditCapability = "meadworks.thing.hex_spawn_audit";

		public static readonly Version Version = new Version(1, 0);

		public const int MaxAmount = 9999;

		public const int MaxCreatureLevel = 100;

		private static readonly Regex Markup = new Regex("</?(?:color|b|i|u|s|size|material|quad|sprite|link|mark|align|alpha|font|style|rotate|sup|sub|nobr|noparse|cspace|mspace|pos|space|indent|margin|line-height|line-indent|lowercase|uppercase|smallcaps|voffset|width|gradient|page)(?:[=\\s][^<>]*)?>", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant);

		private static readonly Regex Unresolved = new Regex("^(?:\\$[A-Za-z0-9_.]+|\\[[A-Za-z0-9_.]+\\])$", RegexOptions.Compiled | RegexOptions.CultureInvariant);

		public static bool PrefabValid(string prefab)
		{
			if (!string.IsNullOrWhiteSpace(prefab) && prefab.Length <= 160)
			{
				return prefab.All((char c) => !char.IsControl(c));
			}
			return false;
		}

		public static bool Valid(HexSpawnRequest request)
		{
			if (request != null && Enum.IsDefined(typeof(HexSpawnKind), request.Kind) && PrefabValid(request.Prefab) && request.Amount >= 1 && request.Amount <= 9999 && request.Level >= 1)
			{
				if (request.Kind != HexSpawnKind.Item)
				{
					if (request.Level <= 100)
					{
						return !request.Inventory;
					}
					return false;
				}
				return !request.Tamed;
			}
			return false;
		}

		public static bool Supported(HexSpawnRequest request, int itemMaxQuality, bool tameable)
		{
			if (Valid(request))
			{
				if (request.Kind != HexSpawnKind.Item)
				{
					return !request.Tamed || tameable;
				}
				return request.Level <= itemMaxQuality;
			}
			return false;
		}

		private static bool Flag(BinaryReader reader)
		{
			byte b = reader.ReadByte();
			if (b > 1)
			{
				throw new FormatException("Invalid spawn flag.");
			}
			return b == 1;
		}

		private static BinaryReader Reader(byte[] bytes, int maximum)
		{
			if (bytes == null || bytes.Length < 2 || bytes.Length > maximum)
			{
				throw new FormatException("Invalid spawn payload length.");
			}
			BinaryReader binaryReader = new BinaryReader(new MemoryStream(bytes, writable: false), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true));
			if (binaryReader.ReadByte() != 1)
			{
				binaryReader.Dispose();
				throw new FormatException("Invalid spawn format.");
			}
			return binaryReader;
		}

		public static byte[] Encode(HexSpawnRequest request)
		{
			if (!Valid(request))
			{
				throw new ArgumentException("Invalid spawn request.");
			}
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream, Encoding.UTF8, leaveOpen: true);
			binaryWriter.Write((byte)1);
			binaryWriter.Write((byte)request.Kind);
			binaryWriter.Write(request.Prefab);
			binaryWriter.Write(request.Amount);
			binaryWriter.Write(request.Level);
			binaryWriter.Write(request.Tamed);
			binaryWriter.Write(request.Inventory);
			return memoryStream.ToArray();
		}

		public static HexSpawnRequest Decode(byte[] bytes)
		{
			using BinaryReader binaryReader = Reader(bytes, 1024);
			HexSpawnRequest hexSpawnRequest = new HexSpawnRequest((HexSpawnKind)binaryReader.ReadByte(), binaryReader.ReadString(), binaryReader.ReadInt32(), binaryReader.ReadInt32(), Flag(binaryReader), Flag(binaryReader));
			if (!Valid(hexSpawnRequest) || binaryReader.BaseStream.Position != binaryReader.BaseStream.Length)
			{
				throw new FormatException("Invalid spawn request.");
			}
			return hexSpawnRequest;
		}

		private static bool Valid(HexSpawnReply reply)
		{
			if (reply != null && Guid.TryParseExact(reply.Receipt, "N", out var _) && reply.Created >= 0)
			{
				return reply.Created <= 9999;
			}
			return false;
		}

		public static byte[] Encode(HexSpawnReply reply)
		{
			if (!Valid(reply))
			{
				throw new ArgumentException("Invalid spawn reply.");
			}
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream, Encoding.UTF8, leaveOpen: true);
			binaryWriter.Write((byte)1);
			binaryWriter.Write(reply.Receipt);
			binaryWriter.Write(reply.Created);
			binaryWriter.Write(reply.Partial);
			return memoryStream.ToArray();
		}

		public static HexSpawnReply DecodeReply(byte[] bytes)
		{
			using BinaryReader binaryReader = Reader(bytes, 128);
			HexSpawnReply hexSpawnReply = new HexSpawnReply(binaryReader.ReadString(), binaryReader.ReadInt32(), Flag(binaryReader));
			if (!Valid(hexSpawnReply) || binaryReader.BaseStream.Position != binaryReader.BaseStream.Length)
			{
				throw new FormatException("Invalid spawn reply.");
			}
			return hexSpawnReply;
		}

		public static string DisplayName(string? localized, string prefab)
		{
			string text = Markup.Replace(localized ?? "", "");
			StringBuilder stringBuilder = new StringBuilder(text.Length);
			string text2 = text;
			foreach (char c in text2)
			{
				stringBuilder.Append((char.IsControl(c) || CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.Format) ? ' ' : c);
			}
			string text3 = Regex.Replace(stringBuilder.ToString(), "\\s+", " ").Trim();
			if (text3.Length != 0 && !Unresolved.IsMatch(text3))
			{
				return text3;
			}
			return prefab;
		}

		public static string Fold(string value)
		{
			StringBuilder stringBuilder = new StringBuilder();
			string text = (value ?? "").Normalize(NormalizationForm.FormD);
			foreach (char c in text)
			{
				if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark && !char.IsWhiteSpace(c) && c != '_' && c != '-')
				{
					stringBuilder.Append(char.ToUpperInvariant(c));
				}
			}
			return stringBuilder.ToString().Normalize(NormalizationForm.FormC);
		}
	}
	public static class HexToolAccess
	{
		public static bool Allows(bool fullAdmin, bool granted, bool mischiefAllowed, bool refusedBecauseNotAdmin, bool adminRequired)
		{
			if (adminRequired && !fullAdmin && !granted)
			{
				return false;
			}
			if (mischiefAllowed)
			{
				return true;
			}
			return granted && refusedBecauseNotAdmin;
		}
	}
	public sealed class LocalClock
	{
		private int selected = -1;

		private bool frozen;

		private float offset;

		public void Reset()
		{
			selected = -1;
			offset = 0f;
		}

		public float Resolve(float native, int minute, bool freeze)
		{
			if (minute < 0 || minute > 1439 || float.IsNaN(native) || float.IsInfinity(native))
			{
				Reset();
				return native;
			}
			float num = (float)minute / 1440f;
			if (selected != minute || frozen != freeze)
			{
				selected = minute;
				frozen = freeze;
				offset = num - native;
			}
			float num2 = (freeze ? num : (native + offset));
			return num2 - (float)Math.Floor(num2);
		}
	}
	public static class SpawnProtectionGeometry
	{
		public readonly struct Point
		{
			public double X { get; }

			public double Z { get; }

			public Point(double x, double z)
			{
				X = x;
				Z = z;
			}
		}

		public readonly struct Circle
		{
			public double X { get; }

			public double Z { get; }

			public double Radius { get; }

			public int Segments { get; }

			public double InnerRadius => Radius * Math.Cos(Math.PI / (double)Segments);

			public Circle(double x, double z, double radius)
			{
				if (!Finite(x) || !Finite(z) || !Finite(radius) || radius <= 0.0 || radius > 1024.0)
				{
					throw new ArgumentOutOfRangeException("radius");
				}
				X = x;
				Z = z;
				Radius = radius;
				Segments = Math.Max(12, (int)Math.Ceiling(Math.PI / Math.Acos(1.0 - Math.Min(0.005, radius) / radius)));
			}
		}

		public sealed class Region
		{
			public IReadOnlyList<Point> Points { get; }

			public bool Covered { get; }

			internal Region(List<Point> points, bool covered)
			{
				Points = points;
				Covered = covered;
			}
		}

		public const double ChordError = 0.005;

		private const double Epsilon = 1E-09;

		private const int MaximumRegions = 512;

		public static IReadOnlyList<Region> Partition(double x, double z, double size, IReadOnlyList<Circle> circles, Circle? extent = null, bool covered = false)
		{
			if (!Finite(x) || !Finite(z) || !Finite(size) || size <= 0.0)
			{
				throw new ArgumentOutOfRangeException("size");
			}
			return Partition(new List<Point>
			{
				new Point(x, z),
				new Point(x + size, z),
				new Point(x + size, z + size),
				new Point(x, z + size)
			}, circles, extent, covered);
		}

		public static IReadOnlyList<Region> PartitionTriangle(Point a, Point b, Point c, IReadOnlyList<Circle> circles, Circle? extent = null, bool covered = false)
		{
			double num = Side(c, a, b);
			if (!Finite(a.X) || !Finite(a.Z) || !Finite(b.X) || !Finite(b.Z) || !Finite(c.X) || !Finite(c.Z) || Math.Abs(num) <= 1E-09)
			{
				throw new ArgumentOutOfRangeException("c");
			}
			return Partition((num > 0.0) ? new List<Point> { a, b, c } : new List<Point> { a, c, b }, circles, extent, covered);
		}

		public static double TriangleHeight(Point point, Point a, double heightA, Point b, double heightB, Point c, double heightC)
		{
			double num = Side(c, a, b);
			if (Math.Abs(num) <= 1E-09)
			{
				throw new ArgumentOutOfRangeException("c");
			}
			double num2 = Side(point, b, c) / num;
			double num3 = Side(point, c, a) / num;
			return num2 * heightA + num3 * heightB + (1.0 - num2 - num3) * heightC;
		}

		private static IReadOnlyList<Region> Partition(List<Point> cell, IReadOnlyList<Circle> circles, Circle? extent, bool covered)
		{
			if (circles == null || circles.Count > 512)
			{
				throw new ArgumentOutOfRangeException("circles");
			}
			if (extent.HasValue)
			{
				cell = Intersect(cell, extent.Value);
			}
			List<Region> list = new List<Region>();
			if (covered)
			{
				if (Valid(cell))
				{
					list.Add(new Region(cell, covered: true));
				}
				return list;
			}
			List<List<Point>> list2 = new List<List<Point>>();
			if (Valid(cell))
			{
				list2.Add(cell);
			}
			foreach (Circle circle in circles)
			{
				List<List<Point>> list3 = new List<List<Point>>();
				foreach (List<Point> item in list2)
				{
					if (Outside(item, circle))
					{
						list3.Add(item);
						continue;
					}
					if (Inside(item, circle))
					{
						list.Add(new Region(item, covered: true));
						continue;
					}
					List<Point> list4 = item;
					for (int i = 0; i < circle.Segments; i++)
					{
						if (!Valid(list4))
						{
							break;
						}
						Edge(circle, i, out var a, out var b);
						List<Point> list5 = Clip(list4, a, b, inside: false);
						if (Valid(list5))
						{
							list3.Add(list5);
						}
						list4 = Clip(list4, a, b, inside: true);
						if (list3.Count + list.Count > 512)
						{
							throw new InvalidOperationException("Protection geometry limit");
						}
					}
					if (Valid(list4))
					{
						list.Add(new Region(list4, covered: true));
					}
				}
				list2 = list3;
				if (list2.Count == 0)
				{
					break;
				}
			}
			foreach (List<Point> item2 in list2)
			{
				list.Add(new Region(item2, covered: false));
			}
			return list;
		}

		private static List<Point> Intersect(List<Point> polygon, Circle circle)
		{
			if (Outside(polygon, circle))
			{
				return new List<Point>();
			}
			if (Inside(polygon, circle))
			{
				return polygon;
			}
			for (int i = 0; i < circle.Segments; i++)
			{
				if (!Valid(polygon))
				{
					break;
				}
				Edge(circle, i, out var a, out var b);
				polygon = Clip(polygon, a, b, inside: true);
			}
			return polygon;
		}

		private static void Edge(Circle circle, int edge, out Point a, out Point b)
		{
			double num = (double)edge * Math.PI * 2.0 / (double)circle.Segments;
			double num2 = (double)(edge + 1) * Math.PI * 2.0 / (double)circle.Segments;
			a = new Point(circle.X + Math.Cos(num) * circle.Radius, circle.Z + Math.Sin(num) * circle.Radius);
			b = new Point(circle.X + Math.Cos(num2) * circle.Radius, circle.Z + Math.Sin(num2) * circle.Radius);
		}

		private static bool Inside(List<Point> polygon, Circle circle)
		{
			double innerRadius = circle.InnerRadius;
			double num = innerRadius * innerRadius;
			foreach (Point item in polygon)
			{
				if ((item.X - circle.X) * (item.X - circle.X) + (item.Z - circle.Z) * (item.Z - circle.Z) > num)
				{
					return false;
				}
			}
			return true;
		}

		private static bool Outside(List<Point> polygon, Circle circle)
		{
			double num = double.PositiveInfinity;
			double num2 = num;
			double num3 = double.NegativeInfinity;
			double num4 = num3;
			foreach (Point item in polygon)
			{
				num = Math.Min(num, item.X);
				num3 = Math.Max(num3, item.X);
				num2 = Math.Min(num2, item.Z);
				num4 = Math.Max(num4, item.Z);
			}
			double num5 = Math.Max(num - circle.X, Math.Max(0.0, circle.X - num3));
			double num6 = Math.Max(num2 - circle.Z, Math.Max(0.0, circle.Z - num4));
			return num5 * num5 + num6 * num6 >= circle.Radius * circle.Radius;
		}

		private static List<Point> Clip(List<Point> polygon, Point a, Point b, bool inside)
		{
			List<Point> list = new List<Point>();
			if (polygon.Count == 0)
			{
				return list;
			}
			Point point = polygon[polygon.Count - 1];
			double num = Side(point, a, b);
			bool flag = (inside ? (num >= 0.0) : (num <= 0.0));
			foreach (Point item in polygon)
			{
				double num2 = Side(item, a, b);
				bool num3 = (inside ? (num2 >= 0.0) : (num2 <= 0.0));
				if (num3 != flag)
				{
					double num4 = num / (num - num2);
					list.Add(new Point(point.X + (item.X - point.X) * num4, point.Z + (item.Z - point.Z) * num4));
				}
				if (num3)
				{
					list.Add(item);
				}
				point = item;
				num = num2;
				flag = num3;
			}
			return list;
		}

		private static double Side(Point point, Point a, Point b)
		{
			return (b.X - a.X) * (point.Z - a.Z) - (b.Z - a.Z) * (point.X - a.X);
		}

		private static bool Valid(List<Point> points)
		{
			if (points.Count >= 3)
			{
				return Area(points) > 1E-09;
			}
			return false;
		}

		private static bool Finite(double value)
		{
			if (!double.IsNaN(value))
			{
				return !double.IsInfinity(value);
			}
			return false;
		}

		public static double Area(IReadOnlyList<Point> points)
		{
			double num = 0.0;
			for (int i = 0; i < points.Count; i++)
			{
				Point point = points[(i + 1) % points.Count];
				num += points[i].X * point.Z - point.X * points[i].Z;
			}
			return Math.Abs(num) * 0.5;
		}
	}
}
namespace ExtraPotions.Hex.Ghost
{
	public readonly struct GhostKey : IEquatable<GhostKey>, IComparable<GhostKey>
	{
		public long User { get; }

		public uint Id { get; }

		public bool IsNone
		{
			get
			{
				if (User == 0L)
				{
					return Id == 0;
				}
				return false;
			}
		}

		public GhostKey(long user, uint id)
		{
			User = user;
			Id = id;
		}

		public bool Equals(GhostKey other)
		{
			if (User == other.User)
			{
				return Id == other.Id;
			}
			return false;
		}

		public override bool Equals(object? obj)
		{
			if (obj is GhostKey other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (User.GetHashCode() * 397) ^ (int)Id;
		}

		public int CompareTo(GhostKey other)
		{
			int num = User.CompareTo(other.User);
			if (num == 0)
			{
				return Id.CompareTo(other.Id);
			}
			return num;
		}

		public static bool operator ==(GhostKey a, GhostKey b)
		{
			return a.Equals(b);
		}

		public static bool operator !=(GhostKey a, GhostKey b)
		{
			return !a.Equals(b);
		}

		public override string ToString()
		{
			return User + ":" + Id;
		}
	}
	public enum GhostVerb : byte
	{
		Off,
		On
	}
	public enum GhostState : byte
	{
		Off,
		Confirmed,
		Refused
	}
	public enum GhostReason : byte
	{
		None,
		Inactive,
		Character,
		Denied,
		Capacity,
		Vanilla
	}
	public readonly struct GhostAnswer : IEquatable<GhostAnswer>
	{
		public GhostState State { get; }

		public GhostReason Reason { get; }

		public bool Keeps => State == GhostState.Confirmed;

		public GhostAnswer(GhostState state, GhostReason reason)
		{
			State = state;
			Reason = reason;
		}

		public bool Equals(GhostAnswer other)
		{
			if (State == other.State)
			{
				return Reason == other.Reason;
			}
			return false;
		}

		public override bool Equals(object? obj)
		{
			if (obj is GhostAnswer other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (int)State * 16 + (int)Reason;
		}

		public override string ToString()
		{
			return State.ToString() + ((Reason == GhostReason.None) ? "" : (":" + Reason));
		}
	}
	public static class GhostDecision
	{
		public static GhostAnswer Decide(GhostVerb verb, bool active, bool characterMatches, bool allowed, bool capacityAvailable, bool vanillaBlocked = false)
		{
			if (!active)
			{
				return new GhostAnswer(GhostState.Refused, GhostReason.Inactive);
			}
			if (!characterMatches)
			{
				return new GhostAnswer(GhostState.Refused, GhostReason.Character);
			}
			if (verb == GhostVerb.Off)
			{
				return new GhostAnswer(GhostState.Off, GhostReason.None);
			}
			if (!allowed)
			{
				return new GhostAnswer(GhostState.Refused, GhostReason.Denied);
			}
			if (vanillaBlocked)
			{
				return new GhostAnswer(GhostState.Refused, GhostReason.Vanilla);
			}
			if (!capacityAvailable)
			{
				return new GhostAnswer(GhostState.Refused, GhostReason.Capacity);
			}
			return new GhostAnswer(GhostState.Confirmed, GhostReason.None);
		}
	}
	public readonly struct GhostRequestFacts : IEquatable<GhostRequestFacts>
	{
		public long Generation { get; }

		public GhostKey Character { get; }

		public bool Wish { get; }

		public bool Confirmed { get; }

		public string Stamp { get; }

		public GhostRequestFacts(long generation, GhostKey character, bool wish, bool confirmed, string stamp)
		{
			Generation = generation;
			Character = character;
			Wish = wish;
			Confirmed = confirmed;
			Stamp = stamp ?? "";
		}

		internal bool SameKey(GhostRequestFacts other)
		{
			if (Generation == other.Generation && Character == other.Character && Wish == other.Wish)
			{
				return string.Equals(Stamp, other.Stamp, StringComparison.Ordinal);
			}
			return false;
		}

		public bool Equals(GhostRequestFacts other)
		{
			if (SameKey(other))
			{
				return Confirmed == other.Confirmed;
			}
			return false;
		}

		public override bool Equals(object? obj)
		{
			if (obj is GhostRequestFacts other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (int)((uint)((Generation.GetHashCode() * 397) ^ Character.GetHashCode()) ^ (Wish ? 1u : 0u)) ^ Stamp.GetHashCode();
		}
	}
	public sealed class GhostRequester
	{
		public const double Spacing = 1.0;

		public const double FailureDelay = 5.0;

		public const int MaxAttempts = 3;

		private GhostRequestFacts? current;

		private GhostRequestFacts? sent;

		private int attempts;

		private bool answered;

		private bool inFlight;

		private double nextAllowed = double.NegativeInfinity;

		public bool InFlight => inFlight;

		public GhostVerb? Next(double now, GhostRequestFacts facts)
		{
			if (facts.Character.IsNone)
			{
				return null;
			}
			if (!current.HasValue || !current.Value.SameKey(facts))
			{
				current = facts;
				attempts = 0;
				answered = false;
			}
			if (facts.Wish == facts.Confirmed || inFlight || answered || attempts >= 3 || now < nextAllowed)
			{
				return null;
			}
			attempts++;
			inFlight = true;
			sent = facts;
			nextAllowed = now + 1.0;
			return facts.Wish ? GhostVerb.On : GhostVerb.Off;
		}

		public void Completed(double now, bool wasAnswered)
		{
			if (!inFlight)
			{
				return;
			}
			inFlight = false;
			bool flag = sent.HasValue && current.HasValue && sent.Value.SameKey(current.Value);
			if (wasAnswered)
			{
				if (flag)
				{
					answered = true;
				}
			}
			else
			{
				nextAllowed = Math.Max(nextAllowed, now + 5.0);
			}
			sent = null;
		}

		public void Reset()
		{
			current = (sent = null);
			attempts = 0;
			answered = (inFlight = false);
			nextAllowed = double.NegativeInfinity;
		}
	}
	public sealed class GhostPublisher
	{
		private sealed class Peer
		{
			public long Delivered = -1L;

			public bool InFlight;

			public double NextAttempt;

			public int Failures;
		}

		public const double Spacing = 2.0;

		public const double MaxBackoff = 10.0;

		private readonly Dictionary<string, Peer> peers = new Dictionary<string, Peer>(StringComparer.Ordinal);

		public bool Due(string peer, long revision, bool empty, double now)
		{
			if (!peers.TryGetValue(peer, out Peer value))
			{
				return !empty;
			}
			if (!value.InFlight && value.Delivered != revision)
			{
				return now >= value.NextAttempt;
			}
			return false;
		}

		public void Sent(string peer, long revision, double now)
		{
			if (!peers.TryGetValue(peer, out Peer value))
			{
				value = (peers[peer] = new Peer());
			}
			value.InFlight = true;
			value.NextAttempt = now + 2.0;
		}

		public void Delivered(string peer, long revision)
		{
			if (peers.TryGetValue(peer, out Peer value))
			{
				value.InFlight = false;
				value.Delivered = revision;
				value.Failures = 0;
			}
		}

		public void Failed(string peer, double now)
		{
			if (peers.TryGetValue(peer, out Peer value))
			{
				value.InFlight = false;
				value.Failures = Math.Min(value.Failures + 1, 8);
				value.NextAttempt = now + Math.Min(10.0, Math.Pow(2.0, value.Failures));
			}
		}

		public void Retain(IEnumerable<string> live)
		{
			if (peers.Count == 0)
			{
				return;
			}
			ICollection<string> collection = (live as ICollection<string>) ?? new HashSet<string>(live ?? Array.Empty<string>(), StringComparer.Ordinal);
			List<string> list = null;
			foreach (string key in peers.Keys)
			{
				if (!collection.Contains(key))
				{
					(list ?? (list = new List<string>())).Add(key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (string item in list)
			{
				peers.Remove(item);
			}
		}

		public void Clear()
		{
			peers.Clear();
		}
	}
	public enum GhostVanillaPolicy
	{
		Allow,
		Refuse
	}
	public static class GhostVanillaRule
	{
		public const GhostVanillaPolicy Default = GhostVanillaPolicy.Allow;

		public static bool Blocks(GhostVanillaPolicy policy, bool vanillaClientsConnected)
		{
			return policy == GhostVanillaPolicy.Refuse && vanillaClientsConnected;
		}

		public static bool VanillaPresent(GhostVanillaPolicy policy, bool known, bool anyVanilla)
		{
			if (!known)
			{
				return policy == GhostVanillaPolicy.Refuse;
			}
			return anyVanilla;
		}

		public static bool BlocksForPeer(bool pending, bool crucible, bool hasHex)
		{
			if (!pending)
			{
				if (crucible)
				{
					return !hasHex;
				}
				return true;
			}
			return false;
		}
	}
	public sealed class GhostVanillaGrace
	{
		public const double GraceSeconds = 5.0;

		private double since = double.NaN;

		public bool Blocks(GhostVanillaPolicy policy, bool known, bool anyVanilla, double now)
		{
			if (policy != GhostVanillaPolicy.Refuse || (known && !anyVanilla))
			{
				since = double.NaN;
				return false;
			}
			if (!known)
			{
				since = double.NaN;
				return true;
			}
			if (double.IsNaN(since))
			{
				since = now;
			}
			return now - since >= 5.0;
		}

		public void Reset()
		{
			since = double.NaN;
		}
	}
	public static class GhostNotices
	{
		public const string RevokedKey = "ghost_revoked";

		public const string SettingKey = "ghost_vanilla_setting";

		public static IReadOnlyList<string> TextKeys { get; } = new string[7] { "ghost_refused_inactive", "ghost_refused_character", "ghost_refused_denied", "ghost_refused_capacity", "ghost_refused_vanilla", "ghost_revoked", "ghost_vanilla_setting" };

		public static string? RefusalKey(GhostReason reason)
		{
			return reason switch
			{
				GhostReason.Inactive => "ghost_refused_inactive", 
				GhostReason.Character => "ghost_refused_character", 
				GhostReason.Denied => "ghost_refused_denied", 
				GhostReason.Capacity => "ghost_refused_capacity", 
				GhostReason.Vanilla => "ghost_refused_vanilla", 
				_ => null, 
			};
		}

		public static string? For(GhostAnswer answer)
		{
			if (answer.State != GhostState.Refused)
			{
				return null;
			}
			return RefusalKey(answer.Reason);
		}
	}
	public sealed class GhostRegistry
	{
		public const int MaxEntries = 256;

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

		private readonly HashSet<GhostKey> keys = new HashSet<GhostKey>();

		public long Revision { get; private set; }

		public int Count => entries.Count;

		public bool Has(string peer)
		{
			if (peer != null)
			{
				return entries.ContainsKey(peer);
			}
			return false;
		}

		public bool Contains(GhostKey key)
		{
			if (!key.IsNone)
			{
				return keys.Contains(key);
			}
			return false;
		}

		public bool CanAdmit(string peer)
		{
			if (!Has(peer))
			{
				return entries.Count < 256;
			}
			return true;
		}

		public bool Grant(string peer, GhostKey key)
		{
			if (string.IsNullOrEmpty(peer))
			{
				throw new ArgumentException("Expected a peer.", "peer");
			}
			if (key.IsNone)
			{
				throw new ArgumentException("Expected a character.", "key");
			}
			if (entries.TryGetValue(peer, out var value) && value == key)
			{
				return false;
			}
			if (!CanAdmit(peer))
			{
				throw new InvalidOperationException("Ghost registry is full.");
			}
			entries[peer] = key;
			Rebuild();
			return true;
		}

		public bool Revoke(string peer)
		{
			if (peer == null || !entries.Remove(peer))
			{
				return false;
			}
			Rebuild();
			return true;
		}

		public IReadOnlyList<string> RetainWhere(Func<string, GhostKey, bool> keep)
		{
			if (keep == null)
			{
				throw new ArgumentNullException("keep");
			}
			string[] array = (from pair in entries
				where !keep(pair.Key, pair.Value)
				select pair.Key).OrderBy<string, string>((string p) => p, StringComparer.Ordinal).ToArray();
			if (array.Length == 0)
			{
				return array;
			}
			string[] array2 = array;
			foreach (string key in array2)
			{
				entries.Remove(key);
			}
			Rebuild();
			return array;
		}

		public void Clear()
		{
			if (entries.Count != 0)
			{
				entries.Clear();
				Rebuild();
			}
		}

		public GhostKey[] Snapshot()
		{
			return keys.OrderBy((GhostKey k) => k).ToArray();
		}

		private void Rebuild()
		{
			keys.Clear();
			foreach (GhostKey value in entries.Values)
			{
				keys.Add(value);
			}
			checked
			{
				Revision++;
			}
		}
	}
	public sealed class GhostView
	{
		private readonly HashSet<GhostKey> keys = new HashSet<GhostKey>();

		private long generation = -1L;

		private long revision = -1L;

		public int Count => keys.Count;

		public long Generation => generation;

		public bool Contains(GhostKey key)
		{
			if (!key.IsNone)
			{
				return keys.Contains(key);
			}
			return false;
		}

		public void Reset(long sessionGeneration)
		{
			generation = sessionGeneration;
			revision = -1L;
			keys.Clear();
		}

		public bool Accept(long sessionGeneration, long setRevision, IReadOnlyCollection<GhostKey> set)
		{
			if (set == null || sessionGeneration != generation || setRevision <= revision)
			{
				return false;
			}
			revision = setRevision;
			keys.Clear();
			foreach (GhostKey item in set)
			{
				if (!item.IsNone)
				{
					keys.Add(item);
				}
			}
			return true;
		}
	}
	public sealed class GhostSet
	{
		public long Revision { get; }

		public IReadOnlyList<GhostKey> Keys { get; }

		public GhostSet(long revision, IReadOnlyList<GhostKey> keys)
		{
			Revision = revision;
			Keys = keys;
		}
	}
	public static class GhostWire
	{
		public const byte Version = 1;

		public const int MaxEntries = 256;

		private const int KeySize = 12;

		private const int SetHeader = 11;

		public static byte[] EncodeRequest(GhostVerb verb, GhostKey key)
		{
			if (verb != GhostVerb.On && verb != GhostVerb.Off)
			{
				throw new ArgumentException("Unknown verb.", "verb");
			}
			byte[] obj = new byte[14]
			{
				1,
				(byte)verb,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0
			};
			WriteKey(obj, 2, key);
			return obj;
		}

		public static (GhostVerb Verb, GhostKey Key) DecodeRequest(byte[] bytes)
		{
			if (bytes == null || bytes.Length != 14 || bytes[0] != 1)
			{
				throw new FormatException("Malformed Ghost request.");
			}
			if (bytes[1] > 1)
			{
				throw new FormatException("Unknown Ghost verb.");
			}
			GhostKey item = ReadKey(bytes, 2);
			if (item.IsNone)
			{
				throw new FormatException("Ghost request without a character.");
			}
			return (Verb: (GhostVerb)bytes[1], Key: item);
		}

		public static byte[] EncodeAnswer(GhostAnswer answer)
		{
			return new byte[3]
			{
				1,
				(byte)answer.State,
				(byte)answer.Reason
			};
		}

		public static GhostAnswer DecodeAnswer(byte[] bytes)
		{
			if (bytes == null || bytes.Length != 3 || bytes[0] != 1)
			{
				throw new FormatException("Malformed Ghost answer.");
			}
			if (bytes[1] > 2 || bytes[2] > 5)
			{
				throw new FormatException("Unknown Ghost answer.");
			}
			return new GhostAnswer((GhostState)bytes[1], (GhostReason)bytes[2]);
		}

		public static byte[] EncodeSet(long revision, IReadOnlyCollection<GhostKey> keys)
		{
			if (keys == null)
			{
				throw new ArgumentNullException("keys");
			}
			if (revision < 0)
			{
				throw new ArgumentException("Negative revision.", "revision");
			}
			GhostKey[] array = (from k in keys.Distinct()
				orderby k
				select k).ToArray();
			if (array.Length > 256)
			{
				throw new ArgumentException("Too many Ghost entries.", "keys");
			}
			if (array.Any((GhostKey k) => k.IsNone))
			{
				throw new ArgumentException("Ghost set with an empty character.", "keys");
			}
			byte[] array2 = new byte[11 + array.Length * 12];
			array2[0] = 1;
			WriteLong(array2, 1, revision);
			array2[9] = (byte)(array.Length >> 8);
			array2[10] = (byte)array.Length;
			for (int num = 0; num < array.Length; num++)
			{
				WriteKey(array2, 11 + num * 12, array[num]);
			}
			return array2;
		}

		public static GhostSet DecodeSet(byte[] bytes)
		{
			if (bytes == null || bytes.Length < 11 || bytes[0] != 1)
			{
				throw new FormatException("Malformed Ghost set.");
			}
			long num = ReadLong(bytes, 1);
			if (num < 0)
			{
				throw new FormatException("Negative Ghost revision.");
			}
			int num2 = (bytes[9] << 8) | bytes[10];
			if (num2 > 256 || bytes.Length != 11 + num2 * 12)
			{
				throw new FormatException("Ghost set length mismatch.");
			}
			GhostKey[] array = new GhostKey[num2];
			for (int i = 0; i < num2; i++)
			{
				array[i] = ReadKey(bytes, 11 + i * 12);
				if (array[i].IsNone)
				{
					throw new FormatException("Ghost set with an empty character.");
				}
				if (i > 0 && array[i - 1].CompareTo(array[i]) >= 0)
				{
					throw new FormatException("Ghost set is not strictly ordered.");
				}
			}
			return new GhostSet(num, array);
		}

		public static byte[] EncodeAck()
		{
			return new byte[2] { 1, 1 };
		}

		public static bool DecodeAck(byte[] bytes)
		{
			if (bytes == null || bytes.Length != 2 || bytes[0] != 1 || bytes[1] != 1)
			{
				throw new FormatException("Malformed Ghost acknowledgment.");
			}
			return true;
		}

		private static void WriteKey(byte[] bytes, int at, GhostKey key)
		{
			WriteLong(bytes, at, key.User);
			for (int i = 0; i < 4; i++)
			{
				bytes[at + 8 + i] = (byte)(key.Id >> 24 - 8 * i);
			}
		}

		private static GhostKey ReadKey(byte[] bytes, int at)
		{
			uint num = 0u;
			for (int i = 0; i < 4; i++)
			{
				num = (num << 8) | bytes[at + 8 + i];
			}
			return new GhostKey(ReadLong(bytes, at), num);
		}

		private static void WriteLong(byte[] bytes, int at, long value)
		{
			for (int i = 0; i < 8; i++)
			{
				bytes[at + i] = (byte)(value >> 56 - 8 * i);
			}
		}

		private static long ReadLong(byte[] bytes, int at)
		{
			long num = 0L;
			for (int i = 0; i < 8; i++)
			{
				num = (num << 8) | bytes[at + i];
			}
			return num;
		}
	}
}

plugins/Hex/Hex.dll

Decompiled 5 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExtraPotions.Hex.Ghost;
using ExtraPotions.Hex.Runtime.Native;
using ExtraPotions.Meadworks.Contracts;
using ExtraPotions.Meadworks.Crucible;
using ExtraPotions.Meadworks.Crucible.UI;
using HarmonyLib;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ExtraPotions")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (C) 2026 expDARE (ExtraPotions Meadworks)")]
[assembly: AssemblyFileVersion("0.1.18.0")]
[assembly: AssemblyInformationalVersion("0.1.18+da1d6644b921fba451b3511c7b98b4c9770d446f")]
[assembly: AssemblyProduct("Hex")]
[assembly: AssemblyTitle("Hex")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.18.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[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 ExtraPotions.Hex.Runtime
{
	public sealed class HexConfig
	{
		private readonly Dictionary<string, ConfigEntryBase> entries = new Dictionary<string, ConfigEntryBase>();

		private readonly Dictionary<string, object> safeValues = new Dictionary<string, object>();

		private readonly Dictionary<string, MischiefCategory> categories = new Dictionary<string, MischiefCategory>();

		private readonly Dictionary<string, string> cheatIds = new Dictionary<string, string>();

		private Dictionary<string, ConfigEntryBase>? preferences;

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

		private bool rememberStale = true;

		private bool neutralStale = true;

		private readonly ConfigFile file;

		private readonly Dictionary<string, ConfigEntry<KeyboardShortcut>> hotkeys = new Dictionary<string, ConfigEntry<KeyboardShortcut>>(StringComparer.Ordinal);

		private readonly HexHotkeyValues hotkeyValues = new HexHotkeyValues();

		internal readonly Dictionary<string, ConfigEntry<KeyboardShortcut>> ActionHotkeys = new Dictionary<string, ConfigEntry<KeyboardShortcut>>(StringComparer.Ordinal);

		internal readonly Dictionary<string, ConfigEntry<bool>> EspKinds = new Dictionary<string, ConfigEntry<bool>>(StringComparer.Ordinal);

		public ConfigEntry<bool> Enabled { get; }

		public ConfigEntry<KeyboardShortcut> PanicKey { get; }

		public ConfigEntry<KeyboardShortcut> MenuKey { get; }

		public ConfigEntry<bool> QuickActions { get; }

		public ConfigEntry<bool> DebugTools { get; }

		public ConfigEntry<bool> MapTools { get; }

		public ConfigEntry<bool> SkillEditor { get; }

		public ConfigEntry<bool> Spawning { get; }

		public ConfigEntry<int> EspDistance { get; }

		public ConfigEntry<string> EspSearch { get; }

		public ConfigEntry<int> ConfirmSpawnAbove { get; }

		public ConfigEntry<bool> RestorePresetOnJoin { get; }

		public ConfigEntry<GhostVanillaPolicy> GhostWithVanilla { get; }

		public HexConfig(ConfigFile file)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Expected O, but got Unknown
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_0251: Unknown result type (might be due to invalid IL or missing references)
			//IL_0571: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f8: Unknown result type (might be due to invalid IL or missing references)
			this.file = file;
			bool saveOnConfigSet = file.SaveOnConfigSet;
			file.SaveOnConfigSet = false;
			try
			{
				Enabled = MeadworksConfig.Bind<bool>(file, "General", "Enabled", true, Localized<bool>("enabled", null, Array.Empty<object>()));
				RestorePresetOnJoin = MeadworksConfig.Bind<bool>(file, "General", "Restore Preset On Join", true, Localized<bool>("preset_restore", null, Array.Empty<object>()), (ConfigScope)0);
				SkillEditor = MeadworksConfig.Bind<bool>(file, "General", "Skill Editor", false, Localized<bool>("skill_editor", null, Array.Empty<object>()), (ConfigScope)0);
				Spawning = MeadworksConfig.Bind<bool>(file, "General", "Spawning", false, Localized<bool>("spawning", null, Array.Empty<object>()), (ConfigScope)0);
				ConfirmSpawnAbove = MeadworksConfig.Bind<int>(file, "General", "Confirm Spawn Above", 100, Localized<int>("spawn_confirm_above", (AcceptableValueBase?)(object)new AcceptableValueRange<int>(1, 9999), new object[1] { (object)new ConfigDependency((Func<bool>)(() => Enabled.Value && Spawning.Value), (Func<string>)(() => "Requires General: Enabled and Spawning."), (Func<bool>)null) }), (ConfigScope)0);
				MapTools = MeadworksConfig.Bind<bool>(file, "General", "Map Tools", false, Localized<bool>("map_tools", null, Array.Empty<object>()), (ConfigScope)0);
				DebugTools = MeadworksConfig.Bind<bool>(file, "General", "Debug Tools", false, Localized<bool>("debug_tools", null, Array.Empty<object>()), (ConfigScope)0);
				QuickActions = MeadworksConfig.Bind<bool>(file, "General", "Quick Actions", false, Localized<bool>("quick_actions", null, Array.Empty<object>()));
				MenuKey = MeadworksConfig.Bind<KeyboardShortcut>(file, "General", "Menu Key", KeyboardShortcut.Empty, Localized<KeyboardShortcut>("menu_key", null, Array.Empty<object>()), (ConfigScope)0);
				PanicKey = MeadworksConfig.Bind<KeyboardShortcut>(file, "General", "Panic Key", KeyboardShortcut.Empty, Localized<KeyboardShortcut>("panic", null, Array.Empty<object>()));
				Toggle("unlimited_stamina");
				Toggle("unlimited_eitr");
				Toggle("infinite_jumps");
				Toggle("moon_gravity");
				Toggle("bouncy");
				Toggle("super_knockback");
				Toggle("party_hits");
				Toggle("disable_durability_loss");
				Toggle("disable_food_degradation");
				Toggle("no_carry_limit");
				Bind("custom_carry_weight", 0, (AcceptableValueBase?)(object)new AcceptableValueRange<int>(0, 99999));
				Number("walk_speed", 10, 300);
				Number("run_speed", 10, 300);
				Number("swim_speed", 10, 300);
				Number("fly_speed", 10, 300);
				Number("mounted_speed", 10, 300);
				Number("jump_power", 25, 500);
				Number("player_size", 25, 300);
				Bind("local_time_minute", -1, (AcceptableValueBase?)(object)new AcceptableValueRange<int>(-1, 1439));
				Toggle("local_time_freeze");
				Toggle("keep_items");
				Toggle("keep_food");
				Toggle("keep_skills");
				Toggle("keep_status_effects");
				BindValue("achievements_despite_cheats", initial: true, safe: false, (MischiefCategory)5);
				BindValue("clear_inventory_marks", initial: true, safe: false, (MischiefCategory)5);
				BindValue("clear_container_marks", initial: true, safe: false, (MischiefCategory)5);
				BindValue("clear_drop_marks", initial: true, safe: false, (MischiefCategory)5);
				Toggle("debug_mode");
				BindValue("esp", initial: false, safe: false, (MischiefCategory)3);
				EspDistance = MeadworksConfig.Bind<int>(file, "ESP", "Max Distance", 100, EspDescription<int>("esp_distance", (AcceptableValueBase?)(object)new AcceptableValueRange<int>(10, 500)), (ConfigScope)0);
				EspSearch = MeadworksConfig.Bind<string>(file, "ESP", "Search", "", EspDescription<string>("esp_search"), (ConfigScope)0);
				string[] array = new string[6] { "players", "creatures", "drops", "resources", "pickables", "dungeons" };
				foreach (string text in array)
				{
					EspKinds.Add(text, MeadworksConfig.Bind<bool>(file, "ESP", text, true, EspDescription<bool>("esp_" + text), (ConfigScope)0));
				}
				Toggle("god_mode");
				Toggle("ghost_mode");
				Toggle("fly");
				Toggle("noclip");
				Toggle("freecam");
				GhostWithVanilla = MeadworksConfig.Bind<GhostVanillaPolicy>(file, "Server", "Ghost With Vanilla Clients", (GhostVanillaPolicy)0, Localized<GhostVanillaPolicy>("ghost_vanilla_setting", null, Array.Empty<object>()), (ConfigScope)0);
				foreach (string key in HexActionKeys.Keys)
				{
					ActionHotkeys.Add(key, MeadworksConfig.Bind<KeyboardShortcut>(file, "Action Hotkeys", key, KeyboardShortcut.Empty, HotkeyDescription(HexActionKeys.Label(key), key.StartsWith("GP_", StringComparison.Ordinal) ? (" " + key) : ""), (ConfigScope)0));
				}
				foreach (KeyValuePair<string, ConfigEntryBase> item in PreferenceEntries())
				{
					hotkeys.Add(item.Key, MeadworksConfig.Bind<KeyboardShortcut>(file, "Hotkeys", item.Key, KeyboardShortcut.Empty, HotkeyDescription("label_" + item.Key), (ConfigScope)0));
				}
			}
			finally
			{
				file.SaveOnConfigSet = saveOnConfigSet;
			}
			file.Save();
			file.SettingChanged += delegate
			{
				rememberStale = (neutralStale = true);
			};
			file.ConfigReloaded += delegate
			{
				rememberStale = (neutralStale = true);
			};
		}

		private ConfigDescription EspDescription<T>(string key, AcceptableValueBase? range = null)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			return Localized<T>(key, range, new object[1] { (object)new ConfigDependency((Func<bool>)(() => Effective("esp", safe: false)), (Func<string>)(() => "Requires ESP enabled and Information permission."), (Func<bool>)null) });
		}

		private static string? CatalogText(string key, string language)
		{
			ProductTranslations val = default(ProductTranslations);
			if (!MeadworksTranslations.Registry.TryGet("hex", ref val))
			{
				return null;
			}
			string text = val.Text(key, language);
			if (!string.Equals(text, key, StringComparison.Ordinal))
			{
				return text;
			}
			return null;
		}

		private static ConfigDescription Localized<T>(string key, AcceptableValueBase? range = null, params object[] tags)
		{
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Expected O, but got Unknown
			string labelKey = ((key == "menu_key") ? "ui_menu_key" : (key.StartsWith("esp_", StringComparison.Ordinal) ? key : ("label_" + key)));
			string helpKey = ((key == "esp_distance") ? "help_esp_distance" : ((key == "esp_search") ? "help_esp_search" : (key.StartsWith("esp_", StringComparison.Ordinal) ? "help_esp_filters" : key)));
			object[] array = new object[tags.Length + 1];
			Array.Copy(tags, array, tags.Length);
			array[tags.Length] = new ConfigPresentation<T>("com.meadworks.hex", (Func<ConfigEntry<T>, string, ConfigPresentationText>)((ConfigEntry<T> _, string language) => new ConfigPresentationText(CatalogText(labelKey, language), (string)null, CatalogText(helpKey, language))));
			return new ConfigDescription(CatalogText(helpKey, "English") ?? key, range, array);
		}

		private static ConfigDescription HotkeyDescription(string labelKey, string suffix = "")
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			return new ConfigDescription(Help("English"), (AcceptableValueBase)null, new object[1]
			{
				new ConfigPresentation<KeyboardShortcut>("com.meadworks.hex", (Func<ConfigEntry<KeyboardShortcut>, string, ConfigPresentationText>)delegate(ConfigEntry<KeyboardShortcut> _, string language)
				{
					//IL_003e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0044: Expected O, but got Unknown
					string text = CatalogText(labelKey, language);
					string text2 = CatalogText("hotkey_description", language);
					return (text != null && text2 != null) ? new ConfigPresentationText(text + suffix, (string)null, string.Format(text2, text + suffix)) : ((ConfigPresentationText)null);
				})
			});
			string Help(string language)
			{
				return string.Format(CatalogText("hotkey_description", language) ?? "{0}", (CatalogText(labelKey, language) ?? labelKey) + suffix);
			}
		}

		private ConfigEntry<T> Bind<T>(string key, T safe, AcceptableValueBase? range = null)
		{
			return BindValue(key, safe, safe, (MischiefCategory)0, range);
		}

		private ConfigEntry<T> BindValue<T>(string key, T initial, T safe, MischiefCategory category, AcceptableValueBase? range = null)
		{
			//IL_062f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0632: Invalid comparison between Unknown and I4
			//IL_0634: Unknown result type (might be due to invalid IL or missing references)
			//IL_0637: Invalid comparison between Unknown and I4
			//IL_0688: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b7: Unknown result type (might be due to invalid IL or missing references)
			string text = key switch
			{
				"unlimited_stamina" => "Unlimited Stamina", 
				"unlimited_eitr" => "Unlimited Eitr", 
				"infinite_jumps" => "Infinite Jumps", 
				"walk_speed" => "Walk Speed Percent", 
				"run_speed" => "Run Speed Percent", 
				"fly_speed" => "Fly Speed Percent", 
				"mounted_speed" => "Mounted Speed Percent", 
				"swim_speed" => "Swim Speed Percent", 
				"player_size" => "Player Size Percent", 
				"party_hits" => "Party Hits", 
				"super_knockback" => "Super Knockback", 
				"bouncy" => "Bouncy", 
				"jump_power" => "Jump Power Percent", 
				"moon_gravity" => "Moon Gravity", 
				"disable_durability_loss" => "Disable Durability Loss", 
				"disable_food_degradation" => "Disable Food Degradation", 
				"no_carry_limit" => "No Carry Limit", 
				"local_time_minute" => "Local Time Minute", 
				"local_time_freeze" => "Freeze Local Time", 
				"custom_carry_weight" => "Custom Carry Weight", 
				"achievements_despite_cheats" => "Achievements Despite Cheats", 
				"clear_inventory_marks" => "Clear Inventory Cheat Marks", 
				"clear_container_marks" => "Clear Container Cheat Marks", 
				"clear_drop_marks" => "Clear Drop Cheat Marks", 
				"keep_items" => "Keep Items On Death", 
				"keep_food" => "Keep Food On Death", 
				"keep_skills" => "Keep Skills On Death", 
				"keep_status_effects" => "Keep Status Effects On Death", 
				"debug_mode" => "Debug Mode", 
				"esp" => "ESP", 
				"god_mode" => "God Mode", 
				"ghost_mode" => "Ghost Mode", 
				"fly" => "Fly", 
				"noclip" => "NoClip", 
				"freecam" => "FreeCam", 
				_ => key, 
			};
			ConfigEntry<T> val = MeadworksConfig.Bind<T>(file, ((int)category == 5) ? "Achievements" : (((int)category == 3) ? "Information" : "Personal"), text, initial, Localized<T>(key, range, Array.Empty<object>()), (ConfigScope)0);
			entries.Add(key, (ConfigEntryBase)(object)val);
			safeValues.Add(key, safe);
			categories.Add(key, category);
			cheatIds.Add(key, CheatId((ConfigEntryBase)(object)val));
			MeadworksMischief.Cheats.Tag("com.meadworks.hex", cheatIds[key], (MischiefCategory?)category);
			return val;
		}

		private void Toggle(string key)
		{
			Bind(key, safe: false);
		}

		private static string CheatId(ConfigEntryBase entry)
		{
			return entry.Definition.Section + "." + entry.Definition.Key;
		}

		private void Number(string key, int min, int max)
		{
			Bind(key, 100, (AcceptableValueBase?)(object)new AcceptableValueRange<int>(min, max));
		}

		internal Dictionary<string, ConfigEntryBase> PreferenceEntries()
		{
			return preferences ?? (preferences = BuildPreferenceEntries());
		}

		private Dictionary<string, ConfigEntryBase> BuildPreferenceEntries()
		{
			return new Dictionary<string, ConfigEntryBase>(entries, StringComparer.Ordinal)
			{
				{
					"quick_actions",
					(ConfigEntryBase)(object)QuickActions
				},
				{
					"debug_tools",
					(ConfigEntryBase)(object)DebugTools
				},
				{
					"map_tools",
					(ConfigEntryBase)(object)MapTools
				},
				{
					"skill_editor",
					(ConfigEntryBase)(object)SkillEditor
				},
				{
					"spawning",
					(ConfigEntryBase)(object)Spawning
				}
			};
		}

		internal MischiefCategory? Category(string key)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (!categories.TryGetValue(key, out var value))
			{
				return null;
			}
			return value;
		}

		internal object SafeValue(string key)
		{
			if (!safeValues.TryGetValue(key, out object value))
			{
				return false;
			}
			return value;
		}

		internal ConfigEntry<KeyboardShortcut> Hotkey(string key)
		{
			return hotkeys[key];
		}

		internal bool SetPreference(string key, object value)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Ready || !Plugin.Active || !ValidPreference(key, value))
			{
				return false;
			}
			if (!object.Equals(value, SafeValue(key)) && categories.TryGetValue(key, out var value2) && (!Enabled.Value || (!MeadworksMischief.PlayersMay(PreferenceEntries()[key]) && !MeadworksMischief.TryUse("com.meadworks.hex", CheatId(PreferenceEntries()[key]), value2, HexText.Text(key)))))
			{
				return false;
			}
			return MeadworksConfig.Amend(PreferenceEntries()[key], value, HexText.Text(key)).Applied;
		}

		internal bool MayUse(string key)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (categories.TryGetValue(key, out var value))
			{
				return MeadworksMischief.AllowsCheat(PreferenceEntries()[key], "com.meadworks.hex", value);
			}
			return true;
		}

		internal string ResetSpeeds()
		{
			if (!Plugin.Ready || !Plugin.Active || !HexMovement.Owned((Character)(object)Player.m_localPlayer))
			{
				return HexText.Text("actions_unavailable");
			}
			foreach (string speed in HexMenu.Speeds)
			{
				if (!SetPreference(speed, SafeValue(speed)))
				{
					return HexText.Text("actions_unavailable");
				}
			}
			return HexText.Text("speeds_reset_done");
		}

		internal void PanicReset()
		{
			HexSpawnProtection.Reset();
			ConfigEntry<bool>[] array = new ConfigEntry<bool>[5] { QuickActions, DebugTools, MapTools, SkillEditor, Spawning };
			for (int i = 0; i < array.Length; i++)
			{
				MeadworksConfig.Amend((ConfigEntryBase)(object)array[i], (object)false, (string)null);
			}
			HexPresets.CancelJoinRestore();
			foreach (KeyValuePair<string, ConfigEntryBase> entry in entries)
			{
				MeadworksConfig.Amend(entry.Value, safeValues[entry.Key], (string)null);
			}
		}

		internal Dictionary<string, object> Snapshot()
		{
			return PreferenceEntries().ToDictionary<KeyValuePair<string, ConfigEntryBase>, string, object>((KeyValuePair<string, ConfigEntryBase> pair) => pair.Key, (KeyValuePair<string, ConfigEntryBase> pair) => pair.Value.BoxedValue, StringComparer.Ordinal);
		}

		internal bool ValidPreference(string key, object value)
		{
			if (PreferenceEntries().TryGetValue(key, out ConfigEntryBase value2) && value != null && value.GetType() == value2.SettingType)
			{
				if (value2.Description.AcceptableValues != null)
				{
					return value2.Description.AcceptableValues.IsValid(value);
				}
				return true;
			}
			return false;
		}

		internal void ApplyPreferences(IReadOnlyDictionary<string, object> snapshot)
		{
			foreach (KeyValuePair<string, object> item in snapshot)
			{
				if (!ValidPreference(item.Key, item.Value))
				{
					throw new ArgumentException("Invalid preset preference.");
				}
			}
			Dictionary<string, ConfigEntryBase> dictionary = PreferenceEntries();
			bool saveOnConfigSet = file.SaveOnConfigSet;
			file.SaveOnConfigSet = false;
			try
			{
				foreach (KeyValuePair<string, object> item2 in snapshot)
				{
					dictionary[item2.Key].BoxedValue = item2.Value;
				}
			}
			finally
			{
				file.SaveOnConfigSet = saveOnConfigSet;
			}
			file.Save();
		}

		public T Effective<T>(string key, T safe)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Ready || !Plugin.Active || !Enabled.Value)
			{
				return safe;
			}
			return MeadworksMischief.Effective<T>((ConfigEntry<T>)(object)entries[key], "com.meadworks.hex", categories[key], safe);
		}

		public void Tick()
		{
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Invalid comparison between Unknown and I4
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Active)
			{
				return;
			}
			if (MeadworksInput.Pressed(PanicKey, (InputContext)0))
			{
				PanicReset();
			}
			else
			{
				if (!Plugin.Active || !Enabled.Value)
				{
					return;
				}
				if (rememberStale)
				{
					rememberStale = false;
					foreach (KeyValuePair<string, ConfigEntryBase> item in PreferenceEntries())
					{
						hotkeyValues.Remember(item.Key, item.Value.BoxedValue, SafeValue(item.Key));
					}
				}
				if (HexMovement.Owned((Character)(object)Player.m_localPlayer) && !((Character)Player.m_localPlayer).IsDead())
				{
					object value = default(object);
					foreach (KeyValuePair<string, ConfigEntry<KeyboardShortcut>> hotkey in hotkeys)
					{
						if (MeadworksInput.Pressed(hotkey.Value, (InputContext)0) && ((!hotkey.Key.StartsWith("achievements_", StringComparison.Ordinal) && !hotkey.Key.StartsWith("clear_", StringComparison.Ordinal)) || HexAchievements.Available))
						{
							ConfigEntryBase val = PreferenceEntries()[hotkey.Key];
							if (hotkeyValues.Next(hotkey.Key, val.BoxedValue, SafeValue(hotkey.Key), ref value))
							{
								SetPreference(hotkey.Key, value);
							}
							else if ((Object)(object)MessageHud.instance != (Object)null)
							{
								MessageHud.instance.ShowMessage((MessageType)2, HexText.Text("hotkey_choose"), 0, (Sprite)null, false, true);
							}
						}
					}
				}
				if (HexMovement.Owned((Character)(object)Player.m_localPlayer))
				{
					foreach (KeyValuePair<string, ConfigEntry<KeyboardShortcut>> actionHotkey in ActionHotkeys)
					{
						if (MeadworksInput.Pressed(actionHotkey.Value, (InputContext)0))
						{
							HexActionShortcuts.Run(actionHotkey.Key);
						}
					}
				}
				if (neutralStale)
				{
					neutralStale = false;
					nonNeutral.Clear();
					foreach (KeyValuePair<string, ConfigEntryBase> entry in entries)
					{
						if (!object.Equals(entry.Value.BoxedValue, safeValues[entry.Key]))
						{
							nonNeutral.Add(entry.Key);
						}
					}
				}
				foreach (string item2 in nonNeutral)
				{
					if ((int)categories[item2] != 5 || HexAchievements.Available)
					{
						BlockedOption obj = MeadworksMischief.Query("com.meadworks.hex", cheatIds[item2], categories[item2]);
						MeadworksBlockedOptions.Notify(obj, obj.Allowed ? null : HexText.Text(item2));
					}
				}
			}
		}
	}
	internal static class EdgeWear
	{
		internal static void Register(ProductRegistration registration)
		{
			registration.AddCapability<Func<object, object, bool>>("meadworks.items.wear_exempt", WearExemptContract.ContractVersion, (Func<object, object, bool>)Exempt);
		}

		internal static bool Exempt(object character, object item)
		{
			if (Plugin.Active)
			{
				Humanoid val = (Humanoid)((character is Humanoid) ? character : null);
				if (val != null)
				{
					ItemData val2 = (ItemData)((item is ItemData) ? item : null);
					if (val2 != null && HexMovement.On((Character)(object)val, "disable_durability_loss"))
					{
						return val.GetInventory().ContainsItem(val2);
					}
				}
			}
			return false;
		}
	}
	internal static class HexActionShortcuts
	{
		internal static void Run(string key)
		{
			if (!Plugin.Ready || !Plugin.Active)
			{
				return;
			}
			HexConfig? settings = Plugin.Settings;
			if (settings != null && settings.Enabled.Value && HexMovement.Owned((Character)(object)Player.m_localPlayer))
			{
				string text = key switch
				{
					"reveal" => HexMap.Execute(new string[2] { "map", "reveal" }), 
					"spawn_protection" => HexSpawnProtection.Toggle(), 
					"estimatepoi" => HexPoi.RequestEstimate(), 
					"poi" => HexPoi.Request(), 
					"seed" => HexInformation.Seed(), 
					"reset" => HexWindow.ConfirmMapReset(), 
					"reset_speeds" => Plugin.Settings.ResetSpeeds(), 
					_ => HexActionKeys.Powers.Contains(key) ? HexActions.Execute(new string[2] { "power", key }) : ((key == "heal" || key == "rested") ? HexActions.Execute(new string[1] { key }) : ""), 
				};
				if (text.Length > 0 && (Object)(object)MessageHud.instance != (Object)null)
				{
					MessageHud.instance.ShowMessage((MessageType)2, text, 0, (Sprite)null, false, true);
				}
			}
		}
	}
	internal sealed class HexImport : IDisposable
	{
		private sealed class CheckedTarget : IValidatedConversionTarget, IConversionTarget
		{
			private readonly HexImport owner;

			private readonly PreviewDocument preview;

			private readonly IConversionTarget target;

			public int SchemaVersion => target.SchemaVersion;

			internal CheckedTarget(HexImport owner, PreviewDocument preview)
			{
				this.owner = owner;
				this.preview = preview;
				target = MeadworksConversion.Target(owner.Owner(preview.Id));
			}

			public void Validate(IReadOnlyDictionary<string, object> values)
			{
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				owner.Admission(preview);
				((IValidatedConversionTarget)target).Validate(values);
				foreach (KeyValuePair<string, object> value in values)
				{
					ConfigEntryBase val = Entry(owner.Owner(preview.Id), value.Key);
					object obj = (val.SettingType.IsInstanceOfType(value.Value) ? value.Value : TomlTypeConverter.ConvertToValue(Convert.ToString(value.Value, CultureInfo.InvariantCulture), val.SettingType));
					if (val.Description.AcceptableValues != null && !val.Description.AcceptableValues.IsValid(obj))
					{
						throw new ArgumentException(HexText.Text("import_invalid"));
					}
				}
				if (owner.Collisions(owner.Owner(preview.Id), values).Any())
				{
					throw new InvalidOperationException(HexText.Text("import_collision_refused"));
				}
			}

			public void Backup()
			{
				owner.Admission(preview);
				target.Backup();
			}

			public void WriteAtomic(IReadOnlyDictionary<string, object> values)
			{
				owner.Admission(preview);
				target.WriteAtomic(values);
			}
		}

		private sealed class PresetTarget : IValidatedConversionTarget, IConversionTarget
		{
			private readonly HexImport owner;

			private readonly PreviewDocument preview;

			private readonly string expected;

			private string proposal = "";

			public int SchemaVersion => 0;

			internal PresetTarget(HexImport owner, PreviewDocument preview)
			{
				this.owner = owner;
				this.preview = preview;
				expected = HexPresets.ImportDisk();
			}

			public void Validate(IReadOnlyDictionary<string, object> values)
			{
				owner.Admission(preview);
				proposal = HexPresets.ImportProposal(expected, values);
			}

			public void Backup()
			{
				owner.Admission(preview);
				HexPresets.ImportBackup(expected);
			}

			public void WriteAtomic(IReadOnlyDictionary<string, object> values)
			{
				owner.Admission(preview);
				if (proposal.Length == 0)
				{
					throw new InvalidOperationException();
				}
				HexPresets.ImportWrite(expected, proposal);
			}
		}

		internal sealed class PreviewDocument
		{
			internal HexImport Owner { get; }

			internal string Id { get; }

			internal ConfigConverter Converter { get; }

			internal long Generation { get; }

			public ConversionPreview Plan { get; }

			public IReadOnlyList<string> Notes { get; }

			public IReadOnlyList<string> Errors { get; }

			public string SourceSha256 { get; }

			public string TargetSha256 { get; }

			internal PreviewDocument(HexImport owner, string id, ConfigConverter converter, ConversionPreview plan, IReadOnlyList<string> notes, IReadOnlyList<string> errors, string source, string target, long generation)
			{
				Owner = owner;
				Id = id;
				Converter = converter;
				Plan = plan;
				Notes = notes;
				Errors = errors.Concat(plan.Errors).ToArray();
				SourceSha256 = source;
				TargetSha256 = target;
				Generation = generation;
			}

			public override string ToString()
			{
				return string.Join("\n", new string[1] { HexText.Format("import_review", Id) }.Concat(Plan.Values.Select((ConversionValue value) => value.SourceId + " → " + value.TargetId + " = " + value.Value)).Concat(Notes).Concat(Errors.Select((string error) => HexText.Format("import_error", error)))
					.Concat(Plan.BindingConflicts.Select((ConversionConflict conflict) => HexText.Format("import_collision", conflict.TargetId)))
					.Concat(new string[2]
					{
						"Source SHA256: " + SourceSha256,
						"Target SHA256: " + TargetSha256
					}));
			}
		}

		private readonly ConfigFile config;

		private readonly List<IDisposable> registrations = new List<IDisposable>();

		private readonly int thread = Thread.CurrentThread.ManagedThreadId;

		private bool disposed;

		private static readonly string[] kinds = new string[4] { "vat", "as", "as-guard", "vat-preset" };

		internal HexImport(ConfigFile config)
		{
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Expected O, but got Unknown
			this.config = config;
			try
			{
				string[] array = kinds;
				foreach (string text in array)
				{
					string id = text;
					registrations.Add(MeadworksConversion.Register(new ConversionRegistration("hex." + id, "com.meadworks.hex", id.StartsWith("vat", StringComparison.Ordinal) ? "com.icecub.valheimadmintool" : "liveriadevs.valheim.achievementsync", id.StartsWith("vat", StringComparison.Ordinal) ? "Valheim_Admin_Tool" : ("AchievementSync" + ((id == "as-guard") ? " (Crucible guard)" : " (Hex preferences)")), (Func<bool>)(() => !disposed && File.Exists(SourcePath(id)) && MeadworksHeadless.AllowsUi), (Func<object>)(() => Preview(id)), (Func<object, IReadOnlyDictionary<string, string>, bool, object>)delegate(object value, IReadOnlyDictionary<string, string> resolutions, bool backup)
					{
						if (!backup)
						{
							throw new InvalidOperationException(HexText.Text("import_backup_required"));
						}
						return Apply((value as PreviewDocument) ?? throw new ArgumentException("Wrong Hex import preview."), resolutions);
					})));
				}
			}
			catch
			{
				Dispose();
				throw;
			}
		}

		public void Dispose()
		{
			if (disposed)
			{
				return;
			}
			disposed = true;
			foreach (IDisposable registration in registrations)
			{
				registration.Dispose();
			}
			registrations.Clear();
		}

		private void Check()
		{
			if (disposed || !Plugin.Ready || thread != Thread.CurrentThread.ManagedThreadId)
			{
				throw new InvalidOperationException(HexText.Text("import_unavailable"));
			}
		}

		private static string SourcePath(string id)
		{
			return Path.Combine(Paths.ConfigPath, (id == "vat") ? "com.icecub.valheimadmintool.cfg" : ((id == "vat-preset") ? "com.icecub.valheimadmintool.cheats.cfg" : "liveriadevs.valheim.achievementsync.cfg"));
		}

		private static string Read(string path, out string hash)
		{
			using FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
			if (fileStream.Length > 1048576)
			{
				throw new IOException("Reference config exceeds 1 MiB.");
			}
			using (SHA256 sHA = SHA256.Create())
			{
				hash = BitConverter.ToString(sHA.ComputeHash(fileStream)).Replace("-", "");
			}
			fileStream.Position = 0L;
			using StreamReader streamReader = new StreamReader(fileStream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true), detectEncodingFromByteOrderMarks: true);
			return streamReader.ReadToEnd();
		}

		private static string Hash(string text)
		{
			using SHA256 sHA = SHA256.Create();
			return BitConverter.ToString(sHA.ComputeHash(Encoding.UTF8.GetBytes(text))).Replace("-", "");
		}

		private ConfigFile Owner(string id)
		{
			if (id != "as-guard")
			{
				return config;
			}
			ConfigEntry<bool> val = default(ConfigEntry<bool>);
			ConfigEntry<KeyboardShortcut> val2 = default(ConfigEntry<KeyboardShortcut>);
			if (!Chainloader.PluginInfos.TryGetValue("com.meadworks.crucible", out var value) || (Object)(object)value.Instance == (Object)null || !value.Instance.Config.TryGetEntry<bool>("Achievements", "SyncPastStats", ref val) || !value.Instance.Config.TryGetEntry<KeyboardShortcut>("Achievements", "ResyncKey", ref val2))
			{
				throw new InvalidOperationException(HexText.Text("import_guard_unavailable"));
			}
			return value.Instance.Config;
		}

		private static string EntryId(ConfigEntryBase entry)
		{
			return entry.Definition.Section + "." + entry.Definition.Key;
		}

		private static ConfigEntryBase Entry(ConfigFile owner, string target)
		{
			return owner[owner.Keys.Single((ConfigDefinition key) => key.Section + "." + key.Key == target)];
		}

		private ConfigEntryBase MappedEntry(string id, string logical)
		{
			if (id == "as-guard")
			{
				return Entry(Owner(id), logical);
			}
			if (logical == "menu")
			{
				return (ConfigEntryBase)(object)Plugin.Settings.MenuKey;
			}
			if (logical.StartsWith("action:", StringComparison.Ordinal))
			{
				return (ConfigEntryBase)(object)Plugin.Settings.ActionHotkeys[logical.Substring(7)];
			}
			if (logical.StartsWith("hotkey:", StringComparison.Ordinal))
			{
				return (ConfigEntryBase)(object)Plugin.Settings.Hotkey(logical.Substring(7));
			}
			return Plugin.Settings.PreferenceEntries()[logical.Substring(11)];
		}

		private static string ConfigHash(ConfigFile owner)
		{
			string hash;
			return Hash((File.Exists(owner.ConfigFilePath) ? Read(owner.ConfigFilePath, out hash) : "missing") + "\n" + string.Join("\n", from key in owner.Keys.OrderBy<ConfigDefinition, string>((ConfigDefinition key) => key.Section, StringComparer.Ordinal).ThenBy<ConfigDefinition, string>((ConfigDefinition key) => key.Key, StringComparer.Ordinal)
				select key.Section + "." + key.Key + "=" + TomlTypeConverter.ConvertToString(owner[key].BoxedValue, owner[key].SettingType)));
		}

		private string TargetHash(string id)
		{
			if (!(id == "vat-preset"))
			{
				return ConfigHash(Owner(id));
			}
			return Hash(HexPresets.ImportDisk());
		}

		internal PreviewDocument Preview(string id)
		{
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bb: Expected O, but got Unknown
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Expected O, but got Unknown
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Expected O, but got Unknown
			Check();
			if (!kinds.Contains(id))
			{
				throw new ArgumentException("Unknown Hex source import.");
			}
			string hash;
			string text = Read(SourcePath(id), out hash);
			IReadOnlyList<KeyValuePair<string, string>> readOnlyList = CfgText.Read(text, "source");
			List<ConversionRule> list = new List<ConversionRule>();
			List<KeyValuePair<string, string>> list2 = new List<KeyValuePair<string, string>>();
			List<string> list3 = new List<string>();
			List<string> list4 = new List<string>();
			if (id == "vat-preset")
			{
				list3.Add(HexText.Text("import_preset_note"));
			}
			if (readOnlyList.Count == 0 && text.Any((char character) => !char.IsWhiteSpace(character)) && !text.TrimStart().StartsWith("#", StringComparison.Ordinal))
			{
				list4.Add(HexText.Text("import_format_unknown"));
			}
			foreach (KeyValuePair<string, string> item in readOnlyList)
			{
				string text2 = item.Key.Substring(7);
				string text3 = ((id == "vat-preset") ? HexSourceImport.PresetKey(text2) : HexSourceImport.Target(id, text2));
				if (text3 == null)
				{
					string text4 = HexSourceImport.Referral(text2);
					list3.Add((text4 != null) ? HexText.Format("import_owner", text2, text4) : HexText.Format("import_unknown", text2));
					continue;
				}
				ConfigEntryBase val = ((id == "vat-preset") ? Plugin.Settings.PreferenceEntries()[text3] : MappedEntry(id, text3));
				if (val.SettingType == typeof(KeyboardShortcut) && string.IsNullOrWhiteSpace(item.Value))
				{
					list3.Add(HexText.Format("import_unassigned", text2));
					continue;
				}
				string text5 = ((id == "vat-preset") ? text3 : EntryId(val));
				string text6 = ((val.SettingType == typeof(KeyboardShortcut)) ? "KeyboardShortcut" : val.SettingType.Name);
				string text7 = ((val.Description.AcceptableValues is AcceptableValueRange<int> val2) ? ("From " + val2.MinValue + " to " + val2.MaxValue) : "");
				list.Add(new ConversionRule(item.Key, text5, text6, text7, false, val.SettingType == typeof(KeyboardShortcut)));
				list2.Add(item);
			}
			ConfigConverter val3 = new ConfigConverter(new ConversionMapping(1, id, 0, (IEnumerable<ConversionRule>)list));
			ConversionPreview val4 = val3.Preview((IEnumerable<KeyValuePair<string, string>>)list2);
			if (id != "vat-preset")
			{
				foreach (string item2 in Collisions(Owner(id), val4.Values.GroupBy<ConversionValue, string>((ConversionValue item) => item.TargetId, StringComparer.Ordinal).ToDictionary((IGrouping<string, ConversionValue> group) => group.Key, (IGrouping<string, ConversionValue> group) => group.First().Value)))
				{
					list3.Add(HexText.Format("import_collision", item2));
				}
			}
			return new PreviewDocument(this, id, val3, val4, list3.Distinct().ToArray(), list4, hash, TargetHash(id), Plugin.Session.Generation);
		}

		private void Admission(PreviewDocument preview)
		{
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			Check();
			if (preview.Owner != this)
			{
				throw new ArgumentException("Preview belongs to another Hex import.");
			}
			Read(SourcePath(preview.Id), out string hash);
			if (hash != preview.SourceSha256 || preview.TargetSha256 != TargetHash(preview.Id) || preview.Generation != Plugin.Session.Generation)
			{
				throw new InvalidOperationException(HexText.Text("import_stale"));
			}
			if (preview.Errors.Count != 0)
			{
				throw new InvalidOperationException(HexText.Text("import_invalid"));
			}
			if (preview.Id == "vat-preset")
			{
				return;
			}
			string text = ((preview.Id == "as-guard") ? "com.meadworks.crucible" : "com.meadworks.hex");
			ConfigEntryMetadata val = default(ConfigEntryMetadata);
			foreach (ConversionValue value in preview.Plan.Values)
			{
				if (!MeadworksConfig.TryGetMetadata(Entry(Owner(preview.Id), value.TargetId), ref val) || val.ProductId != text || (int)val.Scope != 0 || !val.Decision.Allowed || val.Decision.RequiresServerAmendment)
				{
					throw new InvalidOperationException(HexText.Text("import_unavailable"));
				}
			}
		}

		private object Apply(PreviewDocument preview, IReadOnlyDictionary<string, string> resolutions)
		{
			Admission(preview);
			if (preview.Plan.Values.Count == 0)
			{
				return HexText.Text("import_no_changes");
			}
			Dictionary<string, string> choices = resolutions.Where<KeyValuePair<string, string>>((KeyValuePair<string, string> pair) => !pair.Key.StartsWith("binding:", StringComparison.Ordinal)).ToDictionary((KeyValuePair<string, string> pair) => pair.Key, (KeyValuePair<string, string> pair) => pair.Value);
			Dictionary<string, string> bindings = resolutions.Where<KeyValuePair<string, string>>((KeyValuePair<string, string> pair) => pair.Key.StartsWith("binding:", StringComparison.Ordinal)).ToDictionary((KeyValuePair<string, string> pair) => pair.Key.Substring(8), (KeyValuePair<string, string> pair) => pair.Value);
			if (preview.Id == "vat-preset")
			{
				ConversionResult val = preview.Converter.Apply(preview.Plan, (IConversionTarget)(object)new PresetTarget(this, preview), (IReadOnlyDictionary<string, string>)choices, (IReadOnlyDictionary<string, string>)null);
				return HexText.Format("import_applied", val.Written);
			}
			ConversionResult result = null;
			if (!MeadworksConfig.AmendBatch((preview.Id == "as-guard") ? "com.meadworks.crucible" : "com.meadworks.hex", (IReadOnlyList<ConfigEntryBase>)preview.Plan.Values.Select((ConversionValue value) => Entry(Owner(preview.Id), value.TargetId)).Distinct().ToArray(), (Action)delegate
			{
				Admission(preview);
				result = preview.Converter.Apply(preview.Plan, (IConversionTarget)(object)new CheckedTarget(this, preview), (IReadOnlyDictionary<string, string>)choices, (IReadOnlyDictionary<string, string>)bindings);
			}, (string)null).Applied || result == null)
			{
				throw new InvalidOperationException(HexText.Text("import_unavailable"));
			}
			return HexText.Format("import_applied", result.Written);
		}

		private IEnumerable<string> Collisions(ConfigFile owner, IReadOnlyDictionary<string, object> values)
		{
			List<ConfigFile> owners = new List<ConfigFile> { config };
			if (Chainloader.PluginInfos.TryGetValue("com.meadworks.crucible", out var value) && (Object)(object)value.Instance != (Object)null)
			{
				owners.Add(value.Instance.Config);
			}
			foreach (KeyValuePair<string, object> pair in values)
			{
				if (Entry(owner, pair.Key).SettingType != typeof(KeyboardShortcut))
				{
					continue;
				}
				HotkeyChord chord = HotkeyChord.Parse(Convert.ToString(pair.Value, CultureInfo.InvariantCulture));
				if (chord.IsNone)
				{
					continue;
				}
				foreach (ConfigFile other in owners.Distinct())
				{
					foreach (ConfigDefinition key in other.Keys)
					{
						ConfigEntryBase val = other[key];
						if (!(val.SettingType != typeof(KeyboardShortcut)) && (other != owner || !values.ContainsKey(EntryId(val))) && chord == MeadworksInput.Chord((KeyboardShortcut)val.BoxedValue))
						{
							yield return pair.Key + " / " + EntryId(val);
						}
					}
				}
			}
		}
	}
	internal static class HexPauseMenu
	{
		internal const string Id = "hex";

		private static IDisposable? registration;

		internal static void Tick()
		{
			if (!Plugin.Ready || !Plugin.Active || !MeadworksHeadless.AllowsUi)
			{
				Reset();
			}
			else if (registration == null)
			{
				registration = MeadworksMenu.Register("hex", "Hex", (Action)Open, (Func<bool>)(() => Plugin.Ready && Plugin.Active && (Object)(object)Player.m_localPlayer != (Object)null), 100);
			}
		}

		private static void Open()
		{
			if (!Plugin.Ready || !Plugin.Active || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return;
			}
			if (Menu.IsVisible())
			{
				Menu instance = Menu.instance;
				if (instance != null)
				{
					instance.OnClose();
				}
			}
			HexWindow.Open();
		}

		internal static void Reset()
		{
			registration?.Dispose();
			registration = null;
		}
	}
	internal static class HexPolicy
	{
		internal static bool Available
		{
			get
			{
				if (Plugin.Ready && Plugin.Active && Plugin.Session.AuthorityReady && HexMovement.Owned((Character)(object)Player.m_localPlayer) && !((Character)Player.m_localPlayer).IsDead())
				{
					return MeadworksConfig.EditDecision((ConfigScope)1, true, (ServerCrucible?)null).Allowed;
				}
				return false;
			}
		}

		private static ConfigEntry<T>? Entry<T>(string key)
		{
			if (!Available || !Chainloader.PluginInfos.TryGetValue("com.meadworks.crucible", out var value) || (Object)(object)value.Instance == (Object)null)
			{
				return null;
			}
			ConfigEntry<T> result = default(ConfigEntry<T>);
			if (!value.Instance.Config.TryGetEntry<T>("Mischief", key, ref result))
			{
				return null;
			}
			return result;
		}

		internal static string SetAccess(MischiefCategory category, MischiefAccess value)
		{
			//IL_000a: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (!Enum.IsDefined(typeof(MischiefCategory), category) || !Enum.IsDefined(typeof(MischiefAccess), value))
			{
				return HexText.Text("ui_policy_failed");
			}
			return Amend<MischiefAccess>(MischiefPolicy.SettingKey(category), value);
		}

		internal static string ValidatePlayers(string value)
		{
			if (value.Length > 50176)
			{
				return HexText.Text("ui_policy_invalid");
			}
			IReadOnlyList<string> readOnlyList = default(IReadOnlyList<string>);
			MischiefPlayers.Parse(value, ref readOnlyList);
			if (readOnlyList.Count != 0)
			{
				return HexText.Text("ui_policy_invalid");
			}
			return "";
		}

		internal static string SetPlayers(string value)
		{
			if (ValidatePlayers(value).Length != 0)
			{
				return HexText.Text("ui_policy_invalid");
			}
			IReadOnlyList<string> readOnlyList = default(IReadOnlyList<string>);
			MischiefPlayers val = MischiefPlayers.Parse(value, ref readOnlyList);
			return Amend("ListedPlayers", val.Format());
		}

		private static string Amend<T>(string key, T value)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			ConfigEntry<T> val = Entry<T>(key);
			if (val == null)
			{
				return HexText.Text("ui_policy_unavailable");
			}
			try
			{
				ConfigAmendResult val2 = MeadworksConfig.Amend<T>(val, "com.meadworks.crucible", (ConfigScope)1, value, key, true);
				return val2.Applied ? HexText.Text("ui_policy_submitted") : MeadworksBlockedOptions.Reason(val2.Decision.Reason);
			}
			catch
			{
				return HexText.Text("ui_policy_failed");
			}
		}
	}
	internal sealed class HexPresetDocument
	{
		internal string Selected = "";

		internal readonly Dictionary<string, Dictionary<string, object>> Presets = new Dictionary<string, Dictionary<string, object>>(StringComparer.OrdinalIgnoreCase);

		internal HexPresetDocument Copy()
		{
			HexPresetDocument hexPresetDocument = new HexPresetDocument
			{
				Selected = Selected
			};
			foreach (KeyValuePair<string, Dictionary<string, object>> preset in Presets)
			{
				hexPresetDocument.Presets.Add(preset.Key, new Dictionary<string, object>(preset.Value, StringComparer.Ordinal));
			}
			return hexPresetDocument;
		}
	}
	internal static class HexPresetJson
	{
		internal const int MaximumCharacters = 131072;

		internal const int MaximumPresets = 32;

		internal static bool NameValid(string name)
		{
			if (!string.IsNullOrWhiteSpace(name) && name.Length <= 64 && name.Trim() == name)
			{
				return !name.Any(char.IsControl);
			}
			return false;
		}

		internal static HexPresetDocument Read(string text, Func<string, object, bool> valid)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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_004c: Expected O, but got Unknown
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Invalid comparison between Unknown and I4
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Invalid comparison between Unknown and I4
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Invalid comparison between Unknown and I4
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Invalid comparison between Unknown and I4
			if (text == "")
			{
				return new HexPresetDocument();
			}
			if (text.Length > 131072)
			{
				throw new FormatException("Preset file exceeds its size limit.");
			}
			using StringReader stringReader = new StringReader(text);
			JsonTextReader val = new JsonTextReader((TextReader)stringReader)
			{
				MaxDepth = 8,
				DateParseHandling = (DateParseHandling)0
			};
			try
			{
				JObject val2 = JObject.Load((JsonReader)(object)val, new JsonLoadSettings
				{
					DuplicatePropertyNameHandling = (DuplicatePropertyNameHandling)2
				});
				if (((JsonReader)val).Read())
				{
					throw new FormatException("Trailing preset content.");
				}
				if (!val2.Properties().Any((JProperty p) => p.Name != "version" && p.Name != "selected" && p.Name != "presets"))
				{
					JToken obj = val2["version"];
					if (obj != null && (int)obj.Type == 6 && Extensions.Value<long>((IEnumerable<JToken>)val2["version"]) == 1)
					{
						JToken obj2 = val2["selected"];
						if (obj2 != null && (int)obj2.Type == 8)
						{
							JToken obj3 = val2["presets"];
							JObject val3 = (JObject)(object)((obj3 is JObject) ? obj3 : null);
							if (val3 != null)
							{
								HexPresetDocument hexPresetDocument = new HexPresetDocument
								{
									Selected = Extensions.Value<string>((IEnumerable<JToken>)val2["selected"])
								};
								if (((JContainer)val3).Count > 32)
								{
									throw new FormatException("Too many presets.");
								}
								foreach (JProperty item in val3.Properties())
								{
									if (NameValid(item.Name))
									{
										JToken value = item.Value;
										JObject val4 = (JObject)(object)((value is JObject) ? value : null);
										if (val4 != null && !hexPresetDocument.Presets.ContainsKey(item.Name))
										{
											Dictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.Ordinal);
											foreach (JProperty item2 in val4.Properties())
											{
												object obj4;
												if ((int)item2.Value.Type == 9)
												{
													obj4 = Extensions.Value<bool>((IEnumerable<JToken>)item2.Value);
												}
												else
												{
													if ((int)item2.Value.Type != 6)
													{
														throw new FormatException("Preset values must be booleans or integers.");
													}
													long num = Extensions.Value<long>((IEnumerable<JToken>)item2.Value);
													if (num < int.MinValue || num > int.MaxValue)
													{
														throw new FormatException("Preset integer outside range.");
													}
													obj4 = (int)num;
												}
												if (!valid(item2.Name, obj4))
												{
													throw new FormatException("Unknown or invalid preset preference.");
												}
												dictionary.Add(item2.Name, obj4);
											}
											hexPresetDocument.Presets.Add(item.Name, dictionary);
											continue;
										}
									}
									throw new FormatException("Invalid or duplicate preset name.");
								}
								if (hexPresetDocument.Selected != "" && !hexPresetDocument.Presets.ContainsKey(hexPresetDocument.Selected))
								{
									throw new FormatException("Selected preset missing.");
								}
								return hexPresetDocument;
							}
						}
					}
				}
				throw new FormatException("Unsupported preset document.");
			}
			finally
			{
				((IDisposable)val)?.Dispose();
			}
		}

		internal static string Write(HexPresetDocument document)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			//IL_00e4: 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_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			JObject val = new JObject();
			foreach (KeyValuePair<string, Dictionary<string, object>> item in document.Presets.OrderBy<KeyValuePair<string, Dictionary<string, object>>, string>((KeyValuePair<string, Dictionary<string, object>> p) => p.Key, StringComparer.OrdinalIgnoreCase))
			{
				JObject val2 = new JObject();
				foreach (KeyValuePair<string, object> item2 in item.Value.OrderBy<KeyValuePair<string, object>, string>((KeyValuePair<string, object> p) => p.Key, StringComparer.Ordinal))
				{
					val2.Add(item2.Key, JToken.FromObject(item2.Value));
				}
				val.Add(item.Key, (JToken)(object)val2);
			}
			return ((JToken)new JObject
			{
				["version"] = JToken.op_Implicit(1),
				["selected"] = JToken.op_Implicit(document.Selected),
				["presets"] = (JToken)(object)val
			}).ToString((Formatting)1, Array.Empty<JsonConverter>()) + "\n";
		}
	}
	internal static class HexWindow
	{
		[HarmonyPatch(typeof(KitWindow), "Pad")]
		private static class PadRows
		{
			private static bool Prefix(KitWindow __instance, PadButton button)
			{
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Invalid comparison between Unknown and I4
				//IL_0038: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Invalid comparison between Unknown and I4
				//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a4: Invalid comparison between Unknown and I4
				//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
				if (__instance == HexWindow.window)
				{
					KitWindow? window = HexWindow.window;
					if (window != null && window.IsOpen && !MeadworksInput.Typing && KitAlmanacDialog.Active == null && list != null && ((int)button == 12 || (int)button == 13))
					{
						EventSystem current = EventSystem.current;
						GameObject val = ((current != null) ? current.currentSelectedGameObject : null);
						if ((Object)(object)val == (Object)null || !val.transform.IsChildOf((Transform)(object)list.Root))
						{
							return true;
						}
						list.Tick();
						int num = ((list.FocusedKey != null) ? keys.IndexOf(list.FocusedKey) : (-1));
						int num2 = num + (((int)button == 13) ? 1 : (-1));
						if (num < 0 || num2 < 0 || num2 >= keys.Count)
						{
							return true;
						}
						MeadworksInput.PadConsume(button);
						if (CatalogTab)
						{
							PreserveCatalogColumn(val, keys[num2]);
						}
						else
						{
							list.Focus(keys[num2]);
						}
						return false;
					}
				}
				return true;
			}
		}

		private static IReadOnlyList<HexSpawnCatalog.Entry> catalog = Array.Empty<HexSpawnCatalog.Entry>();

		private static readonly List<Selectable> catalogControls = new List<Selectable>();

		private static readonly List<GameObject> catalogObjects = new List<GameObject>();

		private static readonly Dictionary<RectTransform, List<Button>> catalogTiles = new Dictionary<RectTransform, List<Button>>();

		private static KitTextField? catalogField;

		private static KitToggle? catalogEnable;

		private static KitToggle? catalogKind;

		private static TMP_Text? catalogCount;

		private static string search = "";

		private static string category = "";

		private static bool catalogDirty;

		private static bool spawnCreatures;

		private static KitWindow? window;

		private static KitVirtualList? list;

		private static KitToggle? master;

		private static Button? close;

		private static Button? panic;

		private static float nextSkills;

		private static string skillShape = "";

		private static TMP_Text? hint;

		private static string tab = "cheats";

		private static string language = "";

		private static long revision;

		private static bool dirty;

		private static bool focusTabAfterDraw;

		private static Player? actor;

		private static long session = -1L;

		private static int debugRadius = 50;

		private static readonly List<Button> tabs = new List<Button>();

		private static readonly List<string> keys = new List<string>();

		private static readonly Dictionary<RectTransform, List<Action>> cleanup = new Dictionary<RectTransform, List<Action>>();

		private static readonly Dictionary<RectTransform, Action> updates = new Dictionary<RectTransform, Action>();

		private static bool CatalogTab => tab == "spawn";

		private static void SpawnProtectionRow(List<KitVirtualRow> rows)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			rows.Add(new KitVirtualRow("spawn_protection", 100f, (Action<RectTransform>)delegate(RectTransform rect)
			{
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				//IL_0061: Unknown result type (might be due to invalid IL or missing references)
				//IL_0070: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
				cleanup[rect] = new List<Action>();
				string text = HexText.Text("spawn_protection_label");
				KitAlmanacDialog.Label((Transform)(object)rect, "Label", text, Vector2.zero, new Vector2(350f, 35f), 16f);
				KitAlmanacDialog.Label((Transform)(object)rect, "Legend", HexText.Text("spawn_protection_legend"), new Vector2(0f, -40f), new Vector2(708f, 55f), 14f);
				KitToggle toggle = KitToggle.Create(rect, "Value", HexSpawnProtection.IsEnabled, (Action<bool>)delegate(bool value)
				{
					Result(HexSpawnProtection.SetEnabled(value));
				}, new Vector2(380f, 0f), new Vector2(140f, 32f), Ui("on"), Ui("off"));
				toggle.Tooltip(text, HexText.Text("spawn_protection_legend"));
				cleanup[rect].Add((Action)toggle.Dispose);
				updates[rect] = delegate
				{
					//IL_0067: Unknown result type (might be due to invalid IL or missing references)
					toggle.SetValue(HexSpawnProtection.IsEnabled);
					BlockedOption val = MeadworksMischief.Query("com.meadworks.hex", "SpawnProtection", (MischiefCategory)3);
					toggle.SetUsable(Plugin.Settings.Enabled.Value && Plugin.Settings.DebugTools.Value && HexMovement.Owned((Character)(object)Player.m_localPlayer) && val.Allowed, val.Allowed ? "" : MeadworksBlockedOptions.Reason(val.Reason));
				};
				updates[rect]();
				Focus(rect, "spawn_protection");
			}, (Action<RectTransform>)Unbind));
		}

		private static void CatalogHeader()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_0366: Unknown result type (might be due to invalid IL or missing references)
			//IL_0375: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_040d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0449: Unknown result type (might be due to invalid IL or missing references)
			//IL_0458: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				catalog = (spawnCreatures ? HexSpawnCatalog.Creatures() : HexSpawnCatalog.Items());
			}
			catch
			{
				catalog = Array.Empty<HexSpawnCatalog.Entry>();
				Result(HexText.Text("spawn_unsupported"));
			}
			category = "";
			catalogField = KitTextField.Create(window.Panel, "CatalogSearch", (KitFieldMode)0, new Vector2(200f, -60f), new Vector2(360f, 32f), Ui("search"), (string)null);
			if (catalogField != null)
			{
				Help(((Component)catalogField.Input).gameObject, Ui("search"), HexText.Text("help_catalog_search"));
				catalogField.Text = search;
				catalogField.Changed += SearchChanged;
				catalogControls.Add((Selectable)(object)catalogField.Input);
				window.Focusable((Selectable)(object)catalogField.Input, 1, 1);
			}
			Button val = KitButton.Create(window.Panel, "CatalogCategory", Ui("category"), (Action)delegate
			{
				string[] values = catalog.SelectMany(Categories).Distinct<string>(StringComparer.Ordinal).OrderBy<string, string>(CategoryName, StringComparer.CurrentCulture)
					.Prepend("")
					.ToArray();
				string[] names = values.Select((string value) => (value.Length != 0) ? (CategoryName(value) + " (" + value + ")") : Ui("all")).ToArray();
				KitAlmanacChoice.Open(window, Ui("category"), (IReadOnlyList<string>)names, (IReadOnlyCollection<string>)(object)Array.Empty<string>(), false, (Action<IReadOnlyList<string>>)delegate(IReadOnlyList<string> selected)
				{
					int num = ((selected.Count == 1) ? Array.IndexOf(names, selected[0]) : (-1));
					if (num >= 0)
					{
						category = values[num];
						catalogDirty = true;
					}
				});
			}, new Vector2(580f, -60f), new Vector2(200f, 32f));
			Button val2 = KitButton.Create(window.Panel, "CatalogReload", Ui("reload"), (Action)delegate
			{
				dirty = true;
			}, new Vector2(800f, -60f), new Vector2(150f, 32f));
			Help(((Component)val).gameObject, Ui("category"), HexText.Text("help_catalog_category"));
			Help(((Component)val2).gameObject, Ui("reload"), HexText.Text("help_catalog_reload"));
			catalogControls.Add((Selectable)(object)val);
			catalogControls.Add((Selectable)(object)val2);
			catalogObjects.Add(((Component)val).gameObject);
			catalogObjects.Add(((Component)val2).gameObject);
			window.Focusable((Selectable)(object)val, 2, 1);
			window.Focusable((Selectable)(object)val2, 3, 1);
			catalogEnable = KitToggle.Create(window.Panel, "CatalogEnabled", Plugin.Settings.Spawning.Value, (Action<bool>)delegate(bool value)
			{
				Plugin.Settings.SetPreference("spawning", value);
			}, new Vector2(200f, -104f), new Vector2(180f, 30f), Ui("on"), Ui("off"));
			catalogEnable.Tooltip(Label("spawning"), HexText.Text("spawning"));
			catalogControls.Add((Selectable)(object)catalogEnable.Button);
			window.Focusable((Selectable)(object)catalogEnable.Button, 1, 2);
			catalogKind = KitToggle.Create(window.Panel, "CatalogKind", spawnCreatures, (Action<bool>)delegate(bool value)
			{
				spawnCreatures = value;
				dirty = true;
			}, new Vector2(390f, -104f), new Vector2(180f, 30f), Ui("creatures"), Ui("items"));
			catalogKind.Tooltip(Ui("spawn"), HexText.Text("help_spawn_kind"));
			catalogControls.Add((Selectable)(object)catalogKind.Button);
			window.Focusable((Selectable)(object)catalogKind.Button, 2, 2);
			catalogCount = KitAlmanacDialog.Label((Transform)(object)window.Panel, "CatalogCount", "", new Vector2(580f, -104f), new Vector2(370f, 34f), 14f);
			catalogObjects.Add(((Component)catalogCount).gameObject);
			KitAlmanacDialog.Place(list.Root, new Vector2(200f, -148f), new Vector2(750f, 462f));
			DrawCatalog();
		}

		private static void SearchChanged(string value)
		{
			search = value;
			catalogDirty = true;
		}

		private static IEnumerable<string> Categories(HexSpawnCatalog.Entry entry)
		{
			return from value in entry.Category.Split(',')
				select value.Trim() into value
				where value.Length > 0
				select value;
		}

		private static string CategoryName(string value)
		{
			if (value == "Unclassified")
			{
				return Ui("unclassified");
			}
			string text = "$" + (spawnCreatures ? "biome_" : "itemtype_") + value.ToLowerInvariant();
			Localization instance = Localization.instance;
			string text2 = ((instance != null) ? instance.Localize(text) : null) ?? text;
			if (!(text2 == text) && !(text2 == "[" + text.TrimStart('$') + "]"))
			{
				return text2;
			}
			return value;
		}

		private static void TickCatalog()
		{
			if (CatalogTab)
			{
				if (catalogDirty)
				{
					DrawCatalog();
				}
				KitToggle? obj = catalogEnable;
				if (obj != null)
				{
					obj.SetValue(Plugin.Settings.Spawning.Value);
				}
				KitToggle? obj2 = catalogEnable;
				if (obj2 != null)
				{
					obj2.SetLabels(Ui("on"), Ui("off"));
				}
				KitToggle? obj3 = catalogKind;
				if (obj3 != null)
				{
					obj3.SetValue(spawnCreatures);
				}
				KitToggle? obj4 = catalogKind;
				if (obj4 != null)
				{
					obj4.SetLabels(Ui("creatures"), Ui("items"));
				}
				KitToggle? obj5 = catalogEnable;
				if (obj5 != null)
				{
					obj5.SetUsable(Plugin.Settings.Enabled.Value && HexMovement.Owned((Character)(object)Player.m_localPlayer) && MeadworksMischief.Decide("com.meadworks.hex", (MischiefCategory)1).Allowed, "");
				}
			}
		}

		private static void DrawCatalog()
		{
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Expected O, but got Unknown
			catalogDirty = false;
			if (HexWindow.list == null || !CatalogTab)
			{
				return;
			}
			HexSpawnCatalog.Entry[] array = catalog.Where((HexSpawnCatalog.Entry entry) => (Object)(object)entry.Prefab != (Object)null && entry.Matches(search) && (category.Length == 0 || Categories(entry).Contains<string>(category, StringComparer.Ordinal))).ToArray();
			if ((Object)(object)catalogCount != (Object)null)
			{
				catalogCount.text = HexText.Format("ui_catalog_count", array.Length, (category.Length == 0) ? Ui("all") : CategoryName(category));
			}
			List<KitVirtualRow> list = new List<KitVirtualRow>();
			for (int num = 0; num < array.Length; num += 4)
			{
				HexSpawnCatalog.Entry[] entries = array.Skip(num).Take(4).ToArray();
				string key = "catalog:" + entries[0].Identity;
				list.Add(new KitVirtualRow(key, 108f, (Action<RectTransform>)delegate(RectTransform rect)
				{
					BindCatalog(rect, key, entries);
				}, (Action<RectTransform>)Unbind));
			}
			keys.Clear();
			keys.AddRange(list.Select((KitVirtualRow row) => row.Key));
			HexWindow.list.SetRows((IReadOnlyList<KitVirtualRow>)list, ++revision);
		}

		private static void BindCatalog(RectTransform rect, string key, HexSpawnCatalog.Entry[] entries)
		{
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			cleanup[rect] = new List<Action>();
			List<Button> buttons = new List<Button>();
			List<Image> locks = new List<Image>();
			List<HexCatalogLiteralTooltip> tips = new List<HexCatalogLiteralTooltip>();
			catalogTiles[rect] = buttons;
			for (int i = 0; i < entries.Length; i++)
			{
				HexSpawnCatalog.Entry entry = entries[i];
				Button val = KitButton.Create(rect, "Tile" + i, "", (Action)delegate
				{
					SpawnEditor(entry);
				}, new Vector2((float)(i * 177), 0f), new Vector2(169f, 98f));
				buttons.Add(val);
				locks.Add(LockBadge(((Component)val).transform, new Vector2(143f, -7f)));
				GameObject val2 = new GameObject("NativeIcon", new Type[2]
				{
					typeof(RectTransform),
					typeof(Image)
				})
				{
					layer = ((Component)rect).gameObject.layer
				};
				val2.transform.SetParent(((Component)val).transform, false);
				Image component = val2.GetComponent<Image>();
				((Graphic)component).raycastTarget = false;
				component.preserveAspect = true;
				component.sprite = (Sprite)(((Object)(object)entry.Icon != (Object)null) ? ((object)entry.Icon) : ((object)KitGlyphSprites.Of((KitGlyph)10)));
				KitAlmanacDialog.Place(((Graphic)component).rectTransform, new Vector2(60f, -5f), new Vector2(48f, 48f));
				TMP_Text obj = KitAlmanacDialog.Label(((Component)val).transform, "NativeName", entry.Name, new Vector2(5f, -57f), new Vector2(159f, 36f), 13f);
				obj.alignment = (TextAlignmentOptions)258;
				obj.overflowMode = (TextOverflowModes)3;
				HexCatalogLiteralTooltip hexCatalogLiteralTooltip = ((Component)val).gameObject.AddComponent<HexCatalogLiteralTooltip>();
				hexCatalogLiteralTooltip.Topic = entry.Name;
				hexCatalogLiteralTooltip.Detail = entry.Identity + "\n" + string.Join(", ", Categories(entry).Select(CategoryName)) + "\n\n" + HexText.Text("help_spawn_editor");
				tips.Add(hexCatalogLiteralTooltip);
			}
			updates[rect] = delegate
			{
				//IL_009d: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
				foreach (Image item in locks)
				{
					((Component)item).gameObject.SetActive(!MeadworksMischief.Decide("com.meadworks.hex", (MischiefCategory)1).Allowed);
				}
				for (int j = 0; j < buttons.Count; j++)
				{
					KitControlDecision val3 = KitButton.Block(buttons[j], MeadworksMischief.Query("com.meadworks.hex", "Spawn.Create", (MischiefCategory)1), Plugin.Settings.Enabled.Value && Plugin.Settings.Spawning.Value && HexMovement.Owned((Character)(object)Player.m_localPlayer));
					tips[j].Literal = ((KitControlDecision)(ref val3)).Interactable;
					Help(((Component)buttons[j]).gameObject, tips[j].Topic, tips[j].Detail, ((KitControlDecision)(ref val3)).Tooltip);
				}
			};
			cleanup[rect].Add(delegate
			{
				catalogTiles.Remove(rect);
			});
			updates[rect]();
			int num = keys.IndexOf(key);
			for (int num2 = 0; num2 < buttons.Count; num2++)
			{
				window.Focusable((Selectable)(object)buttons[num2], num2 + 1, num + 3);
			}
		}

		private static void SpawnEditor(HexSpawnCatalog.Entry entry)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Invalid comparison between Unknown and I4
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: 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_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Invalid comparison between Unknown and I4
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: 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_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Invalid comparison between Unknown and I4
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Invalid comparison between Unknown and I4
			//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Invalid comparison between Unknown and I4
			//IL_0315: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: Unknown result type (might be due to invalid IL or missing references)
			//IL_0369: Unknown result type (might be due to invalid IL or missing references)
			//IL_0378: Unknown result type (might be due to invalid IL or missing references)
			if (!HexSpawn.Allowed || (Object)(object)entry.Prefab == (Object)null)
			{
				Result(HexText.Text("spawn_denied"));
				return;
			}
			KitAlmanacDialog dialog = KitAlmanacDialog.Create(window, entry.Name, new Vector2(540f, 425f));
			if (dialog == null)
			{
				return;
			}
			int amount = 1;
			int level = 1;
			bool inventory = (int)entry.Kind == 1;
			bool tame = false;
			KitAlmanacDialog.Label((Transform)(object)dialog.Panel, "Identity", entry.Identity, new Vector2(20f, -50f), new Vector2(500f, 26f), 13f);
			KitAlmanacDialog.Label((Transform)(object)dialog.Panel, "AmountLabel", Ui("amount"), new Vector2(20f, -92f), new Vector2(185f, 30f), 16f);
			KitAlmanacDialog.Label((Transform)(object)dialog.Panel, "LevelLabel", Ui(((int)entry.Kind == 1) ? "quality" : "level"), new Vector2(20f, -180f), new Vector2(185f, 30f), 16f);
			KitAlmanacNumber count = Number("Amount", new Vector2(220f, -88f), 9999, () => amount, delegate(int value)
			{
				amount = value;
			});
			KitAlmanacNumber quality = Number("Level", new Vector2(220f, -176f), entry.MaxQuality, () => level, delegate(int value)
			{
				level = value;
			});
			KitToggle option = KitToggle.Create(dialog.Panel, "Option", inventory, (Action<bool>)delegate(bool value)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Invalid comparison between Unknown and I4
				if ((int)entry.Kind == 1)
				{
					inventory = value;
				}
				else
				{
					tame = value;
				}
			}, new Vector2(20f, -270f), new Vector2(500f, 32f), Ui(((int)entry.Kind == 1) ? "inventory" : "tame"), Ui(((int)entry.Kind == 1) ? "drop" : "wild"));
			option.Tooltip(entry.Name, HexText.Text("help_spawn_option"));
			dialog.Own((Action)option.Dispose);
			option.SetUsable((int)entry.Kind == 1 || entry.Tameable, "");
			Button create = KitButton.Create(dialog.Panel, "Spawn", Ui("spawn"), (Action)Submit, new Vector2(280f, -350f), new Vector2(240f, 34f));
			Button val = KitButton.Create(dialog.Panel, "Cancel", Ui("close"), (Action)dialog.Dispose, new Vector2(20f, -350f), new Vector2(240f, 34f));
			Help(((Component)create).gameObject, Ui("spawn"), HexText.Text("help_spawn_submit") + "\n\n" + HexText.Text("spawning"));
			Help(((Component)val).gameObject, Ui("close"), HexText.Text("help_close"));
			dialog.Tick += delegate
			{
				//IL_007a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0080: Invalid comparison between Unknown and I4
				if (!HexSpawn.Allowed || (Object)(object)entry.Prefab == (Object)null)
				{
					dialog.Dispose();
				}
				else
				{
					count.Set(amount.ToString(CultureInfo.InvariantCulture), (double?)null);
					quality.Set(level.ToString(CultureInfo.InvariantCulture), (double?)null);
					option.SetUsable((int)entry.Kind == 1 || entry.Tameable, "");
					((Selectable)create).interactable = count.Field.Valid && quality.Field.Valid;
				}
			};
			dialog.Window.Focusable((Selectable)(object)count.Field.Input, 1, 0);
			dialog.Window.Focusable((Selectable)(object)count.Less, 0, 0);
			dialog.Window.Focusable((Selectable)(object)count.More, 2, 0);
			if ((Object)(object)count.Slider != (Object)null)
			{
				dialog.Window.Focusable((Selectable)(object)count.Slider, 1, 1);
			}
			dialog.Window.Focusable((Selectable)(object)quality.Field.Input, 1, 2);
			dialog.Window.Focusable((Selectable)(object)quality.Less, 0, 2);
			dialog.Window.Focusable((Selectable)(object)quality.More, 2, 2);
			if ((Object)(object)quality.Slider != (Object)null)
			{
				dialog.Window.Focusable((Selectable)(object)quality.Slider, 1, 3);
			}
			dialog.Window.Focusable((Selectable)(object)option.Button, 1, 4);
			dialog.Window.Focusable((Selectable)(object)val, 0, 5);
			dialog.Window.Focusable((Selectable)(object)create, 2, 5);
			KitAlmanacNumber Number(string name, Vector2 position, int maximum, Func<int> read, Action<int> write)
			{
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d1: Invalid comparison between Unknown and I4
				int result;
				KitAlmanacNumber val2 = KitAlmanacNumber.Create(dialog.Panel, name, position, new Vector2(300f, 75f), read().ToString(CultureInfo.InvariantCulture), (Func<string, bool>)((string text) => int.TryParse(text, NumberStyles.None, CultureInfo.InvariantCulture, out result) && result >= 1 && result <= maximum), (Action<string>)delegate(string text)
				{
					if (int.TryParse(text, NumberStyles.None, CultureInfo.InvariantCulture, out result) && result >= 1 && result <= maximum)
					{
						write(result);
					}
				}, (Func<int, string>)((int direction) => Math.Max(1L, Math.Min(maximum, (long)read() + (long)direction)).ToString(CultureInfo.InvariantCulture)), (double?)1.0, (double?)maximum, 1.0, false, (Func<double, string>)((double number) => Math.Round(number).ToString(CultureInfo.InvariantCulture)));
				NumberHelp(val2, Ui((name == "Amount") ? "amount" : (((int)entry.Kind == 1) ? "quality" : "level")), HexText.Text((name == "Amount") ? "help_spawn_amount" : "help_spawn_level"));
				dialog.Own((Action)val2.Dispose);
				return val2;
			}
			void Submit()
			{
				//IL_009d: 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_00cf: Expected O, but got Unknown
				if (!HexSpawn.Allowed)
				{
					Result(HexText.Text("spawn_denied"));
				}
				else if (int.TryParse(count.Field.Text, NumberStyles.None, CultureInfo.InvariantCulture, out amount) && amount >= 1 && amount <= 9999 && int.TryParse(quality.Field.Text, NumberStyles.None, CultureInfo.InvariantCulture, out level) && level >= 1 && level <= entry.MaxQuality)
				{
					HexSpawnRequest request = new HexSpawnRequest(entry.Kind, entry.Identity, amount, level, tame, inventory);
					dialog.Dispose();
					if (amount > Plugin.Settings.ConfirmSpawnAbove.Value)
					{
						KitAlmanacTextEditor.Confirm(window, Ui("spawn"), HexText.Format("spawn_confirm", amount), (Action)delegate
						{
							Result(HexSpawn.Request(request, confirmed: true));
						});
					}
					else
					{
						Result(HexSpawn.Request(request));
					}
				}
			}
		}

		private static Image LockBadge(Transform parent, Vector2 position)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("AuthorityLock", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			})
			{
				layer = ((Component)parent).gameObject.layer
			};
			val.transform.SetParent(parent, false);
			Image component = val.GetComponent<Image>();
			component.sprite = KitGlyphSprites.Of((KitGlyph)20);
			((Graphic)component).raycastTarget = false;
			((Graphic)component).color = KitAppearance.Color((KitColorRole)8);
			KitAlmanacDialog.Place(((Graphic)component).rectTransform, position, new Vector2(18f, 18f));
			return component;
		}

		private static void PreserveCatalogColumn(GameObject selected, string next)
		{
			int val = 0;
			foreach (List<Button> value in catalogTiles.Values)
			{
				int num = value.FindIndex((Button button) => (Object)(object)button != (Object)null && (Object)(object)((Component)button).gameObject == (Object)(object)selected);
				if (num >= 0)
				{
					val = num;
					break;
				}
			}
			list.Focus(next);
			EventSystem current = EventSystem.current;
			GameObject first = ((current != null) ? current.currentSelectedGameObject : null);
			foreach (List<Button> value2 in catalogTiles.Values)
			{
				if (!value2.Any((Button button) => (Object)(object)button != (Object)null && (Object)(object)((Component)button).gameObject == (Object)(object)first))
				{
					continue;
				}
				Button val2 = value2[Math.Min(val, value2.Count - 1)];
				if ((Object)(object)val2 != (Object)null && ((Selectable)val2).IsInteractable())
				{
					EventSystem current3 = EventSystem.current;
					if (current3 != null)
					{
						current3.SetSelectedGameObject(((Component)val2).gameObject);
					}
				}
				break;
			}
		}

		private static void ClearCatalog()
		{
			HexCatalogLiteralTooltip.Restore();
			foreach (Selectable catalogControl in catalogControls)
			{
				KitWindow? obj = window;
				if (obj != null)
				{
					obj.Unfocusable(catalogControl);
				}
			}
			catalogControls.Clear();
			if (catalogField != null)
			{
				catalogField.Changed -= SearchChanged;
				catalogField.Destroy();
				catalogField = null;
			}
			if (catalogEnable != null)
			{
				if ((Object)(object)catalogEnable.Button != (Object)null)
				{
					KitUnity.Retire(((Component)catalogEnable.Button).gameObject);
				}
				catalogEnable.Dispose();
				catalogEnable = null;
			}
			if (catalogKind != null)
			{
				if ((Object)(object)catalogKind.Button != (Object)null)
				{
					KitUnity.Retire(((Component)catalogKind.Button).gameObject);
				}
				catalogKind.Dispose();
				catalogKind = null;
			}
			foreach (GameObject catalogObject in catalogObjects)
			{
				if ((Object)(object)catalogObject != (Object)null)
				{
					KitUnity.Retire(catalogObject);
				}
			}
			catalogObjects.Clear();
			catalogCount = null;
			catalog = Array.Empty<HexSpawnCatalog.Entry>();
			catalogTiles.Clear();
			catalogDirty = false;
		}

		private static float CaptionWidth(Button button)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			TMP_Text val = (((Object)(object)button != (Object)null) ? ((Component)button).GetComponentInChildren<TMP_Text>(true) : null);
			if (!((Object)(object)val == (Object)null))
			{
				return val.GetPreferredValues(val.text).x;
			}
			return 0f;
		}

		private static void Roomy(Button button)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			TMP_Text componentInChildren = ((Component)button).GetComponentInChildren<TMP_Text>(true);
			if (!((Object)(object)componentInChildren == (Object)null))
			{
				RectTransform rectTransform = componentInChildren.rectTransform;
				rectTransform.anchorMin = Vector2.zero;
				rectTransform.anchorMax = Vector2.one;
				rectTransform.offsetMin = Vector2.zero;
				rectTransform.offsetMax = Vector2.zero;
			}
		}

		private static string Ui(string key)
		{
			return HexText.Text("ui_" + key);
		}

		private static string Label(string key)
		{
			return HexText.Text("label_" + key);
		}

		internal static void Tick()
		{
			if (!Plugin.Ready || !Plugin.Active || !MeadworksHeadless.AllowsUi || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				Shutdown();
				return;
			}
			if (window != null && ((Object)(object)actor != (Object)(object)Player.m_localPlayer || session != Plugin.Session.Generation))
			{
				Shutdown();
			}
			ConfigEntry<KeyboardShortcut> menuKey = Plugin.Settings.MenuKey;
			KitWindow? obj = window;
			if (MeadworksInput.Pressed(menuKey, (InputContext)((obj != null && obj.IsOpen) ? 1 : 0)))
			{
				KitWindow? obj2 = window;
				if (obj2 != null && obj2.IsOpen)
				{
					window.Close();
				}
				else
				{
					Open();
				}
			}
			KitWindow? obj3 = window;
			if (obj3 == null || !obj3.IsOpen)
			{
				return;
			}
			KitToggle? obj4 = master;
			if (obj4 != null)
			{
				obj4.SetValue(Plugin.Settings.Enabled.Value);
			}
			if (language != MeadworksBlockedOptions.Language)
			{
				language = MeadworksBlockedOptions.Language;
				dirty = true;
			}
			if (tab == "skills" && Time.unscaledTime >= nextSkills)
			{
				nextSkills = Time.unscaledTime + 1f;
				string text = MeadworksSkills.Registry.Revision + ":" + string.Join(",", from def in ((Character)Player.m_localPlayer).GetSkills().m_skills
					where def != null
					select (int)def.m_skill);
				if (text != skillShape)
				{
					skillShape = text;
					dirty = true;
				}
			}
			PadTabs();
			if (dirty)
			{
				Draw();
			}
			TickCatalog();
			KitVirtualList? obj5 = list;
			if (obj5 != null)
			{
				obj5.Tick();
			}
			Action[] array = updates.Values.ToArray();
			for (int num = 0; num < array.Length; num++)
			{
				array[num]();
			}
		}

		internal static void Open()
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Ready || !Plugin.Active || !MeadworksHeadless.AllowsUi || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)KitCanvas.Font == (Object)null)
			{
				return;
			}
			KitWindow? obj = window;
			if ((Object)(object)((obj != null) ? obj.Panel : null) == (Object)null)
			{
				Shutdown();
				actor = Player.m_localPlayer;
				session = Plugin.Session.Generation;
				window = KitWindow.Create("Hex", new Vector2(980f, 680f), (Transform)null, false, false);
				if (window == null)
				{
					return;
				}
				TMP_Text val = KitAlmanacDialog.Label((Transform)(object)window.Panel, "Title", "Hex", new Vector2(20f, -12f), new Vector2(220f, 32f), 24f);
				if ((Object)(object)KitCanvas.Heading != (Object)null)
				{
					val.font = KitCanvas.Heading;
				}
				master = KitToggle.Create(window.Panel, "Master", Plugin.Settings.Enabled.Value, (Action<bool>)delegate(bool value)
				{
					MeadworksConfig.Amend((ConfigEntryBase)(object)Plugin.Settings.Enabled, (object)value, (string)null);
				}, new Vector2(270f, -12f), new Vector2(160f, 32f), Ui("on"), Ui("off"));
				master.Tooltip("Hex", HexText.Text("enabled"));
				window.Focusable((Selectable)(object)master.Button, 1, 0);
				panic = KitButton.Create(window.Panel, "Panic", Ui("panic"), (Action)delegate
				{
					Plugin.Settings.PanicReset();
				}, new Vector2(620f, -12f), new Vector2(150f, 32f));
				close = KitButton.Create(window.Panel, "Close", Ui("close"), (Action)delegate
				{
					KitWindow? obj3 = window;
					if (obj3 != null)
					{
						obj3.Close();
					}
				}, new Vector2(800f, -12f), new Vector2(150f, 32f));
				Help(((Component)panic).gameObject, Ui("panic"), HexText.Text("panic"));
				Help(((Component)close).gameObject, Ui("close"), HexText.Text("help_close"));
				window.Focusable((Selectable)(object)panic, 2, 0);
				window.Focusable((Selectable)(object)close, 3, 0);
				hint = KitAlmanacDialog.Label((Transform)(object)window.Panel, "Hint", "", new Vector2(200f, -620f), new Vector2(750f, 45f), 14f);
				window.Opened += delegate
				{
					dirty = true;
				};
				window.Closed += CloseEditor;
			}
			window.Open();
			dirty = true;
			KitToggle? obj2 = master;
			if ((Object)(object)((obj2 != null) ? obj2.Button : null) != (Object)null && (Object)(object)EventSystem.current != (Object)null)
			{
				EventSystem.current.SetSelectedGameObject(((Component)master.Button).gameObject);
			}
		}

		private static void CloseEditor()
		{
			if (window != null)
			{
				KitAlmanacDialog active = KitAlmanacDialog.Active;
				if (((active != null) ? active.Parent : null) == window)
				{
					KitAlmanacDialog.Active.Dispose();
				}
			}
		}

		private static void Result(string value)
		{
			if ((Object)(object)hint != (Object)null)
			{
				hint.text = value;
			}
		}

		private static void Select(string value)
		{
			CloseEditor();
			tab = value;
			dirty = (focusTabAfterDraw = true);
			Result("");
		}

		private static void Draw()
		{
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Expected O, but got Unknown
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Expected O, but got Unknown
			//IL_0581: Unknown result type (might be due to invalid IL or missing references)
			//IL_058b: Expected O, but got Unknown
			//IL_067a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0681: Expected I4, but got Unknown
			//IL_06ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_06c4: Expected O, but got Unknown
			if (window == null || Plugin.Settings == null)
			{
				return;
			}
			dirty = false;
			ClearRows();
			foreach (Button tab in tabs)
			{
				window.Unfocusable((Selectable)(object)tab);
				((Component)tab).gameObject.SetActive(false);
				((Object)tab).name = "retired";
				Object.Destroy((Object)(object)((Component)tab).gameObject);
			}
			tabs.Clear();
			List<Button> list = KitTabs.Place(window.Panel, (IList<KitTab>)((IEnumerable<string>)HexMenu.Tabs).Select((Func<string, KitTab>)((string id) => new KitTab
			{
				Id = id,
				Caption = Ui(id),
				Click = delegate
				{
					Select(id);
				}
			})).ToArray(), HexWindow.tab, 20f, 60f, 160f);
			for (int num = 0; num < list.Count; num++)
			{
				Button val = list[num];
				KitAlmanacDialog.Place((RectTransform)((Component)val).transform, new Vector2(20f, (float)(-60 - num * 48)), new Vector2(160f, 40f));
				Help(((Component)val).gameObject, Ui(VisibleTabs()[num]), HexText.Format("help_tab", Ui(VisibleTabs()[num])));
				tabs.Add(val);
				window.Focusable((Selectable)(object)val, 0, num + 1);
			}
			HexWindow.list = KitVirtualList.Create((Transform)(object)window.Panel, "HexRows", new Vector2(750f, 550f), (Func<RectTransform, RectTransform>)delegate(RectTransform parent)
			{
				//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)
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Expected O, but got Unknown
				GameObject val2 = new GameObject("HexRow", new Type[1] { typeof(RectTransform) });
				val2.transform.SetParent((Transform)(object)parent, false);
				return (RectTransform)val2.transform;
			});
			if (HexWindow.list == null)
			{
				return;
			}
			KitAlmanacDialog.Place(HexWindow.list.Root, new Vector2(200f, -60f), new Vector2(750f, 550f));
			List<KitVirtualRow> list2 = new List<KitVirtualRow>();
			string[] array = HexMenu.Preferences[HexWindow.tab];
			foreach (string text in array)
			{
				string name = text;
				ConfigEntryBase entry = Plugin.Settings.PreferenceEntries()[name];
				list2.Add(new KitVirtualRow(name, (float)((name == "debug_mode") ? 144 : ((name == "local_time_minute") ? 170 : ((entry.SettingType == typeof(int)) ? 130 : 96))), (Action<RectTransform>)delegate(RectTransform rect)
				{
					BindPreference(rect, name, entry);
				}, (Action<RectTransform>)Unbind));
			}
			if (HexWindow.tab == "cheats")
			{
				ActionRow(list2, "heal", HexText.Text("actions_heal"), () => HexActions.Execute(new string[1] { "heal" }));
				ActionRow(list2, "rested", HexText.Text("actions_rested"), () => HexActions.Execute(new string[1] { "rested" }));
				ActionRow(list2, "power", HexText.Text("actions_power"), delegate
				{
					KitAlmanacChoice.Open(window, HexText.Text("actions_power"), (IReadOnlyList<string>)new string[8] { "GP_Eikthyr", "GP_TheElder", "GP_Bonemass", "GP_Moder", "GP_Yagluth", "GP_Queen", "GP_Ashlands", "GP_DeepNorth" }, (IReadOnlyCollection<string>)(object)Array.Empty<string>(), false, (Action<IReadOnlyList<string>>)delegate(IReadOnlyList<string> values)
					{
						if (values.Count == 1)
						{
							Result(HexActions.Execute(new string[2]
							{
								"power",
								values[0]
							}));
						}
					});
					return "";
				});
			}
			if (HexWindow.tab == "movement")
			{
				ActionRow(list2, "reset_speeds", HexText.Text("speeds_reset_all"), () => Plugin.Settings.ResetSpeeds());
			}
			if (HexWindow.tab == "map")
			{
				ActionRow(list2, "poi", HexText.Text("poi_actual"), HexPoi.Request);
				ActionRow(list2, "estimatepoi", HexText.Text("poi_estimate"), HexPoi.RequestEstimate);
				ActionRow(list2, "clearpoi", HexText.Text("poi_clear"), HexPoi.Clear);
				ActionRow(list2, "reveal", HexText.Text("map_reveal"), () => HexMap.Execute(new string[2] { "map", "reveal" }));
				ActionRow(list2, "reset", HexText.Text("map_reset"), ConfirmMapReset);
				ActionRow(list2, "seed", HexText.Text("seed_label"), HexInformation.Seed);
			}
			if (HexWindow.tab == "debug")
			{
				SpawnProtectionRow(list2);
				list2.Add(new KitVirtualRow("debug:radius", 90f, (Action<RectTransform>)BindRadius, (Action<RectTransform>)Unbind));
				array = new string[6] { "fly", "build", "kill", "drops", "tame", "event" };
				foreach (string text2 in array)
				{
					string name2 = text2;
					ActionRow(list2, "debug_" + name2, HexText.Text("debug_" + name2), () => DebugAction(name2));
				}
			}
			if (HexWindow.tab == "skills")
			{
				if (HexSkills.Catalog(out IReadOnlyList<HexSkills.Row> rows, out string message))
				{
					foreach (HexSkills.Row item in rows)
					{
						HexSkills.Row row = item;
						list2.Add(new KitVirtualRow("skill:" + (int)row.Type, 100f, (Action<RectTransform>)delegate(RectTransform rect)
						{
							BindSkill(rect, row);
						}, (Action<RectTransform>)Unbind));
					}
				}
				else
				{
					Result(message);
				}
			}
			if (HexWindow.tab == "presets")
			{
				PresetRows(list2);
			}
			keys.Clear();
			keys.AddRange(list2.Select((KitVirtualRow val2) => val2.Key));
			HexWindow.list.SetRows((IReadOnlyList<KitVirtualRow>)list2, ++revision);
			if (CatalogTab)
			{
				CatalogHeader();
			}
			KitToggle? obj = master;
			if (obj != null)
			{
				obj.SetLabels(Ui("on"), Ui("off"));
			}
			KitToggle? obj2 = master;
			if (obj2 != null)
			{
				obj2.Tooltip("Hex", HexText.Text("enabled"));
			}
			if ((Object)(object)close != (Object)null)
			{
				Help(((Component)close).gameObject, Ui("close"), HexText.Text("help_close"));
			}
			if ((Object)(object)panic != (Object)null)
			{
				Help(((Component)panic).gameObject, Ui("panic"), HexText.Text("panic"));
			}
			if ((Object)(object)close != (Object)null)
			{
				GameButtons.Caption(((Component)close).gameObject, Ui("close"));
			}
			if ((Object)(object)panic != (Object)null)
			{
				GameButtons.Caption(((Component)panic).gameObject, Ui("panic"));
			}
			if (focusTabAfterDraw && (Object)(object)EventSystem.current != (Object)null)
			{
				focusTabAfterDraw = false;
				int num3 = Array.IndexOf(VisibleTabs(), HexWindow.tab);
				if (KitAlmanacDialog.Active == null && num3 >= 0 && num3 < tabs.Count)
				{
					EventSystem.current.SetSelectedGameObject(((Component)tabs[num3]).gameObject);
				}
			}
		}

		private static string[] VisibleTabs()
		{
			return HexMenu.Tabs.ToArray();
		}

		private static void PadTabs()
		{
			KitWindow? obj = window;
			if (obj == null || !obj.IsOpen || !MeadworksInput.Allows((InputContext)1) || MeadworksInput.Typing || KitAlmanacDialog.Active != null)
			{
				return;
			}
			EventSystem current = EventSystem.current;
			GameObject val = ((current != null) ? current.currentSelectedGameObject : null);
			if ((Object)(object)val == (Object)null || !val.activeInHierarchy || !val.transform.IsChildOf((Transform)(object)window.Panel))
			{
				return;
			}
			Transform parent = ((Transform)window.Panel).parent;
			int num = ((Transform)window.Panel).GetSiblingIndex() + 1;
			while ((Object)(object)parent != (Object)null && num < parent.childCount)
			{
				if (((Component)parent.GetChild(num)).gameObject.activeInHierarchy)
				{
					return;
				}
				num++;
			}
			string[] array = VisibleTabs();
			int num2 = Array.IndexOf(array, tab);
			if (num2 >= 0 && array.Length != 0)
			{
				if (MeadworksInput.PadDown((PadButton)4))
				{
					MeadworksInput.PadConsume((PadButton)4);
					Select(array[(num2 + array.Length - 1) % array.Length]);
				}
				else if (MeadworksInput.PadDown((PadButton)5))
				{
					MeadworksInput.PadConsume((PadButton)5);
					Select(array[(num2 + 1) % array.Length]);
				}
			}
		}

		private static void BindPreference(RectTransform rect, string key, ConfigEntryBase entry)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Expected O, but got Unknown
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0393: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0431: Unknown result type (might be due to invalid IL or missing references)
			cleanup[rect] = new List<Action>();
			TMP_Text description = KitAlmanacDialog.Label((Transform)(object)rect, "Description", HexText.Text(key), new Vector2(0f, -46f), new Vector2(700f, 44f), 12f);
			TMP_Text label = KitAlmanacDialog.Label((Transform)(object)rect, "Label", Label(key), Vector2.zero, new Vector2(350f, 36f), 16f);
			Func<bool> allowed = () => Plugin.Settings.Enabled.Value && Plugin.Settings.MayUse(key) && ((!key.StartsWith("achievements_", StringComparison.Ordinal) && !key.StartsWith("clear_", StringComparison.Ordinal)) || HexAchievements.Available);
			Button val = KitButton.Create(rect, "Reset", Ui("reset"), (Action)delegate
			{
				Plugin.Settings.SetPreference(key, Plugin.Settings.SafeValue(key));
			}, new Vector2(640f, 0f), new Vector2(68f, 32f));
			Roomy(val);
			Help(((Component)val).gameObject, Ui("reset"), HexText.Format("help_reset", Label(key)) + "\n\n" + HexText.Text(key));
			(float, float) tuple = HexMenu.ResetSpan(CaptionWidth(val));
			KitAlmanacDialog.Place((RectTransform)((Component)val).transform, new Vector2(tuple.Item1, 0f), new Vector2(tuple.Item2, 32f));
			Action action;
			AcceptableValueRange<int> range;
			if (entry.SettingType == typeof(bool))
			{
				KitToggle toggle = KitToggle.Create(rect, "Value", (bool)entry.BoxedValue, (Action<bool>)delegate(bool value)
				{
					Plugin.Settings.SetPreference(key, value);
					if (key == "skill_editor")
					{
						dirty = true;
					}
				}, new Vector2(380f, 0f), new Vector2(HexMenu.ValueWidth(200f, tuple.Item1), 32f), Ui("on"), Ui("off"));
				cleanup[rect].Add((Ac