Decompiled source of ValheimAdminForge v0.4.0

ValheimAdminForge.dll

Decompiled 2 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Splatform;
using UnityEngine;
using ValheimAdminForge.Catalog;
using ValheimAdminForge.Commands;
using ValheimAdminForge.Gui;
using ValheimAdminForge.Net;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("ValheimAdminForge")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.4.0.0")]
[assembly: AssemblyInformationalVersion("0.4.0")]
[assembly: AssemblyProduct("ValheimAdminForge")]
[assembly: AssemblyTitle("ValheimAdminForge")]
[assembly: AssemblyVersion("0.4.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ValheimAdminForge
{
	internal static class ItemSpawner
	{
		public static bool GiveToLocalPlayer(string prefabName, int amount)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return Fail(null, "can't spawn '" + prefabName + "': no local player");
			}
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return Fail(localPlayer, "can't spawn '" + prefabName + "': ObjectDB not ready");
			}
			GameObject itemPrefab = instance.GetItemPrefab(prefabName);
			if ((Object)(object)itemPrefab == (Object)null)
			{
				return Fail(localPlayer, "unknown item '" + prefabName + "'");
			}
			ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null)
			{
				return Fail(localPlayer, "'" + prefabName + "' is not an item (no ItemDrop)");
			}
			int num = Mathf.Max(1, component.m_itemData.m_shared.m_maxStackSize);
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			int num2 = Mathf.Max(1, amount);
			int num3 = 0;
			while (num2 > 0)
			{
				int num4 = Mathf.Min(num2, num);
				if (!inventory.AddItem(itemPrefab, num4))
				{
					break;
				}
				num3 += num4;
				num2 -= num4;
			}
			if (num3 == 0)
			{
				return Fail(localPlayer, "inventory full — gave 0x " + prefabName);
			}
			Plugin.Log.LogInfo((object)$"Gave {num3}x {prefabName} (requested {amount})");
			((Character)localPlayer).Message((MessageType)1, $"Spawned {num3}x {prefabName}", 0, (Sprite)null, false);
			return true;
		}

		private static bool Fail(Player player, string message)
		{
			Plugin.Log.LogWarning((object)message);
			if (player != null)
			{
				((Character)player).Message((MessageType)1, message, 0, (Sprite)null, false);
			}
			return false;
		}
	}
	[BepInPlugin("com.skitale.valheimadminforge", "ValheimAdminForge", "0.4.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.skitale.valheimadminforge";

		public const string PluginName = "ValheimAdminForge";

		public const string PluginVersion = "0.4.0";

		internal static ManualLogSource Log;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"Loading ValheimAdminForge v0.4.0...");
			PluginConfig.Init(((BaseUnityPlugin)this).Config);
			GuiStyles.Init();
			AdminWindow.Init();
			AdminRpc.Init();
			_harmony = new Harmony("com.skitale.valheimadminforge");
			PatchAllTolerant();
			Log.LogInfo((object)"ValheimAdminForge loaded!");
		}

		private void Update()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			AdminRpc.Tick();
			MapPicker.Tick();
			if (!MapPicker.IsArmed)
			{
				KeyboardShortcut value = PluginConfig.ToggleKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					AdminWindow.Toggle();
				}
			}
			if (AdminWindow.IsOpen && Input.GetKeyDown((KeyCode)27))
			{
				AdminWindow.IsOpen = false;
			}
			if (AdminWindow.IsOpen && (Object)(object)Player.m_localPlayer == (Object)null)
			{
				AdminWindow.IsOpen = false;
			}
		}

		private void OnGUI()
		{
			AdminWindow.Draw();
		}

		private void PatchAllTolerant()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			Type[] types = typeof(Plugin).Assembly.GetTypes();
			foreach (Type type in types)
			{
				if (type.GetCustomAttributes(typeof(HarmonyPatch), inherit: true).Length != 0)
				{
					try
					{
						new PatchClassProcessor(_harmony, type).Patch();
					}
					catch (Exception ex)
					{
						Log.LogWarning((object)("skipped patch " + type.Name + ": " + ex.Message));
					}
				}
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal static class PluginConfig
	{
		public static ConfigEntry<KeyboardShortcut> ToggleKey;

		public static ConfigEntry<int> MaxQuantity;

		public static ConfigEntry<bool> AllowNonAdminWindow;

		public static ConfigEntry<int> WindowWidth;

		public static ConfigEntry<int> WindowHeight;

		public static ConfigEntry<float> WindowOpacity;

		public static ConfigEntry<string> WindowTextColor;

		public static ConfigEntry<string> WindowDimTextColor;

		public static ConfigEntry<int> ServerMaxQuantity;

		public static ConfigEntry<bool> ServerStrictItemCheck;

		public static ConfigEntry<float> ServerMaxActionRadius;

		public static ConfigEntry<int> ServerMaxCreatureSpawn;

		public static ConfigEntry<bool> ServerAllowBossSpawn;

		public static ConfigEntry<float> ServerMaxDespawnRadius;

		public static ConfigEntry<bool> ServerPlayerTags;

		public static ConfigEntry<float> ServerTeleportSpread;

		public static void Init(ConfigFile cfg)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Expected O, but got Unknown
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Expected O, but got Unknown
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Expected O, but got Unknown
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Expected O, but got Unknown
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Expected O, but got Unknown
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Expected O, but got Unknown
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Expected O, but got Unknown
			ToggleKey = cfg.Bind<KeyboardShortcut>("General", "ToggleKey", new KeyboardShortcut((KeyCode)277, Array.Empty<KeyCode>()), "Opens/closes the Admin Forge window.");
			MaxQuantity = cfg.Bind<int>("General", "MaxQuantity", 100, new ConfigDescription("Upper bound for the quantity field.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 9999), Array.Empty<object>()));
			AllowNonAdminWindow = cfg.Bind<bool>("General", "AllowNonAdminWindow", false, "Let non-admins open the window anyway (every action is still refused by the server).");
			WindowWidth = cfg.Bind<int>("Window", "Width", 640, new ConfigDescription("Admin Forge window width in pixels. Below ~560 the wider tabs (Creatures, World) clip.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(560, 3000), Array.Empty<object>()));
			WindowHeight = cfg.Bind<int>("Window", "Height", 720, new ConfigDescription("Admin Forge window height in pixels. Below ~560 the tab content overflows the window.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(560, 2000), Array.Empty<object>()));
			WindowOpacity = cfg.Bind<float>("Window", "Opacity", 0.8f, new ConfigDescription("Window background opacity (1 = solid). Very low values make the (also configurable) text hard to read against whatever's behind the window.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 1f), Array.Empty<object>()));
			WindowTextColor = cfg.Bind<string>("Window", "TextColor", "#000000", "Primary text color as a hex string, e.g. #000000. Falls back to the default if unparsable.");
			WindowDimTextColor = cfg.Bind<string>("Window", "DimTextColor", "#000000", "Secondary/dim text color (prefab names, hints, detail text) as a hex string. Falls back to the default if unparsable.");
			ServerMaxQuantity = cfg.Bind<int>("Server", "MaxQuantity", 1000, new ConfigDescription("Hard cap the server enforces on a single give request, regardless of what a client asks for.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100000), Array.Empty<object>()));
			ServerStrictItemCheck = cfg.Bind<bool>("Server", "StrictItemCheck", false, "If true, reject any item OR status effect the server's own ObjectDB doesn't know. Off by default because many content mods (e.g. ValheimArmory) register content only client-side; the requesting admin's client still resolves and applies it.");
			ServerMaxActionRadius = cfg.Bind<float>("Server", "MaxActionRadius", 100f, new ConfigDescription("Hard cap (metres) the server enforces on radius actions — the kill / tame / aggravate sweeps in the Players tab.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 500f), Array.Empty<object>()));
			ServerMaxCreatureSpawn = cfg.Bind<int>("Server", "MaxCreatureSpawn", 20, new ConfigDescription("Hard cap on how many creatures one spawn request may create, regardless of what a client asks for. Guards against lag / crashes.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 200), Array.Empty<object>()));
			ServerAllowBossSpawn = cfg.Bind<bool>("Server", "AllowBossSpawn", false, "Allow spawning creatures flagged as bosses. Off by default — a stray Moder on a base ruins a server.");
			ServerMaxDespawnRadius = cfg.Bind<float>("Server", "MaxDespawnRadius", 100f, new ConfigDescription("Hard cap (metres) the server enforces on the Creatures-tab despawn / cleanup sweep.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 500f), Array.Empty<object>()));
			ServerPlayerTags = cfg.Bind<bool>("Server", "PlayerTags", true, "Enable per-player name tags. When on, the server reads / writes ValheimAdminForge.tags.json next to this file and broadcasts the tag table. Turn off to skip that entirely (no file is written).");
			ServerTeleportSpread = cfg.Bind<float>("Server", "TeleportSpread", 2f, new ConfigDescription("Radius (metres) admins land away from each other when teleporting to the same player, so they don't stack on top of them. 0 disables the offset.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
		}
	}
}
namespace ValheimAdminForge.Net
{
	internal static class AdminGuard
	{
		public static bool IsLocalPlayerAdminHint()
		{
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null || instance.IsServer())
			{
				return true;
			}
			if (instance.LocalPlayerIsAdminOrHost())
			{
				return true;
			}
			if (AdminRpc.ServerSaysAdmin)
			{
				return true;
			}
			return !AdminRpc.ServerModAnswered;
		}

		public static AdminRequestContext ServerContextFor(ZRpc rpc)
		{
			ZNet instance = ZNet.instance;
			object obj;
			if (rpc == null)
			{
				obj = null;
			}
			else
			{
				ISocket socket = rpc.GetSocket();
				obj = ((socket != null) ? socket.GetHostName() : null);
			}
			if (obj == null)
			{
				obj = string.Empty;
			}
			string text = (string)obj;
			long senderPeerId = 0L;
			if ((Object)(object)instance != (Object)null && rpc != null)
			{
				foreach (ZNetPeer peer in instance.GetPeers())
				{
					if (peer.m_rpc == rpc)
					{
						senderPeerId = peer.m_uid;
						break;
					}
				}
			}
			bool senderIsAdmin = !string.IsNullOrEmpty(text) && (Object)(object)instance != (Object)null && (instance.IsAdmin(text) || AdminListContains(instance, text));
			return new AdminRequestContext(senderPeerId, text, senderIsAdmin);
		}

		public static AdminRequestContext LocalHostContext()
		{
			return new AdminRequestContext(0L, string.Empty, senderIsAdmin: true);
		}

		private static bool AdminListContains(ZNet znet, string candidate)
		{
			List<string> adminList = znet.GetAdminList();
			if (adminList == null || string.IsNullOrEmpty(candidate))
			{
				return false;
			}
			string text = candidate.Trim();
			string text2 = StripPlatformPrefix(text);
			foreach (string item in adminList)
			{
				if (!string.IsNullOrEmpty(item))
				{
					string text3 = item.Trim();
					if (text3 == text || StripPlatformPrefix(text3) == text2)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static string StripPlatformPrefix(string s)
		{
			int num = s.IndexOf('_');
			if (num < 0 || num + 1 >= s.Length)
			{
				return s;
			}
			return s.Substring(num + 1);
		}
	}
	internal static class AdminProtocol
	{
		public const int Version = 2;

		public const string RpcRequest = "VAF_Request";

		public const string RpcExec = "VAF_Exec";

		public const string RpcResponse = "VAF_Response";

		public const string RpcHello = "VAF_Hello";

		public const string RpcAdminStatus = "VAF_AdminStatus";

		public const string RpcDropGhost = "VAF_DropGhost";

		public const string RpcTags = "VAF_Tags";

		public const float ResponseTimeout = 5f;
	}
	internal static class AdminRpc
	{
		private struct RateWindow
		{
			public float Start;

			public int Count;
		}

		private struct GhostDrop
		{
			public ZDOID Id;

			public Vector3 Pos;

			public float DueAt;
		}

		private static readonly Dictionary<string, IAdminCommand> _commands = new Dictionary<string, IAdminCommand>(StringComparer.Ordinal);

		private static float _pendingSince = -1f;

		private static bool _helloSent;

		private static bool _helloAnswered;

		private static bool _serverSaysAdmin;

		private static bool _versionWarned;

		private const int MaxRequestsPerSecond = 10;

		private static readonly Dictionary<long, RateWindow> _rate = new Dictionary<long, RateWindow>();

		private static float _lastRatePrune;

		private static readonly List<GhostDrop> _pendingGhostDrops = new List<GhostDrop>();

		private const float GhostDropDelay = 3f;

		private static readonly HashSet<string> _quietOnSuccess = new HashSet<string>(StringComparer.Ordinal) { "give_item", "apply_effect" };

		private static float _tagPoll;

		public static bool ServerSaysAdmin => _serverSaysAdmin;

		public static bool ServerModAnswered => _helloAnswered;

		public static void Init()
		{
			Register(new GiveItemCommand());
			Register(new ApplyEffectCommand());
			Register(new TeleportCommand());
			Register(new PlayerActionCommand());
			Register(new SpawnCreatureCommand());
			Register(new DespawnCommand());
			Register(new EventCommand());
			Register(new EnvCommand());
			Register(new WorldCommand());
		}

		public static void Register(IAdminCommand command)
		{
			_commands[command.Name] = command;
		}

		internal static Action<ZRpc, ZPackage> Safe(string name, Action<ZRpc, ZPackage> handler)
		{
			return delegate(ZRpc rpc, ZPackage pkg)
			{
				try
				{
					handler(rpc, pkg);
				}
				catch (Exception arg)
				{
					Plugin.Log.LogError((object)$"RPC '{name}' handler threw: {arg}");
				}
			};
		}

		public static void Send(string command, ZPackage args)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			ZRpc val = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetServerRPC() : null);
			if (val == null)
			{
				HandleLocally(command, args);
				return;
			}
			ZPackage val2 = new ZPackage();
			val2.Write(2);
			val2.Write(command);
			val2.Write(args);
			_pendingSince = Time.realtimeSinceStartup;
			val.Invoke("VAF_Request", new object[1] { val2 });
		}

		private static void HandleLocally(string command, ZPackage args)
		{
			args.SetPos(0);
			if (!TryAuthorizeAndExec(AdminGuard.LocalHostContext(), 2, command, args, out var error))
			{
				Toast("Admin Forge: " + error);
			}
		}

		public static void OnExec(ZRpc rpc, ZPackage pkg)
		{
			string text = pkg.ReadString();
			ZPackage args = pkg.ReadPackage();
			if (_commands.TryGetValue(text, out var value))
			{
				try
				{
					value.Apply(args);
				}
				catch (Exception arg)
				{
					Plugin.Log.LogError((object)$"Apply '{text}' failed: {arg}");
				}
			}
		}

		public static void OnResponse(ZRpc rpc, ZPackage pkg)
		{
			_pendingSince = -1f;
			bool num = pkg.ReadBool();
			string text = pkg.ReadString();
			string text2 = ((pkg.GetPos() < pkg.Size()) ? pkg.ReadString() : string.Empty);
			if (!num)
			{
				Toast("Admin Forge: " + text);
			}
			else if (!_quietOnSuccess.Contains(text2))
			{
				Toast("Admin Forge: " + (string.IsNullOrEmpty(text2) ? "done" : text2) + " ✓");
			}
		}

		public static void Tick()
		{
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected O, but got Unknown
			ProcessGhostDrops();
			ServerTagTick();
			DespawnCommand.Tick();
			if (_pendingSince >= 0f && Time.realtimeSinceStartup - _pendingSince > 5f)
			{
				_pendingSince = -1f;
				Toast("Admin Forge: no response from server (mod not installed there?)");
			}
			ZRpc val = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetServerRPC() : null);
			if (val == null)
			{
				_helloSent = (_helloAnswered = (_serverSaysAdmin = false));
				if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
				{
					PlayerTags.ClientClear();
				}
			}
			else if (!_helloSent)
			{
				ZPackage val2 = new ZPackage();
				val2.Write(2);
				val2.Write("0.4.0");
				val.Invoke("VAF_Hello", new object[1] { val2 });
				_helloSent = true;
			}
		}

		private static void ServerTagTick()
		{
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null || !instance.IsServer() || !PluginConfig.ServerPlayerTags.Value)
			{
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup - _tagPoll < 2f)
			{
				return;
			}
			_tagPoll = realtimeSinceStartup;
			PlayerTags.ServerEnsureTemplate();
			PlayerTags.ServerReloadIfChanged();
			string signature;
			ZPackage val = PlayerTags.BuildBroadcast(out signature);
			if (val == null || !PlayerTags.SignatureChanged(signature))
			{
				return;
			}
			foreach (ZNetPeer peer in instance.GetPeers())
			{
				if (peer.m_rpc != null)
				{
					peer.m_rpc.Invoke("VAF_Tags", new object[1] { val });
				}
			}
			if (!instance.IsDedicated())
			{
				PlayerTags.ClientReceive(val);
			}
		}

		public static void OnTags(ZRpc rpc, ZPackage pkg)
		{
			PlayerTags.ClientReceive(pkg);
		}

		public static void OnAdminStatus(ZRpc rpc, ZPackage pkg)
		{
			_helloAnswered = true;
			_serverSaysAdmin = pkg.ReadBool();
			bool flag = pkg.ReadBool();
			string text = pkg.ReadString();
			Plugin.Log.LogDebug((object)$"[client] server admin verdict: {_serverSaysAdmin}, versionOk: {flag}");
			if (!flag && !_versionWarned)
			{
				_versionWarned = true;
				Toast("Admin Forge: version mismatch — server " + text + ", you have 0.4.0. Update to match.");
			}
		}

		public static void OnHello(ZRpc rpc, ZPackage pkg)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return;
			}
			pkg.ReadInt();
			string text = ((pkg.Size() > pkg.GetPos()) ? pkg.ReadString() : "?");
			AdminRequestContext adminRequestContext = AdminGuard.ServerContextFor(rpc);
			if (!RateLimited(adminRequestContext.SenderPeerId))
			{
				bool flag = text == "0.4.0";
				ZPackage val = new ZPackage();
				val.Write(adminRequestContext.SenderIsAdmin);
				val.Write(flag);
				val.Write("0.4.0");
				rpc.Invoke("VAF_AdminStatus", new object[1] { val });
				Plugin.Log.LogDebug((object)$"[server] hello from '{adminRequestContext.SenderHostName}' -> admin={adminRequestContext.SenderIsAdmin}, client v{text}");
				if (!flag)
				{
					Plugin.Log.LogWarning((object)("[server] '" + adminRequestContext.SenderHostName + "' runs ValheimAdminForge " + text + ", server is 0.4.0"));
				}
			}
		}

		public static void OnRequest(ZRpc rpc, ZPackage pkg)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return;
			}
			int version = pkg.ReadInt();
			string text = pkg.ReadString();
			ZPackage args = pkg.ReadPackage();
			AdminRequestContext ctx = AdminGuard.ServerContextFor(rpc);
			if (!RateLimited(ctx.SenderPeerId))
			{
				bool flag;
				string error;
				if (ctx.SenderPeerId == 0L)
				{
					flag = false;
					error = "could not identify sender";
				}
				else
				{
					flag = TryAuthorizeAndExec(in ctx, version, text, args, out error);
				}
				ZPackage val = new ZPackage();
				val.Write(flag);
				val.Write(flag ? string.Empty : (error ?? "rejected"));
				val.Write(text);
				rpc.Invoke("VAF_Response", new object[1] { val });
				if (flag)
				{
					Plugin.Log.LogInfo((object)$"[server] authorised '{text}' from '{ctx.SenderHostName}' (peer {ctx.SenderPeerId})");
					return;
				}
				Plugin.Log.LogWarning((object)$"[server] DENIED '{text}' from '{ctx.SenderHostName}' (peer {ctx.SenderPeerId}): {error}");
			}
		}

		private static bool TryAuthorizeAndExec(in AdminRequestContext ctx, int version, string command, ZPackage args, out string error)
		{
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Expected O, but got Unknown
			error = null;
			if (version != 2)
			{
				error = $"protocol mismatch (server {2}, client {version})";
				return false;
			}
			if (!ctx.SenderIsAdmin)
			{
				error = "you are not a server admin";
				return false;
			}
			if (!_commands.TryGetValue(command, out var value))
			{
				error = "unknown command '" + command + "'";
				return false;
			}
			args.SetPos(0);
			if (!value.Validate(in ctx, args, out var targetPeerId, out var execArgs, out error))
			{
				return false;
			}
			ZPackage val = execArgs ?? args;
			if (value.Site == ExecutionSite.Server)
			{
				val.SetPos(0);
				try
				{
					value.Apply(val);
				}
				catch (Exception ex)
				{
					error = "apply failed: " + ex.Message;
				}
				return error == null;
			}
			if (value.Site == ExecutionSite.AllClients)
			{
				ZPackage val2 = new ZPackage();
				val2.Write(command);
				val2.Write(val);
				ZNet instance = ZNet.instance;
				if ((Object)(object)instance != (Object)null)
				{
					foreach (ZNetPeer peer in instance.GetPeers())
					{
						if (peer.m_rpc != null)
						{
							peer.m_rpc.Invoke("VAF_Exec", new object[1] { val2 });
						}
					}
				}
				val.SetPos(0);
				try
				{
					value.Apply(val);
				}
				catch (Exception ex2)
				{
					error = "apply failed: " + ex2.Message;
				}
				return error == null;
			}
			long num = ((targetPeerId == 0L) ? ctx.SenderPeerId : targetPeerId);
			if (num == 0L)
			{
				val.SetPos(0);
				try
				{
					value.Apply(val);
				}
				catch (Exception ex3)
				{
					error = "apply failed: " + ex3.Message;
				}
			}
			else
			{
				ZPackage val3 = new ZPackage();
				val3.Write(command);
				val3.Write(val);
				ExecOn(FindPeer(num), val3, ref error);
			}
			if (error == null && value.TryGetMoveDestination(val, out var dest))
			{
				BroadcastDropGhost(num, dest);
			}
			return error == null;
		}

		private static bool RateLimited(long peerId)
		{
			if (peerId == 0L)
			{
				return false;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup - _lastRatePrune > 60f)
			{
				_lastRatePrune = realtimeSinceStartup;
				List<long> list = new List<long>();
				foreach (KeyValuePair<long, RateWindow> item in _rate)
				{
					if (realtimeSinceStartup - item.Value.Start > 5f)
					{
						list.Add(item.Key);
					}
				}
				foreach (long item2 in list)
				{
					_rate.Remove(item2);
				}
			}
			if (!_rate.TryGetValue(peerId, out var value) || realtimeSinceStartup - value.Start >= 1f)
			{
				_rate[peerId] = new RateWindow
				{
					Start = realtimeSinceStartup,
					Count = 1
				};
				return false;
			}
			value.Count++;
			_rate[peerId] = value;
			return value.Count > 10;
		}

		private static void BroadcastDropGhost(long movedPeerId, Vector3 realPos)
		{
			//IL_0047: 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)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			ZDOID val = ((movedPeerId != 0L) ? (instance.GetPeer(movedPeerId)?.m_characterID ?? ZDOID.None) : (((Object)(object)Player.m_localPlayer != (Object)null) ? ((Character)Player.m_localPlayer).GetZDOID() : ZDOID.None));
			if (((ZDOID)(ref val)).IsNone())
			{
				return;
			}
			ZPackage val2 = new ZPackage();
			val2.Write(val);
			val2.Write(realPos);
			foreach (ZNetPeer peer in instance.GetPeers())
			{
				if (peer.m_uid != movedPeerId && peer.m_rpc != null)
				{
					peer.m_rpc.Invoke("VAF_DropGhost", new object[1] { val2 });
				}
			}
		}

		public static void OnDropGhost(ZRpc rpc, ZPackage pkg)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			GhostDrop item = new GhostDrop
			{
				Id = pkg.ReadZDOID(),
				Pos = pkg.ReadVector3(),
				DueAt = Time.realtimeSinceStartup + 3f
			};
			_pendingGhostDrops.Add(item);
		}

		private static void ProcessGhostDrops()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			for (int num = _pendingGhostDrops.Count - 1; num >= 0; num--)
			{
				GhostDrop ghostDrop = _pendingGhostDrops[num];
				if (!(Time.realtimeSinceStartup < ghostDrop.DueAt))
				{
					_pendingGhostDrops.RemoveAt(num);
					ZDO val = ((ZDOMan.instance != null) ? ZDOMan.instance.GetZDO(ghostDrop.Id) : null);
					if (val != null && !val.IsOwner() && Vector3.Distance(val.GetPosition(), ghostDrop.Pos) > 1f)
					{
						val.SetPosition(ghostDrop.Pos);
					}
					foreach (Player allPlayer in Player.GetAllPlayers())
					{
						if (!((Object)(object)allPlayer == (Object)null) && !((Object)(object)allPlayer == (Object)(object)Player.m_localPlayer) && !(((Character)allPlayer).GetZDOID() != ghostDrop.Id))
						{
							Plugin.Log.LogDebug((object)("[ghost] clearing stale local copy of '" + allPlayer.GetPlayerName() + "'"));
							if ((Object)(object)ZNetScene.instance != (Object)null)
							{
								ZNetScene.instance.Destroy(((Component)allPlayer).gameObject);
							}
							break;
						}
					}
				}
			}
		}

		private static void ExecOn(ZNetPeer peer, ZPackage exec, ref string error)
		{
			if (peer == null || peer.m_rpc == null)
			{
				error = "target player is not connected";
				return;
			}
			peer.m_rpc.Invoke("VAF_Exec", new object[1] { exec });
		}

		private static ZNetPeer FindPeer(long peerId)
		{
			if (!((Object)(object)ZNet.instance != (Object)null))
			{
				return null;
			}
			return ZNet.instance.GetPeer(peerId);
		}

		private static void Toast(string message)
		{
			Plugin.Log.LogInfo((object)message);
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				((Character)localPlayer).Message((MessageType)1, message, 0, (Sprite)null, false);
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
	internal static class ZNetOnNewConnectionPatch
	{
		private static void Postfix(ZNet __instance, ZNetPeer peer)
		{
			if (peer?.m_rpc != null)
			{
				if (__instance.IsServer())
				{
					peer.m_rpc.Register<ZPackage>("VAF_Request", AdminRpc.Safe("VAF_Request", AdminRpc.OnRequest));
					peer.m_rpc.Register<ZPackage>("VAF_Hello", AdminRpc.Safe("VAF_Hello", AdminRpc.OnHello));
					return;
				}
				peer.m_rpc.Register<ZPackage>("VAF_Exec", AdminRpc.Safe("VAF_Exec", AdminRpc.OnExec));
				peer.m_rpc.Register<ZPackage>("VAF_Response", AdminRpc.Safe("VAF_Response", AdminRpc.OnResponse));
				peer.m_rpc.Register<ZPackage>("VAF_AdminStatus", AdminRpc.Safe("VAF_AdminStatus", AdminRpc.OnAdminStatus));
				peer.m_rpc.Register<ZPackage>("VAF_DropGhost", AdminRpc.Safe("VAF_DropGhost", AdminRpc.OnDropGhost));
				peer.m_rpc.Register<ZPackage>("VAF_Tags", AdminRpc.Safe("VAF_Tags", AdminRpc.OnTags));
			}
		}
	}
	internal enum AnchorMode : byte
	{
		Requester,
		Target,
		Coords
	}
	internal static class CmdValidate
	{
		private const float MaxHorizontal = 20000f;

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

		public static float Sane(float f, float fallback)
		{
			if (!Finite(f))
			{
				return fallback;
			}
			return f;
		}

		public static bool InWorldBounds(Vector3 p)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			if (Finite(p.x) && Finite(p.y) && Finite(p.z) && Mathf.Abs(p.x) <= 20000f && Mathf.Abs(p.z) <= 20000f && p.y >= -1000f)
			{
				return p.y <= 10000f;
			}
			return false;
		}

		public static bool IsIdentifier(string s, int maxLen = 64)
		{
			if (string.IsNullOrEmpty(s) || s.Length > maxLen)
			{
				return false;
			}
			foreach (char c in s)
			{
				if (char.IsWhiteSpace(c) || char.IsControl(c))
				{
					return false;
				}
			}
			return true;
		}
	}
	internal readonly struct AdminRequestContext
	{
		public readonly long SenderPeerId;

		public readonly string SenderHostName;

		public readonly bool SenderIsAdmin;

		public AdminRequestContext(long senderPeerId, string senderHostName, bool senderIsAdmin)
		{
			SenderPeerId = senderPeerId;
			SenderHostName = senderHostName;
			SenderIsAdmin = senderIsAdmin;
		}
	}
	internal enum ExecutionSite
	{
		TargetClient,
		Server,
		AllClients
	}
	internal interface IAdminCommand
	{
		string Name { get; }

		ExecutionSite Site { get; }

		bool TryGetMoveDestination(ZPackage execArgs, out Vector3 dest);

		bool Validate(in AdminRequestContext ctx, ZPackage args, out long targetPeerId, out ZPackage execArgs, out string error);

		void Apply(ZPackage args);
	}
	internal static class PlayerTags
	{
		internal sealed class Tag
		{
			public readonly string Text;

			public readonly string Color;

			public Tag(string text, string color)
			{
				Text = text;
				Color = (string.IsNullOrEmpty(color) ? "#FFFFFF" : color);
			}
		}

		private static readonly Dictionary<string, Tag> _byId = new Dictionary<string, Tag>(StringComparer.Ordinal);

		private static DateTime _fileStamp = DateTime.MinValue;

		private static string _lastSignature;

		private static readonly Dictionary<ZDOID, Tag> _clientTags = new Dictionary<ZDOID, Tag>();

		public static string FilePath => Path.Combine(Paths.ConfigPath, "ValheimAdminForge.tags.json");

		public static void ServerReloadIfChanged()
		{
			try
			{
				if (!File.Exists(FilePath))
				{
					if (_byId.Count > 0)
					{
						_byId.Clear();
						_fileStamp = DateTime.MinValue;
					}
					return;
				}
				DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(FilePath);
				if (!(lastWriteTimeUtc == _fileStamp))
				{
					_fileStamp = lastWriteTimeUtc;
					_byId.Clear();
					ParseInto(File.ReadAllText(FilePath), _byId);
					Plugin.Log.LogInfo((object)$"[tags] loaded {_byId.Count} player tag(s) from {FilePath}");
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[tags] can't read " + FilePath + ": " + ex.Message));
			}
		}

		public static void ServerEnsureTemplate()
		{
			try
			{
				if (!File.Exists(FilePath))
				{
					File.WriteAllText(FilePath, "{\n  \"entries\": [\n    { \"id\": \"0000000000000000\", \"tag\": \"MODER\", \"color\": \"#FF8800\" }\n  ]\n}\n");
					Plugin.Log.LogInfo((object)("[tags] wrote a template to " + FilePath));
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[tags] can't write template: " + ex.Message));
			}
		}

		public static ZPackage BuildBroadcast(out string signature)
		{
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Expected O, but got Unknown
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			signature = null;
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			List<KeyValuePair<ZDOID, Tag>> list = new List<KeyValuePair<ZDOID, Tag>>();
			foreach (ZNetPeer peer in instance.GetPeers())
			{
				if (peer != null && !((ZDOID)(ref peer.m_characterID)).IsNone())
				{
					ISocket socket = peer.m_socket;
					string text = ((socket != null) ? socket.GetHostName() : null);
					if (!string.IsNullOrEmpty(text) && _byId.TryGetValue(StripPlatform(text.Trim()), out var value))
					{
						list.Add(new KeyValuePair<ZDOID, Tag>(peer.m_characterID, value));
					}
				}
			}
			if (!instance.IsDedicated() && (Object)(object)Player.m_localPlayer != (Object)null)
			{
				string text2 = TryLocalSteamId();
				if (!string.IsNullOrEmpty(text2) && _byId.TryGetValue(StripPlatform(text2), out var value2))
				{
					list.Add(new KeyValuePair<ZDOID, Tag>(((Character)Player.m_localPlayer).GetZDOID(), value2));
				}
			}
			StringBuilder stringBuilder = new StringBuilder();
			ZPackage val = new ZPackage();
			val.Write(list.Count);
			foreach (KeyValuePair<ZDOID, Tag> item in list)
			{
				val.Write(item.Key);
				val.Write(item.Value.Text);
				val.Write(item.Value.Color);
				stringBuilder.Append(item.Key).Append('=').Append(item.Value.Text)
					.Append(item.Value.Color)
					.Append(';');
			}
			signature = stringBuilder.ToString();
			return val;
		}

		public static bool SignatureChanged(string signature)
		{
			if (signature == _lastSignature)
			{
				return false;
			}
			_lastSignature = signature;
			return true;
		}

		public static void ClientReceive(ZPackage pkg)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			pkg.SetPos(0);
			_clientTags.Clear();
			int num = pkg.ReadInt();
			for (int i = 0; i < num; i++)
			{
				ZDOID key = pkg.ReadZDOID();
				string text = pkg.ReadString();
				string color = pkg.ReadString();
				if (!((ZDOID)(ref key)).IsNone() && !string.IsNullOrEmpty(text))
				{
					_clientTags[key] = new Tag(text, color);
				}
			}
		}

		public static Tag For(ZDOID characterId)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (((ZDOID)(ref characterId)).IsNone() || !_clientTags.TryGetValue(characterId, out var value))
			{
				return null;
			}
			return value;
		}

		public static void ClientClear()
		{
			_clientTags.Clear();
		}

		private static string TryLocalSteamId()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				IDistributionPlatform distributionPlatform = PlatformManager.DistributionPlatform;
				return (distributionPlatform != null) ? ((object)((IUser)distributionPlatform.LocalUser).PlatformUserID/*cast due to .constrained prefix*/).ToString() : null;
			}
			catch
			{
				return null;
			}
		}

		private static void ParseInto(string json, Dictionary<string, Tag> map)
		{
			foreach (Match item in Regex.Matches(json, "\\{[^{}]*\\}"))
			{
				string text = Field(item.Value, "id");
				string text2 = Field(item.Value, "tag");
				if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(text2))
				{
					map[StripPlatform(text.Trim())] = new Tag(text2.Trim(), Field(item.Value, "color")?.Trim());
				}
			}
		}

		private static string Field(string obj, string key)
		{
			Match match = Regex.Match(obj, "\"" + key + "\"\\s*:\\s*\"([^\"]*)\"");
			if (!match.Success)
			{
				return null;
			}
			return match.Groups[1].Value;
		}

		private static string StripPlatform(string s)
		{
			int num = s.IndexOf('_');
			if (num < 0 || num + 1 >= s.Length)
			{
				return s;
			}
			return s.Substring(num + 1);
		}
	}
	[HarmonyPatch(typeof(Player), "GetHoverName")]
	internal static class PlayerHoverNameTagPatch
	{
		private static void Postfix(Player __instance, ref string __result)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance == (Object)null))
			{
				PlayerTags.Tag tag = PlayerTags.For(((Character)__instance).GetZDOID());
				if (tag != null)
				{
					__result = "<color=" + tag.Color + ">[" + tag.Text + "]</color> " + __result;
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class ChatTagPatch
	{
		private static readonly FieldInfo BufferField = AccessTools.Field(typeof(Terminal), "m_chatBuffer");

		private static readonly MethodInfo UpdateChatMethod = AccessTools.Method(typeof(Terminal), "UpdateChat", (Type[])null, (Type[])null);

		private const string NameOpen = "<color=orange>";

		private static MethodBase TargetMethod()
		{
			MethodInfo[] methods = typeof(Terminal).GetMethods();
			foreach (MethodInfo methodInfo in methods)
			{
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (methodInfo.Name == "AddString" && parameters.Length == 4 && parameters[1].ParameterType == typeof(string) && parameters[2].ParameterType == typeof(Type))
				{
					return methodInfo;
				}
			}
			return null;
		}

		private static void Postfix(Terminal __instance, PlatformUserID user)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			PlayerInfo val = default(PlayerInfo);
			if (!(__instance is Chat) || BufferField == null || !ZNet.TryGetPlayerByPlatformUserID(user, ref val))
			{
				return;
			}
			PlayerTags.Tag tag = PlayerTags.For(val.m_characterID);
			if (tag != null && BufferField.GetValue(__instance) is List<string> { Count: not 0 } list)
			{
				int index = list.Count - 1;
				string value = "<color=" + tag.Color + ">[" + tag.Text + "]</color> ";
				int num = list[index].IndexOf("<color=orange>", StringComparison.Ordinal);
				if (num >= 0 && !list[index].Contains(value))
				{
					list[index] = list[index].Insert(num + "<color=orange>".Length, value);
					UpdateChatMethod?.Invoke(__instance, null);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Chat), "UpdateWorldTextField")]
	internal static class ChatWorldTextTagPatch
	{
		private static void Postfix(object wt)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Invalid comparison between Unknown and I4
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Invalid comparison between Unknown and I4
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			if (wt == null)
			{
				return;
			}
			Traverse val = Traverse.Create(wt);
			Type value = val.Field("m_type").GetValue<Type>();
			if ((int)value != 2 && (int)value != 3)
			{
				return;
			}
			UserInfo value2 = val.Field("m_userInfo").GetValue<UserInfo>();
			PlayerInfo val2 = default(PlayerInfo);
			if (value2 == null || !ZNet.TryGetPlayerByPlatformUserID(value2.UserId, ref val2))
			{
				return;
			}
			PlayerTags.Tag tag = PlayerTags.For(val2.m_characterID);
			if (tag != null)
			{
				Traverse val3 = val.Field("m_textMeshField").Property("text", (object[])null);
				string value3 = val3.GetValue<string>();
				string text = "<color=" + tag.Color + ">[" + tag.Text + "]</color> ";
				if (!string.IsNullOrEmpty(value3) && !value3.StartsWith(text, StringComparison.Ordinal))
				{
					val3.SetValue((object)(text + value3));
				}
			}
		}
	}
	internal static class Targeting
	{
		public static bool Resolve(in AdminRequestContext ctx, ZDOID characterZdoid, out long peerId, out string error)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			error = null;
			if (((ZDOID)(ref characterZdoid)).IsNone())
			{
				peerId = ctx.SenderPeerId;
				return true;
			}
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance != (Object)null)
			{
				foreach (ZNetPeer peer in instance.GetPeers())
				{
					if (peer.m_characterID == characterZdoid)
					{
						peerId = peer.m_uid;
						return true;
					}
				}
			}
			peerId = 0L;
			error = "target player is not connected";
			return false;
		}

		public static bool RefPos(in AdminRequestContext ctx, ZDOID anchor, out Vector3 pos)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: 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_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: 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)
			pos = Vector3.zero;
			if (((ZDOID)(ref anchor)).IsNone() && ctx.SenderPeerId == 0L)
			{
				if ((Object)(object)Player.m_localPlayer == (Object)null)
				{
					return false;
				}
				pos = ((Component)Player.m_localPlayer).transform.position;
				return true;
			}
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			long num = (((ZDOID)(ref anchor)).IsNone() ? ctx.SenderPeerId : 0);
			ZDOID val = anchor;
			foreach (ZNetPeer peer in instance.GetPeers())
			{
				if ((num != 0L) ? (peer.m_uid == num) : (peer.m_characterID == anchor))
				{
					pos = peer.GetRefPos();
					if (pos != Vector3.zero)
					{
						return true;
					}
					val = peer.m_characterID;
					break;
				}
			}
			List<PlayerInfo> playerList = instance.GetPlayerList();
			if (playerList != null)
			{
				foreach (PlayerInfo item in playerList)
				{
					if (item.m_characterID == val && item.m_position != Vector3.zero)
					{
						pos = item.m_position;
						return true;
					}
				}
			}
			return false;
		}
	}
}
namespace ValheimAdminForge.Gui
{
	internal static class AdminWindow
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static WindowFunction <0>__DrawContents;
		}

		public static bool IsOpen;

		private const int WindowId = 372480;

		private static Vector2 _pos = new Vector2(60f, 60f);

		private static readonly string[] Tabs = new string[6] { "Items", "Effects", "Players", "Creatures", "Events", "World" };

		private static int _tab;

		private static float _lastTabError = -99f;

		private static string _tooltipSnapshot = string.Empty;

		private static Texture2D _flatWindowBg;

		private static GUIStyle _windowStyle;

		private static GUISkin _windowSkin;

		private static readonly List<GUISkin> _staleSkins = new List<GUISkin>();

		private static GUISkin WindowSkin()
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			foreach (GUISkin staleSkin in _staleSkins)
			{
				Object.Destroy((Object)(object)staleSkin);
			}
			_staleSkins.Clear();
			if ((Object)(object)_windowSkin != (Object)null)
			{
				return _windowSkin;
			}
			GUI.skin = null;
			_windowSkin = Object.Instantiate<GUISkin>(GUI.skin);
			GUISkin windowSkin = _windowSkin;
			GUIStyle val = new GUIStyle(_windowSkin.label);
			val.normal.textColor = GuiStyles.TextColor;
			windowSkin.label = val;
			return _windowSkin;
		}

		public static void Init()
		{
			PluginConfig.WindowTextColor.SettingChanged += delegate
			{
				if ((Object)(object)_windowSkin != (Object)null)
				{
					_staleSkins.Add(_windowSkin);
				}
				_windowSkin = null;
			};
		}

		private static GUIStyle WindowStyle()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			//IL_002f: 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_006d: Expected O, but got Unknown
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			if (_windowStyle != null)
			{
				return _windowStyle;
			}
			_flatWindowBg = new Texture2D(1, 1);
			_flatWindowBg.SetPixel(0, 0, new Color(0.7f, 0.7f, 0.7f));
			_flatWindowBg.Apply();
			((Texture)_flatWindowBg).filterMode = (FilterMode)0;
			((Texture)_flatWindowBg).wrapMode = (TextureWrapMode)1;
			_windowStyle = new GUIStyle(GUI.skin.window);
			_windowStyle.border = new RectOffset(0, 0, 0, 0);
			_windowStyle.normal.background = _flatWindowBg;
			_windowStyle.onNormal.background = _flatWindowBg;
			_windowStyle.focused.background = _flatWindowBg;
			_windowStyle.onFocused.background = _flatWindowBg;
			_windowStyle.hover.background = _flatWindowBg;
			_windowStyle.onHover.background = _flatWindowBg;
			_windowStyle.active.background = _flatWindowBg;
			_windowStyle.onActive.background = _flatWindowBg;
			return _windowStyle;
		}

		public static void Toggle()
		{
			if (!IsOpen && !PluginConfig.AllowNonAdminWindow.Value && !AdminGuard.IsLocalPlayerAdminHint())
			{
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer != null)
				{
					((Character)localPlayer).Message((MessageType)1, "Admin Forge: admins only", 0, (Sprite)null, false);
				}
			}
			else
			{
				IsOpen = !IsOpen;
			}
		}

		public static void Draw()
		{
			//IL_002f: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			if (IsOpen)
			{
				float num = PluginConfig.WindowWidth.Value;
				float num2 = PluginConfig.WindowHeight.Value;
				GUISkin skin = GUI.skin;
				GUI.skin = WindowSkin();
				Color backgroundColor2;
				Color backgroundColor = (backgroundColor2 = GUI.backgroundColor);
				backgroundColor2.a *= PluginConfig.WindowOpacity.Value;
				GUI.backgroundColor = backgroundColor2;
				Rect val = new Rect(_pos.x, _pos.y, num, num2);
				object obj = <>O.<0>__DrawContents;
				if (obj == null)
				{
					WindowFunction val2 = DrawContents;
					<>O.<0>__DrawContents = val2;
					obj = (object)val2;
				}
				Rect val3 = GUI.Window(372480, val, (WindowFunction)obj, "ADMIN FORGE", WindowStyle());
				_pos.x = Mathf.Round(Mathf.Clamp(((Rect)(ref val3)).x, 0f - num + 80f, (float)(Screen.width - 80)));
				_pos.y = Mathf.Round(Mathf.Clamp(((Rect)(ref val3)).y, 0f, (float)(Screen.height - 40)));
				GUI.backgroundColor = backgroundColor;
				GUI.skin = skin;
			}
		}

		private static void DrawContents(int id)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Invalid comparison between Unknown and I4
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			float num = PluginConfig.WindowWidth.Value;
			GUI.backgroundColor = Color.white;
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("drag title bar to move", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) });
			GUILayout.FlexibleSpace();
			if (GUILayout.Button("X", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(26f),
				GUILayout.Height(20f)
			}))
			{
				IsOpen = false;
			}
			GUILayout.EndHorizontal();
			_tab = GUILayout.Toolbar(_tab, Tabs, Array.Empty<GUILayoutOption>());
			try
			{
				switch (_tab)
				{
				case 1:
					EffectsTab.Draw();
					break;
				case 2:
					PlayersTab.Draw();
					break;
				case 3:
					CreaturesTab.Draw();
					break;
				case 4:
					EventsTab.Draw();
					break;
				case 5:
					WorldTab.Draw();
					break;
				default:
					ItemsTab.Draw();
					break;
				}
			}
			catch (Exception arg)
			{
				if (Time.realtimeSinceStartup - _lastTabError > 3f)
				{
					_lastTabError = Time.realtimeSinceStartup;
					Plugin.Log.LogError((object)$"Admin Forge: tab {_tab} draw threw: {arg}");
				}
				return;
			}
			GUILayout.FlexibleSpace();
			GUILayout.Label(_tooltipSnapshot, GuiStyles.Tooltip, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(num - 16f),
				GUILayout.Height(20f)
			});
			if ((int)Event.current.type == 7)
			{
				_tooltipSnapshot = GUI.tooltip ?? string.Empty;
			}
			GUI.DragWindow(new Rect(0f, 0f, num, 18f));
		}
	}
	internal static class CreaturesTab
	{
		private const float RowHeight = 30f;

		private static readonly string[] OriginTabs = new string[3] { "All", "Vanilla", "Modded" };

		private static readonly string[] ScopeTabs = new string[3] { "Wild", "Tamed", "All" };

		private static string _search = "";

		private static int _originIdx;

		private static string _selectedPrefab;

		private static string _modFilter = "";

		private static string[] _modNames = Array.Empty<string>();

		private static int _modNamesVersion = -1;

		private static readonly ModFilterRow _modPicker = new ModFilterRow();

		private static int _count = 1;

		private static string _countText = "1";

		private static int _level = 1;

		private static bool _tamed;

		private static string _healthText = "0";

		private static string _scatterText = "3";

		private static string _despRadiusText = "30";

		private static int _despScope;

		private static string _despNameText = "";

		private static int _despMinLevel;

		private static bool _despItems;

		private static bool _despFish;

		private static bool _despBirds;

		private static readonly PositionPicker _where = new PositionPicker();

		private static readonly FilteredList<CreatureEntry> _list = new FilteredList<CreatureEntry>();

		public static void Draw()
		{
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Expected O, but got Unknown
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Expected O, but got Unknown
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Expected O, but got Unknown
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Expected O, but got Unknown
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0300: Expected O, but got Unknown
			_list.BeginFrame();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Search", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(46f) });
			_search = GUILayout.TextField(_search ?? "", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.MinWidth(150f),
				GUILayout.Height(22f)
			});
			if (GUILayout.Button("clear", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(44f),
				GUILayout.Height(22f)
			}))
			{
				_search = "";
			}
			GUILayout.Space(10f);
			GUILayout.Label("Origin", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(46f) });
			int originIdx = _originIdx;
			int originIdx2 = GUILayout.Toolbar(originIdx, OriginTabs, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(180f) });
			GUILayout.EndHorizontal();
			IReadOnlyList<CreatureEntry> entries = CreatureCatalog.Entries;
			if (originIdx == 2)
			{
				DrawModRow(entries);
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(new GUIContent("Count", "How many to spawn. The server caps this at Server/MaxCreatureSpawn."), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(44f) });
			string text = GUILayout.TextField(_countText, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(40f),
				GUILayout.Height(22f)
			});
			if (text != _countText)
			{
				_countText = text;
				if (int.TryParse(text, out var result))
				{
					_count = Mathf.Max(1, result);
				}
			}
			GUILayout.Label(new GUIContent("Level", "Star level (1 = no stars, up to 9)."), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) });
			if (GUILayout.Button("-", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(22f),
				GUILayout.Height(22f)
			}))
			{
				_level = Mathf.Max(1, _level - 1);
			}
			GUILayout.Label($"{_level}", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(14f) });
			if (GUILayout.Button("+", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(22f),
				GUILayout.Height(22f)
			}))
			{
				_level = Mathf.Min(9, _level + 1);
			}
			_tamed = GUILayout.Toggle(_tamed, new GUIContent(" Tamed", "Spawn friendly. Tameable creatures follow you; others just stay passive and won't attack."), Array.Empty<GUILayoutOption>());
			GUILayout.Label(new GUIContent("HP", "Health override per creature. 0 = use the creature's own (scaled by level)."), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(24f) });
			_healthText = GUILayout.TextField(_healthText, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(46f),
				GUILayout.Height(22f)
			});
			GUILayout.Label(new GUIContent("Spread", "Random scatter radius (m) when spawning more than one."), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(46f) });
			_scatterText = GUILayout.TextField(_scatterText, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(34f),
				GUILayout.Height(22f)
			});
			GUILayout.EndHorizontal();
			_where.Draw();
			IReadOnlyList<CreatureEntry> entries2 = entries;
			string filter = (_search ?? "").Trim();
			string cacheKey = $"{CreatureCatalog.Version}|{originIdx}|{_modFilter}|{filter.ToLowerInvariant()}";
			if (_list.KeyChanged(cacheKey))
			{
				_list.Rebuild(delegate(List<CreatureEntry> m)
				{
					Fill(entries2, filter, m);
				});
			}
			GUILayout.Label($"{_list.Count} / {entries2.Count} creatures", Array.Empty<GUILayoutOption>());
			ScrollList.Draw(_list.Matches, 30f, TabLayout.ListHeight(474f), ref _list.Scroll, DrawRow);
			DrawDetailPanel();
			DrawDespawnBlock();
			_originIdx = originIdx2;
		}

		private static void DrawModRow(IReadOnlyList<CreatureEntry> entries)
		{
			if (_modNamesVersion != CreatureCatalog.Version)
			{
				_modNamesVersion = CreatureCatalog.Version;
				_modNames = (from e in entries
					where !e.IsVanilla && !string.IsNullOrEmpty(e.ModName)
					select e.ModName).Distinct().OrderBy<string, string>((string n) => n, StringComparer.OrdinalIgnoreCase).ToArray();
				if (Array.IndexOf(_modNames, _modFilter) < 0)
				{
					_modFilter = "";
				}
			}
			if (_modNames.Length != 0)
			{
				_modFilter = _modPicker.Draw(_modNames, _modFilter);
			}
		}

		private static void DrawDespawnBlock()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Expected O, but got Unknown
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Expected O, but got Unknown
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Expected O, but got Unknown
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Expected O, but got Unknown
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Expected O, but got Unknown
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a2: Expected O, but got Unknown
			GUILayout.BeginVertical(GUIStyle.op_Implicit("box"), Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("<b>Despawn</b> around", GuiStyles.Info, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) });
			TargetSelector.Draw();
			GUILayout.Label(new GUIContent("radius", "Metres around the target. Server caps at Server/MaxDespawnRadius."), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(44f) });
			_despRadiusText = GUILayout.TextField(_despRadiusText, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(44f),
				GUILayout.Height(22f)
			});
			_despScope = GUILayout.Toolbar(_despScope, ScopeTabs, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(170f) });
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(new GUIContent("name", "Only creatures whose prefab name contains this. Blank = any."), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(44f) });
			_despNameText = GUILayout.TextField(_despNameText ?? "", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(110f),
				GUILayout.Height(22f)
			});
			GUILayout.Label(new GUIContent("lvl ≥", "Only creatures at this star level or higher. 0 = any."), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(34f) });
			if (GUILayout.Button("-", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(22f),
				GUILayout.Height(22f)
			}))
			{
				_despMinLevel = Mathf.Max(0, _despMinLevel - 1);
			}
			GUILayout.Label($"{_despMinLevel}", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(14f) });
			if (GUILayout.Button("+", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(22f),
				GUILayout.Height(22f)
			}))
			{
				_despMinLevel = Mathf.Min(9, _despMinLevel + 1);
			}
			_despItems = GUILayout.Toggle(_despItems, new GUIContent(" items", "Also remove dropped items on the ground (tombstones are never touched)."), Array.Empty<GUILayoutOption>());
			_despFish = GUILayout.Toggle(_despFish, new GUIContent(" fish", "Also remove fish."), Array.Empty<GUILayoutOption>());
			_despBirds = GUILayout.Toggle(_despBirds, new GUIContent(" birds", "Also remove birds."), Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			if (GUILayout.Button(new GUIContent("Despawn", "Remove matching objects — no loot, no death, no progress credit. Players and tombstones are always safe."), (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(80f),
				GUILayout.Height(22f)
			}))
			{
				RequestDespawn();
			}
			GUILayout.EndHorizontal();
			GUILayout.EndVertical();
		}

		private static void RequestDespawn()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			float.TryParse(_despRadiusText, out var result);
			AdminRpc.Send("despawn", DespawnCommand.BuildArgs((result <= 0f) ? 20f : result, (byte)_despScope, _despNameText, _despMinLevel, _despItems, _despFish, _despBirds, TargetSelector.Current));
		}

		private static void DrawRow(CreatureEntry e)
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Expected O, but got Unknown
			GUILayout.BeginHorizontal((e.PrefabName == _selectedPrefab) ? GUIStyle.op_Implicit("box") : GUIStyle.none, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) });
			string text = (e.IsVanilla ? "V" : ((e.ModName.Length > 0) ? e.ModName : "M"));
			string text2 = (e.IsBoss ? " · <b>BOSS</b>" : "");
			if (GUILayout.Button($"{e.DisplayName}   <color={GuiStyles.DimColor}>{text} · {e.Faction} · {e.BaseHealth:0} hp{text2}</color>", GuiStyles.RowLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f) }))
			{
				_selectedPrefab = e.PrefabName;
			}
			GUILayout.FlexibleSpace();
			if (GUILayout.Button(new GUIContent("Spawn", "Spawn with the parameters above."), (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(58f),
				GUILayout.Height(24f)
			}))
			{
				_selectedPrefab = e.PrefabName;
				RequestSpawn(e.PrefabName);
			}
			GUILayout.EndHorizontal();
		}

		private static void DrawDetailPanel()
		{
			//IL_00e0: 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_01be: Expected O, but got Unknown
			GUILayout.BeginVertical(GUIStyle.op_Implicit("box"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(120f) });
			CreatureEntry creatureEntry = CreatureCatalog.ByPrefab(_selectedPrefab);
			if (creatureEntry == null)
			{
				GUILayout.Label("Select a creature to see details.", Array.Empty<GUILayoutOption>());
			}
			else
			{
				GUILayout.Label("<b>" + creatureEntry.DisplayName + "</b>   <color=" + GuiStyles.DimColor + ">" + creatureEntry.PrefabName + "</color>", GuiStyles.Info, Array.Empty<GUILayoutOption>());
				string text = (creatureEntry.IsVanilla ? "vanilla" : ((creatureEntry.ModName.Length > 0) ? ("modded (" + creatureEntry.ModName + ")") : "modded"));
				GUILayout.Label($"Faction: {creatureEntry.Faction}    Base health: {creatureEntry.BaseHealth:0}\n" + "Boss: " + (creatureEntry.IsBoss ? "yes" : "no") + "    Tameable: " + (creatureEntry.IsTameable ? "yes" : "no") + "    Origin: " + text, GuiStyles.Info, Array.Empty<GUILayoutOption>());
				GUILayout.FlexibleSpace();
				if (GUILayout.Button(new GUIContent(string.Format("Spawn {0}x  (lvl {1}{2})", _count, _level, _tamed ? ", tamed" : ""), "Spawn with the parameters above."), (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Width(200f),
					GUILayout.Height(26f)
				}))
				{
					RequestSpawn(creatureEntry.PrefabName);
				}
			}
			GUILayout.EndVertical();
		}

		private static void RequestSpawn(string prefabName)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			int.TryParse(_countText, out var result);
			float.TryParse(_healthText, out var result2);
			float.TryParse(_scatterText, out var result3);
			AdminRpc.Send("spawn_creature", SpawnCreatureCommand.BuildArgs(prefabName, Mathf.Max(1, result), _level, _tamed, result2, result3, _where.ModeByte, _where.Anchor, _where.Coords));
		}

		private static void Fill(IReadOnlyList<CreatureEntry> entries, string filter, List<CreatureEntry> outList)
		{
			foreach (CreatureEntry entry in entries)
			{
				if ((_originIdx != 1 || entry.IsVanilla) && (_originIdx != 2 || !entry.IsVanilla) && (_originIdx != 2 || _modFilter.Length <= 0 || !(entry.ModName != _modFilter)) && (filter.Length <= 0 || entry.DisplayName.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0 || entry.PrefabName.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0))
				{
					outList.Add(entry);
				}
			}
		}
	}
	internal static class EffectsTab
	{
		private const float RowHeight = 34f;

		private static readonly string[] OriginTabs = new string[3] { "All", "Vanilla", "Modded" };

		private static string _search = "";

		private static int _originIdx;

		private static int _selectedHash;

		private static string _durationText = "0";

		private static string _powerText = "0";

		private static string _modFilter = "";

		private static string[] _modNames = Array.Empty<string>();

		private static int _modNamesVersion = -1;

		private static readonly ModFilterRow _modPicker = new ModFilterRow();

		private static readonly FilteredList<StatusEffectEntry> _list = new FilteredList<StatusEffectEntry>();

		public static void Draw()
		{
			_list.BeginFrame();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Search", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(46f) });
			_search = GUILayout.TextField(_search ?? "", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.MinWidth(140f),
				GUILayout.Height(22f)
			});
			if (GUILayout.Button("clear", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(44f),
				GUILayout.Height(22f)
			}))
			{
				_search = "";
			}
			GUILayout.Space(8f);
			GUILayout.Label("Dur s", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(38f) });
			_durationText = GUILayout.TextField(_durationText, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(46f),
				GUILayout.Height(22f)
			});
			GUILayout.Label("Power", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) });
			_powerText = GUILayout.TextField(_powerText, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(46f),
				GUILayout.Height(22f)
			});
			GUILayout.EndHorizontal();
			GUILayout.Label("<color=" + GuiStyles.DimColor + ">Dur 0 = effect default. Power > 0 needed for Poison / Burning / Frost to deal damage.</color>", GuiStyles.Info, Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Origin", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(46f) });
			int originIdx = _originIdx;
			int originIdx2 = GUILayout.Toolbar(originIdx, OriginTabs, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(180f) });
			GUILayout.EndHorizontal();
			IReadOnlyList<StatusEffectEntry> entries = StatusEffectCatalog.Entries;
			if (originIdx == 2)
			{
				DrawModRow(entries);
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			TargetSelector.Draw();
			GUILayout.EndHorizontal();
			string filter = (_search ?? "").Trim();
			string cacheKey = $"{StatusEffectCatalog.Version}|{originIdx}|{_modFilter}|{filter.ToLowerInvariant()}";
			if (_list.KeyChanged(cacheKey))
			{
				_list.Rebuild(delegate(List<StatusEffectEntry> m)
				{
					Fill(entries, filter, m);
				});
			}
			GUILayout.Label($"{_list.Count} / {entries.Count} effects", Array.Empty<GUILayoutOption>());
			ScrollList.Draw(_list.Matches, 34f, TabLayout.ListHeight(423f), ref _list.Scroll, DrawRow);
			DrawDetailPanel();
			_originIdx = originIdx2;
		}

		private static void DrawModRow(IReadOnlyList<StatusEffectEntry> entries)
		{
			if (_modNamesVersion != StatusEffectCatalog.Version)
			{
				_modNamesVersion = StatusEffectCatalog.Version;
				_modNames = (from e in entries
					where !e.IsVanilla && !string.IsNullOrEmpty(e.ModName)
					select e.ModName).Distinct().OrderBy<string, string>((string n) => n, StringComparer.OrdinalIgnoreCase).ToArray();
				if (Array.IndexOf(_modNames, _modFilter) < 0)
				{
					_modFilter = "";
				}
			}
			if (_modNames.Length != 0)
			{
				_modFilter = _modPicker.Draw(_modNames, _modFilter);
			}
		}

		private static void DrawRow(StatusEffectEntry e)
		{
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Expected O, but got Unknown
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Expected O, but got Unknown
			GUILayout.BeginHorizontal((e.NameHash == _selectedHash) ? GUIStyle.op_Implicit("box") : GUIStyle.none, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(34f) });
			IconDrawer.Draw(e.Icon, 28f);
			string text = (e.IsVanilla ? "V" : ((e.ModName.Length > 0) ? e.ModName : "M"));
			string text2 = (string.IsNullOrEmpty(e.Category) ? "" : (" · " + e.Category));
			if (GUILayout.Button(e.DisplayName + "   <color=" + GuiStyles.DimColor + ">" + text + " · " + e.InternalName + text2 + "</color>", GuiStyles.RowLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
			{
				_selectedHash = e.NameHash;
			}
			GUILayout.FlexibleSpace();
			if (GUILayout.Button(new GUIContent("Apply", "Apply this effect to the target (uses Dur / Power above)."), (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(52f),
				GUILayout.Height(26f)
			}))
			{
				RequestApply(e.NameHash, remove: false);
			}
			if (GUILayout.Button(new GUIContent("Clear", "Remove this effect from the target — for effects that ignore their timer."), (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(52f),
				GUILayout.Height(26f)
			}))
			{
				RequestApply(e.NameHash, remove: true);
			}
			GUILayout.EndHorizontal();
		}

		private static void RequestApply(int nameHash, bool remove)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			float duration = Parse(_durationText, 0f, 3600f);
			float power = Parse(_powerText, 0f, 100000f);
			AdminRpc.Send("apply_effect", ApplyEffectCommand.BuildArgs(nameHash, TargetSelector.Current, duration, power, remove));
		}

		private static float Parse(string text, float min, float max)
		{
			if (!float.TryParse(text, out var result))
			{
				result = 0f;
			}
			return Mathf.Clamp(result, min, max);
		}

		private static void DrawDetailPanel()
		{
			GUILayout.BeginVertical(GUIStyle.op_Implicit("box"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(140f) });
			StatusEffectEntry statusEffectEntry = StatusEffectCatalog.ByHash(_selectedHash);
			if (statusEffectEntry == null)
			{
				GUILayout.Label("Select an effect to see details.", Array.Empty<GUILayoutOption>());
			}
			else
			{
				GUILayout.Label("<b>" + statusEffectEntry.DisplayName + "</b>   <color=" + GuiStyles.DimColor + ">" + statusEffectEntry.InternalName + "</color>", GuiStyles.Info, Array.Empty<GUILayoutOption>());
				if (!string.IsNullOrEmpty(statusEffectEntry.Tooltip))
				{
					GUILayout.Label(statusEffectEntry.Tooltip, GuiStyles.Info, Array.Empty<GUILayoutOption>());
				}
				string text = ((statusEffectEntry.Ttl > 0f) ? $"{statusEffectEntry.Ttl:0.#}s" : "until removed");
				string text2 = (statusEffectEntry.IsVanilla ? "vanilla" : ((statusEffectEntry.ModName.Length > 0) ? ("modded (" + statusEffectEntry.ModName + ")") : "modded"));
				GUILayout.Label("Category: " + (string.IsNullOrEmpty(statusEffectEntry.Category) ? "-" : statusEffectEntry.Category) + "    Duration: " + text + "    Origin: " + text2, GuiStyles.Info, Array.Empty<GUILayoutOption>());
				GUILayout.FlexibleSpace();
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				if (GUILayout.Button("Apply to me", (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Width(110f),
					GUILayout.Height(26f)
				}))
				{
					RequestApply(statusEffectEntry.NameHash, remove: false);
				}
				if (GUILayout.Button("Remove", (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Width(90f),
					GUILayout.Height(26f)
				}))
				{
					RequestApply(statusEffectEntry.NameHash, remove: true);
				}
				GUILayout.EndHorizontal();
			}
			GUILayout.EndVertical();
		}

		private static void Fill(IReadOnlyList<StatusEffectEntry> entries, string filter, List<StatusEffectEntry> outList)
		{
			foreach (StatusEffectEntry entry in entries)
			{
				if ((_originIdx != 1 || entry.IsVanilla) && (_originIdx != 2 || !entry.IsVanilla) && (_originIdx != 2 || _modFilter.Length <= 0 || !(entry.ModName != _modFilter)) && (filter.Length == 0 || entry.DisplayName.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0 || entry.InternalName.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0))
				{
					outList.Add(entry);
				}
			}
		}
	}
	internal static class EventsTab
	{
		private const float RowHeight = 28f;

		private static string _search = "";

		private static string _selectedName;

		private static string _detailSnapshotName;

		private static readonly PositionPicker _where = new PositionPicker();

		private static readonly FilteredList<EventEntry> _list = new FilteredList<EventEntry>();

		public static void Draw()
		{
			_list.BeginFrame();
			DrawActiveHeader();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Search", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(46f) });
			_search = GUILayout.TextField(_search ?? "", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.MinWidth(160f),
				GUILayout.Height(22f)
			});
			if (GUILayout.Button("clear", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(44f),
				GUILayout.Height(22f)
			}))
			{
				_search = "";
			}
			GUILayout.EndHorizontal();
			_where.Draw();
			IReadOnlyList<EventEntry> entries = EventCatalog.Entries;
			string filter = (_search ?? "").Trim();
			string cacheKey = $"{EventCatalog.Version}|{filter.ToLowerInvariant()}";
			if (_list.KeyChanged(cacheKey))
			{
				_list.Rebuild(delegate(List<EventEntry> m)
				{
					Fill(entries, filter, m);
				});
			}
			GUILayout.Label($"{_list.Count} / {entries.Count} events", Array.Empty<GUILayoutOption>());
			ScrollList.Draw(_list.Matches, 28f, TabLayout.ListHeight(340f), ref _list.Scroll, DrawRow);
			DrawDetailPanel();
		}

		private static void DrawActiveHeader()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Expected O, but got Unknown
			GUILayout.BeginHorizontal(GUIStyle.op_Implicit("box"), Array.Empty<GUILayoutOption>());
			RandEventSystem instance = RandEventSystem.instance;
			RandomEvent val = (((Object)(object)instance != (Object)null) ? instance.GetCurrentRandomEvent() : null);
			GUILayout.Label((val == null) ? "<b>No event running.</b>" : $"<b>Active:</b> {val.m_name}   <color={GuiStyles.DimColor}>{val.m_biome} · {val.m_duration:0}s</color>", GuiStyles.Info, Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			string obj = ((val == null) ? "Random" : "Stop");
			string text = ((val == null) ? "Force-start a random event from the list at the chosen location." : "Stop the running event.");
			if (GUILayout.Button(new GUIContent(obj, text), (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(80f),
				GUILayout.Height(22f)
			}))
			{
				if (val == null)
				{
					StartRandomFromList();
				}
				else
				{
					Send(1, string.Empty);
				}
			}
			GUILayout.EndHorizontal();
		}

		private static void DrawRow(EventEntry e)
		{
			//IL_005a: 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_00db: Expected O, but got Unknown
			GUILayout.BeginHorizontal((e.Name == _selectedName) ? GUIStyle.op_Implicit("box") : GUIStyle.none, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) });
			if (GUILayout.Button($"{e.Name}   <color={GuiStyles.DimColor}>{e.Biome} · {e.Duration:0}s</color>", GuiStyles.RowLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) }))
			{
				_selectedName = e.Name;
			}
			GUILayout.FlexibleSpace();
			if (GUILayout.Button(new GUIContent("Start", "Start this event at the chosen location."), (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(58f),
				GUILayout.Height(22f)
			}))
			{
				_selectedName = e.Name;
				Send(0, e.Name);
			}
			GUILayout.EndHorizontal();
		}

		private static void DrawDetailPanel()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Expected O, but got Unknown
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Expected O, but got Unknown
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Expected O, but got Unknown
			if ((int)Event.current.type == 8)
			{
				_detailSnapshotName = _selectedName;
			}
			GUILayout.BeginVertical(GUIStyle.op_Implicit("box"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(150f) });
			EventEntry eventEntry = EventCatalog.ByName(_detailSnapshotName);
			if (eventEntry == null)
			{
				GUILayout.Label("Select an event to see details.", Array.Empty<GUILayoutOption>());
			}
			else
			{
				GUILayout.Label("<b>" + eventEntry.Name + "</b>", GuiStyles.Info, Array.Empty<GUILayoutOption>());
				if (!string.IsNullOrEmpty(eventEntry.StartMessage))
				{
					GUILayout.Label("<color=" + GuiStyles.DimColor + ">“" + eventEntry.StartMessage + "”</color>", GuiStyles.Info, Array.Empty<GUILayoutOption>());
				}
				GUILayout.Label($"Biome: {eventEntry.Biome}    Duration: {eventEntry.Duration:0}s    Range: {eventEntry.Range:0}m    " + "Near base only: " + (eventEntry.NearBaseOnly ? "yes" : "no"), GuiStyles.Info, Array.Empty<GUILayoutOption>());
				if (eventEntry.RequiredKeys.Length != 0)
				{
					GUILayout.Label("Requires keys: " + FormatKeys(eventEntry.RequiredKeys), GuiStyles.Info, Array.Empty<GUILayoutOption>());
				}
				if (eventEntry.Spawns.Length != 0)
				{
					GUILayout.Label("Spawns: " + string.Join(", ", eventEntry.Spawns), GuiStyles.Info, Array.Empty<GUILayoutOption>());
				}
				GUILayout.FlexibleSpace();
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				if (GUILayout.Button(new GUIContent("Start", "Start this event at the location chosen above."), (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Width(120f),
					GUILayout.Height(26f)
				}))
				{
					Send(0, eventEntry.Name);
				}
				if (GUILayout.Button(new GUIContent("Random", "Force-start a random event from the list instead."), (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Width(90f),
					GUILayout.Height(26f)
				}))
				{
					StartRandomFromList();
				}
				if (GUILayout.Button(new GUIContent("Stop", "Stop whatever event is running."), (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Width(70f),
					GUILayout.Height(26f)
				}))
				{
					Send(1, string.Empty);
				}
				GUILayout.EndHorizontal();
			}
			GUILayout.EndVertical();
		}

		private static string FormatKeys(string[] keys)
		{
			ZoneSystem instance = ZoneSystem.instance;
			List<string> list = new List<string>(keys.Length);
			foreach (string text in keys)
			{
				bool flag = (Object)(object)instance != (Object)null && instance.GetGlobalKey(text);
				list.Add(flag ? text : ("<color=#C04040>" + text + " (missing)</color>"));
			}
			return string.Join(", ", list.ToArray());
		}

		private static void StartRandomFromList()
		{
			IReadOnlyList<EventEntry> readOnlyList = ((_list.Count > 0) ? _list.Matches : EventCatalog.Entries);
			if (readOnlyList.Count != 0)
			{
				EventEntry eventEntry = readOnlyList[Random.Range(0, readOnlyList.Count)];
				_selectedName = eventEntry.Name;
				Send(0, eventEntry.Name);
			}
		}

		private static void Send(byte op, string name)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			AdminRpc.Send("event", EventCommand.BuildArgs(op, name, _where.ModeByte, _where.Anchor, _where.Coords));
		}

		private static void Fill(IReadOnlyList<EventEntry> entries, string filter, List<EventEntry> outList)
		{
			foreach (EventEntry entry in entries)
			{
				if (filter.Length == 0 || entry.Name.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0 || entry.StartMessage.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					outList.Add(entry);
				}
			}
		}
	}
	internal sealed class FilteredList<T>
	{
		private readonly List<T> _matches = new List<T>();

		private string _key;

		private bool _pendingScrollReset;

		public Vector2 Scroll;

		public IReadOnlyList<T> Matches => _matches;

		public int Count => _matches.Count;

		public void BeginFrame()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (_pendingScrollReset && (int)Event.current.type == 8)
			{
				_pendingScrollReset = false;
				Scroll = Vector2.zero;
			}
		}

		public bool KeyChanged(string cacheKey)
		{
			if (cacheKey == _key)
			{
				return false;
			}
			_key = cacheKey;
			return true;
		}

		public void Rebuild(Action<List<T>> fill)
		{
			_matches.Clear();
			fill(_matches);
			_pendingScrollReset = true;
		}
	}
	internal static class GuiStyles
	{
		private static string _dimColor;

		private static GUIStyle _rowLabel;

		private static GUIStyle _info;

		private static GUIStyle _tooltip;

		public static string DimColor => _dimColor ?? (_dimColor = Validate(PluginConfig.WindowDimTextColor.Value));

		public static Color TextColor
		{
			get
			{
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				Color result = default(Color);
				if (!ColorUtility.TryParseHtmlString(PluginConfig.WindowTextColor.Value, ref result))
				{
					return Color.black;
				}
				return result;
			}
		}

		public static GUIStyle RowLabel
		{
			get
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Expected O, but got Unknown
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0042: Unknown result type (might be due to invalid IL or missing references)
				//IL_004c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0052: Expected O, but got Unknown
				object obj = _rowLabel;
				if (obj == null)
				{
					GUIStyle val = new GUIStyle(GUI.skin.label)
					{
						richText = true,
						alignment = (TextAnchor)3,
						wordWrap = false,
						padding = new RectOffset(4, 4, 2, 2)
					};
					val.normal.textColor = TextColor;
					_rowLabel = val;
					obj = (object)val;
				}
				return (GUIStyle)obj;
			}
		}

		public static GUIStyle Info
		{
			get
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Expected O, but got Unknown
				object obj = _info;
				if (obj == null)
				{
					GUIStyle val = new GUIStyle(GUI.skin.label)
					{
						richText = true,
						wordWrap = true
					};
					val.normal.textColor = TextColor;
					_info = val;
					obj = (object)val;
				}
				return (GUIStyle)obj;
			}
		}

		public static GUIStyle Tooltip
		{
			get
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Expected O, but got Unknown
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0042: Unknown result type (might be due to invalid IL or missing references)
				//IL_004c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0052: Expected O, but got Unknown
				object obj = _tooltip;
				if (obj == null)
				{
					GUIStyle val = new GUIStyle(GUI.skin.box)
					{
						alignment = (TextAnchor)3,
						richText = true,
						wordWrap = false,
						padding = new RectOffset(8, 8, 2, 2)
					};
					val.normal.textColor = TextColor;
					_tooltip = val;
					obj = (object)val;
				}
				return (GUIStyle)obj;
			}
		}

		private static string Validate(string raw)
		{
			Color val = default(Color);
			if (!ColorUtility.TryParseHtmlString(raw, ref val))
			{
				return "#000000";
			}
			return raw;
		}

		public static void Init()
		{
			PluginConfig.WindowTextColor.SettingChanged += delegate
			{
				Invalidate();
			};
			PluginConfig.WindowDimTextColor.SettingChanged += delegate
			{
				Invalidate();
			};
		}

		private static void Invalidate()
		{
			_rowLabel = null;
			_info = null;
			_tooltip = null;
			_dimColor = null;
		}
	}
	internal static class IconDrawer
	{
		public static void Draw(Sprite sprite, float size)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Invalid comparison between Unknown and I4
			//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_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			Rect rect = GUILayoutUtility.GetRect(size, size, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(size),
				GUILayout.Height(size)
			});
			if ((int)Event.current.type == 7 && !((Object)(object)sprite == (Object)null) && !((Object)(object)sprite.texture == (Object)null))
			{
				Texture2D texture = sprite.texture;
				Rect textureRect = sprite.textureRect;
				Rect val = default(Rect);
				((Rect)(ref val))..ctor(((Rect)(ref textureRect)).x / (float)((Texture)texture).width, ((Rect)(ref textureRect)).y / (float)((Texture)texture).height, ((Rect)(ref textureRect)).width / (float)((Texture)texture).width, ((Rect)(ref textureRect)).height / (float)((Texture)texture).height);
				GUI.DrawTextureWithTexCoords(rect, (Texture)(object)texture, val);
			}
		}
	}
	internal static class InputBlocker
	{
		[HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")]
		private static class FreeCursor
		{
			private static void Postfix()
			{
				if (Blocking)
				{
					Cursor.lockState = (CursorLockMode)0;
					Cursor.visible = true;
				}
			}
		}

		[HarmonyPatch(typeof(Player), "TakeInput")]
		private static class SuppressTakeInput
		{
			private static void Postfix(ref bool __result)
			{
				if (Blocking)
				{
					__result = false;
				}
			}
		}

		[HarmonyPatch]
		private static class BlockBoolGetters
		{
			private static IEnumerable<MethodBase> TargetMethods()
			{
				return new MethodInfo[9]
				{
					AccessTools.Method(typeof(ZInput), "GetButton", (Type[])null, (Type[])null),
					AccessTools.Method(typeof(ZInput), "GetButtonDown", (Type[])null, (Type[])null),
					AccessTools.Method(typeof(ZInput), "GetButtonUp", (Type[])null, (Type[])null),
					AccessTools.Method(typeof(ZInput), "GetMouseButton", (Type[])null, (Type[])null),
					AccessTools.Method(typeof(ZInput), "GetMouseButtonDown", (Type[])null, (Type[])null),
					AccessTools.Method(typeof(ZInput), "GetMouseButtonUp", (Type[])null, (Type[])null),
					AccessTools.Method(typeof(ZInput), "GetKey", (Type[])null, (Type[])null),
					AccessTools.Method(typeof(ZInput), "GetKeyDown", (Type[])null, (Type[])null),
					AccessTools.Method(typeof(ZInput), "GetKeyUp", (Type[])null, (Type[])null)
				};
			}

			private static bool Prefix(ref bool __result)
			{
				if (!Blocking)
				{
					return true;
				}
				__result = false;
				return false;
			}
		}

		[HarmonyPatch]
		private static class BlockFloatGetters
		{
			private static IEnumerable<MethodBase> TargetMethods()
			{
				return new MethodInfo[7]
				{
					AccessTools.Method(typeof(ZInput), "GetMouseScrollWheel", (Type[])null, (Type[])null),
					AccessTools.Method(typeof(ZInput), "GetJoyLeftStickX", (Type[])null, (Type[])null),
					AccessTools.Method(typeof(ZInput), "GetJoyLeftStickY", (Type[])null, (Type[])null),
					AccessTools.Method(typeof(ZInput), "GetJoyRightStickX", (Type[])null, (Type[])null),
					AccessTools.Method(typeof(ZInput), "GetJoyRightStickY", (Type[])null, (Type[])null),
					AccessTools.Method(typeof(ZInput), "GetJoyLTrigger", (Type[])null, (Type[])null),
					AccessTools.Method(typeof(ZInput), "GetJoyRTrigger", (Type[])null, (Type[])null)
				};
			}

			private static bool Prefix(ref float __result)
			{
				if (!Blocking)
				{
					return true;
				}
				__result = 0f;
				return false;
			}
		}

		[HarmonyPatch(typeof(ZInput), "GetMouseDelta")]
		private static class BlockMouseDelta
		{
			private static bool Prefix(ref Vector2 __result)
			{
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				if (!Blocking)
				{
					return true;
				}
				__result = Vector2.zero;
				return false;
			}
		}

		private static bool Blocking => AdminWindow.IsOpen;
	}
	internal static class ItemsTab
	{
		private const float RowHeight = 34f;

		private static readonly string[] CategoryTabs = new string[6] { "All", "Weapons", "Armor", "Food", "Resources", "Other" };

		private static readonly string[] OriginTabs = new string[3] { "All", "Vanilla", "Modded" };

		private static readonly string[] SortTabs = new string[2] { "Name", "Type" };

		private static string _search = "";

		private static int _categoryIdx;

		private static int _originIdx;

		private static int _sortIdx;

		private static int _quantity = 1;

		private static string _qtyText = "1";

		private static string _selectedPrefab;

		private static string _modFilter = "";

		private static string[] _modNames = Array.Empty<string>();

		private static int _modNamesVersion = -1;

		private static readonly ModFilterRow _modPicker = new ModFilterRow();

		private static readonly FilteredList<ItemEntry> _list = new FilteredList<ItemEntry>();

		public static void Draw()
		{
			_list.BeginFrame();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Search", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(46f) });
			_search = GUILayout.TextField(_search ?? "", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.MinWidth(160f),
				GUILayout.Height(22f)
			});
			if (GUILayout.Button("clear", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(44f),
				GUILayout.Height(22f)
			}))
			{
				_search = "";
			}
			GUILayout.Space(10f);
			GUILayout.Label("Sort", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(32f) });
			_sortIdx = GUILayout.Toolbar(_sortIdx, SortTabs, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) });
			GUILayout.EndHorizontal();
			_categoryIdx = GUILayout.Toolbar(_categoryIdx, CategoryTabs, Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Origin", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(46f) });
			int originIdx = _originIdx;
			int originIdx2 = GUILayout.Toolbar(originIdx, OriginTabs, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(210f) });
			GUILayout.FlexibleSpace();
			DrawQuantityStepper();
			GUILayout.EndHorizontal();
			IReadOnlyList<ItemEntry> entries = ItemCatalog.Entries;
			if (originIdx == 2)
			{
				DrawModRow(entries);
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			TargetSelector.Draw();
			GUILayout.EndHorizontal();
			string filter = (_search ?? "").Trim();
			string cacheKey = $"{ItemCatalog.Version}|{_categoryIdx}|{originIdx}|{_modFilter}|{_sortIdx}|{filter.ToLowerInvariant()}";
			if (_list.KeyChanged(cacheKey))
			{
				_list.Rebuild(delegate(List<ItemEntry> m)
				{
					Fill(entries, filter, m);
				});
			}
			GUILayout.Label($"{_list.Count} / {entries.Count} items", Array.Empty<GUILayoutOption>());
			ScrollList.Draw(_list.Matches, 34f, TabLayout.ListHeight(438f), ref _list.Scroll, DrawRow);
			DrawDetailPanel();
			_originIdx = originIdx2;
		}

		private static void DrawModRow(IReadOnlyList<ItemEntry> entries)
		{
			if (_modNamesVersion != ItemCatalog.Version)
			{
				_modNamesVersion = ItemCatalog.Version;
				_modNames = (from e in entries
					where e.Origin == ItemOrigin.Modded && !string.IsNullOrEmpty(e.ModName)
					select e.ModName).Distinct().OrderBy<string, string>((string n) => n, StringComparer.OrdinalIgnoreCase).ToArray();
				if (Array.IndexOf(_modNames, _modFilter) < 0)
				{
					_modFilter = "";
				}
			}
			if (_modNames.Length != 0)
			{
				_modFilter = _modPicker.Draw(_modNames, _modFilter);
			}
		}

		private static void DrawQuantityStepper()
		{
			GUILayout.Label("Qty", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(28f) });
			if (GUILayout.Button("-10", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(34f),
				GUILayout.Height(22f)
			}))
			{
				SetQuantity(_quantity - 10);
			}
			if (GUILayout.Button("-", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(24f),
				GUILayout.Height(22f)
			}))
			{
				SetQuantity(_quantity - 1);
			}
			string text = GUILayout.TextField(_qtyText, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(50f),
				GUILayout.Height(22f)
			});
			if (text != _qtyText)
			{
				_qtyText = text;
				if (int.TryParse(text, out var result))
				{
					_quantity = Mathf.Clamp(result, 1, PluginConfig.MaxQuantity.Value);
				}
			}
			if (GUILayout.Button("+", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(24f),
				GUILayout.Height(22f)
			}))
			{
				SetQuantity(_quantity + 1);
			}
			if (GUILayout.Button("+10", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(34f),
				GUILayout.Height(22f)
			}))
			{
				SetQuantity(_quantity + 10);
			}
		}

		private static void SetQuantity(int value)
		{
			_quantity = Mathf.Clamp(value, 1, PluginConfig.MaxQuantity.Value);
			_qtyText = _quantity.ToString();
		}

		private static void DrawRow(ItemEntry e)
		{
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Expected O, but got Unknown
			GUILayout.BeginHorizontal((e.PrefabName == _selectedPrefab) ? GUIStyle.op_Implicit("box") : GUIStyle.none, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(34f) });
			IconDrawer.Draw(e.Icon, 28f);
			string text = ((e.Origin == ItemOrigin.Vanilla) ? "V" : ((e.ModName.Length