Decompiled source of Provisioner v1.0.2

plugins/Provisioner.dll

Decompiled a day 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.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Forgeplan.Ui;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Forgeplan
{
	public static class AutoSnapshot
	{
		public static bool Enabled;

		public static float Minutes = 2f;

		public static Vector3? Home;

		public static bool LastWasAuto;

		private const float Settle = 3f;

		private const float AfterChest = 1f;

		private const float CheckEvery = 2f;

		private static bool _inside;

		private static float _check;

		private static float _snapAt = -1f;

		private static float _nextPeriodic;

		public static bool TryHome(out Vector3 home)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			if (Home.HasValue)
			{
				home = Home.Value;
				return true;
			}
			PlayerProfile val = (((Object)(object)Game.instance != (Object)null) ? Game.instance.GetPlayerProfile() : null);
			if (val != null && val.HaveCustomSpawnPoint())
			{
				home = val.GetCustomSpawnPoint();
				return true;
			}
			home = Vector3.zero;
			return false;
		}

		public static void SetHomeHere()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				Home = ((Component)localPlayer).transform.position;
				_inside = false;
			}
		}

		public static void Taken()
		{
			_snapAt = -1f;
			_nextPeriodic = Time.unscaledTime + Mathf.Max(0.5f, Minutes) * 60f;
		}

		public static void ChestClosed()
		{
			if (Enabled && Pin.Gather && _inside)
			{
				_snapAt = Time.unscaledTime + 1f;
			}
		}

		public static void Reset()
		{
			_inside = false;
			_snapAt = -1f;
			_check = 0f;
		}

		public static void Tick()
		{
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			if (!Enabled || !Pin.Gather)
			{
				Reset();
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead())
			{
				Reset();
				return;
			}
			float unscaledTime = Time.unscaledTime;
			if (((Character)localPlayer).IsTeleporting())
			{
				_inside = false;
				_snapAt = -1f;
			}
			else if (_snapAt >= 0f && unscaledTime >= _snapAt)
			{
				_snapAt = -1f;
				Take(unscaledTime);
			}
			else
			{
				if (unscaledTime < _check)
				{
					return;
				}
				_check = unscaledTime + 2f;
				if (TryHome(out var home))
				{
					bool flag = Vector3.Distance(((Component)localPlayer).transform.position, home) <= Stock.SnapshotRadius;
					if (flag && !_inside)
					{
						_snapAt = unscaledTime + 3f;
					}
					else if (flag && _snapAt < 0f && unscaledTime >= _nextPeriodic)
					{
						Take(unscaledTime);
					}
					_inside = flag;
				}
			}
		}

		private static void Take(float now)
		{
			Pin.Snapshot();
			LastWasAuto = true;
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "CloseContainer")]
	internal static class SnapshotOnChestClose
	{
		private static void Prefix(InventoryGui __instance)
		{
			if ((Object)(object)__instance.m_currentContainer != (Object)null)
			{
				AutoSnapshot.ChestClosed();
			}
		}
	}
	[BepInPlugin("jimmymcattaboy.provisioner", "Provisioner", "1.0.2")]
	[BepInProcess("valheim.exe")]
	public class ForgeplanPlugin : BaseUnityPlugin
	{
		public const string Guid = "jimmymcattaboy.provisioner";

		private const string OriginalGuid = "dev.forgeplanner.forgeplan";

		public const string Version = "1.0.2";

		internal static ManualLogSource Log;

		internal static readonly PlannerPanel Panel = new PlannerPanel();

		private ConfigEntry<KeyboardShortcut> _hotkey;

		private ConfigEntry<float> _chestRadius;

		private ConfigEntry<bool> _includeChests;

		private ConfigEntry<bool> _useOwned;

		private ConfigEntry<bool> _selfTest;

		private ConfigEntry<bool> _russian;

		private ConfigEntry<Progress.Mode> _spoilers;

		private ConfigEntry<bool> _stationButton;

		private ConfigEntry<float> _stationX;

		private ConfigEntry<float> _stationY;

		private ConfigEntry<StationButton.Corner> _stationCorner;

		private ConfigEntry<bool> _pinEnabled;

		private ConfigEntry<PinHud.Corner> _pinCorner;

		private ConfigEntry<float> _pinX;

		private ConfigEntry<float> _pinY;

		private ConfigEntry<float> _pinInterval;

		private ConfigEntry<int> _pinRows;

		private ConfigEntry<bool> _pinHideDone;

		private ConfigEntry<bool> _pinBars;

		private ConfigEntry<float> _snapshotRadius;

		private ConfigEntry<bool> _autoSnapshot;

		private ConfigEntry<float> _autoMinutes;

		private ConfigEntry<float> _pinScale;

		private ConfigEntry<bool> _cardEnabled;

		private ConfigEntry<bool> _cardCompare;

		private ConfigEntry<KeyCode> _cardDetails;

		private Harmony _harmony;

		internal static int OpenRequest;

		internal static bool SpoofGui = true;

		private void Awake()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_055f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0564: Unknown result type (might be due to invalid IL or missing references)
			//IL_067c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0686: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			_hotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "Open", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Hotkey that opens the planner.");
			_includeChests = ((BaseUnityPlugin)this).Config.Bind<bool>("Stock", "CountChests", true, "Count nearby chests, not just your backpack.");
			_chestRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Stock", "Radius", 20f, "How far a chest counts as yours, in metres.");
			_useOwned = ((BaseUnityPlugin)this).Config.Bind<bool>("Stock", "UpgradeOwned", false, "Take the level of already-made gear from your backpack and nearby chests instead of marking it by hand. Also toggled by the Owned button.");
			Planner.UseOwned = _useOwned.Value;
			_russian = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Russian", false, "Window labels in Russian. Also toggled by the button in the header.");
			L.Ru = _russian.Value;
			BindSpoilers();
			_stationButton = ((BaseUnityPlugin)this).Config.Bind<bool>("Station", "Button", true, "Show the ForgePlanner button on the crafting panel.");
			_stationCorner = ((BaseUnityPlugin)this).Config.Bind<StationButton.Corner>("Station", "Corner", StationButton.Corner.BottomRight, "Which side of the panel the button's shelf sits on. The shelf is always below the panel, so this reads as left or right.");
			_stationX = ((BaseUnityPlugin)this).Config.Bind<float>("Station", "OffsetX", 14f, "Shelf offset from the panel edge, in points.");
			_stationY = ((BaseUnityPlugin)this).Config.Bind<float>("Station", "DropDown", 0f, "How far below the panel edge to drop the shelf, in points. 0 keeps it flush with the panel.");
			StationButton.Enabled = _stationButton.Value;
			StationButton.Where = _stationCorner.Value;
			StationButton.Offset = new Vector2(_stationX.Value, _stationY.Value);
			_pinEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Pin", "Enabled", true, "Keep pinned materials on screen after the planner is closed.");
			_pinCorner = ((BaseUnityPlugin)this).Config.Bind<PinHud.Corner>("Pin", "Corner", PinHud.Corner.TopRight, "Which corner of the screen the pinned list sits in.");
			_pinX = ((BaseUnityPlugin)this).Config.Bind<float>("Pin", "OffsetX", 42f, "Distance from the side of the screen, in points. Dragging the panel writes this.");
			_pinY = ((BaseUnityPlugin)this).Config.Bind<float>("Pin", "OffsetY", 268f, "Distance from the top or bottom of the screen, in points. The default clears the minimap.");
			_pinInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Pin", "RefreshSeconds", 1f, "How often the remaining amounts are recounted. Counting chests walks the loaded scene, so this is not done every frame.");
			_pinScale = ((BaseUnityPlugin)this).Config.Bind<float>("Pin", "Scale", 1f, "Size of the pinned panel, 0.6 to 2.5. The - and + buttons on the panel, shown while the Esc menu is open, write this.");
			_pinBars = ((BaseUnityPlugin)this).Config.Bind<bool>("Pin", "Bars", false, "Show pinned materials as bars (chests, backpack, still to get) instead of numbers. Also in Settings.");
			_snapshotRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Stock", "SnapshotRadius", 50f, "How far the storage snapshot looks for chests, in metres (20 to 150). Also in Settings.");
			_autoSnapshot = ((BaseUnityPlugin)this).Config.Bind<bool>("Stock", "AutoSnapshot", false, "Update the storage snapshot by itself when you arrive home (on foot or by portal) and every few minutes while there. Home is set in Settings, or your bed. Also in Settings.");
			_autoMinutes = ((BaseUnityPlugin)this).Config.Bind<float>("Stock", "AutoSnapshotMinutes", 2f, "How often the automatic storage snapshot updates while you are home, in minutes.");
			_pinHideDone = ((BaseUnityPlugin)this).Config.Bind<bool>("Pin", "HideGathered", false, "Hide materials you already carry enough of, instead of moving them to the bottom");
			_pinRows = ((BaseUnityPlugin)this).Config.Bind<int>("Pin", "MaxRows", 8, "How many materials to list before collapsing the rest into a count.");
			PinHud.Enabled = _pinEnabled.Value;
			PinHud.Where = _pinCorner.Value;
			if (_pinX.Value == 0f && _pinY.Value == 0f)
			{
				_pinX.Value = (float)((ConfigEntryBase)_pinX).DefaultValue;
				_pinY.Value = (float)((ConfigEntryBase)_pinY).DefaultValue;
				Log.LogInfo((object)"закреплённый список: положение (0, 0) — след старой ошибки, вернул умолчание");
			}
			PinHud.Offset = new Vector2(_pinX.Value, _pinY.Value);
			PinHud.Interval = _pinInterval.Value;
			PinHud.MaxRows = _pinRows.Value;
			PinHud.HideDone = _pinHideDone.Value;
			PinHud.Bars = _pinBars.Value;
			Stock.SnapshotRadius = _snapshotRadius.Value;
			AutoSnapshot.Enabled = _autoSnapshot.Value;
			AutoSnapshot.Minutes = _autoMinutes.Value;
			PinHud.Scale = Mathf.Clamp(_pinScale.Value, 0.6f, 2.5f);
			PinHud.OnScaled = delegate(float v)
			{
				_pinScale.Value = v;
			};
			Pin.Changed = PinHud.Invalidate;
			PinHud.OnMoved = delegate(Vector2 p)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				_pinX.Value = p.x;
				_pinY.Value = p.y;
			};
			_cardEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Tooltip", "Enabled", true, "Show an item card with stats and recipe when hovering a row in the planner.");
			_cardCompare = ((BaseUnityPlugin)this).Config.Bind<bool>("Tooltip", "Compare", true, "Compare the hovered item with what you have equipped in the same slot. Off shows the item's own stats only.");
			_cardDetails = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Tooltip", "DetailsKey", (KeyCode)308, "Hold this key over the item card to see the full text of the set bonus and the item's effect in place of the recipe. With LeftAlt the right Alt works too.");
			ItemCard.Enabled = _cardEnabled.Value;
			ItemCard.Compare = _cardCompare.Value;
			ItemCard.DetailsKey = _cardDetails.Value;
			_cardDetails.SettingChanged += delegate
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				ItemCard.DetailsKey = _cardDetails.Value;
			};
			_selfTest = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "SelfTest", false, "On entering a world, build the catalogue and dump the conversion table and a few calculated orders to the log. Used to check the mod against the website after a game update.");
			UiKit.Verbose = _selfTest.Value;
			Panel.OnLanguageChanged = delegate(bool ru)
			{
				_russian.Value = ru;
			};
			Panel.OnSpoilersChanged = delegate(Progress.Mode mode)
			{
				_spoilers.Value = mode;
			};
			Panel.OnChestsChanged = delegate(bool on)
			{
				_includeChests.Value = on;
			};
			Panel.OnOwnedChanged = delegate(bool on)
			{
				_useOwned.Value = on;
			};
			Panel.OnPinBarsChanged = delegate(bool on)
			{
				_pinBars.Value = on;
			};
			Panel.OnSnapshotRadiusChanged = delegate(float r)
			{
				_snapshotRadius.Value = r;
			};
			Panel.OnAutoSnapshotChanged = delegate(bool on)
			{
				_autoSnapshot.Value = on;
			};
			Panel.OnCardChanged = delegate(bool on, bool compare)
			{
				_cardEnabled.Value = on;
				_cardCompare.Value = compare;
			};
			Panel.Chests = _includeChests.Value;
			_harmony = new Harmony("jimmymcattaboy.provisioner");
			_harmony.PatchAll();
			Log.LogInfo((object)"Provisioner 1.0.2 загружен");
		}

		private void Start()
		{
			if (Chainloader.PluginInfos.ContainsKey("dev.forgeplanner.forgeplan"))
			{
				Log.LogWarning((object)"ForgePlanner (оригинал) тоже установлен. Provisioner его форк: оставьте один из двух. Provisioner отключается.");
				if (_harmony != null)
				{
					_harmony.UnpatchSelf();
				}
				((Behaviour)this).enabled = false;
			}
		}

		private void OnDestroy()
		{
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}

		private void BindSpoilers()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			Dictionary<ConfigDefinition, string> dictionary = null;
			try
			{
				dictionary = typeof(ConfigFile).GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(((BaseUnityPlugin)this).Config) as Dictionary<ConfigDefinition, string>;
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("конфиг: старые ключи не прочитать — " + ex.Message));
			}
			ConfigDefinition key = new ConfigDefinition("General", "HideUnreached");
			string value = null;
			bool flag = dictionary == null || !dictionary.ContainsKey(new ConfigDefinition("General", "Spoilers"));
			dictionary?.TryGetValue(key, out value);
			_spoilers = ((BaseUnityPlugin)this).Config.Bind<Progress.Mode>("General", "Spoilers", Progress.Mode.Discovered, "What the catalogue shows. Discovered: only what your character has discovered, the same recipes the game's crafting menu shows. Bosses: a biome opens when the boss before it falls; Meadows, Black Forest and Ocean are open from the start. Off: everything. Also switched in the Settings window.");
			if (value != null)
			{
				if (flag && value.Trim().ToLowerInvariant() == "false")
				{
					_spoilers.Value = Progress.Mode.Off;
				}
				dictionary.Remove(key);
				((BaseUnityPlugin)this).Config.Save();
				Log.LogInfo((object)("конфиг: HideUnreached = " + value.Trim() + " перенесён в Spoilers = " + _spoilers.Value));
			}
			Progress.Current = _spoilers.Value;
		}

		private void Update()
		{
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			if (_selfTest.Value && !SelfTest.Done && GameData.Build())
			{
				SelfTest.Run();
			}
			PlanStore.Tick();
			AutoSnapshot.Tick();
			if (Panel.Visible)
			{
				Stock.IncludeChests = Panel.Chests;
			}
			PinHud.Tick(Panel.Visible);
			if (Panel.Visible)
			{
				if (GameGuiReallyOpen())
				{
					Panel.Hide();
				}
				else if (Input.GetKeyDown((KeyCode)27))
				{
					if (!Panel.Escape())
					{
						Panel.Hide();
					}
				}
				else
				{
					Panel.Tick();
				}
			}
			if (OpenRequest > 0)
			{
				OpenRequest--;
				if (!Panel.Visible && !IsGameBusy())
				{
					OpenRequest = 0;
					OpenPanel();
				}
			}
			KeyboardShortcut value = _hotkey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown() && (Panel.Visible || !IsGameBusy()))
			{
				OpenPanel();
			}
		}

		private void OpenPanel()
		{
			Panel.Chests = _includeChests.Value;
			Stock.ChestRadius = _chestRadius.Value;
			Panel.Toggle();
			if (!Panel.Visible && (Object)(object)GameCamera.instance != (Object)null)
			{
				GameCamera.instance.UpdateMouseCapture();
			}
		}

		private void LateUpdate()
		{
			if (Panel.Visible)
			{
				Cursor.visible = true;
				Cursor.lockState = (CursorLockMode)0;
			}
		}

		internal static bool BlockFor(Player p)
		{
			if (Panel.Visible && (Object)(object)p != (Object)null)
			{
				return (Object)(object)p == (Object)(object)Player.m_localPlayer;
			}
			return false;
		}

		private static bool GameGuiReallyOpen()
		{
			SpoofGui = false;
			try
			{
				return Menu.IsVisible() || InventoryGui.IsVisible();
			}
			finally
			{
				SpoofGui = true;
			}
		}

		private static bool IsGameBusy()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Invalid comparison between Unknown and I4
			if ((Object)(object)Player.m_localPlayer == (Object)null)
			{
				return true;
			}
			if ((Object)(object)Minimap.instance != (Object)null && (int)Minimap.instance.m_mode == 2)
			{
				return true;
			}
			if (GameGuiReallyOpen() || Console.IsVisible())
			{
				return true;
			}
			if ((Object)(object)TextViewer.instance != (Object)null && TextViewer.instance.IsVisible())
			{
				return true;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Shutdown")]
	internal static class ResetOnLeave
	{
		private static void Postfix()
		{
			PlanStore.Leave();
			ForgeplanPlugin.Panel.Drop();
			ForgeplanPlugin.Panel.ResetFilters();
			PinHud.Drop();
			GameData.Reset();
			Trade.Reset();
			Progress.Reset();
			Planner.Cart.Clear();
			Pin.Clear();
			SelfTest.Done = false;
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "IsVisible")]
	internal static class PretendGuiOpen
	{
		private static void Postfix(ref bool __result)
		{
			if (ForgeplanPlugin.SpoofGui && ForgeplanPlugin.Panel.Visible)
			{
				__result = true;
			}
		}
	}
	[HarmonyPatch(typeof(Player), "PlayerAttackInput")]
	internal static class NoAttacksWhileOpen
	{
		private static bool Prefix(Player __instance)
		{
			return !ForgeplanPlugin.BlockFor(__instance);
		}
	}
	[HarmonyPatch(typeof(Player), "UpdatePlacement")]
	internal static class NoBuildingWhileOpen
	{
		private static void Prefix(Player __instance, ref bool takeInput)
		{
			if (ForgeplanPlugin.BlockFor(__instance))
			{
				takeInput = false;
			}
		}
	}
	[HarmonyPatch(typeof(Player), "UseHotbarItem")]
	internal static class NoHotbarWhileOpen
	{
		private static bool Prefix(Player __instance)
		{
			return !ForgeplanPlugin.BlockFor(__instance);
		}
	}
	[HarmonyPatch(typeof(Player), "UpdateCrouch")]
	internal static class NoCrouchWhileOpen
	{
		private static bool Prefix(Player __instance)
		{
			return !ForgeplanPlugin.BlockFor(__instance);
		}
	}
	[HarmonyPatch(typeof(Player), "StartGuardianPower")]
	internal static class NoGuardianPowerWhileOpen
	{
		private static bool Prefix(Player __instance, ref bool __result)
		{
			if (!ForgeplanPlugin.BlockFor(__instance))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(Player), "SetControls")]
	internal static class BlockControlsWhileOpen
	{
		private static void Prefix(ref Vector3 movedir, ref bool attack, ref bool attackHold, ref bool secondaryAttack, ref bool secondaryAttackHold, ref bool block, ref bool blockHold, ref bool jump, ref bool crouch, ref bool run, ref bool autoRun, ref bool dodge)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if (ForgeplanPlugin.Panel.Visible)
			{
				movedir = Vector3.zero;
				attack = (attackHold = (secondaryAttack = (secondaryAttackHold = false)));
				block = (blockHold = (jump = (crouch = (run = (autoRun = (dodge = false))))));
			}
		}
	}
	[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
	internal static class FreezeCameraWhileOpen
	{
		private static bool Prefix()
		{
			return !ForgeplanPlugin.Panel.Visible;
		}
	}
	[HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")]
	internal static class FreeCursorWhileOpen
	{
		private static bool Prefix()
		{
			return !ForgeplanPlugin.Panel.Visible;
		}
	}
	public class ItemDef
	{
		public string Id;

		public string Name;

		public string Token = "";

		public Sprite Icon;

		public GameObject Prefab;

		public int Out = 1;

		public string Station = "";

		public int MinStationLevel = 1;

		public int MaxQuality = 1;

		public List<Dictionary<string, int>> Levels = new List<Dictionary<string, int>>();

		public bool IsMaterial;

		public Kind Group = Kind.Other;

		public int Tier = -1;

		public string Haystack = "";

		public string Ru;

		public string En;

		public List<string> MoreStations;

		public bool Totem;

		public bool FromConversion;

		public bool HasRecipe => Levels.Count > 0;

		public string Shown
		{
			get
			{
				string text = (L.Ru ? Ru : En);
				if (!string.IsNullOrEmpty(text))
				{
					return text;
				}
				if (!Nameless(Name))
				{
					return Name;
				}
				string text2 = (L.Ru ? En : Ru);
				if (!string.IsNullOrEmpty(text2))
				{
					return text2;
				}
				return Name;
			}
		}

		public static bool Nameless(string name)
		{
			if (!string.IsNullOrEmpty(name))
			{
				return name[0] == '[';
			}
			return true;
		}
	}
	public enum Kind
	{
		Weapon,
		Armor,
		Tool,
		Food,
		Material,
		Piece,
		Other
	}
	public class Rule
	{
		public Dictionary<string, int> Mats = new Dictionary<string, int>();

		public string Station = "";

		public int Out = 1;

		public int Sec;

		public int Cap;

		public int Slots = 1;
	}
	public static class GameData
	{
		public static readonly Dictionary<string, ItemDef> Items = new Dictionary<string, ItemDef>();

		public static readonly Dictionary<string, Rule> Convert = new Dictionary<string, Rule>();

		public static readonly Dictionary<string, string> StationNames = new Dictionary<string, string>();

		public static readonly Dictionary<string, Sprite> StationIcons = new Dictionary<string, Sprite>();

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

		public static readonly List<string> Shadowed = new List<string>();

		public static int Mirrored;

		public static int SkippedUpgraders;

		public static int Pieces;

		public static readonly Dictionary<string, List<int>> RecipeAmounts = new Dictionary<string, List<int>>();

		private static readonly Dictionary<string, int> TierMemo = new Dictionary<string, int>();

		public static Rule KilnRule;

		private static readonly HashSet<string> SkipTools = new HashSet<string> { "cultivator" };

		public static int SkippedPlanting;

		public static int SkippedServings;

		public static int SkippedNameless;

		private static readonly string[] CookOrder = new string[5] { "fermenter", "piece_oven", "windmill", "piece_cookingstation", "piece_cookingstation_iron" };

		private static readonly Dictionary<string, string> Prefer = new Dictionary<string, string>
		{
			{ "iron", "ironscrap" },
			{ "copper", "copperore" }
		};

		public static bool Ready { get; private set; }

		public static Sprite StationIcon(string id)
		{
			if (!StationIcons.TryGetValue(id, out var value))
			{
				return null;
			}
			return value;
		}

		public static string StationName(string id)
		{
			if (string.IsNullOrEmpty(id))
			{
				return id;
			}
			string text = Names.Get(L.Ru ? Names.StationRu : Names.StationEn, id);
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			if (!StationNames.TryGetValue(id, out var value))
			{
				return id;
			}
			return value;
		}

		public static string Slug(string prefab)
		{
			if (string.IsNullOrEmpty(prefab))
			{
				return "";
			}
			StringBuilder stringBuilder = new StringBuilder(prefab.Length);
			bool flag = false;
			for (int i = 0; i < prefab.Length; i++)
			{
				char c = char.ToLowerInvariant(prefab[i]);
				if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'))
				{
					if (flag && stringBuilder.Length > 0)
					{
						stringBuilder.Append('_');
					}
					flag = false;
					stringBuilder.Append(c);
				}
				else
				{
					flag = true;
				}
			}
			return stringBuilder.ToString();
		}

		public static ItemDef Get(string id)
		{
			if (Items.TryGetValue(id, out var value))
			{
				return value;
			}
			if (!PlanTotems.IsTotem(id))
			{
				return null;
			}
			return PlanTotems.Def(id);
		}

		public static string IdByToken(string token)
		{
			if (string.IsNullOrEmpty(token))
			{
				return null;
			}
			if (ByToken.Count == 0)
			{
				foreach (ItemDef value2 in Items.Values)
				{
					if (!value2.Id.StartsWith("piece:") && !string.IsNullOrEmpty(value2.Token) && !ByToken.ContainsKey(value2.Token))
					{
						ByToken[value2.Token] = value2.Id;
					}
				}
			}
			if (!ByToken.TryGetValue(token, out var value))
			{
				return null;
			}
			return value;
		}

		public static string NameOf(string id)
		{
			ItemDef itemDef = Get(id);
			if (itemDef != null)
			{
				return itemDef.Shown;
			}
			string text = Names.Get(L.Ru ? Names.Ru : Names.En, id);
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			return id;
		}

		public static void Reset()
		{
			Items.Clear();
			Convert.Clear();
			StationNames.Clear();
			Shadowed.Clear();
			ByToken.Clear();
			PlanTotems.Reset();
			StationIcons.Clear();
			TierMemo.Clear();
			RecipeAmounts.Clear();
			KilnRule = null;
			Mirrored = 0;
			SkippedUpgraders = 0;
			Pieces = 0;
			Ready = false;
			SkippedPlanting = 0;
			SkippedServings = 0;
			SkippedNameless = 0;
		}

		public static int TierOf(ItemDef it)
		{
			return TierOf(it, 0);
		}

		private static int TierOf(ItemDef it, int depth)
		{
			if (it == null || it.Levels.Count == 0)
			{
				return -1;
			}
			int num = -1;
			foreach (string key in it.Levels[0].Keys)
			{
				int num2 = MatTier(key, 0);
				if (num2 > num)
				{
					num = num2;
				}
			}
			if (depth < 4 && !string.IsNullOrEmpty(it.Station))
			{
				ItemDef itemDef = Get(PieceId(it.Station));
				if (itemDef != null && itemDef != it)
				{
					int num3 = TierOf(itemDef, depth + 1);
					if (num3 > num)
					{
						num = num3;
					}
				}
			}
			return num;
		}

		private static int MatTier(string id, int depth)
		{
			if (TierMemo.TryGetValue(id, out var value))
			{
				return value;
			}
			if (depth > 8)
			{
				return -1;
			}
			TierMemo[id] = -1;
			if (Tiers.OfMaterial.TryGetValue(id, out value))
			{
				TierMemo[id] = value;
				return value;
			}
			int num = -1;
			if (Convert.TryGetValue(id, out var value2))
			{
				foreach (string key in value2.Mats.Keys)
				{
					int num2 = MatTier(key, depth + 1);
					if (num2 > num)
					{
						num = num2;
					}
				}
			}
			else
			{
				ItemDef itemDef = Get(id);
				if (itemDef != null && itemDef.Levels.Count > 0)
				{
					foreach (string key2 in itemDef.Levels[0].Keys)
					{
						int num3 = MatTier(key2, depth + 1);
						if (num3 > num)
						{
							num = num3;
						}
					}
				}
			}
			TierMemo[id] = num;
			return num;
		}

		public static bool Build()
		{
			if (Ready)
			{
				return true;
			}
			if ((Object)(object)ObjectDB.instance == (Object)null || ObjectDB.instance.m_items.Count == 0)
			{
				return false;
			}
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				return false;
			}
			Stopwatch stopwatch = Stopwatch.StartNew();
			Reset();
			IndexItems();
			IndexRecipes();
			IndexConversions();
			DropShadowed();
			LiftKiln();
			MirrorConversions();
			IndexPieces();
			foreach (ItemDef value in Items.Values)
			{
				value.Tier = TierOf(value);
				string text = (value.Id.StartsWith("piece:") ? value.Id.Substring(6) : value.Id);
				value.Ru = Names.Get(Names.Ru, text);
				value.En = Names.Get(Names.En, text);
				value.Haystack = (value.Name + " " + text + " " + value.Ru + " " + value.En).ToLowerInvariant();
			}
			DropNameless();
			Ready = true;
			ForgeplanPlugin.Log.LogInfo((object)$"каталог собран за {stopwatch.ElapsedMilliseconds} мс: {Items.Count} предметов, из них {Pieces} построек; отброшено: посадок {SkippedPlanting}, подач на стол {SkippedServings}, без названия {SkippedNameless}");
			return true;
		}

		private static void DropShadowed()
		{
			foreach (KeyValuePair<string, Rule> item in Convert)
			{
				ItemDef itemDef = Get(item.Key);
				if (itemDef != null && itemDef.HasRecipe)
				{
					Shadowed.Add(item.Key);
				}
			}
			foreach (string item2 in Shadowed)
			{
				Convert.Remove(item2);
			}
		}

		private static void MirrorConversions()
		{
			foreach (KeyValuePair<string, Rule> item in Convert)
			{
				ItemDef itemDef = Get(item.Key);
				if (itemDef != null && !itemDef.HasRecipe)
				{
					itemDef.Levels.Add(new Dictionary<string, int>(item.Value.Mats));
					itemDef.Out = Mathf.Max(1, item.Value.Out);
					itemDef.Station = item.Value.Station;
					itemDef.MinStationLevel = 1;
					itemDef.FromConversion = true;
					Mirrored++;
				}
			}
		}

		private static void LiftKiln()
		{
			if (Convert.TryGetValue("coal", out var value))
			{
				KilnRule = value;
				Convert.Remove("coal");
			}
		}

		private static void IndexItems()
		{
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Invalid comparison between Unknown and I4
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			foreach (GameObject item in ObjectDB.instance.m_items)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				ItemDrop component = item.GetComponent<ItemDrop>();
				if (!((Object)(object)component == (Object)null) && component.m_itemData != null)
				{
					SharedData shared = component.m_itemData.m_shared;
					string text = Slug(((Object)item).name);
					if (!Items.ContainsKey(text))
					{
						Items[text] = new ItemDef
						{
							Id = text,
							Prefab = item,
							Name = Localization.instance.Localize(shared.m_name),
							Token = (shared.m_name ?? ""),
							Icon = ((shared.m_icons != null && shared.m_icons.Length != 0) ? shared.m_icons[0] : null),
							MaxQuality = Mathf.Max(1, shared.m_maxQuality),
							IsMaterial = ((int)shared.m_itemType == 1),
							Group = GroupOf(shared.m_itemType)
						};
					}
				}
			}
		}

		private static Kind GroupOf(ItemType t)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected I4, but got Unknown
			switch (t - 1)
			{
			case 2:
			case 3:
			case 8:
			case 13:
			case 19:
			case 21:
			case 22:
				return Kind.Weapon;
			case 4:
			case 5:
			case 6:
			case 10:
			case 11:
			case 16:
			case 17:
			case 23:
				return Kind.Armor;
			case 14:
			case 18:
				return Kind.Tool;
			case 1:
				return Kind.Food;
			case 0:
				return Kind.Material;
			default:
				return Kind.Other;
			}
		}

		public static string PieceId(string prefab)
		{
			return "piece:" + Slug(prefab);
		}

		private static HashSet<GameObject> Buildable()
		{
			HashSet<GameObject> hashSet = new HashSet<GameObject>();
			HashSet<GameObject> hashSet2 = new HashSet<GameObject>();
			foreach (GameObject item in ObjectDB.instance.m_items)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				ItemDrop component = item.GetComponent<ItemDrop>();
				if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null)
				{
					continue;
				}
				PieceTable buildPieces = component.m_itemData.m_shared.m_buildPieces;
				if ((Object)(object)buildPieces == (Object)null || buildPieces.m_pieces == null)
				{
					continue;
				}
				HashSet<GameObject> hashSet3 = (SkipTools.Contains(Slug(((Object)item).name)) ? hashSet2 : hashSet);
				foreach (GameObject piece in buildPieces.m_pieces)
				{
					if ((Object)(object)piece != (Object)null)
					{
						hashSet3.Add(piece);
					}
				}
			}
			hashSet2.ExceptWith(hashSet);
			SkippedPlanting = hashSet2.Count;
			return hashSet;
		}

		private static void DropNameless()
		{
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, ItemDef> item in Items)
			{
				ItemDef value = item.Value;
				if (ItemDef.Nameless(value.Name) && string.IsNullOrEmpty(value.Ru) && string.IsNullOrEmpty(value.En))
				{
					list.Add(item.Key);
				}
			}
			foreach (string item2 in list)
			{
				if (Items[item2].Group == Kind.Piece)
				{
					Pieces--;
				}
				Items.Remove(item2);
				ForgeplanPlugin.Log.LogInfo((object)("без названия, пропущено: " + item2));
			}
			SkippedNameless = list.Count;
		}

		private static void IndexPieces()
		{
			HashSet<GameObject> hashSet = Buildable();
			foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
			{
				if ((Object)(object)prefab == (Object)null || !hashSet.Contains(prefab))
				{
					continue;
				}
				Piece component = prefab.GetComponent<Piece>();
				if ((Object)(object)component == (Object)null || !component.m_enabled || component.m_resources == null || component.m_resources.Length == 0)
				{
					continue;
				}
				string text = PieceId(((Object)prefab).name);
				if (Items.ContainsKey(text))
				{
					continue;
				}
				Dictionary<string, int> dictionary = new Dictionary<string, int>();
				ItemDrop single = null;
				Requirement[] resources = component.m_resources;
				foreach (Requirement val in resources)
				{
					if (val != null && !((Object)(object)val.m_resItem == (Object)null) && val.m_amount > 0)
					{
						dictionary[Slug(((Object)((Component)val.m_resItem).gameObject).name)] = val.m_amount;
						single = val.m_resItem;
					}
				}
				if (dictionary.Count == 0)
				{
					continue;
				}
				string name = Localization.instance.Localize(component.m_name);
				if (IsServing(dictionary, single, name))
				{
					SkippedServings++;
					continue;
				}
				string station = (((Object)(object)component.m_craftingStation != (Object)null) ? Slug(((Object)((Component)component.m_craftingStation).gameObject).name) : "");
				ItemDef itemDef = new ItemDef
				{
					Id = text,
					Name = name,
					Token = (component.m_name ?? ""),
					Icon = component.m_icon,
					MaxQuality = 1,
					Out = 1,
					Station = station,
					MinStationLevel = 1,
					Group = Kind.Piece
				};
				itemDef.Levels.Add(dictionary);
				Items[text] = itemDef;
				if ((Object)(object)component.m_craftingStation != (Object)null)
				{
					Remember(station, component.m_craftingStation.m_name);
				}
				Pieces++;
			}
		}

		private static bool IsServing(Dictionary<string, int> cost, ItemDrop single, string name)
		{
			if (cost.Count != 1 || (Object)(object)single == (Object)null || string.IsNullOrEmpty(name))
			{
				return false;
			}
			foreach (KeyValuePair<string, int> item in cost)
			{
				if (item.Value != 1)
				{
					return false;
				}
			}
			if (single.m_itemData == null || single.m_itemData.m_shared == null)
			{
				return false;
			}
			return Localization.instance.Localize(single.m_itemData.m_shared.m_name) == name;
		}

		private static void IndexRecipes()
		{
			foreach (Recipe recipe in ObjectDB.instance.m_recipes)
			{
				if ((Object)(object)recipe == (Object)null || (Object)(object)recipe.m_item == (Object)null || !recipe.m_enabled)
				{
					continue;
				}
				string text = Slug(((Object)((Component)recipe.m_item).gameObject).name);
				ItemDef itemDef = Get(text);
				if (itemDef == null)
				{
					continue;
				}
				int num = Mathf.Max(1, recipe.m_amount);
				if (!RecipeAmounts.TryGetValue(text, out var value))
				{
					value = (RecipeAmounts[text] = new List<int>());
				}
				value.Add(num);
				if (itemDef.HasRecipe && num >= itemDef.Out)
				{
					continue;
				}
				itemDef.Out = num;
				itemDef.Station = (((Object)(object)recipe.m_craftingStation != (Object)null) ? Slug(((Object)((Component)recipe.m_craftingStation).gameObject).name) : "");
				itemDef.MinStationLevel = Mathf.Max(1, recipe.m_minStationLevel);
				if ((Object)(object)recipe.m_craftingStation != (Object)null)
				{
					Remember(itemDef.Station, recipe.m_craftingStation.m_name, ((Component)recipe.m_craftingStation).gameObject);
				}
				itemDef.Levels.Clear();
				for (int i = 1; i <= itemDef.MaxQuality; i++)
				{
					Dictionary<string, int> dictionary = new Dictionary<string, int>();
					Requirement[] resources = recipe.m_resources;
					foreach (Requirement val in resources)
					{
						if (val == null || (Object)(object)val.m_resItem == (Object)null)
						{
							continue;
						}
						if (val.m_upgraderResource)
						{
							if (i == 1)
							{
								SkippedUpgraders++;
							}
							continue;
						}
						int amount = val.GetAmount(i);
						if (amount > 0)
						{
							dictionary[Slug(((Object)((Component)val.m_resItem).gameObject).name)] = amount;
						}
					}
					itemDef.Levels.Add(dictionary);
				}
			}
		}

		private static void IndexConversions()
		{
			foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
			{
				if ((Object)(object)prefab == (Object)null)
				{
					continue;
				}
				string station = Slug(((Object)prefab).name);
				Smelter component = prefab.GetComponent<Smelter>();
				if ((Object)(object)component != (Object)null)
				{
					Remember(station, PieceName(prefab, component.m_name), prefab);
					foreach (ItemConversion item in component.m_conversion)
					{
						if (item != null && !((Object)(object)item.m_from == (Object)null) && !((Object)(object)item.m_to == (Object)null))
						{
							Rule rule = new Rule
							{
								Station = station,
								Out = 1,
								Sec = Mathf.RoundToInt(component.m_secPerProduct),
								Cap = component.m_maxOre,
								Slots = 1
							};
							rule.Mats[Slug(((Object)((Component)item.m_from).gameObject).name)] = 1;
							if ((Object)(object)component.m_fuelItem != (Object)null && component.m_fuelPerProduct > 0)
							{
								rule.Mats[Slug(((Object)((Component)component.m_fuelItem).gameObject).name)] = component.m_fuelPerProduct;
							}
							Put(Slug(((Object)((Component)item.m_to).gameObject).name), rule);
						}
					}
				}
				Fermenter component2 = prefab.GetComponent<Fermenter>();
				if ((Object)(object)component2 != (Object)null)
				{
					Remember(station, PieceName(prefab, component2.m_name), prefab);
					foreach (ItemConversion item2 in component2.m_conversion)
					{
						if (item2 != null && !((Object)(object)item2.m_from == (Object)null) && !((Object)(object)item2.m_to == (Object)null))
						{
							Rule rule2 = new Rule
							{
								Station = station,
								Out = Mathf.Max(1, item2.m_producedItems),
								Sec = Mathf.RoundToInt(component2.m_fermentationDuration),
								Slots = 1
							};
							rule2.Mats[Slug(((Object)((Component)item2.m_from).gameObject).name)] = 1;
							Put(Slug(((Object)((Component)item2.m_to).gameObject).name), rule2);
						}
					}
				}
				CookingStation component3 = prefab.GetComponent<CookingStation>();
				if (!((Object)(object)component3 != (Object)null))
				{
					continue;
				}
				Remember(station, PieceName(prefab, component3.m_name), prefab);
				int num = ((component3.m_slots == null) ? 1 : component3.m_slots.Length);
				foreach (ItemConversion item3 in component3.m_conversion)
				{
					if (item3 != null && !((Object)(object)item3.m_from == (Object)null) && !((Object)(object)item3.m_to == (Object)null))
					{
						Rule rule3 = new Rule
						{
							Station = station,
							Out = 1,
							Sec = Mathf.RoundToInt(item3.m_cookTime),
							Slots = Mathf.Max(1, num)
						};
						rule3.Mats[Slug(((Object)((Component)item3.m_from).gameObject).name)] = 1;
						Put(Slug(((Object)((Component)item3.m_to).gameObject).name), rule3);
					}
				}
			}
		}

		private static int CookRank(string station)
		{
			int num = Array.IndexOf(CookOrder, station);
			if (num >= 0)
			{
				return num;
			}
			return int.MaxValue;
		}

		private static void Put(string to, Rule rule)
		{
			if (!string.IsNullOrEmpty(to))
			{
				string value;
				bool flag = Prefer.TryGetValue(to, out value) && rule.Mats.ContainsKey(value);
				if (!Convert.TryGetValue(to, out var value2) || flag || CookRank(rule.Station) < CookRank(value2.Station))
				{
					Convert[to] = rule;
				}
			}
		}

		private static string PieceName(GameObject prefab, string fallback)
		{
			Piece component = prefab.GetComponent<Piece>();
			if (!((Object)(object)component != (Object)null) || string.IsNullOrEmpty(component.m_name))
			{
				return fallback;
			}
			return component.m_name;
		}

		private static void Remember(string station, string token, GameObject prefab = null)
		{
			if (string.IsNullOrEmpty(station))
			{
				return;
			}
			if ((Object)(object)prefab != (Object)null && !StationIcons.ContainsKey(station))
			{
				Piece component = prefab.GetComponent<Piece>();
				if ((Object)(object)component != (Object)null && (Object)(object)component.m_icon != (Object)null)
				{
					StationIcons[station] = component.m_icon;
				}
			}
			if (!string.IsNullOrEmpty(token) && !StationNames.ContainsKey(station))
			{
				StationNames[station] = Localization.instance.Localize(token);
			}
		}
	}
	public enum Better
	{
		Higher,
		Lower,
		None
	}
	public class Stat
	{
		public string Key;

		public int Order;

		public string Label;

		public float Value;

		public string Text;

		public Better Dir;

		public Func<float, string> Delta;
	}
	public class Detail
	{
		public string Key;

		public string Name;

		public string Title;

		public string Sub;

		public string Body;
	}
	public static class ItemStats
	{
		private static readonly string[] OrderKeys = new string[38]
		{
			"damage", "slash", "blunt", "pierce", "fire", "frost", "lightning", "poison", "spirit", "chop",
			"pickaxe", "tooltier", "armor", "block", "parry", "deflect", "knockback", "backstab", "stamina", "eitr",
			"health", "eitrregen", "adrenaline", "res_header", "res_blunt", "res_slash", "res_pierce", "res_fire", "res_frost", "res_lightning",
			"res_poison", "res_spirit", "movement", "durability", "weight", "effect", "adreffect", "set"
		};

		private static readonly CultureInfo Inv = CultureInfo.InvariantCulture;

		public static bool Wearable(ItemType t)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected I4, but got Unknown
			switch (t - 3)
			{
			case 0:
			case 1:
			case 2:
			case 3:
			case 4:
			case 6:
			case 8:
			case 11:
			case 12:
			case 14:
			case 15:
			case 16:
			case 17:
			case 19:
			case 21:
				return true;
			default:
				return false;
			}
		}

		private static bool InHands(ItemType t)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Invalid comparison between Unknown and I4
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected I4, but got Unknown
			if (t - 3 > 1)
			{
				switch (t - 14)
				{
				case 0:
				case 1:
				case 5:
				case 6:
				case 8:
					break;
				default:
					return false;
				}
			}
			return true;
		}

		public static ItemData Equipped(Player p, ItemType t)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Invalid comparison between Unknown and I4
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Invalid comparison between Unknown and I4
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected I4, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Invalid comparison between Unknown and I4
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Invalid comparison between Unknown and I4
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Invalid comparison between Unknown and I4
			if ((Object)(object)p == (Object)null)
			{
				return null;
			}
			if (InHands(t))
			{
				if (((Humanoid)p).m_rightItem != null)
				{
					return ((Humanoid)p).m_rightItem;
				}
				ItemData leftItem = ((Humanoid)p).m_leftItem;
				if (leftItem != null && InHands(leftItem.m_shared.m_itemType))
				{
					return leftItem;
				}
				return null;
			}
			if ((int)t <= 17)
			{
				switch (t - 5)
				{
				default:
					if ((int)t != 17)
					{
						break;
					}
					return ((Humanoid)p).m_shoulderItem;
				case 0:
				{
					ItemData leftItem2 = ((Humanoid)p).m_leftItem;
					if (leftItem2 == null || (int)leftItem2.m_shared.m_itemType != 5)
					{
						return null;
					}
					return leftItem2;
				}
				case 1:
					return ((Humanoid)p).m_helmetItem;
				case 2:
					return ((Humanoid)p).m_chestItem;
				case 6:
					return ((Humanoid)p).m_legItem;
				case 4:
					return ((Humanoid)p).m_ammoItem;
				case 3:
				case 5:
					break;
				}
			}
			else
			{
				if ((int)t == 18)
				{
					return ((Humanoid)p).m_utilityItem;
				}
				if ((int)t == 24)
				{
					return ((Humanoid)p).m_trinketItem;
				}
			}
			return null;
		}

		private static int OrderOf(string key)
		{
			int num = Array.IndexOf(OrderKeys, key);
			if (num >= 0)
			{
				return num;
			}
			return OrderKeys.Length;
		}

		private static string Num(float v)
		{
			float num = Mathf.Round(v * 10f) / 10f;
			if (!Mathf.Approximately(num, Mathf.Round(num)))
			{
				return num.ToString("0.0", Inv);
			}
			return Mathf.RoundToInt(num).ToString(Inv);
		}

		private static string Signed(string body, float v)
		{
			return ((v > 0f) ? "+" : ((v < 0f) ? "−" : "")) + body;
		}

		private static string Pct(float v)
		{
			return Num(v * 100f) + "%";
		}

		private static Stat Numeric(List<Stat> list, string key, string label, float value, Better dir, Func<float, string> fmt = null)
		{
			if (fmt == null)
			{
				fmt = Num;
			}
			Stat stat = new Stat
			{
				Key = key,
				Order = OrderOf(key),
				Label = label,
				Value = value,
				Dir = dir,
				Delta = (float d) => Signed(fmt(Mathf.Abs(d)), d)
			};
			stat.Text = ((key == "movement" || key == "eitrregen") ? Signed(fmt(Mathf.Abs(value)), value) : fmt(value));
			list.Add(stat);
			return stat;
		}

		private static void Words(List<Stat> list, string key, string label, string text)
		{
			if (!string.IsNullOrEmpty(text))
			{
				list.Add(new Stat
				{
					Key = key,
					Order = OrderOf(key),
					Label = label,
					Text = text,
					Dir = Better.None
				});
			}
		}

		private static string Localized(StatusEffect se)
		{
			if ((Object)(object)se == (Object)null || string.IsNullOrEmpty(se.m_name))
			{
				return null;
			}
			return Localization.instance.Localize(se.m_name);
		}

		public static List<Stat> Read(ItemData d, int quality, float worldLevel)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Invalid comparison between Unknown and I4
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Invalid comparison between Unknown and I4
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Invalid comparison between Unknown and I4
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_0385: Unknown result type (might be due to invalid IL or missing references)
			//IL_0388: Invalid comparison between Unknown and I4
			//IL_0464: Unknown result type (might be due to invalid IL or missing references)
			//IL_0467: Invalid comparison between Unknown and I4
			List<Stat> list = new List<Stat>();
			if (d == null || d.m_shared == null)
			{
				return list;
			}
			SharedData shared = d.m_shared;
			ItemType itemType = shared.m_itemType;
			quality = Mathf.Max(1, quality);
			int num;
			if (!InHands(itemType))
			{
				num = (((int)itemType == 9) ? 1 : 0);
				if (num == 0)
				{
					goto IL_0186;
				}
			}
			else
			{
				num = 1;
			}
			DamageTypes damage = d.GetDamage(quality, worldLevel);
			Dmg(list, "damage", L.StDamage, damage.m_damage);
			Dmg(list, "slash", L.StSlash, damage.m_slash);
			Dmg(list, "blunt", L.StBlunt, damage.m_blunt);
			Dmg(list, "pierce", L.StPierce, damage.m_pierce);
			Dmg(list, "fire", L.StFire, damage.m_fire);
			Dmg(list, "frost", L.StFrost, damage.m_frost);
			Dmg(list, "lightning", L.StLightning, damage.m_lightning);
			Dmg(list, "poison", L.StPoison, damage.m_poison);
			Dmg(list, "spirit", L.StSpirit, damage.m_spirit);
			Dmg(list, "chop", L.StChop, damage.m_chop);
			Dmg(list, "pickaxe", L.StPickaxe, damage.m_pickaxe);
			if (shared.m_toolTier > 0 && (damage.m_chop > 0f || damage.m_pickaxe > 0f))
			{
				Numeric(list, "tooltier", L.StToolTier, shared.m_toolTier, Better.Higher);
			}
			goto IL_0186;
			IL_0186:
			if (num != 0 || (int)itemType == 5)
			{
				float baseBlockPower = d.GetBaseBlockPower(quality);
				if (baseBlockPower > 0f)
				{
					Numeric(list, "block", L.StBlock, baseBlockPower, Better.Higher);
				}
				if (shared.m_timedBlockBonus > 1f)
				{
					Numeric(list, "parry", L.StParry, shared.m_timedBlockBonus, Better.Higher, (float v) => "×" + Num(v));
				}
			}
			if ((int)itemType == 5)
			{
				float deflectionForce = d.GetDeflectionForce(quality);
				if (deflectionForce > 0f)
				{
					Numeric(list, "deflect", L.StDeflect, deflectionForce, Better.Higher);
				}
			}
			if (InHands(itemType))
			{
				if (shared.m_attackForce > 0f)
				{
					Numeric(list, "knockback", L.StKnockback, shared.m_attackForce, Better.Higher);
				}
				if (shared.m_backstabBonus > 1f)
				{
					Numeric(list, "backstab", L.StBackstab, shared.m_backstabBonus, Better.Higher, (float v) => "×" + Num(v));
				}
				Attack attack = shared.m_attack;
				if (attack != null)
				{
					if (attack.m_attackStamina > 0f)
					{
						Numeric(list, "stamina", L.StStamina, attack.m_attackStamina, Better.Lower);
					}
					if (attack.m_attackEitr > 0f)
					{
						Numeric(list, "eitr", L.StEitr, attack.m_attackEitr, Better.Lower);
					}
					if (attack.m_attackHealth > 0f)
					{
						Numeric(list, "health", L.StHealth, attack.m_attackHealth, Better.Lower);
					}
				}
			}
			float armor = d.GetArmor(quality, worldLevel);
			if (armor > 0f)
			{
				Numeric(list, "armor", L.StArmor, armor, Better.Higher);
			}
			if (!Mathf.Approximately(shared.m_eitrRegenModifier, 0f))
			{
				Numeric(list, "eitrregen", L.StEitrRegen, shared.m_eitrRegenModifier, Better.Higher, Pct);
			}
			if ((int)itemType == 24 && shared.m_maxAdrenaline > 0f)
			{
				Numeric(list, "adrenaline", L.StAdrenaline, shared.m_maxAdrenaline, Better.Lower);
			}
			Resistances(list, shared.m_damageModifiers);
			if (!Mathf.Approximately(shared.m_movementModifier, 0f))
			{
				Numeric(list, "movement", L.StMovement, shared.m_movementModifier, Better.Higher, Pct);
			}
			if (shared.m_useDurability)
			{
				Numeric(list, "durability", L.StDurability, d.GetMaxDurability(quality), Better.Higher);
			}
			if (shared.m_weight > 0f)
			{
				Numeric(list, "weight", L.StWeight, shared.m_weight, Better.Lower);
			}
			Words(list, "effect", L.StEffect, Localized(shared.m_equipStatusEffect));
			if ((int)itemType == 24)
			{
				Words(list, "adreffect", L.StEffect, Localized(shared.m_fullAdrenalineSE));
			}
			if ((Object)(object)shared.m_setStatusEffect != (Object)null && shared.m_setSize > 1)
			{
				string text = Localized(shared.m_setStatusEffect);
				if (text != null)
				{
					Words(list, "set", L.StSet, text + " (" + shared.m_setSize + ")");
				}
			}
			return list;
		}

		public static List<Detail> Details(ItemData d, int quality, Player p)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Invalid comparison between Unknown and I4
			List<Detail> list = new List<Detail>();
			if (d == null || d.m_shared == null)
			{
				return list;
			}
			SharedData s = d.m_shared;
			quality = Mathf.Max(1, quality);
			float skill = (((Object)(object)p != (Object)null) ? ((Character)p).GetSkillLevel(s.m_skillType) : 0f);
			string text = Localized(s.m_equipStatusEffect);
			if (text != null)
			{
				Add(list, "effect", text, L.StEffect, null, Safe(() => d.GetStatusEffectTooltip(quality, skill)));
			}
			if ((int)s.m_itemType == 24)
			{
				string text2 = Localized(s.m_fullAdrenalineSE);
				if (text2 != null)
				{
					Add(list, "adreffect", text2, L.StAdrenaline, null, Safe(() => s.m_fullAdrenalineSE.GetTooltipString()));
				}
			}
			if ((Object)(object)s.m_setStatusEffect != (Object)null && s.m_setSize > 1)
			{
				string text3 = Localized(s.m_setStatusEffect);
				if (text3 != null)
				{
					int worn = (((Object)(object)p != (Object)null && !string.IsNullOrEmpty(s.m_setName)) ? ((Humanoid)p).GetSetCount(s.m_setName) : 0);
					Add(list, "set", text3, L.StSet, L.DetWorn(worn, s.m_setSize), Safe(() => d.GetSetStatusEffectTooltip(quality, skill)));
				}
			}
			return list;
		}

		private static void Add(List<Detail> list, string key, string name, string kind, string sub, string body)
		{
			list.Add(new Detail
			{
				Key = key,
				Name = name,
				Title = kind + " · " + name,
				Sub = sub,
				Body = (string.IsNullOrEmpty(body) ? L.DetNoText : Localization.instance.Localize(body).Trim())
			});
		}

		private static string Safe(Func<string> read)
		{
			try
			{
				return read();
			}
			catch (Exception ex)
			{
				ForgeplanPlugin.Log.LogWarning((object)("описание эффекта не прочиталось: " + ex.Message));
				return null;
			}
		}

		private static void Dmg(List<Stat> list, string key, string label, float v)
		{
			if (v > 0f)
			{
				Numeric(list, key, label, v, Better.Higher);
			}
		}

		public static int Rank(DamageModifier m)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected I4, but got Unknown
			return (m - 1) switch
			{
				5 => -3, 
				1 => -2, 
				7 => -1, 
				6 => 1, 
				0 => 2, 
				4 => 3, 
				2 => 4, 
				3 => 4, 
				_ => 0, 
			};
		}

		public static string RankName(int r)
		{
			return r switch
			{
				-3 => L.ModVeryWeak, 
				-2 => L.ModWeak, 
				-1 => L.ModSlightlyWeak, 
				1 => L.ModSlightlyResistant, 
				2 => L.ModResistant, 
				3 => L.ModVeryResistant, 
				4 => L.ModImmune, 
				_ => L.ModNormal, 
			};
		}

		private static string DamageName(DamageType t)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Invalid comparison between Unknown and I4
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected I4, but got Unknown
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Invalid comparison between Unknown and I4
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Invalid comparison between Unknown and I4
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Invalid comparison between Unknown and I4
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Invalid comparison between Unknown and I4
			if ((int)t <= 64)
			{
				switch (t - 1)
				{
				default:
					if ((int)t != 32)
					{
						if ((int)t != 64)
						{
							break;
						}
						return L.StFrost;
					}
					return L.StFire;
				case 0:
					return L.StBlunt;
				case 1:
					return L.StSlash;
				case 3:
					return L.StPierce;
				case 2:
					break;
				}
			}
			else
			{
				if ((int)t == 128)
				{
					return L.StLightning;
				}
				if ((int)t == 256)
				{
					return L.StPoison;
				}
				if ((int)t == 512)
				{
					return L.StSpirit;
				}
			}
			return null;
		}

		private unsafe static void Resistances(List<Stat> list, List<DamageModPair> mods)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			if (mods == null)
			{
				return;
			}
			foreach (DamageModPair mod in mods)
			{
				string text = DamageName(mod.m_type);
				if (text == null)
				{
					continue;
				}
				int num = Rank(mod.m_modifier);
				if (num != 0)
				{
					DamageType type = mod.m_type;
					string key = "res_" + ((object)(*(DamageType*)(&type))/*cast due to .constrained prefix*/).ToString().ToLowerInvariant();
					list.Add(new Stat
					{
						Key = key,
						Order = OrderOf(key),
						Label = "  " + text,
						Value = num,
						Text = RankName(num),
						Dir = Better.Higher,
						Delta = (float d) => (!(d > 0f)) ? ((!(d < 0f)) ? "=" : "−") : "+"
					});
				}
			}
		}

		public static Stat Absent(Stat like)
		{
			bool flag = like.Key.StartsWith("res_");
			return new Stat
			{
				Key = like.Key,
				Order = like.Order,
				Label = like.Label,
				Value = 0f,
				Dir = like.Dir,
				Delta = like.Delta,
				Text = ((like.Dir == Better.None) ? "—" : (flag ? L.ModNormal : "—"))
			};
		}

		public static Stat ResistHeader()
		{
			return new Stat
			{
				Key = "res_header",
				Order = OrderOf("res_header"),
				Label = L.StResist,
				Text = "",
				Dir = Better.None
			};
		}
	}
	public static class Names
	{
		public static readonly Dictionary<string, string> Ru = new Dictionary<string, string>(1569)
		{
			{ "acorn", "Желуди" },
			{ "amber", "Янтарь" },
			{ "amberpearl", "Янтарная жемчужина" },
			{ "ancientcoin", "Древняя монета" },
			{ "ancientgemstoneblack", "Драумикс" },
			{ "ancientgemstonegreen", "Гримварн" },
			{ "ancientgemstoneorange", "Солрит" },
			{ "ancientgemstonepurple", "Вейдрис" },
			{ "ancientseed", "Древнее семя" },
			{ "armorashlandsmediumchest", "Кираса Аска" },
			{ "armorashlandsmediumlegs", "Штаны Аска" },
			{ "armorberserkerchest", "Медвежьи узоры" },
			{ "armorberserkerlegs", "Медвежья повязка" },
			{ "armorberserkerundeadchest", "Гнилокостная нагрудная клетка" },
			{ "armorberserkerundeadlegs", "Гнилокостный набедренник" },
			{ "armorbronzechest", "Бронзовая кираса" },
			{ "armorbronzelegs", "Бронзовые наголенники" },
			{ "armorcarapacechest", "Панцирный нагрудник" },
			{ "armorcarapacelegs", "Панцирные поножи" },
			{ "armordeepnorthheavychest", "Нагрудник защитника" },
			{ "armordeepnorthheavylegs", "Штаны защитника" },
			{ "armordeepnorthmagechest", "Одеяние призывателя" },
			{ "armordeepnorthmagelegs", "Штаны призывателя" },
			{ "armordeepnorthmediumchest", "Нагрудник авангарда" },
			{ "armordeepnorthmediumlegs", "Штаны авангарда" },
			{ "armordress1", "Простое коричневое платье" },
			{ "armordress10", "Простое платье" },
			{ "armordress2", "Коричневое платье с шалью" },
			{ "armordress3", "Коричневое платье в бусинах" },
			{ "armordress4", "Простое синее платье" },
			{ "armordress5", "Синее платье с шалью" },
			{ "armordress6", "Синее платье в бусинах" },
			{ "armordress7", "Простое желтое платье" },
			{ "armordress8", "Желтое платье с шалью" },
			{ "armordress9", "Желтое платье в бусинах" },
			{ "armorfenringchest", "Облачение Фенриса" },
			{ "armorfenringlegs", "Поножи Фенриса" },
			{ "armorflametalchest", "Огнеметаллическая кираса" },
			{ "armorflametallegs", "Огнеметаллические поножи" },
			{ "armorgoldheavychestuncooked", "Заготовка: нагрудник защитника" },
			{ "armorgoldheavyhelmetuncooked", "Заготовка: шлем защитника" },
			{ "armorgoldheavylegsuncooked", "Заготовка: штаны защитника" },
			{ "armorgoldmagechestuncooked", "Заготовка: одеяние призывателя" },
			{ "armorgoldmagehelmetuncooked", "Заготовка: головной убор призывателя" },
			{ "armorgoldmagelegsuncooked", "Заготовка: штаны призывателя" },
			{ "armorgoldmediumchestuncooked", "Заготовка: нагрудник авангарда" },
			{ "armorgoldmediumhelmetuncooked", "Заготовка: капюшон авангарда" },
			{ "armorgoldmediumlegsuncooked", "Заготовка: штаны авангарда" },
			{ "armorharvester1", "Туника урожая" },
			{ "armorharvester2", "Одежда урожая" },
			{ "armorironchest", "Чешуйчатый железный доспех" },
			{ "armorironlegs", "Железные наголенники" },
			{ "armorleatherchest", "Кожаная туника" },
			{ "armorleatherlegs", "Кожаные штаны" },
			{ "armorloxchest", "Куртка из меха локса" },
			{ "armorloxlegs", "Штаны из меха локса" },
			{ "armormagechest", "Сшитое из эйтра одеяние" },
			{ "armormagechest_ashlands", "Одежды Эмблы" },
			{ "armormagelegs", "Сшитые из эйтра штаны" },
			{ "armormagelegs_ashlands", "Штаны Эмблы" },
			{ "armorpaddedcuirass", "Обитая кираса" },
			{ "armorpaddedgreaves", "Обитые наголенники" },
			{ "armorragschest", "Холщовая туника" },
			{ "armorragslegs", "Холщовые штаны" },
			{ "armorrootchest", "Корневой нагрудник" },
			{ "armorrootlegs", "Корневые поножи" },
			{ "armorstand", "Стойка для брони" },
			{ "armorstand_female", "Стойка для брони" },
			{ "armortrollleatherchest", "Туника из кожи тролля" },
			{ "armortrollleatherlegs", "Штаны из кожи тролля" },
			{ "armortunic1", "Простая синяя туника" },
			{ "armortunic10", "Простая туника" },
			{ "armortunic2", "Синяя туника с капюшоном" },
			{ "armortunic3", "Синяя туника в бусинах" },
			{ "armortunic4", "Простая красная туника" },
			{ "armortunic5", "Красная туника с капюшоном" },
			{ "armortunic6", "Красная туника в бусинах" },
			{ "armortunic7", "Простая желтая туника" },
			{ "armortunic8", "Желтая туника с капюшоном" },
			{ "armortunic9", "Желтая туника в бусинах" },
			{ "armorwolfchest", "Волчий нагрудник" },
			{ "armorwolflegs", "Волчья защита для ног" },
			{ "arrowbloodgold", "Стрела из кровавого золота" },
			{ "arrowbronze", "Стрела с бронзовым наконечником" },
			{ "arrowcarapace", "Панцирная стрела" },
			{ "arrowcharred", "Обугленная стрела" },
			{ "arrowfire", "Огненная стрела" },
			{ "arrowflint", "Стрела с кремниевым наконечником" },
			{ "arrowfrost", "Ледяная стрела" },
			{ "arrowiron", "Стрела с железным наконечником" },
			{ "arrowneedle", "Игольная стрела" },
			{ "arrowobsidian", "Обсидиановая стрела" },
			{ "arrowpoison", "Отравленная стрела" },
			{ "arrowsilver", "Серебряная стрела" },
			{ "arrowwood", "Деревянная стрела" },
			{ "artisan_ext1", "Ремесленный пресс" },
			{ "ashlands_arch1", "Каменная стена 1x1" },
			{ "ashlands_arch2", "Каменная стена 1x1" },
			{ "ashlands_wallblock_1x2x2", "Каменная стена 1x1" },
			{ "ashlands_wallblock_base", "Каменная стена 1x1" },
			{ "ashwood_arch_big", "Арка из пепельного дерева" },
			{ "ashwood_arch_bottom", "Нижняя арка из пепельного дерева" },
			{ "ashwood_arch_top", "Верхняя арка из пепельного дерева" },
			{ "ashwood_beam_1m", "Брус из пепельного дерева (1 м)" },
			{ "ashwood_beam_2m", "Брус из пепельного дерева (2 м)" },
			{ "ashwood_bed", "Кровать из пепельного дерева" },
			{ "ashwood_deco_floor", "Декоративный пол из пепельного дерева" },
			{ "ashwood_decowall_2x2", "Декоративная стена из пепельного дерева" },
			{ "ashwood_decowall_divider", "Разделитель из пепельного дерева" },
			{ "ashwood_decowall_tree", "Декоративное окно из пепельного дерева" },
			{ "ashwood_door", "Дверь из пепельного дерева" },
			{ "ashwood_floor_1x1", "Пол из пепельного дерева 1x1" },
			{ "ashwood_floor_2x2", "Пол из пепельного дерева 2x2" },
			{ "ashwood_halfwall_1x2", "Полустена из пепельного дерева" },
			{ "ashwood_pole_1m", "Столб из пепельного дерева (1 м)" },
			{ "ashwood_pole_2m", "Столб из пепельного дерева (2 м)" },
			{ "ashwood_quarterwall_1x1", "Четверть стены из пепельного дерева" },
			{ "ashwood_stair", "Лестница из пепельного дерева" },
			{ "ashwood_wall_2x2", "Стена из пепельного дерева" },
			{ "ashwood_wall_arch", "Арочная стена из пепельного дерева" },
			{ "ashwood_wall_beam_26", "Брус из пепельного дерева (26°)" },
			{ "ashwood_wall_beam_26_alt", "Брус из пепельного дерева (26°)" },
			{ "ashwood_wall_beam_45", "Брус из пепельного дерева (45°)" },
			{ "ashwood_wall_beam_45_alt", "Брус из пепельного дерева (45°)" },
			{ "ashwood_wall_beam_67", "Брус из пепельного дерева 67°" },
			{ "ashwood_wall_cross_26", "Перекладина из пепельного дерева (26°)" },
			{ "ashwood_wall_cross_26_alt", "Перекладина из пепельного дерева (26°)" },
			{ "ashwood_wall_cross_45", "Перекладина из пепельного дерева (45°)" },
			{ "ashwood_wall_cross_45_alt", "Перекладина из пепельного дерева (45°)" },
			{ "ashwood_wall_cross_67", "Перекладина из пепельного дерева 67°" },
			{ "ashwood_wall_roof_26", "Стена из пепельного дерева (26°)" },
			{ "ashwood_wall_roof_26_upsidedown", "Обратная стена из пепельного дерева (26°)" },
			{ "ashwood_wall_roof_45", "Стена из пепельного дерева (45°)" },
			{ "ashwood_wall_roof_45_upsidedown", "Обратная стена из пепельного дерева (45°)" },
			{ "ashwood_wall_roof_67_a", "Стена из пепельного дерева 67°" },
			{ "ashwood_wall_roof_67_upsidedown", "Стена из пепельного дерева 67° (обратная)" },
			{ "askbladder", "Мочевой пузырь пеплозавра" },
			{ "askhide", "Шкура пеплозавра" },
			{ "asksvincarrionneck", "Шея пеплозавра" },
			{ "asksvincarrionpelvic", "Таз пеплозавра" },
			{ "asksvincarrionribcage", "Ребра пеплозавра" },
			{ "asksvincarrionskull", "Череп пеплозавра" },
			{ "asksvinegg", "Яйцо пеплозавра" },
			{ "asksvinmeat", "Хвост пеплозавра" },
			{ "atgeirblackmetal", "Алебарда из черного металла" },
			{ "atgeirbronze", "Бронзовая алебарда" },
			{ "atgeirgold", "Нордская алебарда" },
			{ "atgeirgold_bloodlightning", "Алебарда громовой крови" },
			{ "atgeirgold_frostfire", "Алебарда льда и огня" },
			{ "atgeirgolduncooked", "Заготовка: нордская алебарда" },
			{ "atgeirhimminafl", "Химминафль" },
			{ "atgeiriron", "Железная алебарда" },
			{ "atgeirwood", "Деревянная алебарда" },
			{ "axeberzerkr", "Топоры берсеркира" },
			{ "axeberzerkrblood", "Кровоточащие топоры берсеркира" },
			{ "axeberzerkrlightning", "Громовые топоры берсеркира" },
			{ "axeberzerkrnature", "Первобытные топоры берсеркира" },
			{ "axeblackmetal", "Топор из черного металла" },
			{ "axebronze", "Бронзовый топор" },
			{ "axeearly", "Древние топоры" },
			{ "axeflint", "Кремневый топор" },
			{ "axegold", "Нордский топор" },
			{ "axegold_bloodlightning", "Топор громовой крови" },
			{ "axegold_frostfire", "Топор льда и огня" },
			{ "axegolduncooked", "Заготовка: нордский топор" },
			{ "axehead1", "Необычное лезвие топора" },
			{ "axehead2", "Загадочное лезвие топора" },
			{ "axeiron", "Железный топор" },
			{ "axejotunbane", "Погибель йотунов" },
			{ "axestone", "Каменный топор" },
			{ "axewood", "Деревянный топор" },
			{ "bakedpoteitr", "Запеченный картофэйтр" },
			{ "bakedpoteitruncooked", "Сырой картофейтр" },
			{ "bar_blackmetal_stack", "Стопка черного металла" },
			{ "bar_bronze_stack", "Стопка бронзы" },
			{ "bar_copper_stack", "Стопка меди" },
			{ "bar_flametal_stack", "Стопка огнеметалла" },
			{ "bar_gold_stack", "Стопка кровавого золота" },
			{ "bar_iron_stack", "Стопка железа" },
			{ "bar_silver_stack", "Стопка серебра" },
			{ "bar_tin_stack", "Стопка олова" },
			{ "barberkit", "Набор цирюльника" },
			{ "barkabranch", "Замерзшая ветвь" },
			{ "barley", "Ячмень" },
			{ "barleyflour", "Ячменная мука" },
			{ "barleywine", "Огненное ячменное вино" },
			{ "barleywinebase", "Основа ячменного вина: огнестойкость" },
			{ "barrelrings", "Обручи для бочек" },
			{ "batteringram", "Таран" },
			{ "battleaxe", "Боевой топор" },
			{ "battleaxeblackmetal", "Боевой топор из черного металла" },
			{ "battleaxecrystal", "Кристальный боевой топор" },
			{ "battleaxegold", "Нордская секира" },
			{ "battleaxegold_bloodlightning", "Секира громовой крови" },
			{ "battleaxegold_frostfire", "Секира льда и огня" },
			{ "battleaxegolduncooked", "Заготовка: нордская секира" },
			{ "battleaxeskullsplittur", "Крушитель черепов" },
			{ "battleaxewood", "Деревянный боевой топор" },
			{ "beard1", "Длинная 1" },
			{ "beard10", "Заплетенная\u00a04" },
			{ "beard11", "Густая 2" },
			{ "beard12", "Королевская 1" },
			{ "beard13", "Королевская 2" },
			{ "beard14", "Заплетенная 5" },
			{ "beard15", "Короткая 4" },
			{ "beard16", "Каменная" },
			{ "beard17", "Уложенная" },
			{ "beard18", "Королевская 3" },
			{ "beard19", "Густая" },
			{ "beard2", "Длинная 2" },
			{ "beard20", "Острая" },
			{ "beard21", "Короткая 5" },
			{ "beard22", "Усы" },
			{ "beard23", "Ловец крошек" },
			{ "beard24", "Вощеные" },
			{ "beard25", "Подстриженный" },
			{ "beard26", "Рулевые усы" },
			{ "beard3", "Короткая 1" },
			{ "beard4", "Короткая 2" },
			{ "beard5", "Заплетенная 1" },
			{ "beard6", "Заплетенная 2" },
			{ "beard7", "Короткая\u00a03" },
			{ "beard8", "Густая\u00a01" },
			{ "beard9", "Заплетенная\u00a03" },
			{ "beardnone", "Без бороды" },
			{ "bed", "Кровать" },
			{ "beech_sapling", "Саженец бука" },
			{ "beechseeds", "Семена бука" },
			{ "bell", "Колокол" },
			{ "bellfragment", "Фрагмент колокола" },
			{ "beltstrength", "Мегингьорд" },
			{ "bilebag", "Желчный мешок" },
			{ "birch_sapling", "Саженец березы" },
			{ "birchseeds", "Семена березы" },
			{ "bjornhide", "Медвежья шкура" },
			{ "bjornmeat", "Медвежье мясо" },
			{ "bjornpaw", "Медвежья лапа" },
			{ "blackcore", "Черное ядро" },
			{ "blackforge", "Чёрная кузница" },
			{ "blackforge_ext1", "Охладитель черной кузницы" },
			{ "blackforge_ext2_vise", "Тиски" },
			{ "blackforge_ext3_metalcutter", "Резак по металлу" },
			{ "blackforge_ext4_gemcutter", "Резак для самоцветов" },
			{ "blackforge_ext5_apron", "Фартуки кузнеца" },
			{ "blackmarble", "Черный мрамор" },
			{ "blackmarble_1x1", "Черный мрамор 1x1x1" },
			{ "blackmarble_2x1x1", "Черный мрамор 2x1x1" },
			{ "blackmarble_2x2_enforced", "Усиленный черный мрамор" },
			{ "blackmarble_2x2x1", "Черный мрамор 2x2x1" },
			{ "blackmarble_2x2x2", "Черный мрамор 2x2x2" },
			{ "blackmarble_arch", "Арка из черного мрамора" },
			{ "blackmarble_base_1", "Постамент из черного мрамора" },
			{ "blackmarble_base_2", "Широкий постамент из черного мрамора" },
			{ "blackmarble_basecorner", "Угловой постамент из черного мрамора" },
			{ "blackmarble_column_1", "Маленькая колонна из черного мрамора" },
			{ "blackmarble_column_2", "Широкая колонна из черного мрамора" },
			{ "blackmarble_column_3", "Высокая колонна из черного мрамора" },
			{ "blackmarble_creep_4x1x1", "Черный мрамор 2x2x1" },
			{ "blackmarble_creep_4x2x1", "Черный мрамор 2x2x1" },
			{ "blackmarble_creep_slope_inverted_1x1x2", "Карниз из черного мрамора" },
			{ "blackmarble_creep_slope_inverted_2x2x1", "Карниз из черного мрамора" },
			{ "blackmarble_creep_stair", "Лестница из черного мрамора" },
			{ "blackmarble_floor", "Пол из черного мрамора" },
			{ "blackmarble_floor_large", "Пол из черного мрамора 4x4" },
			{ "blackmarble_floor_triangle", "Треугольный пол из черного мрамора" },
			{ "blackmarble_head01", "Голова 1 из черного мрамора" },
			{ "blackmarble_head02", "Голова 2 из черного мрамора" },
			{ "blackmarble_head_big01", "Большая голова 1 из черного мрамора" },
			{ "blackmarble_head_big02", "Большая голова 2 из черного мрамора" },
			{ "blackmarble_out_1", "Карниз из черного мрамора" },
			{ "blackmarble_out_2", "Широкий карниз из черного мрамора" },
			{ "blackmarble_outcorner", "Угловой карниз из черного мрамора" },
			{ "blackmarble_pile", "Груда черного мрамора" },
			{ "blackmarble_slope_1x2", "Склон из черного мрамора" },
			{ "blackmarble_slope_inverted_1x2", "Перевернутый склон из черного мрамора" },
			{ "blackmarble_stair", "Лестница из черного мрамора" },
			{ "blackmarble_stair_corner", "Лестница направо из черного мрамора" },
			{ "blackmarble_stair_corner_left", "Лестница налево из черного мрамора" },
			{ "blackmarble_tile_floor_1x1", "Малая напольная плитка из черного мрамора" },
			{ "blackmarble_tile_floor_2x2", "Большая напольная плитка из черного мрамора" },
			{ "blackmarble_tile_wall_1x1", "Малая настенная плитка из черного мрамора" },
			{ "blackmarble_tile_wall_2x2", "Большая настенная плитка из черного мрамора" },
			{ "blackmarble_tile_wall_2x4", "Высокая настенная плитка из черного мрамора" },
			{ "blackmarble_tip", "Четверть шпиля из черного мрамора" },
			{ "blackmetal", "Черный металл" },
			{ "blackmetalscrap", "Кусок черного металла" },
			{ "blacksoup", "Черный суп" },
			{ "blackwood", "Пепельная древесина" },
			{ "blackwood_stack", "Стопка пепельной древесины" },
			{ "blastfurnace", "Доменная печь" },
			{ "blobvial", "Флакон с пробкой" },
			{ "bloodbag", "Туша" },
			{ "bloodgoldkey", "Сложный ключ" },
			{ "bloodpudding", "Кровяная колбаса" },
			{ "blueberries", "Черника" },
			{ "boarjerky", "Вяленая кабанина" },
			{ "bogwitch_fire_pit", "Костер" },
			{ "boltblackmetal", "Болт из черного металла" },
			{ "boltbloodgold", "Болт из кровавого золота" },
			{ "boltbone", "Костяной болт" },
			{ "boltcarapace", "Панцирный болт" },
			{ "boltcharred", "Обугленный болт" },
			{ "boltiron", "Железный болт" },
			{ "bombbile", "Желчная бомба" },
			{ "bombblob_frost", "Сгустень-бомба: Лед" },
			{ "bombblob_lava", "Сгустень-бомба: Лава" },
			{ "bombblob_morkhalla", "Сгустень-бомба: масса" },
			{ "bombblob_poison", "Сгустень-бомба: Яд" },
			{ "bombblob_poisonelite", "Сгустень-бомба: Элитный яд" },
			{ "bombblob_tar", "Сгустень-бомба: Деготь" },
			{ "bombdynamite", "Угольный заряд" },
			{ "bomblava", "Базальтовая бомба" },
			{ "bombooze", "Гнилостная бомба" },
			{ "bombsiege", "Взрывной снаряд" },
			{ "bombsmoke", "Дымовая шашка" },
			{ "bone_stack", "Груда костей" },
			{ "bonefragments", "Обломки костей" },
			{ "bonemawserpentmeat", "Мясо Костепасти" },
			{ "bonemawserpentscale", "Чешуя Костепасти" },
			{ "bonemawserpenttooth", "Зуб Костепасти" },
			{ "bonfire", "Большой костер" },
			{ "bow", "Грубый лук" },
			{ "bowashlands", "Пепельный клык" },
			{ "bowashlandsblood", "Кровавый клык" },
			{ "bowashlandsroot", "Корневой клык" },
			{ "bowashlandsstorm", "Штормовой клык" },
			{ "bowdraugrfang", "Клык Драугра" },
			{ "bowfinewood", "Хороший лук" },
			{ "bowgold", "Нордский лук" },
			{ "bowgold_bloodlightning", "Лук громовой крови" },
			{ "bowgold_frostfire", "Лук льда и огня" },
			{ "bowgolduncooked", "Заготовка: нордский лук" },
			{ "bowhuntsman", "Охотничий лук" },
			{ "bowspinesnap", "Хребтолом" },
			{ "bread", "Хлеб" },
			{ "breaddough", "Тесто для хлеба" },
			{ "bronze", "Бронза" },
			{ "bronzenails", "Бронзовые гвозди" },
			{ "bronzescrap", "Бронзовый металлолом" },
			{ "bugmeat", "Мясо искателя" },
			{ "candle_resin", "Смоляная свеча" },
			{ "candle_resin_bogwitch", "Смоляная свеча" },
			{ "candlewick", "Свечной фитиль" },
			{ "capeash", "Пепельный плащ" },
			{ "capeasksvin", "Плащ из шкуры пеплозавра" },
			{ "capedeepnorth", "Плащ из шкуры лося" },
			{ "capedeepnorthmage", "Плащ призывателя" },
			{ "capedeerhide", "Плащ из шкуры оленя" },
			{ "capefeather", "Накидка из перьев" },
			{ "capelinen", "Льняной плащ" },
			{ "capelox", "Плащ из шкуры быкоящера" },
			{ "capeodin", "Плащ Одина" },
			{ "capetrollhide", "Плащ из шкуры тролля" },
			{ "capewolf", "Плащ из шкуры волка" },
			{ "carapace", "Панцирь" },
			{ "carrot", "Морковь" },
			{ "carrotseeds", "Семена моркови" },
			{ "carrotsoup", "Морковный суп" },
			{ "cart", "Повозка" },
			{ "catapult", "Катапульта" },
			{ "catapult_ammo", "Снаряд из серокамня" },
			{ "catapult_ammo_bloodgold", "Катапультный снаряд из кровавого золота" },
			{ "cauldron_ext1_spice", "Сушилка для трав" },
			{ "cauldron_ext3_butchertable", "Мясницкий стол" },
			{ "cauldron_ext4_pots", "Кухонная утварь" },
			{ "cauldron_ext5_mortarandpestle", "Ступка и пестик" },
			{ "cauldron_ext6_rollingpins", "Скалки и разделочные доски" },
			{ "cauldron_ext7_smoker", "Коптильня" },
			{ "celestialfeather", "Небесное перо" },
			{ "ceramicplate", "Керамическая пластина" },
			{ "chain", "Цепь" },
			{ "charcoal_kiln", "Углевыжигательная печь" },
			{ "charcoalresin", "Угольная смола" },
			{ "charred_shieldgenerator", "Генератор щита" },
			{ "charredbone", "Обугленная кость" },
			{ "charredcogwheel", "Обгорелая шестерня" },
			{ "charredskull", "Обугленный череп" },
			{ "chest_hildir1", "Медный сундук Хильдир" },
			{ "chest_hildir2", "Серебряный сундук Хильдир" },
			{ "chest_hildir3", "Бронзовый сундук Хильдир" },
			{ "chickenegg", "Яйцо" },
			{ "chickenmeat", "Курятина" },
			{ "chitin", "Хитин" },
			{ "cloudberry", "Морошка" },
			{ "club", "Дубина" },
			{ "coal", "Уголь" },
			{ "coal_pile", "Груда угля" },
			{ "coins", "Монеты" },
			{ "cookedasksvinmeat", "Жареный хвост пеплозавра" },
			{ "cookedbjornmeat", "Приготовленное медвежье мясо" },
			{ "cookedbonemawserpentmeat", "Приготовленное мясо Костепасти" },
			{ "cookedbugmeat", "Приготовленное мясо искателя" },
			{ "cookedchickenmeat", "Приготовленная курятина" },
			{ "cookeddeermeat", "Приготовленная оленина" },
			{ "cookedegg", "Приготовленное яйцо" },
			{ "cookedharemeat", "Приготовленная зайчатина" },
			{ "cookedloxmeat", "Приготовленное мясо быкоящера" },
			{ "cookedmeat", "Приготовленная кабанина" },
			{ "cookedmoosemeat", "Приготовленное мясо лося" },
			{ "cookedsealblubber", "Приготовленный тюлений жир" },
			{ "cookedvolturemeat", "Приготовленное мясо стервулканника" },
			{ "cookedwolfmeat", "Приготовленная волчатина" },
			{ "copper", "Медь" },
			{ "copperore", "Медная руда" },
			{ "copperscrap", "Медный металлолом" },
			{ "crossbowarbalest", "Арбалет" },
			{ "crossbowgold", "Нордский арбалет" },
			{ "crossbowgold_bloodlightning", "Арбалет громовой крови" },
			{ "crossbowgold_frostfire", "Арбалет льда и огня" },
			{ "crossbowgolduncooked", "Заготовка: нордский арбалет" },
			{ "crossbowripper", "Разрыватель" },
			{ "crossbowripperblood", "Ранящий разрыватель" },
			{ "crossbowripperlightning", "Штормовой разрыватель" },
			{ "crossbowrippernature", "Корневой разрыватель" },
			{ "crownjewel", "Жемчужина короны" },
			{ "cryptkey", "Болотный ключ" },
			{ "crystal", "Кристалл" },
			{ "crystal_wall_1x1", "Кристальная стена 1х1" },
			{ "cultivator", "Пропашник" },
			{ "curedsquirrelhamstring", "Дубленые беличьи сухожилия" },
			{ "dandelion", "Одуванчик" },
			{ "darkwood_arch", "Арка из темного дерева" },
			{ "darkwood_beam", "Брус из темного дерева 2\u00a0м" },
			{ "darkwood_beam4x4", "Брус из темного дерева 4\u00a0м" },
			{ "darkwood_beam_26", "Брус из темного дерева 26°" },
			{ "darkwood_beam_45", "Брус из темного дерева 45°" },
			{ "darkwood_decowall", "Резная перегородка из темного дерева" },
			{ "darkwood_gate", "Ворота из темного дерева" },
			{ "darkwood_pole", "Столб из темного дерева 2\u00a0м" },
			{ "darkwood_pole4", "Столб из темного дерева 4\u00a0м" },
			{ "darkwood_raven", "Ворон (украшение)" },
			{ "darkwood_roof", "Шиферная крыша 26°" },
			{ "darkwood_roof_45", "Шиферная крыша 45°" },
			{ "darkwood_roof_67", "Шиферная крыша 67°" },
			{ "darkwood_roof_icorner", "Внутренний угол шиферной крыши 26°" },
			{ "darkwood_roof_icorner_45", "Внутренний угол шиферной крыши 45°" },
			{ "darkwood_roof_icorner_67", "Внутренний угол шиферной крыши 67°" },
			{ "darkwood_roof_ocorner", "Внешний угол шиферной крыши 26°" },
			{ "darkwood_roof_ocorner_45", "Внешний угол шиферной крыши 45°" },
			{ "darkwood_roof_ocorner_67", "Внешний угол шиферной крыши 67°" },
			{ "darkwood_roof_top", "Конек шиферной крыши 26°" },
			{ "darkwood_roof_top_45", "Конек шиферной крыши 45°" },
			{ "darkwood_roof_top_67", "Конек шиферной крыши 67°" },
			{ "darkwood_wolf", "Волк (украшение)" },
			{ "deerhide", "Шкура оленя" },
			{ "deermeat", "Оленина" },
			{ "deerstew", "Рагу из оленины" },
			{ "demister", "Свет светлячка" },
			{ "dragonegg", "Яйцо дракона" },
			{ "dragontear", "Драконья слеза" },
			{ "dverger_guardstone", "Оберег" },
			{ "dvergerarbalest", "Арбалет" },
			{ "dvergerarbalest_shoot", "Арбалет" },
			{ "dvergerarbalest_shootashlands", "Арбалет" },
			{ "dvergerarbalest_shootdeepnorth", "Арбалет" },
			{ "dvergrkey", "Разрушитель печатей" },
			{ "dvergrkeyfragment", "Фрагмент разрушителя печатей" },
			{ "dvergrneedle", "Экстрактор двергов" },
			{ "dvergrprops_wood_floor", "Деревянный пол 2x2" },
			{ "dvergrprops_wood_stair", "Деревянная лестница" },
			{ "dyrnwynbladefragment", "Лезвие Дирнвина" },
			{ "dyrnwynhiltfragment", "Рукоять Дирнвина" },
			{ "dyrnwyntipfragment", "Острие Дирнвина" },
			{ "ectoplasm", "Эктоплазма" },
			{ "eitr", "Переработанный эйтр" },
			{ "eitrrefinery", "Машина для переработки эйтра" },
			{ "elakinghairbundle", "Клок шерсти элакинга" },
			{ "elderbark", "Древняя кора" },
			{ "entrails", "Потроха" },
			{ "eyescream", "Глазированное мороженое" },
			{ "faderdrop", "Реликвия Прародителя" },
			{ "faderember", "Искры" },
			{ "feastashlands", "Пир из Пепельных земель" },
			{ "feastashlands_material", "Пир из Пепельных земель" },
			{ "feastblackforest", "Деликатесы Черного леса" },
			{ "feastblackforest_material", "Деликатесы Черного леса" },
			{ "feastdeepnorth", "Северный завтрак" },
			{ "feastdeepnorth_material", "Северный завтрак" },
			{ "feaster", "Поднос для подачи" },
			{ "feastmeadows", "Луговой кабан на вертеле" },
			{ "feastmeadows_material", "Луговой кабан на вертеле" },
			{ "feastmistlands", "Грибное ассорти из Туманных земель" },
			{ "feastmistlands_material", "Грибное ассорти из Туманных земель" },
			{ "feastmountains", "Сытное жаркое горного лесоруба" },
			{ "feastmountains_material", "Сытное жаркое горного лесоруба" },
			{ "feastoceans", "Добыча моряка" },
			{ "feastoceans_material", "Добыча моряка" },
			{ "feastplains", "Равнинный пикник с пирогом" },
			{ "feastplains_material", "Равнинный пикник с пирогом" },
			{ "feastswamps", "Лакомство болотного жителя" },
			{ "feastswamps_material", "Лакомство болотного жителя" },
			{ "feathers", "Перья" },
			{ "fermenter", "Бродильная бочка" },
			{ "fiddleheadfern", "Рахис" },
			{ "fierysvinstew", "Огненное тушеное рагу" },
			{ "finewood", "Качественная древесина" },
			{ "fircone", "Пихтовая шишка" },
			{ "firconefrost", "Шишка северной ели" },
			{ "fire_pit", "Костер" },
			{ "fire_pit_haldor", "Костер" },
			{ "fire_pit_hildir", "Костер" },
			{ "fire_pit_iron", "Железная костровая чаша" },
			{ "fireworksrocket_blue", "Синий фейерверк" },
			{ "fireworksrocket_cyan", "Бирюзовый фейерверк" },
			{ "fireworksrocket_green", "Зеленый фейерверк" },
			{ "fireworksrocket_purple", "Фиолетовый фейерверк" },
			{ "fireworksrocket_red", "Красный фейерверк" },
			{ "fireworksrocket_white", "Обычный фейерверк" },
			{ "fireworksrocket_yellow", "Желтый фейерверк" },
			{ "firtree_big_sapling", "Саженец северной ели" },
			{ "firtree_sapling", "Саженец пихты" },
			{ "fish1", "Окунь" },
			{ "fish10", "Северный лосось" },
			{ "fish11", "Магмарыбка" },
			{ "fish12", "Иглобрюх" },
			{ "fish2", "Щука" },
			{ "fish3", "Тунец" },
			{ "fish4_cave", "Тетра" },
			{ "fish5", "Тролль-рыба" },
			{ "fish6", "Гигантская сельдь" },
			{ "fish7", "Групер" },
			{ "fish8", "Коралловая треска" },
			{ "fish9", "Удильщик" },
			{ "fishandbread", "Рыба с хлебом" },
			{ "fishandbreaduncooked", "Сырая рыба с хлебом" },
			{ "fishanglerraw", "Сырая рыба" },
			{ "fishcooked", "Приготовленная рыба" },
			{ "fishingbait", "Наживка" },
			{ "fishingbaitashlands", "Горячая наживка для рыбалки" },
			{ "fishingbaitcave", "Холодная наживка для рыбалки" },
			{ "fishingbaitdeepnorth", "Ледяная наживка для рыбалки" },
			{ "fishingbaitforest", "Мшистая наживка для рыбалки" },
			{ "fishingbaitmistlands", "Туманная наживка для рыбалки" },
			{ "fishingbaitocean", "Тяжелая наживка для рыбалки" },
			{ "fishingbaitplains", "Скупая наживка для рыбалки" },
			{ "fishingbaitswamp", "Липкая наживка для рыбалки" },
			{ "fishingrod", "Удочка" },
			{ "fishraw", "Сырая рыба" },
			{ "fishsoup", "Рыбный суп" },
			{ "fishwraps", "Рыбные рулетики" },
			{ "fistbjornclaw", "Медвежьи лапы" },
			{ "fistbjornundeadclaw", "Гнилокостные когти" },
			{ "fistfenrirclaw", "Потрошители плоти" },
			{ "fistgold", "Нордские цепные кастеты" },
			{ "fistgold_bloodlightning", "Цепные кастеты громовой крови" },
			{ "fistgold_frostfire", "Цепные кастеты льда и огня" },
			{ "fistgolduncooked", "Заготовка: нордские цепные кастеты" },
			{ "flametal", "Древний металл" },
			{ "flametal_gate", "Огнеметаллические ворота" },
			{ "flametalnew", "Огнеметалл" },
			{ "flametalore", "Светящаяся металлическая руда" },
			{ "flametalorenew", "Огнеметаллическая руда" },
			{ "flax", "Лен" },
			{ "flint", "Кремень" },
			{ "flint_pile", "Куча кремня" },
			{ "forge", "Кузница" },
			{ "forge_delete", "Кузница" },
			{ "forge_ext1", "Кузнечные меха" },
			{ "forge_ext2", "Наковальни" },
			{ "forge_ext3", "Шлифовальный круг" },
			{ "forge_ext4", "Большая наковальня" },
			{ "forge_ext5", "Кузнечный охладитель" },
			{ "forge_ext6", "Стойка для инструментов" },
			{ "fragrantbundle", "Ароматный букет" },
			{ "freezegland", "Морозная железа" },
			{ "freshseaweed", "Свежие водоросли" },
			{ "frostcore", "Морозное ядро" },
			{ "frostwood", "Древесина северной ели" },
			{ "frozenfuel", "Жидкий лед" },
			{ "frozenkingdrop", "Жертвенная кровь" },
			{ "fuling_trap", "Капкан" },
			{ "fuling_turret", "Баллиста" },
			{ "fw_armorbronzechest", "Бронзовая кираса" },
			{ "fw_armorbronzelegs", "Бронзовые наголенники" },
			{ "fw_armorfenringchest", "Облачение Фенриса" },
			{ "fw_armorfenringlegs", "Поножи Фенриса" },
			{ "fw_armormagechest", "Сшитое из эйтра одеяние" },
			{ "fw_armormagechest_ashlands", "Одежды Эмблы" },
			{ "fw_armormagelegs", "Сшитые из эйтра штаны" },
			{ "fw_armormagelegs_ashlands", "Штаны Эмблы" },
			{ "fw_armorpaddedcuirass", "Обитая кираса" },
			{ "fw_armorpaddedgreaves", "Обитые наголенники" },
			{ "fw_armortrollleatherchest", "Туника из кожи тролля" },
			{ "fw_armortrollleatherlegs", "Штаны из кожи тролля" },
			{ "fw_axebronze", "Бронзовый топор" },
			{ "fw_battleaxecrystal", "Кристальный боевой топор" },
			{ "fw_bowdraugrfang", "Клык Драугра" },
			{ "fw_capelinen", "Льняной плащ" },
			{ "fw_capetrollhide", "Плащ из шкуры тролля" },
			{ "fw_capewolf", "Плащ из шкуры волка" },
			{ "fw_helmetbronze", "Бронзовый шлем" },
			{ "fw_knifesilver", "Серебряный нож" },
			{ "fw_knifeskollandhati", "Сколль и Хати" },
			{ "fw_shieldblackmetaltower", "Башенный щит из черного металла" },
			{ "fw_stafffireball", "Посох огня" },
			{ "fw_stafflightning", "Дундр" },
			{ "