Decompiled source of Nexus Admin Tools v1.8.7

BepInEx/plugins/ValheimSpawner/ValheimSpawner.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ValheimSpawner")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.8.7.0")]
[assembly: AssemblyInformationalVersion("1.8.7+3d7b5aa696e25836ea219ce323e5afe0779b2d82")]
[assembly: AssemblyProduct("ValheimSpawner")]
[assembly: AssemblyTitle("ValheimSpawner")]
[assembly: AssemblyVersion("1.8.7.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 SuperNova.ValheimSpawner
{
	internal static class AdminRules
	{
		internal const int Protocol = 185;

		internal const int MaxPacketBytes = 16384;

		internal const int AllModeBits = 1023;

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

		internal static bool Modes(int bits, float damage, float xp)
		{
			if (bits >= 0 && (bits & -1024) == 0 && Finite(damage) && damage >= 1f && damage <= 25f && Finite(xp) && xp >= 1f)
			{
				return xp <= 1000f;
			}
			return false;
		}

		internal static bool Spawn(string prefab, int count, int level, string name)
		{
			if (!string.IsNullOrWhiteSpace(prefab) && prefab.Length <= 128 && count >= 1 && count <= 50 && level >= 1 && level <= 3 && name != null)
			{
				return name.Length <= 48;
			}
			return false;
		}

		internal static bool Clock(int hour, int minute)
		{
			if (hour >= 0 && hour < 24 && minute >= 0)
			{
				return minute < 60;
			}
			return false;
		}

		internal static bool Skill(float level)
		{
			if (Finite(level) && level >= 0f)
			{
				return level <= 100f;
			}
			return false;
		}

		internal static int CycleIndex(int currentIndex, int delta, int count)
		{
			if (count <= 0)
			{
				return -1;
			}
			return (int)(((long)((currentIndex >= 0 && currentIndex < count) ? currentIndex : 0) + (long)(delta % count) + count) % count);
		}

		internal static string LocationName(string name, string prefab)
		{
			if (!string.IsNullOrWhiteSpace(name))
			{
				return name;
			}
			return prefab ?? string.Empty;
		}

		internal static bool LocationNameInput(string value, bool allowEmpty)
		{
			if (value == null || value.Length > 48)
			{
				return false;
			}
			string text = value.Trim();
			if (text.Length == 0)
			{
				return allowEmpty;
			}
			if (text.Length <= 48)
			{
				return !text.Any(char.IsControl);
			}
			return false;
		}

		internal static bool WorldPosition(float x, float y, float z, float maxCoordinate = 10500f)
		{
			if (Finite(x) && Finite(y) && Finite(z) && Math.Abs(x) <= maxCoordinate && Math.Abs(z) <= maxCoordinate && y >= -1000f)
			{
				return y <= 10000f;
			}
			return false;
		}

		internal static bool AdminDetail(string value)
		{
			if (value != null)
			{
				return value.Length <= 512;
			}
			return false;
		}

		internal static double SolarFraction(double raw)
		{
			if (!(raw < 0.15))
			{
				if (!(raw <= 0.85))
				{
					return 0.75 + (raw - 0.85) / 0.15 * 0.25;
				}
				return 0.25 + (raw - 0.15) / 0.7 * 0.5;
			}
			return raw / 0.15 * 0.25;
		}

		internal static double RawFraction(int hour, int minute)
		{
			if (!Clock(hour, minute))
			{
				throw new ArgumentOutOfRangeException("hour");
			}
			double num = (double)(hour * 60 + minute) / 1440.0;
			if (!(num < 0.25))
			{
				if (!(num <= 0.75))
				{
					return 0.85 + (num - 0.75) / 0.25 * 0.15;
				}
				return 0.15 + (num - 0.25) / 0.5 * 0.7;
			}
			return num / 0.25 * 0.15;
		}

		internal static double NextTime(double now, long dayLength, int hour, int minute)
		{
			if (!Finite(now) || now < 0.0 || dayLength < 1)
			{
				throw new ArgumentOutOfRangeException("now");
			}
			double num = Math.Floor(now / (double)dayLength) * (double)dayLength + RawFraction(hour, minute) * (double)dayLength;
			if (!(num < now))
			{
				return num;
			}
			return num + (double)dayLength;
		}
	}
	internal sealed class AdminRequestGate
	{
		private int _lastId;

		private double _nextPoll;

		private double _nextAction;

		internal bool TryAccept(int id, bool poll, double now)
		{
			if (!AdminRules.Finite(now) || now < 0.0 || id <= _lastId)
			{
				return false;
			}
			_lastId = id;
			if (poll)
			{
				if (now < _nextPoll)
				{
					return false;
				}
				_nextPoll = now + 0.5;
			}
			else
			{
				if (now < _nextAction)
				{
					return false;
				}
				_nextAction = now + 0.25;
			}
			return true;
		}
	}
	internal enum CreatureCategory
	{
		Regular,
		Boss
	}
	internal sealed class CreatureMetadata
	{
		public string English;

		public string Russian;

		public CreatureCategory Category;

		public string[] Biomes;

		public CreatureMetadata(string english, string russian, CreatureCategory category, string biomeList)
		{
			English = english;
			Russian = russian;
			Category = category;
			Biomes = (string.IsNullOrWhiteSpace(biomeList) ? new string[0] : biomeList.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries));
		}
	}
	internal static class CreatureCatalog
	{
		private const string CatalogData = "\nEikthyr|Eikthyr|Эйктюр|Boss|Meadows\ngd_king|The Elder|Древний|Boss|Black Forest\nBonemass|Bonemass|Масса костей|Boss|Swamp\nDragon|Moder|Модер|Boss|Mountains\nGoblinKing|Yagluth|Яглут|Boss|Plains\nSeekerQueen|The Queen|Королева|Boss|Mistlands\nFader|Fader|Прародитель|Boss|Ashlands\nFrozenKing|Kall Fimbulbringer|Калль Фимбульбрингер|Boss|Deep North\nFrozenKing_p2|Kall Fimbulbringer (phase 2)|Калль Фимбульбрингер (фаза 2)|Boss|Deep North\nFrozenKing_p3|Kall Fimbulbringer (phase 3)|Калль Фимбульбрингер (фаза 3)|Boss|Deep North\nKallFimbulbringer|Kall Fimbulbringer|Калль Фимбульбрингер|Boss|Deep North\nBrenna|Brenna|Бренна|Boss|Black Forest\nGeirrhafa|Geirrhafa|Гейрафа|Boss|Mountains\nZil|Zil|Зил|Boss|Mistlands\nThungr|Thungr|Тангр|Boss|Mistlands\nCharred_Melee_Dyrnwyn|Lord Reto|Владыка Рето|Boss|Ashlands\nBoar|Boar|Кабан|Regular|Meadows;Black Forest\nBoar_piggy|Boar piglet|Поросёнок кабана|Regular|Meadows;Black Forest\nDeer|Deer|Олень|Regular|Meadows;Black Forest\nDeer_White|White deer|Белый олень|Regular|Deep North\nNeck|Neck|Никс|Regular|Meadows\nGreyling|Greyling|Грейлинг|Regular|Meadows\nGreydwarf|Greydwarf|Грейдворф|Regular|Black Forest\nGreydwarf_Elite|Greydwarf Brute|Грейдворф-берсерк|Regular|Black Forest\nGreydwarf_Shaman|Greydwarf Shaman|Грейдворф-шаман|Regular|Black Forest\nGreydwarf_Spawn|Greydwarf nest spawn|Порождение грейдворфов|Regular|Black Forest\nGreydwarf_Frozen|Frozen greydwarf|Ледяной грейдворф|Regular|Deep North\nGreydwarf_Shaman_Frozen|Frozen greydwarf shaman|Ледяной грейдворф-шаман|Regular|Deep North\nTroll|Troll|Тролль|Regular|Black Forest\nTrollFrost|Gammeltroll|Гаммельтролль|Regular|Deep North\nTroll_sleeping|Sleeping troll|Спящий тролль|Regular|Deep North\nSkeleton|Skeleton|Скелет|Regular|Black Forest;Swamp;Mountains\nSkeleton_NoArcher|Skeleton|Скелет|Regular|Black Forest;Swamp;Mountains\nSkeleton_Poison|Poison skeleton|Ядовитый скелет|Regular|Swamp\nSkeleton_Meadows|Meadows skeleton|Скелет лугов|Regular|Deep North\nSkeleton_Meadows_noarcher|Meadows skeleton|Скелет лугов|Regular|Deep North\nSkeleton_Mountains|Mountain skeleton|Горный скелет|Regular|Deep North\nSkeleton_Mountains_noarcher|Mountain skeleton|Горный скелет|Regular|Deep North\nSkeleton_Swamps|Swamp skeleton|Болотный скелет|Regular|Deep North\nSkeleton_Swamps_noarcher|Swamp skeleton|Болотный скелет|Regular|Deep North\nSkeleton_aspect|Skeleton aspect|Аспект скелета|Regular|Deep North\nDraugr|Draugr|Драугр|Regular|Swamp\nDraugr_Elite|Draugr Elite|Драугр-элита|Regular|Swamp\nDraugr_Ranged|Draugr Archer|Драугр-лучник|Regular|Swamp\nDraugr_Ranged_down|Draugr Archer (down)|Драугр-лучник (лежит)|Regular|Swamp\nDraugr_Elite_sleeping|Sleeping draugr elite|Спящий драугр-элита|Regular|Deep North\nDraugr_Ranged_sleeping|Sleeping draugr archer|Спящий драугр-лучник|Regular|Deep North\nDraugr_sleeping|Sleeping draugr|Спящий драугр|Regular|Deep North\nBlob|Blob|Сгустень|Regular|Swamp\nBlobElite|Blob elite|Большой сгустень|Regular|Swamp\nBlobTar|Tar blob|Дегтевой сгустень|Regular|Plains\nBlobMork|Shapeless Pulp|Бесформенная слизь|Regular|Deep North\nBlobMorkMini|Tiny Pulp|Крошечная слизь|Regular|Deep North\nBlobAspect|Blob aspect|Аспект сгустня|Regular|Deep North\nLeech|Leech|Пиявка|Regular|Swamp\nWraith|Wraith|Призрак|Regular|Swamp\nGhost|Ghost|Призрак|Regular|Black Forest\nGhost_old|Old ghost|Старый призрак|Regular|Deep North\nGhost_sleeping|Sleeping ghost|Спящий призрак|Regular|Deep North\nGhost_Void|Void ghost|Пустотный призрак|Regular|Deep North\nAbomination|Abomination|Мерзость|Regular|Swamp\nSurtling|Surtling|Суртлинг|Regular|Swamp;Ashlands\nWolf|Wolf|Волк|Regular|Mountains\nWolf_cub|Wolf cub|Волчонок|Regular|Mountains\nWolf_spiritcaller|Spirit-caller wolf|Волк призывателя духов|Regular|Deep North\nFenring|Fenring|Фенринг|Regular|Mountains\nFenring_Cultist|Fenring Cultist|Фенринг-культист|Regular|Mountains\nHatchling|Drake|Дракончик|Regular|Mountains\nStoneGolem|Stone Golem|Каменный голем|Regular|Mountains\nUlv|Ulv|Ульв|Regular|Mountains\nBat|Bat|Летучая мышь|Regular|Mountains\nBear|Bear|Медведь|Regular|Deep North\nCultist|Cultist|Культист|Regular|Mountains\nSerpent|Serpent|Морской змей|Regular|Ocean\nDeathsquito|Deathsquito|Смертожал|Regular|Plains\nLox|Lox|Локс|Regular|Plains\nGoblin|Fuling|Фулинг|Regular|Plains\nGoblinArcher|Fuling Archer|Фулинг-лучник|Regular|Plains\nGoblinShaman|Fuling Shaman|Фулинг-шаман|Regular|Plains\nGoblinBrute|Fuling Berserker|Фулинг-берсерк|Regular|Plains\nAsksvin|Asksvin|Асксвин|Regular|Ashlands\nAsksvin_cub|Asksvin calf|Детёныш асксвина|Regular|Ashlands\nMorgen|Morgen|Морген|Regular|Ashlands\nMorgen_Naked|Morgen (unarmored)|Морген без брони|Regular|Ashlands\nFallenValkyrie|Charred Valkyrie|Обугленная валькирия|Regular|Ashlands\nCharred_Twitcher|Charred Twitcher|Обугленный прыгун|Regular|Ashlands\nCharred_Melee|Charred Warrior|Обугленный воин|Regular|Ashlands\nCharred_Archer|Charred Marksman|Обугленный стрелок|Regular|Ashlands\nCharred_Mage|Charred Mage|Обугленный маг|Regular|Ashlands\nVolture|Volture|Вольтур|Regular|Ashlands\nTick|Tick|Клещ|Regular|Mistlands\nSeeker|Seeker|Искатель|Regular|Mistlands\nSeekerBrood|Seeker Brood|Выводок искателя|Regular|Mistlands\nSeekerBrute|Seeker Soldier|Искатель-солдат|Regular|Mistlands\nGjall|Gjall|Гьялль|Regular|Mistlands\nHare|Hare|Заяц|Regular|Mistlands\nDverger|Dvergr|Дверг|Regular|Mistlands\nDvergerMage|Dvergr Mage|Дверг-маг|Regular|Mistlands\nDvergerMageFire|Dvergr Fire Mage|Дверг-маг огня|Regular|Mistlands\nDvergerMageIce|Dvergr Frost Mage|Дверг-маг льда|Regular|Mistlands\nDvergerMageSupport|Dvergr Support Mage|Дверг-маг поддержки|Regular|Mistlands\nDvergerRogue|Dvergr Rogue|Дверг-разведчик|Regular|Mistlands\nChicken|Chicken|Курица|Regular|Any Biome\nHen|Hen|Курица-несушка|Regular|Any Biome\nFish1|Fish|Рыба|Regular|Rivers;Ocean\nFish2|Fish|Рыба|Regular|Rivers;Ocean\nFish3|Fish|Рыба|Regular|Ocean\nFish4_cave|Cave fish|Пещерная рыба|Regular|Mountain Caves\nCrow|Crow|Ворон|Regular|Any Biome\nAshCrow|Ash crow|Пепельный ворон|Regular|Ashlands\nGull|Gull|Чайка|Regular|Ocean;Meadows;Black Forest;Plains\nLeviathan|Leviathan|Левиафан|Regular|Ocean\nHugin|Hugin|Хугин|Regular|Any Biome\nMunin|Munin|Мунин|Regular|Mistlands;Ashlands\nOdin|Odin|Один|Regular|Any Biome\nValkyrie|Valkyrie|Валькирия|Regular|Any Biome\nHaldor|Haldor|Хальдор|Regular|Black Forest\nHildir|Hildir|Хильдир|Regular|Meadows\nBogWitch|The Bog Witch|Болотная ведьма|Regular|Swamp\nHalstein|Halstein|Хальштейн|Regular|Meadows\nBlub|Blåbær|Блубэр|Regular|Meadows\nHallon|Hallon|Халлон|Regular|Meadows\nBoar_spiritcaller|Spirit-caller boar|Кабан призывателя духов|Regular|Deep North\nMoose|Moose|Лось|Regular|Deep North\nMoose_calf|Moose calf|Лосёнок|Regular|Deep North\nMoose_spiritcaller|Spirit-caller moose|Лось призывателя духов|Regular|Deep North\nSeal|Seal|Тюлень|Regular|Deep North\nSeal_Pup|Seal pup|Детёныш тюленя|Regular|Deep North\nFrysling|Frysling|Фризлинг|Regular|Deep North\nFrostWisp|Frost Wisp|Ледяной дух|Regular|Deep North\nBat_Swamp|Swamp bat|Болотная летучая мышь|Regular|Swamp\nBarka|Barka|Барка|Regular|Deep North\nElaking|Elaking|Элакинг|Regular|Deep North\nElakingLantern|Elaking Lantern|Элакинг с фонарём|Regular|Deep North\nElakingMole|Eyeless One|Безглазый|Regular|Deep North\nFallenWarrior|Fallen Warrior|Павший воин|Regular|Deep North\nJotunWarrior|Krigen|Криген|Regular|Deep North\nJotunWarriorDualWield|Krigen (dual wield)|Криген с двумя оружиями|Regular|Deep North\nJotunWitch|Hexen|Хексен|Regular|Deep North\nShadowPerson|Shadow|Тень|Regular|Deep North\nTendril|Tendril|Усик|Regular|Deep North\nTendril_back|Back tendril|Задний усик|Regular|Deep North\nTentaRoot_wild|Wild tentaroot|Дикая тентакорень|Regular|Deep North\nWrithan|Writhan|Ритхан|Regular|Deep North\nGoblinDeepNorth|Deep North goblin|Гоблин Дальнего севера|Regular|Deep North\nDvergerDeepNorth|Imprisoned Dvergr|Пленённый дверг|Regular|Deep North\nBjorn_sleeping|Sleeping Bjorn|Спящий Бьёрн|Regular|Deep North\nBjorn_spiritcaller|Spirit-caller Bjorn|Бьёрн призывателя духов|Regular|Deep North\nAspect_Eikthyr|Aspect of the Lightning Stag|Аспект Эйктюра|Boss|Any Biome\nAspect_Elder|Aspect of the Living Forest|Аспект Древнего|Boss|Any Biome\nAspect_Bonemass|Aspect of the Twisted Soul|Аспект Массы костей|Boss|Any Biome\nAspect_Moder|Aspect of the Dragon Mother|Аспект Модер|Boss|Any Biome\nAspect_Yagluth|Aspect of the Writhing Dead|Аспект Яглута|Boss|Any Biome\nAspect_SeekerQueen|Aspect of the Crawling Matriarch|Аспект Королевы|Boss|Any Biome\nAspect_Fader|Aspect of the Emerald Flame|Аспект Прародителя|Boss|Any Biome\nAspect_TentaRoot|Aspect of the Tentaroot|Аспект тентакорня|Boss|Any Biome\n";

		private static readonly Dictionary<string, CreatureMetadata> Metadata = Build();

		private static Dictionary<string, CreatureMetadata> Build()
		{
			Dictionary<string, CreatureMetadata> dictionary = new Dictionary<string, CreatureMetadata>(StringComparer.OrdinalIgnoreCase);
			string[] array = "\nEikthyr|Eikthyr|Эйктюр|Boss|Meadows\ngd_king|The Elder|Древний|Boss|Black Forest\nBonemass|Bonemass|Масса костей|Boss|Swamp\nDragon|Moder|Модер|Boss|Mountains\nGoblinKing|Yagluth|Яглут|Boss|Plains\nSeekerQueen|The Queen|Королева|Boss|Mistlands\nFader|Fader|Прародитель|Boss|Ashlands\nFrozenKing|Kall Fimbulbringer|Калль Фимбульбрингер|Boss|Deep North\nFrozenKing_p2|Kall Fimbulbringer (phase 2)|Калль Фимбульбрингер (фаза 2)|Boss|Deep North\nFrozenKing_p3|Kall Fimbulbringer (phase 3)|Калль Фимбульбрингер (фаза 3)|Boss|Deep North\nKallFimbulbringer|Kall Fimbulbringer|Калль Фимбульбрингер|Boss|Deep North\nBrenna|Brenna|Бренна|Boss|Black Forest\nGeirrhafa|Geirrhafa|Гейрафа|Boss|Mountains\nZil|Zil|Зил|Boss|Mistlands\nThungr|Thungr|Тангр|Boss|Mistlands\nCharred_Melee_Dyrnwyn|Lord Reto|Владыка Рето|Boss|Ashlands\nBoar|Boar|Кабан|Regular|Meadows;Black Forest\nBoar_piggy|Boar piglet|Поросёнок кабана|Regular|Meadows;Black Forest\nDeer|Deer|Олень|Regular|Meadows;Black Forest\nDeer_White|White deer|Белый олень|Regular|Deep North\nNeck|Neck|Никс|Regular|Meadows\nGreyling|Greyling|Грейлинг|Regular|Meadows\nGreydwarf|Greydwarf|Грейдворф|Regular|Black Forest\nGreydwarf_Elite|Greydwarf Brute|Грейдворф-берсерк|Regular|Black Forest\nGreydwarf_Shaman|Greydwarf Shaman|Грейдворф-шаман|Regular|Black Forest\nGreydwarf_Spawn|Greydwarf nest spawn|Порождение грейдворфов|Regular|Black Forest\nGreydwarf_Frozen|Frozen greydwarf|Ледяной грейдворф|Regular|Deep North\nGreydwarf_Shaman_Frozen|Frozen greydwarf shaman|Ледяной грейдворф-шаман|Regular|Deep North\nTroll|Troll|Тролль|Regular|Black Forest\nTrollFrost|Gammeltroll|Гаммельтролль|Regular|Deep North\nTroll_sleeping|Sleeping troll|Спящий тролль|Regular|Deep North\nSkeleton|Skeleton|Скелет|Regular|Black Forest;Swamp;Mountains\nSkeleton_NoArcher|Skeleton|Скелет|Regular|Black Forest;Swamp;Mountains\nSkeleton_Poison|Poison skeleton|Ядовитый скелет|Regular|Swamp\nSkeleton_Meadows|Meadows skeleton|Скелет лугов|Regular|Deep North\nSkeleton_Meadows_noarcher|Meadows skeleton|Скелет лугов|Regular|Deep North\nSkeleton_Mountains|Mountain skeleton|Горный скелет|Regular|Deep North\nSkeleton_Mountains_noarcher|Mountain skeleton|Горный скелет|Regular|Deep North\nSkeleton_Swamps|Swamp skeleton|Болотный скелет|Regular|Deep North\nSkeleton_Swamps_noarcher|Swamp skeleton|Болотный скелет|Regular|Deep North\nSkeleton_aspect|Skeleton aspect|Аспект скелета|Regular|Deep North\nDraugr|Draugr|Драугр|Regular|Swamp\nDraugr_Elite|Draugr Elite|Драугр-элита|Regular|Swamp\nDraugr_Ranged|Draugr Archer|Драугр-лучник|Regular|Swamp\nDraugr_Ranged_down|Draugr Archer (down)|Драугр-лучник (лежит)|Regular|Swamp\nDraugr_Elite_sleeping|Sleeping draugr elite|Спящий драугр-элита|Regular|Deep North\nDraugr_Ranged_sleeping|Sleeping draugr archer|Спящий драугр-лучник|Regular|Deep North\nDraugr_sleeping|Sleeping draugr|Спящий драугр|Regular|Deep North\nBlob|Blob|Сгустень|Regular|Swamp\nBlobElite|Blob elite|Большой сгустень|Regular|Swamp\nBlobTar|Tar blob|Дегтевой сгустень|Regular|Plains\nBlobMork|Shapeless Pulp|Бесформенная слизь|Regular|Deep North\nBlobMorkMini|Tiny Pulp|Крошечная слизь|Regular|Deep North\nBlobAspect|Blob aspect|Аспект сгустня|Regular|Deep North\nLeech|Leech|Пиявка|Regular|Swamp\nWraith|Wraith|Призрак|Regular|Swamp\nGhost|Ghost|Призрак|Regular|Black Forest\nGhost_old|Old ghost|Старый призрак|Regular|Deep North\nGhost_sleeping|Sleeping ghost|Спящий призрак|Regular|Deep North\nGhost_Void|Void ghost|Пустотный призрак|Regular|Deep North\nAbomination|Abomination|Мерзость|Regular|Swamp\nSurtling|Surtling|Суртлинг|Regular|Swamp;Ashlands\nWolf|Wolf|Волк|Regular|Mountains\nWolf_cub|Wolf cub|Волчонок|Regular|Mountains\nWolf_spiritcaller|Spirit-caller wolf|Волк призывателя духов|Regular|Deep North\nFenring|Fenring|Фенринг|Regular|Mountains\nFenring_Cultist|Fenring Cultist|Фенринг-культист|Regular|Mountains\nHatchling|Drake|Дракончик|Regular|Mountains\nStoneGolem|Stone Golem|Каменный голем|Regular|Mountains\nUlv|Ulv|Ульв|Regular|Mountains\nBat|Bat|Летучая мышь|Regular|Mountains\nBear|Bear|Медведь|Regular|Deep North\nCultist|Cultist|Культист|Regular|Mountains\nSerpent|Serpent|Морской змей|Regular|Ocean\nDeathsquito|Deathsquito|Смертожал|Regular|Plains\nLox|Lox|Локс|Regular|Plains\nGoblin|Fuling|Фулинг|Regular|Plains\nGoblinArcher|Fuling Archer|Фулинг-лучник|Regular|Plains\nGoblinShaman|Fuling Shaman|Фулинг-шаман|Regular|Plains\nGoblinBrute|Fuling Berserker|Фулинг-берсерк|Regular|Plains\nAsksvin|Asksvin|Асксвин|Regular|Ashlands\nAsksvin_cub|Asksvin calf|Детёныш асксвина|Regular|Ashlands\nMorgen|Morgen|Морген|Regular|Ashlands\nMorgen_Naked|Morgen (unarmored)|Морген без брони|Regular|Ashlands\nFallenValkyrie|Charred Valkyrie|Обугленная валькирия|Regular|Ashlands\nCharred_Twitcher|Charred Twitcher|Обугленный прыгун|Regular|Ashlands\nCharred_Melee|Charred Warrior|Обугленный воин|Regular|Ashlands\nCharred_Archer|Charred Marksman|Обугленный стрелок|Regular|Ashlands\nCharred_Mage|Charred Mage|Обугленный маг|Regular|Ashlands\nVolture|Volture|Вольтур|Regular|Ashlands\nTick|Tick|Клещ|Regular|Mistlands\nSeeker|Seeker|Искатель|Regular|Mistlands\nSeekerBrood|Seeker Brood|Выводок искателя|Regular|Mistlands\nSeekerBrute|Seeker Soldier|Искатель-солдат|Regular|Mistlands\nGjall|Gjall|Гьялль|Regular|Mistlands\nHare|Hare|Заяц|Regular|Mistlands\nDverger|Dvergr|Дверг|Regular|Mistlands\nDvergerMage|Dvergr Mage|Дверг-маг|Regular|Mistlands\nDvergerMageFire|Dvergr Fire Mage|Дверг-маг огня|Regular|Mistlands\nDvergerMageIce|Dvergr Frost Mage|Дверг-маг льда|Regular|Mistlands\nDvergerMageSupport|Dvergr Support Mage|Дверг-маг поддержки|Regular|Mistlands\nDvergerRogue|Dvergr Rogue|Дверг-разведчик|Regular|Mistlands\nChicken|Chicken|Курица|Regular|Any Biome\nHen|Hen|Курица-несушка|Regular|Any Biome\nFish1|Fish|Рыба|Regular|Rivers;Ocean\nFish2|Fish|Рыба|Regular|Rivers;Ocean\nFish3|Fish|Рыба|Regular|Ocean\nFish4_cave|Cave fish|Пещерная рыба|Regular|Mountain Caves\nCrow|Crow|Ворон|Regular|Any Biome\nAshCrow|Ash crow|Пепельный ворон|Regular|Ashlands\nGull|Gull|Чайка|Regular|Ocean;Meadows;Black Forest;Plains\nLeviathan|Leviathan|Левиафан|Regular|Ocean\nHugin|Hugin|Хугин|Regular|Any Biome\nMunin|Munin|Мунин|Regular|Mistlands;Ashlands\nOdin|Odin|Один|Regular|Any Biome\nValkyrie|Valkyrie|Валькирия|Regular|Any Biome\nHaldor|Haldor|Хальдор|Regular|Black Forest\nHildir|Hildir|Хильдир|Regular|Meadows\nBogWitch|The Bog Witch|Болотная ведьма|Regular|Swamp\nHalstein|Halstein|Хальштейн|Regular|Meadows\nBlub|Blåbær|Блубэр|Regular|Meadows\nHallon|Hallon|Халлон|Regular|Meadows\nBoar_spiritcaller|Spirit-caller boar|Кабан призывателя духов|Regular|Deep North\nMoose|Moose|Лось|Regular|Deep North\nMoose_calf|Moose calf|Лосёнок|Regular|Deep North\nMoose_spiritcaller|Spirit-caller moose|Лось призывателя духов|Regular|Deep North\nSeal|Seal|Тюлень|Regular|Deep North\nSeal_Pup|Seal pup|Детёныш тюленя|Regular|Deep North\nFrysling|Frysling|Фризлинг|Regular|Deep North\nFrostWisp|Frost Wisp|Ледяной дух|Regular|Deep North\nBat_Swamp|Swamp bat|Болотная летучая мышь|Regular|Swamp\nBarka|Barka|Барка|Regular|Deep North\nElaking|Elaking|Элакинг|Regular|Deep North\nElakingLantern|Elaking Lantern|Элакинг с фонарём|Regular|Deep North\nElakingMole|Eyeless One|Безглазый|Regular|Deep North\nFallenWarrior|Fallen Warrior|Павший воин|Regular|Deep North\nJotunWarrior|Krigen|Криген|Regular|Deep North\nJotunWarriorDualWield|Krigen (dual wield)|Криген с двумя оружиями|Regular|Deep North\nJotunWitch|Hexen|Хексен|Regular|Deep North\nShadowPerson|Shadow|Тень|Regular|Deep North\nTendril|Tendril|Усик|Regular|Deep North\nTendril_back|Back tendril|Задний усик|Regular|Deep North\nTentaRoot_wild|Wild tentaroot|Дикая тентакорень|Regular|Deep North\nWrithan|Writhan|Ритхан|Regular|Deep North\nGoblinDeepNorth|Deep North goblin|Гоблин Дальнего севера|Regular|Deep North\nDvergerDeepNorth|Imprisoned Dvergr|Пленённый дверг|Regular|Deep North\nBjorn_sleeping|Sleeping Bjorn|Спящий Бьёрн|Regular|Deep North\nBjorn_spiritcaller|Spirit-caller Bjorn|Бьёрн призывателя духов|Regular|Deep North\nAspect_Eikthyr|Aspect of the Lightning Stag|Аспект Эйктюра|Boss|Any Biome\nAspect_Elder|Aspect of the Living Forest|Аспект Древнего|Boss|Any Biome\nAspect_Bonemass|Aspect of the Twisted Soul|Аспект Массы костей|Boss|Any Biome\nAspect_Moder|Aspect of the Dragon Mother|Аспект Модер|Boss|Any Biome\nAspect_Yagluth|Aspect of the Writhing Dead|Аспект Яглута|Boss|Any Biome\nAspect_SeekerQueen|Aspect of the Crawling Matriarch|Аспект Королевы|Boss|Any Biome\nAspect_Fader|Aspect of the Emerald Flame|Аспект Прародителя|Boss|Any Biome\nAspect_TentaRoot|Aspect of the Tentaroot|Аспект тентакорня|Boss|Any Biome\n".Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length == 0 || text.StartsWith("#", StringComparison.Ordinal))
				{
					continue;
				}
				string[] array2 = text.Split('|');
				if (array2.Length >= 5)
				{
					CreatureCategory category = CreatureCategory.Regular;
					if (array2[3].Equals("Boss", StringComparison.OrdinalIgnoreCase))
					{
						category = CreatureCategory.Boss;
					}
					dictionary[array2[0].Trim()] = new CreatureMetadata(array2[1].Trim(), array2[2].Trim(), category, array2[4].Trim());
				}
			}
			return dictionary;
		}

		public static bool TryGet(string prefabName, out CreatureMetadata metadata)
		{
			return Metadata.TryGetValue(prefabName ?? string.Empty, out metadata);
		}
	}
	internal sealed class FavoriteIds
	{
		private const int MaxEntries = 1000;

		private const int MaxIdLength = 256;

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

		public int Count => _ids.Count;

		public bool Contains(string id)
		{
			if (!string.IsNullOrWhiteSpace(id))
			{
				return _ids.Contains(id);
			}
			return false;
		}

		public bool Toggle(string id)
		{
			if (!IsValidId(id))
			{
				return false;
			}
			if (_ids.Remove(id))
			{
				return false;
			}
			if (_ids.Count >= 1000)
			{
				return false;
			}
			_ids.Add(id);
			return true;
		}

		public string ToEncodedString()
		{
			List<string> list = new List<string>(_ids);
			list.Sort(StringComparer.OrdinalIgnoreCase);
			List<string> list2 = new List<string>(list.Count);
			for (int i = 0; i < list.Count; i++)
			{
				list2.Add(Convert.ToBase64String(Encoding.UTF8.GetBytes(list[i])));
			}
			return string.Join(",", list2.ToArray());
		}

		public static FavoriteIds FromEncodedString(string data)
		{
			FavoriteIds favoriteIds = new FavoriteIds();
			if (string.IsNullOrWhiteSpace(data))
			{
				return favoriteIds;
			}
			string[] array = data.Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				if (favoriteIds._ids.Count >= 1000)
				{
					break;
				}
				try
				{
					string text = Encoding.UTF8.GetString(Convert.FromBase64String(array[i]));
					if (IsValidId(text))
					{
						favoriteIds._ids.Add(text);
					}
				}
				catch (FormatException)
				{
				}
			}
			return favoriteIds;
		}

		private static bool IsValidId(string id)
		{
			if (string.IsNullOrWhiteSpace(id) || id.Length > 256)
			{
				return false;
			}
			for (int i = 0; i < id.Length; i++)
			{
				if (char.IsControl(id[i]))
				{
					return false;
				}
			}
			return true;
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("com.supernova.valheimspawner", "Nexus Admin Tools", "1.8.7")]
	public sealed class ValheimSpawnerPlugin : BaseUnityPlugin
	{
		private sealed class OutgoingHitState
		{
			internal HitData Hit;

			internal DamageTypes Original;
		}

		private enum AdminAction
		{
			Poll,
			Local,
			Time,
			Spawn,
			Cleanup,
			Weather,
			Raids,
			Locations,
			Teleport,
			Return,
			Audit,
			AddLocation,
			RenameLocation,
			DeleteLocation,
			PlayerRoster,
			TeleportToPlayer,
			TeleportPlayerHere,
			KickPlayer,
			BanPlayer,
			UnbanPlayer,
			FreezePlayer,
			ClearDroppedItems,
			PlayerReturn,
			PlayerReturnDismiss
		}

		private sealed class PeerState
		{
			internal readonly AdminRequestGate Gate = new AdminRequestGate();

			internal int Modes;

			internal float Damage;

			internal float Xp;

			internal float LastSeen;
		}

		private sealed class PendingAction
		{
			internal ZRpc Rpc;

			internal float Until;

			internal AdminAction Kind;

			internal Action<ZPackage> Callback;
		}

		private sealed class AdminOnlinePlayer
		{
			internal long Uid;

			internal string Name;

			internal bool Frozen;
		}

		private sealed class AdminBanEntry
		{
			internal string Identifier;

			internal long ExpiresAt;
		}

		private sealed class SavedTeleportPoint
		{
			internal string Id;

			internal string Name;

			internal Vector3 Position;
		}

		private sealed class NexusWorldLocation
		{
			internal string Key;

			internal string Name;

			internal string NameOverride;

			internal string Prefab;

			internal Vector3 Position;

			internal bool IsCustom;
		}

		private sealed class InventoryAddResult
		{
			public int Added;

			public string Reason = string.Empty;
		}

		private enum ItemCategory
		{
			Weapons,
			Armor,
			Food,
			Materials,
			Other
		}

		private sealed class ItemEntry
		{
			public readonly GameObject Prefab;

			public readonly string PrefabName;

			public readonly string DisplayName;

			public readonly string EnglishName;

			public readonly string LocalizedName;

			public readonly string ItemTypeLabel;

			public readonly ItemCategory Category;

			public readonly int MaxQuality;

			public readonly int MaxStack;

			public readonly bool UsesDurability;

			public readonly Texture2D IconTexture;

			public readonly Rect IconUv;

			public ItemEntry(GameObject prefab, string prefabName, string englishName, string localizedName, string itemTypeLabel, ItemCategory category, int maxQuality, int maxStack, bool usesDurability, Sprite icon)
			{
				//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
				//IL_011b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0120: Unknown result type (might be due to invalid IL or missing references)
				Prefab = prefab;
				PrefabName = prefabName ?? string.Empty;
				EnglishName = (string.IsNullOrWhiteSpace(englishName) ? HumanizePrefabName(PrefabName) : englishName);
				LocalizedName = (string.IsNullOrWhiteSpace(localizedName) ? EnglishName : localizedName);
				DisplayName = EnglishName;
				ItemTypeLabel = itemTypeLabel ?? string.Empty;
				Category = category;
				MaxQuality = Mathf.Clamp(maxQuality, 1, 10);
				MaxStack = Mathf.Clamp(maxStack, 1, 9999);
				UsesDurability = usesDurability;
				if (!((Object)(object)icon != (Object)null))
				{
					return;
				}
				try
				{
					Texture2D texture = icon.texture;
					if ((Object)(object)texture != (Object)null && ((Texture)texture).width > 0 && ((Texture)texture).height > 0)
					{
						Rect textureRect = icon.textureRect;
						IconTexture = texture;
						IconUv = new Rect(((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);
					}
				}
				catch (Exception)
				{
				}
			}
		}

		private sealed class CreatureEntry
		{
			public readonly GameObject Prefab;

			public readonly string PrefabName;

			public readonly string EnglishName;

			public readonly string RussianName;

			public readonly string LocalizedName;

			public readonly CreatureCategory Category;

			public readonly string[] Biomes;

			public string CategoryLabel
			{
				get
				{
					if (Category != CreatureCategory.Boss)
					{
						return "Regular";
					}
					return "Boss";
				}
			}

			public string BiomeLabel
			{
				get
				{
					if (Biomes != null && Biomes.Length != 0)
					{
						return string.Join(", ", Biomes);
					}
					return "Unknown";
				}
			}

			public CreatureEntry(GameObject prefab, string prefabName, string englishName, string russianName, string localizedName, CreatureCategory category, string[] biomes)
			{
				Prefab = prefab;
				PrefabName = prefabName ?? string.Empty;
				EnglishName = (string.IsNullOrWhiteSpace(englishName) ? PrefabName : englishName);
				RussianName = (string.IsNullOrWhiteSpace(russianName) ? PrefabName : russianName);
				LocalizedName = localizedName ?? string.Empty;
				Category = category;
				Biomes = biomes ?? new string[1] { "Unknown" };
			}
		}

		private bool _adminGhost;

		private bool _infiniteGuardianPower;

		private Player _preferencesPlayer;

		private Player _effectsPlayer;

		private string _preferencesScope;

		private ConfigEntry<int> _savedModes;

		private ConfigEntry<float> _savedDamage;

		private ConfigEntry<float> _savedXp;

		private ConfigEntry<float> _savedCarryWeight;

		private ConfigEntry<bool> _savedCarryWeightEnabled;

		private ConfigEntry<string> _savedSkill;

		private ConfigEntry<int> _savedSkillLevel;

		private ConfigEntry<int> _savedHour;

		private ConfigEntry<int> _savedMinute;

		private ConfigEntry<int> _savedTimedBanHours;

		private ConfigEntry<bool> _savedCleanupTamed;

		private ConfigEntry<bool> _savedCleanupBosses;

		private ConfigEntry<int> _savedAdminSection;

		private int _timeHour = 12;

		private int _timeMinute;

		private int _skillTarget = 100;

		private SkillType _skillChoice = (SkillType)1;

		private float _nextEffectsApply;

		private float _carryWeightTarget = 300f;

		private float _priorCarryWeight = 300f;

		private string _carryWeightInput = "300";

		private bool _carryWeightEnabled;

		private bool _effectsActive;

		private bool _priorFly;

		private bool _priorCreative;

		private bool _priorGhost;

		private int _lastLocalAuditedModes = -1;

		private float _lastLocalAuditedDamage = float.NaN;

		private float _lastLocalAuditedXp = float.NaN;

		private const string CustomItemNameKey = "com.supernova.valheimnexus.itemname.v1";

		private const string CustomItemDescriptionKey = "com.supernova.valheimnexus.itemdescription.v1";

		private ConfigEntry<string> _advancedDataConfig;

		private NexusAdvancedData _advanced = new NexusAdvancedData();

		private string _itemCustomName = string.Empty;

		private string _itemCustomDescription = string.Empty;

		private string _advancedDataPath;

		private bool _advancedSaveBlocked;

		private bool _advancedSaveError;

		private string _newKitName = string.Empty;

		private int _activeKitIndex;

		private int _doctorItemIndex;

		private string _doctorSearch = string.Empty;

		private string _doctorReport = string.Empty;

		private string _radarReport = string.Empty;

		private Vector2 _advancedScroll;

		private bool _showSpawnPreview;

		private const string CleanupOwnerRpc = "SN_Nexus_CleanupOwner185";

		private const int MaxSpawnMarkerCount = 12;

		private readonly List<GameObject> _spawnMarkerGroups = new List<GameObject>();

		private GameObject _spawnMarkerRoot;

		private Material _spawnMarkerMaterial;

		private float _nextMarkerRefresh;

		private Vector2 _adminScroll;

		private GUIStyle _hudSectionHeader;

		private NexusKit _workshopKit;

		private int _editingKitPart = -1;

		private bool _showKitRename;

		private string _kitRenameInput = string.Empty;

		private string _kitPartCountInput = "1";

		private string _kitPartQualityInput = "1";

		private string _kitPartNameInput = string.Empty;

		private string _kitPartDescriptionInput = string.Empty;

		private string _historyFilter = string.Empty;

		private int _historyKindFilter;

		private static readonly Vector2 HudTopLeft = new Vector2(0f, 1f);

		private static readonly Color HudGold = new Color(1f, 0.78f, 0.36f);

		private static AudioClip _nativeClickClip;

		private GameObject _nativeHud;

		private GameObject _nativeBody;

		private Canvas _nativeCanvas;

		private Text _nativeStatus;

		private Text _nativeClock;

		private RectTransform _nativeRect;

		private ScrollRect _nativeList;

		private readonly List<Action> _hudDynamic = new List<Action>();

		private bool _hudDirty = true;

		private bool _listDirty = true;

		private bool _legacyToolsOpen;

		private bool _nativeInputBlocked;

		private int _nativeMode;

		private int _adminSection;

		private int _catalogPage;

		private int _catalogTotal;

		private int _catalogSelectionKind;

		private int _toolsSection = 1;

		private string _globalSearch = string.Empty;

		private bool _globalFavoritesOnly;

		private float _nextHudRefresh;

		private string _nativeListKey;

		private float _catalogScrollPosition = 1f;

		private int _skillPage;

		private int _locationPage;

		private int _locationTotal;

		private int _locationSelection;

		private int _loadedLocationPage = -1;

		private bool _playerReturnAvailable;

		private string _newLocationName = string.Empty;

		private string _locationRenameInput = string.Empty;

		private int _auditPage;

		private int _auditTotal;

		private int _auditSelection;

		private int _loadedAuditPage = -1;

		private List<NexusWorldLocation> _adminLocations = new List<NexusWorldLocation>();

		private List<string> _adminAuditPage = new List<string>();

		private bool _returnAvailable;

		private const float HudWidth = 1100f;

		private const float HudHeight = 860f;

		private const float BodyWidth = 1052f;

		private int _historyPage;

		private int _reportPage;

		private const string RequestRpc = "SN_Nexus_Request185";

		private const string ReplyRpc = "SN_Nexus_Reply185";

		private const string TargetCommandRpc = "SN_Nexus_Target185";

		private readonly Dictionary<ZRpc, PeerState> _peerStates = new Dictionary<ZRpc, PeerState>();

		private readonly Dictionary<int, PendingAction> _pendingActions = new Dictionary<int, PendingAction>();

		private readonly HashSet<ZDOID> _networkGhosts = new HashSet<ZDOID>();

		private readonly HashSet<ZDOID> _networkFrozenCharacters = new HashSet<ZDOID>();

		private ZNet _networkSession;

		private ZRpc _serverConnection;

		private float _nextNetworkPoll;

		private float _accessUntil;

		private float _ghostSnapshotUntil;

		private int _nextRequestId;

		private bool _executingApprovedLocal;

		private const int AdminPlayerPageSize = 6;

		private const int MaxTimedBanHours = 8760;

		private const byte TargetCommandTeleport = 1;

		private const byte TargetCommandFreeze = 2;

		private const byte TargetCommandUnfreeze = 3;

		private readonly HashSet<long> _serverFrozenPlayers = new HashSet<long>();

		private readonly Dictionary<string, long> _timedBans = new Dictionary<string, long>(StringComparer.Ordinal);

		private ConfigEntry<string> _savedTimedBanEntries;

		private string _moderationScope;

		private float _nextTimedBanCheck;

		private int _onlinePlayerPage;

		private int _bannedPlayerPage;

		private int _onlinePlayerTotal;

		private int _bannedPlayerTotal;

		private int _timedBanHours = 24;

		private int _loadedOnlinePlayerPage = -1;

		private int _loadedBannedPlayerPage = -1;

		private long _selectedAdminPlayerUid;

		private string _selectedAdminPlayerName = string.Empty;

		private string _selectedBannedIdentifier = string.Empty;

		private bool _targetLocalFrozen;

		private bool _selectedAdminPlayerFrozen;

		private List<AdminOnlinePlayer> _adminOnlinePlayers = new List<AdminOnlinePlayer>();

		private List<AdminBanEntry> _adminBannedPlayers = new List<AdminBanEntry>();

		private GameObject _playerReturnPrompt;

		private const string TrashSaveHeader = "NEXUS-ADMIN-TRASH-1";

		private const int MaxTrashSaveBytes = 524288;

		private ItemData _trashedItem;

		private Vector2i _trashOriginalPosition;

		private string _trashScope;

		private string _trashLoadedScope;

		private Button _trashDropTarget;

		private Button _trashRestoreButton;

		private Image _trashItemIcon;

		private Text _trashItemLabel;

		private const int LocationPageSize = 9;

		private const int AuditPageSize = 8;

		private const int AuditMaxEntries = 1000;

		private const long AuditMaxBytes = 1048576L;

		private const int MaxSavedTeleportPoints = 100;

		private const int MaxLocationNameLength = 48;

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

		private readonly Dictionary<long, Vector3> _adminReturnPositions = new Dictionary<long, Vector3>();

		private ConfigEntry<bool> _savedRaidSuppression;

		private ConfigEntry<string> _savedForcedWeather;

		private ConfigEntry<string> _savedTeleportLocations;

		private string _serverStateScope;

		private string _auditFilePath;

		private string _lastAppliedWeather;

		private string _serverForcedWeather = string.Empty;

		private bool _serverRaidsDisabled;

		private bool _auditLoaded;

		private readonly List<SavedTeleportPoint> _customTeleportPoints = new List<SavedTeleportPoint>();

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

		public const string PluginGuid = "com.supernova.valheimspawner";

		public const string PluginName = "Nexus Admin Tools";

		public const string PluginVersion = "1.8.7";

		private const int ExtendedNonWeaponQualityCap = 10;

		private const int MaxUnstackableItemsPerAction = 100;

		private const int MaxStackBatchesPerAction = 200;

		private ConfigEntry<KeyCode> _toggleKey;

		private ConfigEntry<KeyCode> _spawnFrontKey;

		private ConfigEntry<KeyCode> _spawnAimKey;

		private ConfigEntry<int> _defaultCount;

		private ConfigEntry<int> _defaultLevel;

		private ConfigEntry<string> _languageSetting;

		private ConfigEntry<float> _killRadius;

		private ConfigEntry<bool> _spawnMarkerConfig;

		private ConfigEntry<bool> _spawnMarkerCrosshairConfig;

		private ConfigEntry<string> _favoriteItemsConfig;

		private ConfigEntry<string> _favoriteCreaturesConfig;

		private ConfigEntry<float> _hudPositionXConfig;

		private ConfigEntry<float> _hudPositionYConfig;

		private FavoriteIds _favoriteItems = new FavoriteIds();

		private FavoriteIds _favoriteCreatures = new FavoriteIds();

		private bool _itemFavoritesOnly;

		private bool _creatureFavoritesOnly;

		private bool _searchAllItems;

		private Harmony _harmony;

		private static ValheimSpawnerPlugin _activeInstance;

		private float _suppressInputUntil;

		private readonly List<CreatureEntry> _entries = new List<CreatureEntry>();

		private readonly List<CreatureEntry> _filtered = new List<CreatureEntry>();

		private readonly List<ItemEntry> _itemEntries = new List<ItemEntry>();

		private readonly List<ItemEntry> _filteredItems = new List<ItemEntry>();

		private readonly string[] _biomeOptions = new string[14]
		{
			"All Biomes", "Meadows", "Black Forest", "Swamp", "Mountains", "Plains", "Ocean", "Rivers", "Mistlands", "Ashlands",
			"Deep North", "Mountain Caves", "Any Biome", "Unknown"
		};

		private static readonly Dictionary<string, string> RussianItemNames = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			{ "AxeStone", "Каменный топор" },
			{ "AxeFlint", "Кремнёвый топор" },
			{ "AxeBronze", "Бронзовый топор" },
			{ "AxeIron", "Железный топор" },
			{ "AxeBlackMetal", "Чернометаллический топор" },
			{ "AxeJotunBane", "Топор йотунов" },
			{ "AxeBer", "Бер" },
			{ "AtgeirBronze", "Бронзовая алебарда" },
			{ "AtgeirIron", "Железная алебарда" },
			{ "AtgeirBlackmetal", "Чернометаллическая алебарда" },
			{ "AtgeirHimminAfl", "Химмин-Афль" },
			{ "Battleaxe", "Боевой топор" },
			{ "BattleaxeCrystal", "Кристальный боевой топор" },
			{ "BattleaxeBloodthirst", "Жажда крови" },
			{ "Bow", "Лук" },
			{ "BowFineWood", "Лук из ценной древесины" },
			{ "BowHuntsman", "Лук охотника" },
			{ "BowDraugrFang", "Клык драугра" },
			{ "BowSpineSnap", "Хребтолом" },
			{ "CrossbowArbalest", "Арбалет" },
			{ "KnifeFlint", "Кремнёвый нож" },
			{ "KnifeCopper", "Медный нож" },
			{ "KnifeSilver", "Серебряный нож" },
			{ "KnifeBlackMetal", "Чернометаллический нож" },
			{ "KnifeSkollAndHati", "Сколль и Хати" },
			{ "KnifeButcher", "Нож мясника" },
			{ "MaceBronze", "Бронзовая булава" },
			{ "MaceIron", "Железная булава" },
			{ "MaceSilver", "Серебряная булава" },
			{ "MaceNeedle", "Игла" },
			{ "MacePorcupine", "Дикобраз" },
			{ "MaceDemolisher", "Разрушитель" },
			{ "SledgeStagbreaker", "Оленебой" },
			{ "SledgeIron", "Железная кувалда" },
			{ "SpearFlint", "Кремнёвое копьё" },
			{ "SpearBronze", "Бронзовое копьё" },
			{ "SpearElderbark", "Древеснокорое копьё" },
			{ "SpearWolfFang", "Копьё с волчьим клыком" },
			{ "SpearCarapace", "Карапасное копьё" },
			{ "SpearChitin", "Гарпун бездны" },
			{ "SwordBronze", "Бронзовый меч" },
			{ "SwordIron", "Железный меч" },
			{ "SwordSilver", "Серебряный меч" },
			{ "SwordBlackmetal", "Чернометаллический меч" },
			{ "SwordMistwalker", "Туманоход" },
			{ "SwordNiedhogg", "Нидхёгг" },
			{ "SwordKrom", "Кром" },
			{ "SwordDyrnwyn", "Дюрнвин" },
			{ "StaffFireball", "Посох огненного шара" },
			{ "StaffIceShards", "Посох ледяных осколков" },
			{ "StaffShield", "Посох защиты" },
			{ "StaffSkeleton", "Посох скелетов" },
			{ "StaffGreenRoots", "Посох зелёных корней" },
			{ "StaffLightning", "Посох молнии" },
			{ "Torch", "Факел" },
			{ "ArrowWood", "Деревянная стрела" },
			{ "ArrowFire", "Огненная стрела" },
			{ "ArrowFlint", "Кремнёвая стрела" },
			{ "ArrowBronze", "Бронзовая стрела" },
			{ "ArrowIron", "Железная стрела" },
			{ "ArrowSilver", "Серебряная стрела" },
			{ "ArrowObsidian", "Обсидиановая стрела" },
			{ "ArrowNeedle", "Игла" },
			{ "ArrowCarapace", "Карапасная стрела" },
			{ "ArrowCharred", "Обугленная стрела" },
			{ "ArrowFrost", "Морозная стрела" },
			{ "ArrowPoison", "Отравленная стрела" },
			{ "BoltWood", "Деревянный болт" },
			{ "BoltBone", "Костяной болт" },
			{ "BoltIron", "Железный болт" },
			{ "BoltBlackmetal", "Чернометаллический болт" },
			{ "BoltCarapace", "Карапасный болт" },
			{ "BoltCharred", "Обугленный болт" },
			{ "ShieldWood", "Деревянный щит" },
			{ "ShieldWoodTower", "Деревянный башенный щит" },
			{ "ShieldBoneTower", "Костяной башенный щит" },
			{ "ShieldBronzeBuckler", "Бронзовый круглый щит" },
			{ "ShieldIronSquare", "Железный щит" },
			{ "ShieldBanded", "Полосатый щит" },
			{ "ShieldSerpentscale", "Щит из чешуи змея" },
			{ "ShieldBlackmetal", "Чернометаллический щит" },
			{ "ShieldBlackmetalTower", "Чернометаллический башенный щит" },
			{ "ShieldCarapace", "Карапасный щит" },
			{ "ShieldCarapaceBuckler", "Карапасный круглый щит" },
			{ "ShieldFlametal", "Пламеннометаллический щит" }
		};

		private Rect _windowRect = new Rect(30f, 35f, 980f, 820f);

		private Vector2 _listScroll;

		private Vector2 _itemListScroll;

		private int _mainTab;

		private int _itemCount = 1;

		private string _itemCountInput = "1";

		private int _itemQuality = 1;

		private bool _spawnTamed;

		private bool _infiniteHealth;

		private bool _infiniteStamina;

		private bool _infiniteEitr;

		private bool _adminFly;

		private bool _adminCreative;

		private bool _adminHotkeys;

		private bool _infiniteAdrenaline;

		private bool _superDamage;

		private float _superDamageMultiplier = 5f;

		private float _nextAdrenalineRefresh;

		private bool _showCreatureSafety;

		private bool _showItemTechnicalDetails;

		private bool _showItemCustomFields = true;

		private bool _outgoingDamageHookAvailable;

		private bool _adrenalineHookAvailable;

		private float _nextAdminRefresh;

		private float _skillXpMultiplier = 1f;

		private string _skillXpInput = "1";

		private string _adminToast = string.Empty;

		private float _adminToastUntil;

		private string _itemSearch = string.Empty;

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

		private bool _isRussian;

		private bool _itemCatalogReady;

		private object _objectDbInstance;

		private object _lastObjectDb;

		private bool _isOpen;

		private bool _inventoryVisibleLastFrame;

		private bool _searchHasFocus;

		private bool _nameHasFocus;

		private bool _killIncludeTamed;

		private bool _killIncludeBosses;

		private bool _cursorStateStored;

		private bool _oldCursorVisible;

		private CursorLockMode _oldCursorLockState;

		private bool _catalogReady;

		private float _nextRefresh;

		private string _search = string.Empty;

		private string _customName = string.Empty;

		private string _status = "Enter a world to load the catalogue.";

		private int _categoryFilter;

		private int _biomeFilter;

		private int _count = 1;

		private int _level = 1;

		private CreatureEntry _selected;

		private ItemEntry _selectedItem;

		private Type _objectDbType;

		private Type _itemDropType;

		private Type _characterType;

		private Type _zNetSceneType;

		private Type _zNetType;

		private Type _playerType;

		private Type _zNetViewType;

		private Component _playerComponent;

		private object _zNetSceneInstance;

		private object _lastCatalogScene;

		private object _zNetInstance;

		private bool AdminContextMatches
		{
			get
			{
				if ((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)ZNet.instance != (Object)null && Player.m_localPlayer == _preferencesPlayer)
				{
					return _preferencesScope == AdminScope();
				}
				return false;
			}
		}

		private int DesiredModeBits => (int)((_infiniteHealth ? 1u : 0u) | (uint)(_infiniteStamina ? 2 : 0) | (uint)(_infiniteEitr ? 4 : 0) | (uint)(_infiniteAdrenaline ? 8 : 0) | (uint)(_superDamage ? 16 : 0) | (uint)(_adminFly ? 32 : 0) | (uint)(_adminCreative ? 64 : 0) | (uint)(_adminGhost ? 128 : 0) | (uint)(_adminHotkeys ? 256 : 0)) | (_infiniteGuardianPower ? 512 : 0);

		private string CatalogueViewKey => _mainTab + ":" + _catalogPage + ":" + _search + ":" + _itemSearch + ":" + _globalSearch + ":" + _categoryFilter + ":" + _biomeFilter + ":" + _searchAllItems + ":" + _globalFavoritesOnly + ":" + _creatureFavoritesOnly + ":" + _itemFavoritesOnly;

		private bool HasAdminAccess
		{
			get
			{
				if ((Object)(object)ZNet.instance != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null)
				{
					if (!ZNet.instance.IsServer())
					{
						if (_serverConnection != null && Time.unscaledTime < _accessUntil)
						{
							return ZNet.instance.GetServerPeer()?.m_rpc == _serverConnection;
						}
						return false;
					}
					return true;
				}
				return false;
			}
		}

		private bool TrashPageActive
		{
			get
			{
				if (_isOpen && !_legacyToolsOpen && _nativeMode == 1)
				{
					return _adminSection == 3;
				}
				return false;
			}
		}

		private string AdminScope()
		{
			return "Admin." + ZNet.instance.GetWorldUID().ToString("X16") + "." + Player.m_localPlayer.GetPlayerID().ToString("X16");
		}

		private void ResetAdminContext()
		{
			_preferencesPlayer = null;
			_preferencesScope = null;
			_savedModes = null;
			_infiniteHealth = (_infiniteStamina = (_infiniteEitr = (_infiniteAdrenaline = (_superDamage = false))));
			_adminFly = (_adminCreative = (_adminGhost = (_adminHotkeys = false)));
			_infiniteGuardianPower = false;
			_superDamageMultiplier = 5f;
			_skillXpMultiplier = 1f;
			_lastLocalAuditedModes = -1;
		}

		private void TickAdminPreferences()
		{
			//IL_0403: Unknown result type (might be due to invalid IL or missing references)
			//IL_040c: Unknown result type (might be due to invalid IL or missing references)
			//IL_040d: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!HasAdminAccess || (Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead())
			{
				SuspendAdminEffects();
				return;
			}
			string text = AdminScope();
			if (text != _preferencesScope || localPlayer != _preferencesPlayer)
			{
				SuspendAdminEffects();
				_preferencesPlayer = localPlayer;
				_preferencesScope = text;
				_savedModes = ((BaseUnityPlugin)this).Config.Bind<int>(text, "Modes", 0, "Remembered admin choices for this world and character. Permissions are rechecked on every connection.");
				_savedDamage = ((BaseUnityPlugin)this).Config.Bind<float>(text, "DamageMultiplier", 5f, (ConfigDescription)null);
				_savedXp = ((BaseUnityPlugin)this).Config.Bind<float>(text, "SkillXpMultiplier", 1f, (ConfigDescription)null);
				_savedCarryWeight = ((BaseUnityPlugin)this).Config.Bind<float>(text, "CarryWeight", 300f, "Personal base carry weight configured by Nexus.");
				_savedCarryWeightEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>(text, "CarryWeightEnabled", false, "Apply the personal carry weight override while administrator access is available.");
				_savedSkill = ((BaseUnityPlugin)this).Config.Bind<string>(text, "SelectedSkill", "Swords", (ConfigDescription)null);
				_savedSkillLevel = ((BaseUnityPlugin)this).Config.Bind<int>(text, "SkillTarget", 100, (ConfigDescription)null);
				_savedHour = ((BaseUnityPlugin)this).Config.Bind<int>(text, "TimeHour", 12, (ConfigDescription)null);
				_savedMinute = ((BaseUnityPlugin)this).Config.Bind<int>(text, "TimeMinute", 0, (ConfigDescription)null);
				_savedCleanupTamed = ((BaseUnityPlugin)this).Config.Bind<bool>(text, "CleanupTamed", false, (ConfigDescription)null);
				_savedCleanupBosses = ((BaseUnityPlugin)this).Config.Bind<bool>(text, "CleanupBosses", false, (ConfigDescription)null);
				_savedTimedBanHours = ((BaseUnityPlugin)this).Config.Bind<int>(text, "TimedBanHours", 24, (ConfigDescription)null);
				_savedAdminSection = ((BaseUnityPlugin)this).Config.Bind<int>(text, "Section", 0, (ConfigDescription)null);
				_killIncludeTamed = _savedCleanupTamed.Value;
				_killIncludeBosses = _savedCleanupBosses.Value;
				_adminSection = Mathf.Clamp(_savedAdminSection.Value, 0, 6);
				int num = _savedModes.Value & 0x3FF;
				_infiniteHealth = (num & 1) != 0;
				_infiniteStamina = (num & 2) != 0;
				_infiniteEitr = (num & 4) != 0;
				_infiniteAdrenaline = (num & 8) != 0;
				_superDamage = (num & 0x10) != 0;
				_adminFly = (num & 0x20) != 0;
				_adminCreative = (num & 0x40) != 0;
				_adminGhost = (num & 0x80) != 0;
				_adminHotkeys = (num & 0x100) != 0;
				_infiniteGuardianPower = (num & 0x200) != 0;
				_superDamageMultiplier = (AdminRules.Finite(_savedDamage.Value) ? Mathf.Clamp(_savedDamage.Value, 1f, 25f) : 5f);
				_skillXpMultiplier = (AdminRules.Finite(_savedXp.Value) ? Mathf.Clamp(_savedXp.Value, 1f, 1000f) : 1f);
				_carryWeightTarget = (AdminRules.Finite(_savedCarryWeight.Value) ? Mathf.Clamp(_savedCarryWeight.Value, 1f, 10000f) : 300f);
				_carryWeightInput = _carryWeightTarget.ToString("0.##", CultureInfo.InvariantCulture);
				_carryWeightEnabled = _savedCarryWeightEnabled.Value;
				_skillXpInput = _skillXpMultiplier.ToString(CultureInfo.InvariantCulture);
				_skillTarget = Mathf.Clamp(_savedSkillLevel.Value, 0, 100);
				_timeHour = Mathf.Clamp(_savedHour.Value, 0, 23);
				_timeMinute = Mathf.Clamp(_savedMinute.Value, 0, 59);
				_timedBanHours = Mathf.Clamp(_savedTimedBanHours.Value, 1, 8760);
				if (Enum.TryParse<SkillType>(_savedSkill.Value, out SkillType result) && SkillChoices().Contains(result))
				{
					_skillChoice = result;
				}
				_lastLocalAuditedModes = DesiredModeBits;
				_lastLocalAuditedDamage = _superDamageMultiplier;
				_lastLocalAuditedXp = _skillXpMultiplier;
				_hudDirty = true;
			}
			if (!_effectsActive || _effectsPlayer != localPlayer)
			{
				_effectsPlayer = localPlayer;
				object obj = ReadMember(localPlayer, "m_debugFly");
				bool flag = default(bool);
				int num2;
				if (obj is bool)
				{
					flag = (bool)obj;
					num2 = 1;
				}
				else
				{
					num2 = 0;
				}
				_priorFly = (byte)((uint)num2 & (flag ? 1u : 0u)) != 0;
				obj = ReadMember(localPlayer, "m_noPlacementCost");
				bool flag2 = default(bool);
				int num3;
				if (obj is bool)
				{
					flag2 = (bool)obj;
					num3 = 1;
				}
				else
				{
					num3 = 0;
				}
				_priorCreative = (byte)((uint)num3 & (flag2 ? 1u : 0u)) != 0;
				obj = ReadMember(localPlayer, "m_ghostMode");
				bool flag3 = default(bool);
				int num4;
				if (obj is bool)
				{
					flag3 = (bool)obj;
					num4 = 1;
				}
				else
				{
					num4 = 0;
				}
				_priorGhost = (byte)((uint)num4 & (flag3 ? 1u : 0u)) != 0;
				_priorCarryWeight = ((ReadMember(localPlayer, "m_maxCarryWeight") is float num5 && AdminRules.Finite(num5)) ? num5 : 300f);
				_effectsActive = true;
				_nextEffectsApply = 0f;
			}
			if (Time.unscaledTime >= _nextEffectsApply)
			{
				_nextEffectsApply = Time.unscaledTime + 0.25f;
				ApplyFlightState(localPlayer, _adminFly || _priorFly);
				TrySetBoolMember(localPlayer, "m_noPlacementCost", _adminCreative || _priorCreative);
				localPlayer.SetGhostMode(_adminGhost || _priorGhost);
				TrySetFloatMember(localPlayer, "m_maxCarryWeight", _carryWeightEnabled ? _carryWeightTarget : _priorCarryWeight);
				if (_infiniteGuardianPower)
				{
					TrySetFloatMember(localPlayer, "m_guardianPowerCooldown", 0f);
				}
			}
		}

		private void SuspendAdminEffects()
		{
			if (_effectsActive && (Object)(object)_effectsPlayer != (Object)null)
			{
				ApplyFlightState(_effectsPlayer, _priorFly);
				TrySetBoolMember(_effectsPlayer, "m_noPlacementCost", _priorCreative);
				_effectsPlayer.SetGhostMode(_priorGhost);
				TrySetFloatMember(_effectsPlayer, "m_maxCarryWeight", _priorCarryWeight);
			}
			_effectsActive = false;
			_effectsPlayer = null;
		}

		private void SaveAdminPreferences()
		{
			if (HasAdminAccess && _savedModes != null && Player.m_localPlayer == _preferencesPlayer)
			{
				_savedModes.Value = DesiredModeBits;
				_savedDamage.Value = _superDamageMultiplier;
				_savedXp.Value = _skillXpMultiplier;
				_savedCarryWeight.Value = _carryWeightTarget;
				_savedCarryWeightEnabled.Value = _carryWeightEnabled;
				_savedSkill.Value = ((object)Unsafe.As<SkillType, SkillType>(ref _skillChoice)/*cast due to .constrained prefix*/).ToString();
				_savedSkillLevel.Value = _skillTarget;
				_savedHour.Value = _timeHour;
				_savedMinute.Value = _timeMinute;
				_savedCleanupTamed.Value = _killIncludeTamed;
				_savedCleanupBosses.Value = _killIncludeBosses;
				_savedTimedBanHours.Value = _timedBanHours;
				_savedAdminSection.Value = _adminSection;
				if (ZNet.instance.IsServer())
				{
					AuditLocalModeChanges();
				}
				_nextEffectsApply = 0f;
				TrySavePreferences();
			}
		}

		private void AuditLocalModeChanges()
		{
			int desiredModeBits = DesiredModeBits;
			if (_lastLocalAuditedModes >= 0)
			{
				for (int i = 0; i < 10; i++)
				{
					int num = 1 << i;
					if (((desiredModeBits ^ _lastLocalAuditedModes) & num) != 0)
					{
						AppendAdminAudit(Player.m_localPlayer.GetPlayerName(), Player.m_localPlayer.GetPlayerID(), AdminModeName(i) + (((desiredModeBits & num) != 0) ? " enabled" : " disabled"), "OK");
					}
				}
				if (Math.Abs(_superDamageMultiplier - _lastLocalAuditedDamage) > 0.001f)
				{
					AppendAdminAudit(Player.m_localPlayer.GetPlayerName(), Player.m_localPlayer.GetPlayerID(), "damage multiplier ×" + _superDamageMultiplier.ToString("0.##", CultureInfo.InvariantCulture), "OK");
				}
				if (Math.Abs(_skillXpMultiplier - _lastLocalAuditedXp) > 0.001f)
				{
					AppendAdminAudit(Player.m_localPlayer.GetPlayerName(), Player.m_localPlayer.GetPlayerID(), "skill XP multiplier ×" + _skillXpMultiplier.ToString("0.##", CultureInfo.InvariantCulture), "OK");
				}
			}
			_lastLocalAuditedModes = desiredModeBits;
			_lastLocalAuditedDamage = _superDamageMultiplier;
			_lastLocalAuditedXp = _skillXpMultiplier;
		}

		private static void ApplyFlightState(Player player, bool enabled)
		{
			ZNetView val = (((Object)(object)player == (Object)null) ? null : ((Component)player).GetComponent<ZNetView>());
			if (!((Object)(object)val == (Object)null) && val.IsValid() && val.IsOwner() && player.InDebugFlyMode() != enabled)
			{
				player.ToggleDebugFly();
			}
		}

		private string WorldClock()
		{
			if ((Object)(object)ZNet.instance == (Object)null || (Object)(object)EnvMan.instance == (Object)null || EnvMan.instance.m_dayLengthSec < 1)
			{
				return "—";
			}
			double timeSeconds = ZNet.instance.GetTimeSeconds();
			double num = EnvMan.instance.m_dayLengthSec;
			double raw = timeSeconds % num / num;
			int num2 = Math.Min(1439, (int)(AdminRules.SolarFraction(raw) * 1440.0));
			return T("Day ", "День ") + EnvMan.instance.GetDay() + "  ·  " + (num2 / 60).ToString("00") + ":" + (num2 % 60).ToString("00");
		}

		private SkillType[] SkillChoices()
		{
			Player localPlayer = Player.m_localPlayer;
			return ((localPlayer == null) ? null : (from s in ((Character)localPlayer).GetSkills()?.m_skills?.Select((SkillDef s) => s.m_skill)
				where (int)s != 0 && (int)s != 999
				select s).Distinct().ToArray()) ?? Array.Empty<SkillType>();
		}

		private unsafe string SkillName(SkillType skill)
		{
			string text = "$skill_" + ((object)(*(SkillType*)(&skill))/*cast due to .constrained prefix*/).ToString().ToLowerInvariant();
			Localization instance = Localization.instance;
			string text2 = ((instance != null) ? instance.Localize(text) : null);
			if (!string.IsNullOrEmpty(text2) && !(text2 == text))
			{
				return text2;
			}
			return ((object)(*(SkillType*)(&skill))/*cast due to .constrained prefix*/).ToString();
		}

		private unsafe void RaiseSkills(bool all, SkillType choice, int target)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Expected I4, but got Unknown
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			if (!AdminRules.Skill(target) || !AuthorizeLocal(delegate
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				RaiseSkills(all, choice, target);
			}, (all ? "set all skills to " : ("set " + ((object)(*(SkillType*)(&choice))/*cast due to .constrained prefix*/).ToString() + " to ")) + target.ToString(CultureInfo.InvariantCulture)))
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			Skills val = ((localPlayer != null) ? ((Character)localPlayer).GetSkills() : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			SkillType[] array = SkillChoices();
			if (!all && !array.Contains(choice))
			{
				_status = T("Skill unavailable.", "Навык недоступен.");
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(typeof(Skills), "GetSkill", new Type[1] { typeof(SkillType) }, (Type[])null);
			int num = 0;
			SkillType[] array2 = (SkillType[])(all ? ((Array)array) : ((Array)new SkillType[1] { (SkillType)(int)choice }));
			foreach (SkillType val2 in array2)
			{
				if (!(Mathf.Abs(val.GetSkillLevel(val2) - (float)target) < 0.01f))
				{
					object instance = methodInfo.Invoke(val, new object[1] { val2 });
					if (TrySetFloatMember(instance, "m_level", target))
					{
						TrySetFloatMember(instance, "m_accumulator", 0f);
						num++;
					}
				}
			}
			ShowAdminToast(T("Skill levels set: ", "Установлено навыков: ") + num + " → " + target);
		}

		private void HealSelf()
		{
			if (AuthorizeLocal(HealSelf, "restore player health"))
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null))
				{
					((Character)localPlayer).Heal(((Character)localPlayer).GetMaxHealth(), true);
					_status = T("Health restored.", "Здоровье восстановлено.");
				}
			}
		}

		private void SetMaxCarryWeight(float weight)
		{
			if (!AdminRules.Finite(weight) || weight < 1f || weight > 10000f)
			{
				_status = T("Carry weight must be between 1 and 10,000.", "Вес должен быть от 1 до 10 000.");
			}
			else if (AuthorizeLocal(delegate
			{
				SetMaxCarryWeight(weight);
			}, "set personal carry weight to " + weight.ToString("0.##", CultureInfo.InvariantCulture)))
			{
				_carryWeightTarget = weight;
				_carryWeightEnabled = true;
				_carryWeightInput = weight.ToString("0.##", CultureInfo.InvariantCulture);
				SaveAdminPreferences();
				TickAdminPreferences();
				Player localPlayer = Player.m_localPlayer;
				float num = (((Object)(object)localPlayer == (Object)null) ? weight : localPlayer.GetMaxCarryWeight());
				ShowAdminToast(T("Base carry weight set to ", "Базовый переносимый вес установлен: ") + weight.ToString("0.##", CultureInfo.InvariantCulture) + T(" kg. Effective limit: ", " кг. Текущий лимит: ") + num.ToString("0.##", CultureInfo.InvariantCulture) + " kg.");
			}
		}

		private void ResetMaxCarryWeight()
		{
			if (AuthorizeLocal(ResetMaxCarryWeight, "restore vanilla personal carry weight"))
			{
				_carryWeightEnabled = false;
				SaveAdminPreferences();
				TickAdminPreferences();
				ShowAdminToast(T("Vanilla carry weight restored.", "Обычный переносимый вес восстановлен."));
			}
		}

		private void InitializeNexusAdvanced()
		{
			_advancedDataConfig = ((BaseUnityPlugin)this).Config.Bind<string>("NexusAdvanced", "Data", string.Empty, "Legacy v1.4.0 state; retained read-only for migration to SuperNova.ValheimNexus.Advanced.json.");
			_advancedDataPath = Path.Combine(Paths.ConfigPath, "SuperNova.ValheimNexus.Advanced.json");
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Nexus Advanced storage path: " + _advancedDataPath));
			_advancedSaveBlocked = false;
			_advancedSaveError = false;
			_advanced = new NexusAdvancedData();
			if (File.Exists(_advancedDataPath))
			{
				if (TryLoadAdvancedFile(_advancedDataPath, out var value, out var reason))
				{
					_advanced = value;
					string text = File.ReadAllText(_advancedDataPath, Encoding.UTF8);
					if (text.IndexOf("\"Format\":1", StringComparison.Ordinal) >= 0 && (text.IndexOf("\"Kits\"", StringComparison.Ordinal) < 0 || text.IndexOf("\"History\"", StringComparison.Ordinal) < 0 || text.IndexOf("\"Snapshot\"", StringComparison.Ordinal) < 0))
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)"Legacy Nexus JSON contains missing collections (Unity JsonUtility data loss). Existing omitted entries cannot be restored from this file; original file kept until next save.");
					}
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Nexus Advanced state loaded: " + _advanced.Kits.Count + " kits, " + _advanced.History.Count + " history entries, " + _advanced.Snapshot.Count + " snapshot records."));
					return;
				}
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Nexus Advanced primary state is unreadable: " + reason));
				string text2 = _advancedDataPath + ".bak";
				if (TryLoadAdvancedFile(text2, out value, out reason))
				{
					_advanced = value;
					try
					{
						File.Copy(_advancedDataPath, _advancedDataPath + ".corrupt", overwrite: true);
						File.Copy(text2, _advancedDataPath, overwrite: true);
						((BaseUnityPlugin)this).Logger.LogWarning((object)"Restored Nexus Advanced state from .bak; damaged main file preserved as .corrupt.");
						return;
					}
					catch (Exception ex)
					{
						_advancedSaveBlocked = true;
						((BaseUnityPlugin)this).Logger.LogError((object)("Nexus state recovered in memory but cannot restore primary file; writes disabled: " + ex.Message));
						return;
					}
				}
				if (!string.IsNullOrWhiteSpace(_advancedDataConfig.Value) && NexusAdvancedData.TryLoad(_advancedDataConfig.Value, out var data, out var _))
				{
					_advanced = data;
					_advancedSaveBlocked = true;
					((BaseUnityPlugin)this).Logger.LogWarning((object)"Recovered legacy Nexus data in memory, but existing file is corrupt. Writes disabled until backup is made manually.");
				}
				else
				{
					_advancedSaveBlocked = true;
					((BaseUnityPlugin)this).Logger.LogError((object)("Nexus Advanced state cannot be read and no usable backup exists. Writes disabled to protect existing data. " + reason));
				}
				return;
			}
			if (TryLoadAdvancedFile(_advancedDataPath + ".bak", out var value2, out var _))
			{
				_advanced = value2;
				try
				{
					File.Copy(_advancedDataPath + ".bak", _advancedDataPath);
					((BaseUnityPlugin)this).Logger.LogWarning((object)"Nexus Advanced primary JSON was missing; restored from .bak.");
					return;
				}
				catch (Exception ex2)
				{
					_advancedSaveBlocked = true;
					((BaseUnityPlugin)this).Logger.LogError((object)("Backup recovered in memory, but could not be copied to main state. Writes disabled: " + ex2.Message));
					return;
				}
			}
			string value3 = _advancedDataConfig.Value;
			if (!string.IsNullOrWhiteSpace(value3))
			{
				if (!NexusAdvancedData.TryLoad(value3, out var data2, out var reason4))
				{
					_advancedSaveBlocked = true;
					((BaseUnityPlugin)this).Logger.LogError((object)("Legacy Nexus Advanced state could not be decoded; refusing to overwrite it. " + reason4));
				}
				else
				{
					_advanced = data2;
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Migrating legacy Nexus Advanced configuration: " + _advanced.Kits.Count + " kits."));
					SaveNexusAdvanced();
				}
			}
		}

		private static bool TryLoadAdvancedFile(string path, out NexusAdvancedData value, out string reason)
		{
			value = null;
			reason = "File does not exist.";
			if (!File.Exists(path))
			{
				return false;
			}
			try
			{
				return NexusAdvancedData.TryLoad(File.ReadAllText(path, Encoding.UTF8), out value, out reason);
			}
			catch (Exception ex)
			{
				reason = ex.GetType().Name + ": " + ex.Message;
				return false;
			}
		}

		private bool SaveNexusAdvanced()
		{
			if (_advancedSaveBlocked)
			{
				_status = T("Nexus data could not be read; saving is disabled to protect your old data.", "Данные Nexus не прочитаны; сохранение отключено для защиты старых данных.");
				return false;
			}
			if (_advancedDataPath == null || _advanced == null)
			{
				return false;
			}
			string text = _advancedDataPath + ".tmp";
			try
			{
				string text2 = _advanced.Save();
				if (!NexusAdvancedData.TryLoad(text2, out var data, out var reason) || !_advanced.SamePersistedContent(data))
				{
					throw new InvalidDataException("State JSON serialization failed verification: " + reason);
				}
				Directory.CreateDirectory(Path.GetDirectoryName(_advancedDataPath));
				File.WriteAllText(text, text2, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
				if (!TryLoadAdvancedFile(text, out data, out reason) || !_advanced.SamePersistedContent(data))
				{
					throw new InvalidDataException("Staged state file failed verification: " + reason);
				}
				bool flag = false;
				if (File.Exists(_advancedDataPath))
				{
					string text3 = File.ReadAllText(_advancedDataPath, Encoding.UTF8);
					if (!NexusAdvancedData.TryLoad(text3, out var _, out var reason2))
					{
						throw new InvalidDataException("Existing state changed or became invalid before save: " + reason2);
					}
					flag = text3.IndexOf("\"Format\":1", StringComparison.Ordinal) >= 0;
					if (flag)
					{
						string text4 = _advancedDataPath + ".legacy-format1.json";
						if (!File.Exists(text4))
						{
							File.Copy(_advancedDataPath, text4);
						}
					}
				}
				if (!File.Exists(_advancedDataPath))
				{
					File.Move(text, _advancedDataPath);
					File.Copy(_advancedDataPath, _advancedDataPath + ".bak", overwrite: false);
				}
				else
				{
					try
					{
						File.Replace(text, _advancedDataPath, _advancedDataPath + ".bak");
					}
					catch (PlatformNotSupportedException)
					{
						File.Copy(_advancedDataPath, _advancedDataPath + ".bak", overwrite: true);
						File.Delete(_advancedDataPath);
						File.Move(text, _advancedDataPath);
					}
				}
				if (!TryLoadAdvancedFile(_advancedDataPath, out data, out reason) || !_advanced.SamePersistedContent(data))
				{
					throw new InvalidDataException("Committed Nexus state differs from memory: " + reason);
				}
				if (flag)
				{
					File.Copy(_advancedDataPath, _advancedDataPath + ".bak", overwrite: true);
				}
				_advancedSaveError = false;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Nexus Advanced state saved: " + _advanced.Kits.Count + " kits, " + _advanced.History.Count + " history entries, " + _advanced.Snapshot.Count + " snapshot records to " + _advancedDataPath));
				return true;
			}
			catch (Exception ex2)
			{
				_advancedSaveError = true;
				((BaseUnityPlugin)this).Logger.LogError((object)("Nexus Advanced state save failed: " + ex2));
				_status = T("Could not save Nexus data. Check BepInEx log and folder permissions.", "Не удалось сохранить данные Nexus. Проверь журнал BepInEx и права на папку.");
				return false;
			}
			finally
			{
				try
				{
					if (File.Exists(text))
					{
						File.Delete(text);
					}
				}
				catch
				{
				}
			}
		}

		private void RecordNexusHistory(string kind, string prefab, int count, int quality, int level, string name, string description = "")
		{
			if (count > 0 && _advanced != null)
			{
				_advanced.AddHistory(kind, prefab, count, quality, level, name, description);
				SaveNexusAdvanced();
			}
		}

		private void DrawNexusAdvancedTabs()
		{
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("NEXUS ADVANCED", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(142f) });
			DrawMainTabButton(T("Doctor", "Диагностика"), 7);
			DrawMainTabButton(T("Kits", "Наборы"), 8);
			DrawMainTabButton(T("History", "История"), 9);
			DrawMainTabButton(T("Radar", "Радар"), 10);
			GUILayout.EndHorizontal();
			if (_advancedSaveBlocked || _advancedSaveError)
			{
				GUILayout.Label(T("WARNING: Nexus data was not saved. Check BepInEx log; do not delete old configuration files.", "ВНИМАНИЕ: данные Nexus не сохранены. Проверь лог BepInEx; не удаляй старые конфиги."), Array.Empty<GUILayoutOption>());
			}
		}

		private void DrawNexusAdvancedPanel()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			_advancedScroll = GUILayout.BeginScrollView(_advancedScroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) });
			switch (_mainTab)
			{
			case 7:
				DrawDoctorPanel();
				break;
			case 8:
				DrawKitsPanel();
				break;
			case 9:
				DrawHistoryPanel();
				break;
			case 10:
				DrawRadarPanel();
				break;
			}
			GUILayout.EndScrollView();
			GUILayout.Label(_status, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
		}

		private void DrawDoctorPanel()
		{
			GUILayout.Label(T("Nexus Doctor — inspect registered item prefabs. Results are advisory, not an in-game equipment test.", "Nexus Doctor — проверка зарегистрированных префабов. Результат не заменяет тест экипировки в игре."), Array.Empty<GUILayoutOption>());
			if (_itemEntries.Count == 0)
			{
				GUILayout.Label(T("Enter a world and refresh catalogues first.", "Войди в мир и обнови каталоги."), Array.Empty<GUILayoutOption>());
				return;
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(T("Filter ID:", "Поиск ID:"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(85f) });
			GUI.SetNextControlName("ValheimSpawner.DoctorSearch");
			_doctorSearch = GUILayout.TextField(_doctorSearch, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			_nameHasFocus = GUI.GetNameOfFocusedControl() == "ValheimSpawner.DoctorSearch";
			GUILayout.EndHorizontal();
			List<ItemEntry> list = new List<ItemEntry>();
			for (int i = 0; i < _itemEntries.Count; i++)
			{
				if (list.Count >= 250)
				{
					break;
				}
				if (string.IsNullOrWhiteSpace(_doctorSearch) || _itemEntries[i].PrefabName.IndexOf(_doctorSearch, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					list.Add(_itemEntries[i]);
				}
			}
			if (list.Count == 0)
			{
				GUILayout.Label(T("No matching items.", "Предметы не найдены."), Array.Empty<GUILayoutOption>());
				return;
			}
			_doctorItemIndex = Mathf.Clamp(_doctorItemIndex, 0, list.Count - 1);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("◀", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(34f) }))
			{
				_doctorItemIndex = (_doctorItemIndex + list.Count - 1) % list.Count;
			}
			GUILayout.Label(list[_doctorItemIndex].PrefabName + " — " + GetItemDisplayName(list[_doctorItemIndex]), Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("▶", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(34f) }))
			{
				_doctorItemIndex = (_doctorItemIndex + 1) % list.Count;
			}
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button(T("Run Diagnostics", "Проверить"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(34f) }))
			{
				_doctorReport = InspectItemPrefab(list[_doctorItemIndex]);
			}
			GUI.enabled = !string.IsNullOrEmpty(_doctorReport);
			if (GUILayout.Button(T("Copy Report", "Копировать отчёт"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(34f) }))
			{
				GUIUtility.systemCopyBuffer = _doctorReport;
				_status = T("Diagnostic report copied.", "Диагностический отчёт скопирован.");
			}
			GUI.enabled = true;
			GUILayout.EndHorizontal();
			if (!string.IsNullOrEmpty(_doctorReport))
			{
				GUILayout.TextArea(_doctorReport, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinHeight(280f) });
			}
		}

		private string InspectItemPrefab(ItemEntry entry)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("SuperNova Nexus Doctor v1.8.7");
			stringBuilder.AppendLine("Prefab ID: " + entry.PrefabName);
			stringBuilder.AppendLine("Category: " + entry.Category.ToString() + " | Type: " + entry.ItemTypeLabel);
			stringBuilder.AppendLine("Max stack: " + entry.MaxStack + " | UI quality limit: " + entry.MaxQuality);
			stringBuilder.AppendLine("Durability: " + (entry.UsesDurability ? "yes" : "no"));
			stringBuilder.AppendLine("Icon: " + (((Object)(object)entry.IconTexture != (Object)null) ? "present" : "MISSING"));
			GameObject prefab = entry.Prefab;
			if ((Object)(object)prefab == (Object)null)
			{
				stringBuilder.AppendLine("[FAIL] Prefab reference is missing.");
				return stringBuilder.ToString();
			}
			stringBuilder.AppendLine("[OK] Prefab: " + ((Object)prefab).name);
			Component val = ((_itemDropType == null) ? null : prefab.GetComponent(_itemDropType));
			object obj = ReadMember(val, "m_itemData");
			object obj2 = ReadMember(obj, "m_shared");
			stringBuilder.AppendLine(((Object)(object)val == (Object)null) ? "[FAIL] ItemDrop missing" : "[OK] ItemDrop present");
			stringBuilder.AppendLine((obj == null) ? "[FAIL] ItemData missing" : "[OK] ItemData present");
			stringBuilder.AppendLine((obj2 == null) ? "[FAIL] SharedData missing" : "[OK] SharedData present");
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			int num = 0;
			int num2 = 0;
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if ((Object)(object)componentsInChildren[i] == (Object)null)
				{
					continue;
				}
				num++;
				Material[] sharedMaterials = componentsInChildren[i].sharedMaterials;
				if (sharedMaterials == null || sharedMaterials.Length == 0)
				{
					num2++;
					continue;
				}
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					if ((Object)(object)sharedMaterials[j] == (Object)null)
					{
						num2++;
					}
				}
			}
			stringBuilder.AppendLine("Renderer components on item prefab: " + num);
			stringBuilder.AppendLine("Missing renderer material slots: " + num2);
			int num3 = 0;
			Transform[] componentsInChildren2 = prefab.GetComponentsInChildren<Transform>(true);
			for (int k = 0; k < componentsInChildren2.Length; k++)
			{
				if ((Object)(object)componentsInChildren2[k] != (Object)null && ((Object)componentsInChildren2[k]).name.StartsWith("attach", StringComparison.OrdinalIgnoreCase))
				{
					num3++;
				}
			}
			stringBuilder.AppendLine("Attachment-like transforms: " + num3);
			stringBuilder.AppendLine("Important: an equipped visual may use separate attach prefabs and skeleton bones.");
			stringBuilder.AppendLine("If the model is invisible, verify the result by equipping the item in-game.");
			return stringBuilder.ToString();
		}

		private void AddSelectedItemToKit()
		{
			if (_selectedItem == null || _advanced.Kits.Count == 0)
			{
				_status = T("Select an item and create a kit first.", "Выбери предмет и сначала создай набор.");
				return;
			}
			_activeKitIndex = Mathf.Clamp(_activeKitIndex, 0, _advanced.Kits.Count - 1);
			NexusKit nexusKit = _advanced.Kits[_activeKitIndex];
			if (nexusKit == null || nexusKit.Items == null || nexusKit.Items.Count >= 100)
			{
				_status = T("Kit limit: 100 item rows.", "Ограничение набора: 100 строк предметов.");
				return;
			}
			if (!TryParseItemAmount(_itemCountInput, out var amount))
			{
				_status = T("Enter a valid count first.", "Сначала введи корректное количество.");
				return;
			}
			string text = NexusAdvancedData.CleanName(_itemCustomName);
			string text2 = NexusAdvancedData.CleanDescription(_itemCustomDescription);
			if ((text.Length > 0 || text2.Length > 0) && _selectedItem.MaxStack > 1)
			{
				_status = T("Custom names require max stack 1.", "Своё имя требует размера стака 1.");
				return;
			}
			NexusKitPart item = new NexusKitPart
			{
				PrefabId = _selectedItem.PrefabName,
				Count = Mathf.Clamp(amount, 1, 9999),
				Quality = Mathf.Clamp(_itemQuality, 1, _selectedItem.MaxQuality),
				CustomName = text,
				CustomDescription = text2
			};
			nexusKit.Items.Add(item);
			if (SaveNexusAdvanced())
			{
				_status = T("Item added to kit: ", "Предмет добавлен в набор: ") + nexusKit.Name;
			}
			else
			{
				nexusKit.Items.Remove(item);
			}
		}

		private void DrawKitsPanel()
		{
			GUILayout.Label(T("Equipment Kits — save item IDs, counts, quality, custom names and descriptions.", "Наборы — хранение ID, количества, качества, собственных имён и описаний."), Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUI.SetNextControlName("ValheimSpawner.KitName");
			_newKitName = GUILayout.TextField(_newKitName, 48, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.MinWidth(150f),
				GUILayout.ExpandWidth(true)
			});
			_nameHasFocus = GUI.GetNameOfFocusedControl() == "ValheimSpawner.KitName";
			if (GUILayout.Button(T("New Kit", "Создать набор"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(130f) }))
			{
				string text = NexusAdvancedData.CleanName(_newKitName);
				if (text.Length == 0)
				{
					_status = T("Enter a kit name.", "Введи название набора.");
				}
				else if (_advanced.Kits.Count >= 25)
				{
					_status = T("Kit limit reached (25).", "Лимит наборов: 25.");
				}
				else
				{
					_advanced.Kits.Add(new NexusKit
					{
						Name = text
					});
					_activeKitIndex = _advanced.Kits.Count - 1;
					_newKitName = string.Empty;
					SaveNexusAdvanced();
				}
			}
			GUILayout.EndHorizontal();
			if (_advanced.Kits.Count == 0)
			{
				GUILayout.Label(T("Create a kit, then select an item in its category and click Add to kit.", "Создай набор, затем выбери предмет в каталоге и нажми «В набор»."), Array.Empty<GUILayoutOption>());
				return;
			}
			_activeKitIndex = Mathf.Clamp(_activeKitIndex, 0, _advanced.Kits.Count - 1);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("◀", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(34f) }))
			{
				_activeKitIndex = (_activeKitIndex + _advanced.Kits.Count - 1) % _advanced.Kits.Count;
			}
			NexusKit nexusKit = _advanced.Kits[_activeKitIndex];
			GUILayout.Label(nexusKit.Name + " (" + nexusKit.Items.Count + "/" + 100 + ")", Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("▶", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(34f) }))
			{
				_activeKitIndex = (_activeKitIndex + 1) % _advanced.Kits.Count;
			}
			if (GUILayout.Button(T("Delete Kit", "Удалить набор"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) }))
			{
				_advanced.Kits.RemoveAt(_activeKitIndex);
				_activeKitIndex = Mathf.Clamp(_activeKitIndex, 0, _advanced.Kits.Count - 1);
				SaveNexusAdvanced();
				return;
			}
			GUILayout.EndHorizontal();
			if (DrawKitWorkshopActions(nexusKit))
			{
				return;
			}
			for (int num = nexusKit.Items.Count - 1; num >= 0; num--)
			{
				NexusKitPart nexusKitPart = nexusKit.Items[num];
				if (nexusKitPart != null)
				{
					GUILayout.BeginHorizontal(GUIStyle.op_Implicit("box"), Array.Empty<GUILayoutOption>());
					GUILayout.Label(nexusKitPart.PrefabId + " ×" + nexusKitPart.Count + "  Q" + nexusKitPart.Quality + (string.IsNullOrEmpty(nexusKitPart.CustomName) ? "" : ("  [" + nexusKitPart.CustomName + "]")) + (string.IsNullOrEmpty(nexusKitPart.CustomDescription) ? "" : "  [custom description]"), Array.Empty<GUILayoutOption>());
					if (GUILayout.Button(T("Edit", "Изменить"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }))
					{
						BeginEditKitPart(nexusKit, num);
					}
					if (GUILayout.Button(T("Remove", "Убрать"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }))
					{
						nexusKit.Items.RemoveAt(num);
						_editingKitPart = -1;
						SaveNexusAdvanced();
					}
					GUILayout.EndHorizontal();
				}
			}
			DrawKitPartEditor(nexusKit);
			if (GUILayout.Button(T("Apply Kit to Inventory", "Добавить набор в инвентарь"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(36f) }))
			{
				ApplySelectedKit(nexusKit);
			}
			GUILayout.Label(T("Safety: at most 1,000 total units per application; incomplete insertion is reported. No auto-equip.", "Ограничение: максимум 1 000 предметов за применение; неполное добавление отображается. Без автоэкипировки."), Array.Empty<GUILayoutOption>());
		}

		private void ApplySelectedKit(NexusKit kit)
		{
			if (!NexusKitWorkshop.Validate(kit, out var reason))
			{
				_status = reason;
				return;
			}
			kit = NexusKitWorkshop.DeepCopy(kit);
			if (!AuthorizeLocal(delegate
			{
				ApplySelectedKit(kit);
			}, "apply kit " + kit.Name))
			{
				return;
			}
			RefreshGameReferences();
			if (!HasAdminAccess || (Object)(object)_playerComponent == (Object)null)
			{
				_status = T("Kit insertion requires a host player in a world.", "Для набора нужен игрок-хост в мире.");
				return;
			}
			object playerInventory = GetPlayerInventory();
			if (playerInventory == null)
			{
				_status = T("Inventory unavailable.", "Инвентарь недоступен.");
				return;
			}
			int num = 0;
			List<ItemEntry> list = new List<ItemEntry>();
			foreach (NexusKitPart item in kit.Items)
			{
				if (item == null || item.Count < 1 || item.Count > 9999)
				{
					_status = T("Invalid kit item amount.", "Недопустимое количество в наборе.");
					return;
				}
				num += item.Count;
				if (num > 1000)
				{
					_status = T("Kit exceeds 1,000 items per action.", "Набор превышает 1 000 предметов за одно действие.");
					return;
				}
				ItemEntry itemEntry = FindItemById(item.PrefabId);
				if (itemEntry == null)
				{
					_status = T("Missing prefab: ", "Нет префаба: ") + item.PrefabId;
					return;
				}
				if ((!string.IsNullOrEmpty(item.CustomName) || !string.IsNullOrEmpty(item.CustomDescription)) && itemEntry.MaxStack > 1)
				{
					_status = T("Named stack is unsupported: ", "Именованный стак не поддерживается: ") + item.PrefabId;
					return;
				}
				list.Add(itemEntry);
			}
			int num2 = 0;
			for (int num3 = 0; num3 < list.Count; num3++)
			{
				NexusKitPart nexusKitPart = kit.Items[num3];
				InventoryAddResult inventoryAddResult = AddItemBatches(playerInventory, list[num3], nexusKitPart.Count, Mathf.Clamp(nexusKitPart.Quality, 1, list[num3].MaxQuality), NexusAdvancedData.CleanName(nexusKitPart.CustomName), NexusAdvancedData.CleanDescription(nexusKitPart.CustomDescription));
				num2 += inventoryAddResult.Added;
				if (inventoryAddResult.Added != nexusKitPart.Count)
				{
					_status = T("Kit partially applied: ", "Набор добавлен частично: ") + num2 + "/" + num + ". " + inventoryAddResult.Reason;
					if (num2 > 0)
					{
						RecordNexusHistory("kit", kit.Name, num2, 1, 1, string.Empty);
					}
					return;
				}
			}
			if (num2 > 0)
			{
				RecordNexusHistory("kit", kit.Name, num2, 1, 1, string.Empty);
			}
			_status = T("Kit applied: ", "Набор добавлен: ") + kit.Name + " ×" + num2;
		}

		private ItemEntry FindItemById(string prefabId)
		{
			for (int i = 0; i < _itemEntries.Count; i++)
			{
				if (string.Equals(_itemEntries[i].PrefabName, prefabId, StringComparison.OrdinalIgnoreCase))
				{
					return _itemEntries[i];
				}
			}
			return null;
		}

		private void DrawHistoryPanel()
		{
			GUILayout.Label(T("Recent Nexus operations (last 100). Reuse fills controls; it never automatically repeats a spawn.", "Последние 100 операций Nexus. Повтор заполняет поля, но не создаёт объекты автоматически."), Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(T("Search:", "Поиск:"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(65f) });
			GUI.SetNextControlName("ValheimNexus.HistorySearch");
			_historyFilter = GUILayout.TextField(_historyFilter, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			_nameHasFocus = GUI.GetNameOfFocusedControl() == "ValheimNexus.HistorySearch";
			if (GUILayout.Button(T("Clear History", "Очистить историю"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(160f) }))
			{
				_advanced.History.Clear();
				SaveNexusAdvanced();
			}
			GUILayout.EndHorizontal();
			_historyKindFilter = GUILayout.Toolbar(_historyKindFilter, new string[4]
			{
				T("All", "Все"),
				T("Items", "Предметы"),
				T("Creatures", "Существа"),
				T("Kits", "Наборы")
			}, Array.Empty<GUILayoutOption>());
			int num = 0;
			for (int i = 0; i < _advanced.History.Count; i++)
			{
				NexusHistoryRecord nexusHistoryRecord = _advanced.History[i];
				if (nexusHistoryRecord != null && (_historyKindFilter != 1 || !(nexusHistoryRecord.Kind != "item")) && (_historyKindFilter != 2 || !(nexusHistoryRecord.Kind != "creature")) && (_historyKindFilter != 3 || !(nexusHistoryRecord.Kind != "kit")) && (string.IsNullOrWhiteSpace(_historyFilter) || (nexusHistoryRecord.PrefabId ?? string.Empty).IndexOf(_historyFilter, StringComparison.OrdinalIgnoreCase) >= 0 || (nexusHistoryRecord.CustomName ?? string.Empty).IndexOf(_historyFilter, StringComparison.OrdinalIgnoreCase) >= 0 || (nexusHistoryRecord.CustomDescription ?? string.Empty).IndexOf(_historyFilter, StringComparison.OrdinalIgnoreCase) >= 0))
				{
					num++;
					GUILayout.BeginHorizontal(GUIStyle.op_Implicit("box"), Array.Empty<GUILayoutOption>());
					GUILayout.Label(nexusHistoryRecord.Utc + " | " + nexusHistoryRecord.Kind + " | " + nexusHistoryRecord.PrefabId + " ×" + nexusHistoryRecord.Count + (string.IsNullOrEmpty(nexusHistoryRecord.CustomName) ? "" : (" [" + nexusHistoryRecord.CustomName + "]")), Array.Empty<GUILayoutOption>());
					if (nexusHistoryRecord.Kind != "kit" && GUILayout.Button(T("Reuse", "Повторить"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(95f) }))
					{
						LoadHistoryControls(nexusHistoryRecord);
					}
					GUILayout.EndHorizontal();
				}
			}
			GUILayout.Label(T("Matching entries: ", "Найдено записей: ") + num, Array.Empty<GUILayoutOption>());
		}

		private void LoadHistoryControls(NexusHistoryRecord record)
		{
			if (record.Kind == "item")
			{
				ItemEntry itemEntry = FindItemById(record.PrefabId);
				if (itemEntry == null)
				{
					_status = T("Item is no longer registered.", "Предмет больше не зарегистрирован.");
					return;
				}
				_selectedItem = itemEntry;
				_mainTab = (int)(1 + itemEntry.Category);
				_searchAllItems = true;
				_itemFavoritesOnly = false;
				_itemSearch = record.PrefabId;
				_itemCount = Mathf.Clamp(record.Count, 1, 9999);
				_itemCountInput = _itemCount.ToString();
				_itemQuality = Mathf.Clamp(record.Quality, 1, itemEntry.MaxQuality);
				_itemCustomName = NexusAdvancedData.CleanName(record.CustomName);
				_itemCustomDescription = NexusAdvancedData.CleanDescription(record.CustomDescription);
			}
			else if (record.Kind == "creature")
			{
				CreatureEntry creatureEntry = null;
				for (int i = 0; i < _entries.Count; i++)
				{
					if (string.Equals(_entries[i].PrefabName, record.PrefabId, StringComparison.OrdinalIgnoreCase))
					{
						creatureEntry = _entries[i];
						break;
					}
				}
				if (creatureEntry == null)
				{
					_status = T("Creature is no longer registered.", "Существо больше не зарегистрировано.");
					return;
				}
				_selected = creatureEntry;
				_mainTab = 0;
				_creatureFavoritesOnly = false;
				_categoryFilter = 0;
				_biomeFilter = 0;
				_search = record.PrefabId;
				_count = Mathf.Clamp(record.Count, 1, 50);
				_level = Mathf.Clamp(record.Level, 1, 3);
				_customName = NexusAdvancedData.CleanName(record.CustomName);
			}
			_status = T("Settings restored. Review them before spawning.", "Параметры восстановлены. Проверь перед созданием.");
		}

		private void DrawRadarPanel()
		{
			GUILayout.Label(T("Compatibility Radar — compare runtime prefab catalogues with a saved snapshot.", "Радар совместимости — сравнение игровых каталогов с сохранённым снимком."), Array.Empty<GUILayoutOption>());
			GUILayout.Label(T("Baseline: ", "Базовый снимок: ") + (string.IsNullOrEmpty(_advanced.SnapshotUtc) ? T("none", "отсутствует") : _advanced.SnapshotUtc), Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button(T("Compare Catalogues", "Сравнить каталоги"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(36f) }))
			{
				_radarReport = CompareCatalogues();
			}
			if (GUILayout.Button(T("Save Snapshot", "Сохранить снимок"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(36f) }))
			{
				_advanced.Snapshot = BuildCatalogueSnapshot();
				_advanced.SnapshotUtc = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss 'UTC'");
				if (SaveNexusAdvanced())
				{
					_radarReport = T("Snapshot saved. Compare again after a game or mod update.", "Снимок сохранён. Сравни после обновления игры или модов.");
				}
				else
				{
					_radarReport = T("Snapshot save failed! Check BepInEx log.", "Снимок не сохранён! Проверь журнал BepInEx.");
				}
			}
			GUILayout.EndHorizontal();
			GUI.enabled = !string.IsNullOrEmpty(_radarReport);
			if (GUILayout.Button(T("Copy Comparison", "Копировать сравнение"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(190f) }))
			{
				GUIUtility.systemCopyBuffer = _radarReport;
			}
			GUI.enabled = true;
			if (!string.IsNullOrEmpty(_radarReport))
			{
				GUILayout.TextArea(_radarReport, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinHeight(150f) });
			}
		}

		private List<NexusCatalogueRecord> BuildCatalogueSnapshot()
		{
			List<NexusCatalogueRecord> list = new List<NexusCatalogueRecord>();
			for (int i = 0; i < _itemEntries.Count; i++)
			{
				if (list.Count >= 4500)
				{
					break;
				}
				ItemEntry itemEntry = _itemEntries[i];
				list.Add(new NexusCatalogueRecord
				{
					Id = "item:" + itemEntry.PrefabName,
					Signature = itemEntry.ItemTypeLabel + "/" + itemEntry.Category.ToString() + "/" + itemEntry.MaxStack + "/" + itemEntry.MaxQuality + "/" + itemEntry.UsesDurability + "/" + ((Object)(object)itemEntry.IconTexture != (Object)null)
				});
			}
			for (int j = 0; j < _entries.Count; j++)
			{
				if (list.Count >= 4500)
				{
					break;
				}
				list.Add(new NexusCatalogueRecord
				{
					Id = "creature:" + _entries[j].PrefabName,
					Signature = _entries[j].Category.ToString()
				});
			}
			return list;
		}

		private string CompareCatalogues()
		{
			if (_advanced.Snapshot.Count == 0)
			{
				return T("No baseline. Save a snapshot first.", "Нет базового снимка. Сначала сохрани его.");
			}
			if (_itemEntries.Count == 0 || _entries.Count == 0)
			{
				return T("Load both catalogues in a world first.", "Сначала загрузи оба каталога в мире.");
			}
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);