Decompiled source of ValheimUnified v0.11.1

plugins/ValheimUnified.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GUIFramework;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.PostProcessing;
using UnityEngine.UI;
using ValheimUnified;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: InternalsVisibleTo("ValheimUnifiedPublishRun")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Chistix
{
	public static class ModMenuApi
	{
		public static bool IsSettingsOpen => SettingsUI.IsOpen;

		public static string GetMenuInfo()
		{
			return JsonConvert.SerializeObject((object)new
			{
				Api = 1,
				Publisher = "Chistix",
				Id = "chistix.valheimunified",
				Name = "ValheimUnified",
				Version = "0.11.1",
				ApplyPolicies = new string[3] { "Live", "WorldRestart", "GameRestart" }
			});
		}

		public static void OpenSettings(Action onClosed)
		{
			SettingsUI.Open(onClosed);
		}

		public static void CloseSettings()
		{
			SettingsUI.Reset();
		}

		public static string GetApplyPolicy(string settingId)
		{
			return SettingsUI.Policy(settingId);
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public string AssemblyName { get; }

		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
			AssemblyName = assemblyName;
		}
	}
}
namespace ValheimUnified
{
	public static class AdminBridge
	{
		public const int ApiVersion = 1;

		internal static readonly string[] DropScopes = new string[2] { "world", "game" };

		private static bool GameHost => Network.ServerSide;

		internal static bool AdminPanelOpen
		{
			get
			{
				try
				{
					PluginInfo val = AdminMenuPlugin.Find();
					if (val == null || !Object.op_Implicit((Object)(object)val.Instance))
					{
						return false;
					}
					return (bool)(((object)val.Instance).GetType().GetProperty("IsPanelOpen", BindingFlags.Static | BindingFlags.Public)?.GetValue(null, null) ?? ((object)false));
				}
				catch
				{
					return false;
				}
			}
		}

		public static string GetEquipmentBindings(string module)
		{
			try
			{
				if (!EquipmentBindings.Sections.Contains(module))
				{
					throw new ArgumentException(Lang.L("Поддерживаются Diving и VeinMining."));
				}
				return JsonConvert.SerializeObject((object)new
				{
					Success = true,
					Rows = EquipmentBindings.Get(module),
					Host = (Network.ServerSide && WorldProfile.WorldId != 0)
				});
			}
			catch (Exception ex)
			{
				return JsonConvert.SerializeObject((object)new
				{
					Success = false,
					Message = ex.Message
				});
			}
		}

		public static string SetEquipmentBindings(string module, string json)
		{
			try
			{
				WorldProfileCodec.RequireHost(Network.ServerSide, WorldProfile.WorldId);
				if (!Modules.Active("AdminIntegration"))
				{
					throw new InvalidOperationException(Lang.L("Хранилище настроек остановлено."));
				}
				if (!EquipmentBindings.Sections.Contains(module))
				{
					throw new ArgumentException(Lang.L("Поддерживаются Diving и VeinMining."));
				}
				List<EquipmentRequirement> list = EquipmentBindings.Parse(json);
				WorldProfileData worldProfileData = CaptureProfile();
				worldProfileData.Settings[module + ".RequiredEquipment"] = TomlTypeConverter.ConvertToString((object)JsonConvert.SerializeObject((object)list), typeof(string));
				worldProfileData.Settings["General.ServerLocksRules"] = "true";
				WorldProfile.Save(worldProfileData);
				return JsonConvert.SerializeObject((object)new
				{
					Success = true,
					Message = Lang.L("Привязки и бонусы экипировки сохранены для мира и отправлены клиентам.")
				});
			}
			catch (Exception ex)
			{
				return JsonConvert.SerializeObject((object)new
				{
					Success = false,
					Message = ex.Message
				});
			}
		}

		private static List<DropRule> ScopeRules(string scope)
		{
			if (!(scope == "game"))
			{
				return WorldProfile.WorldDrops();
			}
			return Rules.GameDrops;
		}

		private static bool Own(IEnumerable<DropRule> rules, string prefab)
		{
			return rules.Any((DropRule r) => r.Kind == "Creature" && r.Source == prefab && r.ReplaceAll);
		}

		private static List<DropRule> RowsOf(IEnumerable<DropRule> rules, string prefab)
		{
			return rules.Where((DropRule r) => r.Kind == "Creature" && r.Source == prefab && !r.ReplaceAll && !string.IsNullOrEmpty(r.Item)).ToList();
		}

		public static string GetCreatureDrops(string prefab)
		{
			return GetCreatureDropsScoped(prefab, "world");
		}

		public static string GetCreatureDropsScoped(string prefab, string scope)
		{
			try
			{
				if (!DropScopes.Contains(scope))
				{
					throw new ArgumentException(Lang.L("Область правил: world или game."));
				}
				ZNetScene instance = ZNetScene.instance;
				GameObject val = ((instance != null) ? instance.GetPrefab(prefab) : null);
				if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.GetComponent<Character>()))
				{
					throw new ArgumentException(Lang.L("Неизвестное существо."));
				}
				List<DropRule> rules = ScopeRules(scope);
				bool flag = Own(rules, prefab);
				bool flag2 = !flag && scope == "world" && Own(Rules.GameDrops, prefab);
				bool overriddenByWorld = scope == "game" && Own(WorldProfile.WorldDrops(), prefab);
				List<DropRule> list = (flag ? RowsOf(rules, prefab) : (flag2 ? RowsOf(Rules.GameDrops, prefab) : new List<DropRule>()));
				if (!flag && !flag2)
				{
					CharacterDrop component = val.GetComponent<CharacterDrop>();
					if (Object.op_Implicit((Object)(object)component))
					{
						foreach (Drop item in component.m_drops.Where((Drop x) => Object.op_Implicit((Object)(object)x?.m_prefab)))
						{
							list.Add(new DropRule
							{
								Source = prefab,
								Item = ((Object)item.m_prefab).name,
								Min = item.m_amountMin,
								Max = item.m_amountMax,
								Chance = item.m_chance
							});
						}
					}
				}
				bool host = ((scope == "game") ? GameHost : (Network.ServerSide && WorldProfile.WorldId != 0));
				return JsonConvert.SerializeObject((object)new
				{
					Success = true,
					Scope = scope,
					Scopes = DropScopes,
					Host = host,
					Customized = flag,
					Inherited = flag2,
					OverriddenByWorld = overriddenByWorld,
					Enabled = Settings.Get<bool>("Drops", "Enabled"),
					Rows = list
				});
			}
			catch (Exception ex)
			{
				return JsonConvert.SerializeObject((object)new
				{
					Success = false,
					Message = ex.Message
				});
			}
		}

		public static string SetCreatureDrops(string prefab, string json)
		{
			return SetCreatureDropsScoped(prefab, json, "world");
		}

		public static string SetCreatureDropsScoped(string prefab, string json, string scope)
		{
			try
			{
				if (!DropScopes.Contains(scope))
				{
					throw new ArgumentException(Lang.L("Область правил: world или game."));
				}
				if (scope == "game")
				{
					if (!GameHost)
					{
						throw new InvalidOperationException(Lang.L("Правила для всей игры меняет хост или одиночная игра."));
					}
				}
				else
				{
					WorldProfileCodec.RequireHost(Network.ServerSide, WorldProfile.WorldId);
				}
				if (!Modules.Active("AdminIntegration"))
				{
					throw new InvalidOperationException(Lang.L("Хранилище настроек отключено."));
				}
				ZNetScene instance = ZNetScene.instance;
				GameObject val = ((instance != null) ? instance.GetPrefab(prefab) : null);
				if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.GetComponent<Character>()) || Object.op_Implicit((Object)(object)val.GetComponent<Player>()))
				{
					throw new ArgumentException(Lang.L("Неизвестное существо."));
				}
				if (json == null || json.Length > 64000)
				{
					throw new ArgumentException(Lang.L("Слишком большой список дропа."));
				}
				bool flag = json == "null";
				List<DropRule> list = (flag ? new List<DropRule>() : WorldProfileCodec.Rows<DropRule>(json));
				if (list.Count > 128)
				{
					throw new ArgumentException(Lang.L("Максимум 128 ячеек."));
				}
				foreach (DropRule item in list)
				{
					ObjectDB instance2 = ObjectDB.instance;
					GameObject val2 = ((instance2 != null) ? instance2.GetItemPrefab(item.Item) : null);
					if (!Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)val2.GetComponent<ItemDrop>()))
					{
						throw new ArgumentException(Lang.L("Неизвестный предмет: ") + item.Item);
					}
					item.Source = prefab;
					item.Kind = "Creature";
					item.Biome = "";
					item.Replace = false;
					item.ReplaceAll = false;
					item.MinLevel = 1;
					item.MaxLevel = 100;
				}
				List<DropRule> list2 = (from r in ScopeRules(scope)
					where r.Source != prefab || r.Kind != "Creature"
					select r).ToList();
				if (!flag)
				{
					list2.Add(new DropRule
					{
						Source = prefab,
						ReplaceAll = true,
						Chance = 0f,
						Min = 0,
						Max = 0
					});
				}
				list2.AddRange(list);
				if (scope == "game")
				{
					string text = JsonConvert.SerializeObject((object)list2, (Formatting)1);
					WorldProfile.Validate(new WorldProfileData
					{
						Drops = text
					});
					AtomicFile.Write(Path.Combine(Plugin.RulesDir, "drops.json"), text);
					Rules.Reload();
					Network.ForceSync();
					return JsonConvert.SerializeObject((object)new
					{
						Success = true,
						Message = (flag ? Lang.L("Правило дропа для всей игры сброшено.") : (Own(WorldProfile.WorldDrops(), prefab) ? Lang.L("Дроп сохранён для всей игры. В этом мире действует своё правило мира.") : Lang.L("Дроп сохранён для всей игры и отправлен клиентам.")))
					});
				}
				WorldProfileData worldProfileData = CaptureProfile();
				worldProfileData.Drops = JsonConvert.SerializeObject((object)list2);
				worldProfileData.Settings["General.ServerLocksRules"] = "true";
				WorldProfile.Save(worldProfileData);
				return JsonConvert.SerializeObject((object)new
				{
					Success = true,
					Message = (flag ? Lang.L("Правило мира сброшено; действует правило для всей игры, если оно задано.") : Lang.L("Дроп сохранён в ValheimUnified для этого мира и отправлен клиентам."))
				});
			}
			catch (Exception ex)
			{
				return JsonConvert.SerializeObject((object)new
				{
					Success = false,
					Message = ex.Message
				});
			}
		}

		internal static WorldProfileData CaptureProfile()
		{
			return new WorldProfileData
			{
				World = WorldProfile.WorldId,
				Settings = Settings.Entries.Where((KeyValuePair<string, ConfigEntryBase> x) => Settings.WorldSetting(x.Value)).ToDictionary((KeyValuePair<string, ConfigEntryBase> x) => x.Key, (KeyValuePair<string, ConfigEntryBase> x) => TomlTypeConverter.ConvertToString(Settings.Value(x.Key), x.Value.SettingType)),
				Drops = JsonConvert.SerializeObject((object)WorldProfile.WorldDrops()),
				Raids = JsonConvert.SerializeObject((object)Rules.Raids),
				Plants = JsonConvert.SerializeObject((object)Rules.Plants),
				Surfaces = JsonConvert.SerializeObject((object)Rules.Surfaces),
				Skills = JsonConvert.SerializeObject((object)Rules.Skills)
			};
		}

		public static string SetDropEnabled(bool enabled)
		{
			try
			{
				WorldProfileCodec.RequireHost(Network.ServerSide, WorldProfile.WorldId);
				if (!Modules.Active("AdminIntegration"))
				{
					throw new InvalidOperationException(Lang.L("Хранилище настроек отключено."));
				}
				WorldProfileData worldProfileData = CaptureProfile();
				worldProfileData.Settings["General.ServerLocksRules"] = "true";
				worldProfileData.Settings["Drops.Enabled"] = (enabled ? "true" : "false");
				WorldProfile.Save(worldProfileData);
				return JsonConvert.SerializeObject((object)new
				{
					Success = true,
					Message = (enabled ? Lang.L("Дроп включён для мира.") : Lang.L("Дроп выключен для мира."))
				});
			}
			catch (Exception ex)
			{
				return JsonConvert.SerializeObject((object)new
				{
					Success = false,
					Message = ex.Message
				});
			}
		}

		public static string GetState()
		{
			bool host = Network.ServerSide && WorldProfile.WorldId != 0;
			var rows = (from x in Settings.Entries
				where Settings.WorldSetting(x.Value)
				orderby x.Key
				select x).Select(delegate(KeyValuePair<string, ConfigEntryBase> x)
			{
				string key = x.Key;
				string section = x.Value.Definition.Section;
				string key2 = x.Value.Definition.Key;
				string name = x.Value.SettingType.Name;
				string value = TomlTypeConverter.ConvertToString(Settings.Value(x.Key), x.Value.SettingType);
				string description = Settings.Describe(x.Value);
				AcceptableValueBase acceptableValues = x.Value.Description.AcceptableValues;
				return new
				{
					Id = key,
					Section = section,
					Key = key2,
					Type = name,
					Value = value,
					Description = description,
					Range = ((acceptableValues != null) ? acceptableValues.ToDescriptionString() : null),
					Status = (Modules.All.ContainsKey(x.Value.Definition.Section) ? Modules.All[x.Value.Definition.Section].Fault : null),
					Editable = (host && x.Key != "General.ServerLocksRules")
				};
			}).ToArray();
			return JsonConvert.SerializeObject((object)new
			{
				Api = 1,
				Version = "0.11.1",
				Host = host,
				World = WorldProfile.WorldId,
				WorldProfile = (WorldProfile.Current != null),
				Peers = Network.Peers.Count(),
				Rows = rows,
				Drops = JsonConvert.SerializeObject((object)Rules.Drops, (Formatting)1),
				Raids = JsonConvert.SerializeObject((object)Rules.Raids, (Formatting)1),
				Plants = JsonConvert.SerializeObject((object)Rules.Plants, (Formatting)1),
				Surfaces = JsonConvert.SerializeObject((object)Rules.Surfaces, (Formatting)1),
				Skills = JsonConvert.SerializeObject((object)Rules.Skills, (Formatting)1)
			});
		}

		public static string Execute(string command, string payload)
		{
			try
			{
				long worldId = WorldProfile.WorldId;
				WorldProfileCodec.RequireHost(Network.ServerSide, worldId);
				if (!Modules.Active("AdminIntegration"))
				{
					throw new InvalidOperationException(Lang.L("Модуль интеграции остановлен: F8 для повторной попытки."));
				}
				WorldProfile.Tick();
				switch (command)
				{
				case "apply":
					WorldProfile.Save(WorldProfileCodec.Read(payload, worldId));
					break;
				case "reset":
					WorldProfile.Remove();
					break;
				case "retry":
					Plugin.Reload();
					break;
				default:
					throw new ArgumentException(Lang.L("Неизвестная команда интеграции."));
				}
				return JsonConvert.SerializeObject((object)new
				{
					Success = true,
					Message = Lang.L("Настройки этого мира применены и отправлены клиентам.")
				});
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("AdminMenu integration: " + ex.Message));
				return JsonConvert.SerializeObject((object)new
				{
					Success = false,
					Message = ex.Message
				});
			}
		}
	}
	internal static class WorldProfile
	{
		internal static WorldProfileData Current;

		private static long loaded;

		private static bool attempted;

		internal static long WorldId
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)ZNet.instance))
				{
					return 0L;
				}
				try
				{
					return ZNet.instance.GetWorldUID();
				}
				catch (NullReferenceException)
				{
					return 0L;
				}
			}
		}

		private static string PathFor(long world)
		{
			return Path.Combine(Plugin.RulesDir, "world-settings", world.ToString(CultureInfo.InvariantCulture) + ".json");
		}

		internal static void Tick()
		{
			if (Network.ShuttingDown)
			{
				return;
			}
			if (!Network.ServerSide)
			{
				if (loaded != 0L)
				{
					Reset();
				}
				return;
			}
			long worldId = WorldId;
			if (worldId != 0L && (loaded != worldId || !attempted))
			{
				Reset();
				loaded = worldId;
				attempted = true;
				string path = PathFor(worldId);
				if (File.Exists(path))
				{
					WorldProfileData worldProfileData = WorldProfileCodec.Read(File.ReadAllText(path), worldId);
					Dictionary<string, object> values = Validate(worldProfileData);
					Install(worldProfileData, values);
					Plugin.Log.LogInfo((object)("World rules loaded: " + worldId));
					Network.ForceSync();
				}
			}
		}

		internal static Dictionary<string, object> Validate(WorldProfileData data)
		{
			Dictionary<string, object> next = new Dictionary<string, object>();
			foreach (KeyValuePair<string, string> setting in data.Settings)
			{
				if (!Settings.Entries.TryGetValue(setting.Key, out var value) || !Settings.WorldSetting(value))
				{
					throw new ArgumentException(Lang.L("Неизвестный или локальный параметр: ") + setting.Key);
				}
				object obj = TomlTypeConverter.ConvertToValue(setting.Value, value.SettingType);
				if (obj is float && (float.IsNaN((float)obj) || float.IsInfinity((float)obj)))
				{
					throw new ArgumentException(Lang.L("Недопустимое число: ") + setting.Key);
				}
				if (value.Description.AcceptableValues != null && !value.Description.AcceptableValues.IsValid(obj))
				{
					throw new ArgumentException(Lang.L("Значение вне диапазона: ") + setting.Key);
				}
				if (EquipmentBindings.IsSetting(setting.Key))
				{
					EquipmentBindings.Parse((string)obj);
				}
				if (setting.Key == "GuardianPowers.PowerRules")
				{
					PowerTuning.Parse((string)obj);
				}
				FeatureSettings.Validate(setting.Key, obj);
				next[setting.Key] = obj;
			}
			List<SurfaceRule> list = WorldProfileCodec.Rows<SurfaceRule>(data.Surfaces);
			List<SkillRule> list2 = WorldProfileCodec.Rows<SkillRule>(data.Skills);
			SurfaceEffects.Validate(list);
			SkillBonuses.Validate(list2);
			List<DropRule> list3 = WorldProfileCodec.Rows<DropRule>(data.Drops);
			List<RaidRule> list4 = WorldProfileCodec.Rows<RaidRule>(data.Raids);
			List<PlantRule> list5 = WorldProfileCodec.Rows<PlantRule>(data.Plants);
			foreach (DropRule item in list3)
			{
				if ((item.Kind != "Creature" && item.Kind != "World") || (string.IsNullOrWhiteSpace(item.Item) && !item.ReplaceAll) || float.IsNaN(item.Chance) || item.Chance < 0f || item.Chance > 1f || item.Min < 0 || item.Max < item.Min || item.Max > 10000 || item.MinLevel < 1 || item.MaxLevel < item.MinLevel || (item.ReplaceAll && (item.Kind != "Creature" || item.Source == "*")))
				{
					throw new ArgumentException(Lang.L("Некорректное правило дропа."));
				}
			}
			foreach (PlantRule item2 in list5)
			{
				PlantRules.Validate(item2);
			}
			foreach (RaidRule item3 in list4)
			{
				RaidProgress.Validate(item3);
				if (string.IsNullOrWhiteSpace(item3.Event) || float.IsNaN(item3.Duration) || float.IsInfinity(item3.Duration) || item3.Duration < -1f || item3.Duration > 7200f)
				{
					throw new ArgumentException(Lang.L("Некорректное правило рейда."));
				}
				if (item3.Spawns == null)
				{
					continue;
				}
				if (item3.Spawns.Count > 256)
				{
					throw new ArgumentException(Lang.L("Слишком много существ рейда."));
				}
				foreach (RaidSpawn spawn in item3.Spawns)
				{
					if (spawn == null || string.IsNullOrWhiteSpace(spawn.Prefab) || spawn.MaxSpawned < 1 || spawn.MaxSpawned > 100 || spawn.GroupMin < 1 || spawn.GroupMax < spawn.GroupMin || spawn.GroupMax > 20 || spawn.MinLevel < 1 || spawn.MaxLevel < spawn.MinLevel || spawn.MaxLevel > 10 || float.IsNaN(spawn.Interval) || float.IsInfinity(spawn.Interval) || spawn.Interval < 1f || spawn.Interval > 600f || float.IsNaN(spawn.Chance) || spawn.Chance < 0f || spawn.Chance > 100f)
					{
						throw new ArgumentException(Lang.L("Некорректная группа существ рейда."));
					}
				}
			}
			string config = JsonConvert.SerializeObject((object)Settings.Entries.Where((KeyValuePair<string, ConfigEntryBase> x) => Settings.WorldSetting(x.Value)).ToDictionary((KeyValuePair<string, ConfigEntryBase> x) => x.Key, (KeyValuePair<string, ConfigEntryBase> x) => TomlTypeConverter.ConvertToString(next.ContainsKey(x.Key) ? next[x.Key] : x.Value.BoxedValue, x.Value.SettingType)));
			if (JsonConvert.SerializeObject((object)new ServerSnapshot
			{
				Version = "0.11.1",
				Locked = true,
				Config = config,
				Drops = list3,
				Raids = list4,
				Plants = list5,
				Surfaces = list,
				Skills = list2
			}).Length > 256000)
			{
				throw new ArgumentException(Lang.L("Правила слишком велики для передачи клиентам."));
			}
			return next;
		}

		private static void Install(WorldProfileData profile, Dictionary<string, object> values)
		{
			Current = profile;
			Settings.WorldValues.Clear();
			Settings.Touch();
			foreach (KeyValuePair<string, object> value in values)
			{
				Settings.WorldValues[value.Key] = value.Value;
			}
			ApplyRules();
			Modules.RefreshStates();
		}

		internal static List<DropRule> WorldDrops()
		{
			if (Current != null)
			{
				return WorldProfileCodec.Rows<DropRule>(Current.Drops);
			}
			return new List<DropRule>();
		}

		internal static void ApplyRules()
		{
			if (Current != null)
			{
				Rules.Drops = Rules.MergeDrops(WorldDrops(), Rules.GameDrops);
				Rules.Raids = WorldProfileCodec.Rows<RaidRule>(Current.Raids);
				Rules.Plants = WorldProfileCodec.Rows<PlantRule>(Current.Plants);
				Rules.Surfaces = WorldProfileCodec.Rows<SurfaceRule>(Current.Surfaces);
				Rules.Skills = WorldProfileCodec.Rows<SkillRule>(Current.Skills);
			}
		}

		internal static void Save(WorldProfileData profile)
		{
			Dictionary<string, object> values = Validate(profile);
			string text = JsonConvert.SerializeObject((object)profile, (Formatting)1);
			if (text.Length > 240000)
			{
				throw new ArgumentException(Lang.L("Размер правил превышает 240000 символов."));
			}
			Directory.CreateDirectory(Path.GetDirectoryName(PathFor(profile.World)));
			AtomicFile.Write(PathFor(profile.World), text);
			Install(profile, values);
			Network.ForceSync();
		}

		internal static void Reload()
		{
			if (Network.ServerSide && loaded != 0L)
			{
				string path = PathFor(loaded);
				if (!File.Exists(path))
				{
					Current = null;
					Settings.WorldValues.Clear();
					Settings.Touch();
				}
				else
				{
					WorldProfileData worldProfileData = WorldProfileCodec.Read(File.ReadAllText(path), loaded);
					Dictionary<string, object> values = Validate(worldProfileData);
					Install(worldProfileData, values);
				}
			}
		}

		internal static void Remove()
		{
			string text = PathFor(loaded);
			if (File.Exists(text))
			{
				File.Copy(text, text + ".bak", overwrite: true);
				File.Delete(text);
			}
			Current = null;
			Settings.WorldValues.Clear();
			Settings.Touch();
			Rules.Reload();
			Modules.RefreshStates();
			Network.ForceSync();
		}

		internal static void Reset()
		{
			bool num = Current != null;
			Current = null;
			loaded = 0L;
			attempted = false;
			Settings.WorldValues.Clear();
			Settings.Touch();
			if (num)
			{
				Rules.Reload();
			}
		}
	}
	internal static class AdminMenuPlugin
	{
		internal static readonly string[] Guids = new string[2] { "chistix.adminmenu", "local.valheim.adminmenu" };

		internal static bool Present => Find() != null;

		internal static PluginInfo Find()
		{
			string[] guids = Guids;
			foreach (string key in guids)
			{
				if (Chainloader.PluginInfos.TryGetValue(key, out var value))
				{
					return value;
				}
			}
			return null;
		}
	}
	internal static class Harvest
	{
		private static readonly Queue<MonoBehaviour> pending = new Queue<MonoBehaviour>();

		private static readonly HashSet<ItemDrop> before = new HashSet<ItemDrop>();

		private static readonly HashSet<ItemDrop> requested = new HashSet<ItemDrop>();

		private static readonly Queue<ItemDrop> created = new Queue<ItemDrop>();

		private static readonly HashSet<MonoBehaviour> interacted = new HashSet<MonoBehaviour>();

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

		private static Player player;

		private static Vector3 origin;

		private static float radius;

		private static float expires;

		private static bool started;

		private static bool alt;

		private static bool watching;

		internal static void Created(ItemDrop item)
		{
			if (watching && created.Count < 512)
			{
				created.Enqueue(item);
			}
		}

		internal static bool Eligible(float distanceSquared, float range, string item, string first, bool sameOnly, string excluded)
		{
			if (distanceSquared <= range * range && !string.IsNullOrEmpty(item) && !Settings.InList(item, excluded))
			{
				if (sameOnly)
				{
					return string.Equals(item, first, StringComparison.OrdinalIgnoreCase);
				}
				return true;
			}
			return false;
		}

		internal static bool Modifier(KeyCode configured, bool configuredHeld, bool rightShiftHeld)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			if ((int)configured != 0)
			{
				if (!configuredHeld)
				{
					return (int)configured == 304 && rightShiftHeld;
				}
				return true;
			}
			return false;
		}

		private static bool Held()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			KeyCode val = Settings.Key("AreaHarvest", "ModifierKey");
			return Modifier(val, Input.GetKey(val), Input.GetKey((KeyCode)303));
		}

		private static string Output(MonoBehaviour target)
		{
			Pickable val = (Pickable)(object)((target is Pickable) ? target : null);
			if (val != null)
			{
				if (!Object.op_Implicit((Object)(object)val.m_itemPrefab))
				{
					return "";
				}
				return Utils.GetPrefabName(val.m_itemPrefab);
			}
			Beehive val2 = (Beehive)(object)((target is Beehive) ? target : null);
			if (val2 != null)
			{
				if (!Object.op_Implicit((Object)(object)val2.m_honeyItem))
				{
					return "";
				}
				return Utils.GetPrefabName(((Component)val2.m_honeyItem).gameObject);
			}
			PickableItem val3 = (PickableItem)(object)((target is PickableItem) ? target : null);
			if (val3 != null)
			{
				if (!Object.op_Implicit((Object)(object)val3.m_itemPrefab))
				{
					return "";
				}
				return Utils.GetPrefabName(((Component)val3.m_itemPrefab).gameObject);
			}
			return "";
		}

		private static bool Ready(MonoBehaviour target)
		{
			if (!Object.op_Implicit((Object)(object)target) || !((Behaviour)target).isActiveAndEnabled)
			{
				return false;
			}
			Pickable val = (Pickable)(object)((target is Pickable) ? target : null);
			if (val != null)
			{
				if (!Object.op_Implicit((Object)(object)val.m_nview) || !val.m_nview.IsValid() || val.GetEnabled == 0 || val.m_picked)
				{
					return false;
				}
				Floating val2 = ((!val.m_tarPreventsPicking) ? null : (Object.op_Implicit((Object)(object)val.m_floating) ? val.m_floating : ((Component)val).GetComponent<Floating>()));
				if (Object.op_Implicit((Object)(object)val2))
				{
					return !val2.IsInTar();
				}
				return true;
			}
			Beehive val3 = (Beehive)(object)((target is Beehive) ? target : null);
			if (val3 != null)
			{
				if (Settings.Get<bool>("AreaHarvest", "IncludeBeehives") && Object.op_Implicit((Object)(object)val3.m_nview) && val3.m_nview.IsValid())
				{
					return val3.GetHoneyLevel() > 0;
				}
				return false;
			}
			PickableItem val4 = (PickableItem)(object)((target is PickableItem) ? target : null);
			if (val4 != null)
			{
				if (Object.op_Implicit((Object)(object)val4.m_nview) && val4.m_nview.IsValid() && !val4.m_picked)
				{
					return Object.op_Implicit((Object)(object)val4.m_itemPrefab);
				}
				return false;
			}
			return false;
		}

		private static bool Allowed(MonoBehaviour target, string first)
		{
			//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)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			if (Ready(target))
			{
				Vector3 val = ((Component)target).transform.position - origin;
				if (Eligible(((Vector3)(ref val)).sqrMagnitude, radius, Output(target), first, Settings.Get<bool>("AreaHarvest", "SameItemOnly"), Settings.Get<string>("AreaHarvest", "ExcludedPrefabs")))
				{
					return Network.Ward(((Component)target).transform.position, player.GetPlayerID());
				}
			}
			return false;
		}

		private static void AddOutputs(MonoBehaviour target)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			outputs.Add(Output(target));
			Pickable val = (Pickable)(object)((target is Pickable) ? target : null);
			if (val == null || val.m_extraDrops == null)
			{
				return;
			}
			foreach (DropData drop in val.m_extraDrops.m_drops)
			{
				if (Object.op_Implicit((Object)(object)drop.m_item))
				{
					outputs.Add(Utils.GetPrefabName(drop.m_item));
				}
			}
		}

		internal static bool Begin(Player actor, GameObject go, bool hold, bool alternate)
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			if (hold || !Util.Local(actor) || !Util.InputAllowed() || !Held() || ((Character)actor).InAttack() || ((Character)actor).InDodge() || !Object.op_Implicit((Object)(object)go))
			{
				return false;
			}
			Interactable componentInParent = go.GetComponentInParent<Interactable>();
			MonoBehaviour val = (MonoBehaviour)(object)((componentInParent is MonoBehaviour) ? componentInParent : null);
			if (!(val is Pickable) && !(val is PickableItem) && !(val is Beehive))
			{
				return false;
			}
			if (Object.op_Implicit((Object)(object)player) && pending.Count > 0)
			{
				return false;
			}
			if (!Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)actor || Time.unscaledTime >= expires)
			{
				Reset();
			}
			if (interacted.Contains(val))
			{
				return false;
			}
			player = actor;
			origin = ((Component)actor).transform.position;
			radius = Settings.Get<float>("AreaHarvest", "HarvestRadius");
			string first = Output(val);
			if (!Allowed(val, first))
			{
				Reset();
				return false;
			}
			alt = alternate;
			interacted.Add(val);
			AddOutputs(val);
			HashSet<MonoBehaviour> hashSet = new HashSet<MonoBehaviour>();
			Collider[] array = Physics.OverlapSphere(origin, radius);
			for (int i = 0; i < array.Length; i++)
			{
				Interactable componentInParent2 = ((Component)array[i]).GetComponentInParent<Interactable>();
				MonoBehaviour val2 = (MonoBehaviour)(object)((componentInParent2 is MonoBehaviour) ? componentInParent2 : null);
				if (Object.op_Implicit((Object)(object)val2) && (Object)(object)val2 != (Object)(object)val && !interacted.Contains(val2) && (val2 is Pickable || val2 is PickableItem || val2 is Beehive) && Allowed(val2, first))
				{
					hashSet.Add(val2);
				}
			}
			foreach (MonoBehaviour item in hashSet.OrderBy(delegate(MonoBehaviour t)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				Vector3 val3 = ((Component)t).transform.position - origin;
				return ((Vector3)(ref val3)).sqrMagnitude;
			}).Take(Settings.Get<int>("AreaHarvest", "MaxTargets") - 1))
			{
				pending.Enqueue(item);
				interacted.Add(item);
				AddOutputs(item);
			}
			if (Settings.Get<bool>("AreaHarvest", "PickupHarvested") && !watching)
			{
				watching = true;
			}
			return true;
		}

		internal static void Finish()
		{
			started = true;
			expires = Time.unscaledTime + 3f;
		}

		internal static void Tick()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)player))
			{
				return;
			}
			if (started && Util.Local(player) && Util.InputAllowed())
			{
				Vector3 val = ((Component)player).transform.position - origin;
				if (!(((Vector3)(ref val)).sqrMagnitude > radius * radius))
				{
					for (int i = 0; i < Settings.Get<int>("AreaHarvest", "InteractionsPerFrame"); i++)
					{
						if (pending.Count <= 0)
						{
							break;
						}
						MonoBehaviour val2 = pending.Dequeue();
						if (Ready(val2))
						{
							val = ((Component)val2).transform.position - ((Component)player).transform.position;
							if (!(((Vector3)(ref val)).sqrMagnitude > radius * radius) && !Settings.InList(Output(val2), Settings.Get<string>("AreaHarvest", "ExcludedPrefabs")) && Network.Ward(((Component)val2).transform.position, player.GetPlayerID()))
							{
								((Interactable)val2).Interact((Humanoid)(object)player, false, alt);
								expires = Time.unscaledTime + 3f;
							}
						}
					}
					if (Settings.Get<bool>("AreaHarvest", "PickupHarvested"))
					{
						int num = 0;
						int num2 = Math.Min(32, created.Count);
						for (int j = 0; j < num2; j++)
						{
							ItemDrop val3 = created.Dequeue();
							if (!Object.op_Implicit((Object)(object)val3) || before.Contains(val3) || requested.Contains(val3) || val3.InTar() || !val3.m_autoPickup || !Object.op_Implicit((Object)(object)val3.m_itemData.m_dropPrefab) || !outputs.Contains(Util.Prefab(val3.m_itemData)))
							{
								continue;
							}
							val = ((Component)val3).transform.position - origin;
							if (Eligible(((Vector3)(ref val)).sqrMagnitude, radius + 3f, Util.Prefab(val3.m_itemData), "", sameOnly: false, Settings.Get<string>("AreaHarvest", "ExcludedPrefabs")) && Network.Ward(((Component)val3).transform.position, player.GetPlayerID()) && ((Humanoid)player).GetInventory().CanAddItem(val3.m_itemData, val3.m_itemData.m_stack))
							{
								requested.Add(val3);
								val3.Pickup((Humanoid)(object)player);
								if (++num >= 8)
								{
									break;
								}
							}
						}
					}
					if (pending.Count == 0 && Time.unscaledTime >= expires)
					{
						Reset();
					}
					return;
				}
			}
			Reset();
		}

		private unsafe static string ModifierName(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Invalid comparison between Unknown and I4
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Invalid comparison between Unknown and I4
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Invalid comparison between Unknown and I4
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Invalid comparison between Unknown and I4
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			if ((int)key != 304 && (int)key != 303)
			{
				if ((int)key != 306 && (int)key != 305)
				{
					if ((int)key != 308 && (int)key != 307)
					{
						return ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString();
					}
					return "Alt";
				}
				return "Ctrl";
			}
			return "Shift";
		}

		internal static string Hint(MonoBehaviour target, string original)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(original) || Settings.InList(Output(target), Settings.Get<string>("AreaHarvest", "ExcludedPrefabs")))
			{
				return original;
			}
			return original + Localization.instance.Localize("\n[<color=yellow>" + ModifierName(Settings.Key("AreaHarvest", "ModifierKey")) + Lang.L(" + $KEY_Use</color>] Собрать рядом (") + Settings.Get<float>("AreaHarvest", "HarvestRadius").ToString("0.#") + Lang.L(" м)"));
		}

		internal static void Reset()
		{
			pending.Clear();
			before.Clear();
			requested.Clear();
			created.Clear();
			outputs.Clear();
			interacted.Clear();
			player = null;
			started = (watching = false);
		}
	}
	[HarmonyPatch(typeof(Player), "Interact", new Type[]
	{
		typeof(GameObject),
		typeof(bool),
		typeof(bool)
	})]
	internal static class AreaHarvestHooks
	{
		private static void Prefix(Player __instance, GameObject go, bool hold, bool alt, out bool __state)
		{
			__state = Modules.Try("AreaHarvest", () => Harvest.Begin(__instance, go, hold, alt), fallback: false);
		}

		private static void Postfix(bool __state)
		{
			if (__state)
			{
				Modules.Run("AreaHarvest", Harvest.Finish);
			}
		}
	}
	[HarmonyPatch]
	internal static class HarvestHintHooks
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return AccessTools.Method(typeof(Pickable), "GetHoverText", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(PickableItem), "GetHoverText", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(Beehive), "GetHoverText", (Type[])null, (Type[])null);
		}

		private static void Postfix(MonoBehaviour __instance, ref string __result)
		{
			string original = __result;
			__result = Modules.Try("AreaHarvest", () => ((int)Settings.Key("AreaHarvest", "ModifierKey") != 0) ? Harvest.Hint(__instance, original) : original, original);
		}
	}
	internal static class AutoConsumption
	{
		private sealed class Demand
		{
			internal string Role;

			internal string[] Items;

			internal int Capacity;
		}

		private static readonly HashSet<ZNetView> index = new HashSet<ZNetView>();

		private static int cursor;

		private static readonly Dictionary<ZNetView, float> checks = new Dictionary<ZNetView, float>();

		private static readonly HashSet<ZNetView> waiting = new HashSet<ZNetView>();

		private static readonly HashSet<string> warned = new HashSet<string>();

		private static readonly List<ZNetView> owned = new List<ZNetView>();

		private static readonly List<ZNetView> stale = new List<ZNetView>();

		internal static void Add(Component component)
		{
			ZNetView component2 = component.GetComponent<ZNetView>();
			if (Object.op_Implicit((Object)(object)component2) && component2.IsValid())
			{
				index.Add(component2);
			}
		}

		internal static void Reset()
		{
			index.Clear();
			checks.Clear();
			waiting.Clear();
			warned.Clear();
			cursor = 0;
		}

		internal static void ApplyTick()
		{
		}

		private static bool On(string role)
		{
			string k = role switch
			{
				"Shield" => "SupplyShields", 
				"Cooking" => "SupplyCookingFuel", 
				"Fire" => "SupplyFireplaces", 
				"Food" => "FeedAnimals", 
				_ => "SupplySmelters", 
			};
			if (Modules.Active("NearbyResources"))
			{
				return Settings.Get<bool>("NearbyResources", k);
			}
			return false;
		}

		internal static void Tick()
		{
			if (!Network.Ready || !Modules.Active("NearbyResources"))
			{
				return;
			}
			index.RemoveWhere((ZNetView v) => !Object.op_Implicit((Object)(object)v) || !v.IsValid());
			stale.Clear();
			foreach (ZNetView key in checks.Keys)
			{
				if (!Object.op_Implicit((Object)(object)key) || !index.Contains(key))
				{
					stale.Add(key);
				}
			}
			foreach (ZNetView item in stale)
			{
				checks.Remove(item);
			}
			stale.Clear();
			waiting.RemoveWhere((ZNetView v) => !Object.op_Implicit((Object)(object)v) || !index.Contains(v));
			owned.Clear();
			foreach (ZNetView item2 in index)
			{
				if (item2.IsOwner())
				{
					owned.Add(item2);
				}
			}
			if (owned.Count == 0)
			{
				return;
			}
			int num = Settings.Get<int>("NearbyResources", "DevicesPerPass");
			int num2 = 0;
			int num3 = Settings.Get<int>("NearbyResources", "ConsumerResultsPerFrame");
			cursor %= owned.Count;
			for (int num4 = 0; num4 < num && num4 < owned.Count; num4++)
			{
				if (num2 >= num3)
				{
					break;
				}
				ZNetView val = owned[(cursor + num4) % owned.Count];
				bool flag = false;
				try
				{
					flag = Serve(val);
				}
				catch (Exception ex)
				{
					Containers.Warn("Supply " + (Object.op_Implicit((Object)(object)val) ? Utils.GetPrefabName(((Component)val).gameObject) : "?"), ex);
				}
				if (flag)
				{
					num2++;
				}
			}
			cursor = (cursor + num) % owned.Count;
			owned.Clear();
		}

		private static bool Serve(ZNetView view)
		{
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			if (Legacy(view))
			{
				return false;
			}
			if (!waiting.Contains(view) && checks.TryGetValue(view, out var value) && Time.unscaledTime < value)
			{
				return false;
			}
			checks[view] = Time.unscaledTime + Settings.Get<float>("NearbyResources", "ConsumerInterval");
			Demand demand = Need(view);
			if (demand == null || demand.Capacity < 1)
			{
				waiting.Remove(view);
				return false;
			}
			int reserve = (Settings.Get<bool>("NearbyResources", "LeaveLastItem") ? 1 : 0);
			foreach (Container chest in Nearby(view))
			{
				string item = demand.Items.FirstOrDefault((string prefab) => Available(chest, prefab) > reserve);
				if (item == null)
				{
					continue;
				}
				string reason;
				switch (Lease.Acquire(chest, LeasePurpose.Feed, view.GetZDO().m_uid, out reason, hold: false))
				{
				case LeaseState.Waiting:
					waiting.Add(view);
					return false;
				case LeaseState.Failed:
					if (reason != null && warned.Add(reason))
					{
						Plugin.Log.LogInfo((object)("Supply skipped a chest: " + reason));
					}
					continue;
				}
				waiting.Remove(view);
				int num = BatchLimit((demand.Role == "Food") ? 1 : Settings.Get<int>("NearbyResources", "ConsumerBatch"), Available(chest, item), demand.Capacity, reserve > 0);
				if (num >= 1)
				{
					List<ItemData> taken = new List<ItemData>();
					if (ExactInventory.Withdraw(chest.GetInventory(), (ItemData i) => Util.Prefab(i) == item && i.m_worldLevel >= Game.m_worldLevel, num, taken) >= 1)
					{
						Apply(view, demand.Role, item, taken);
						checks[view] = Time.unscaledTime + Math.Min(1f, Settings.Get<float>("NearbyResources", "ConsumerInterval"));
						return true;
					}
				}
			}
			waiting.Remove(view);
			return false;
		}

		private static int Available(Container c, string prefab)
		{
			int num = 0;
			foreach (ItemData allItem in c.GetInventory().GetAllItems())
			{
				if (Util.Prefab(allItem) == prefab && allItem.m_worldLevel >= Game.m_worldLevel && !allItem.m_equipped)
				{
					num += allItem.m_stack;
				}
			}
			return num;
		}

		private static Demand Need(ZNetView view)
		{
			ZDO zDO = view.GetZDO();
			string protectedList = Settings.Get<string>("NearbyResources", "ProtectedFuelPrefabs");
			Func<IEnumerable<string>, string[]> func = (IEnumerable<string> list) => list.Where((string x) => !string.IsNullOrEmpty(x) && !Settings.InList(x, protectedList)).Distinct().ToArray();
			Smelter component = ((Component)view).GetComponent<Smelter>();
			if (Object.op_Implicit((Object)(object)component) && On("Fuel"))
			{
				if (component.m_maxFuel > 0 && Object.op_Implicit((Object)(object)component.m_fuelItem))
				{
					int num = Capacity(zDO, "Fuel");
					string[] array = func(new string[1] { ((Object)((Component)component.m_fuelItem).gameObject).name });
					if (num > 0 && array.Length != 0)
					{
						return new Demand
						{
							Role = "Fuel",
							Items = array,
							Capacity = num
						};
					}
				}
				if (component.m_maxOre > 0)
				{
					int num2 = Capacity(zDO, "Ore");
					string[] array2 = func(from c in component.m_conversion
						where Object.op_Implicit((Object)(object)c.m_from)
						select ((Object)((Component)c.m_from).gameObject).name);
					if (num2 > 0 && array2.Length != 0)
					{
						return new Demand
						{
							Role = "Ore",
							Items = array2,
							Capacity = num2
						};
					}
				}
				return null;
			}
			Tameable component2 = ((Component)view).GetComponent<Tameable>();
			if (Object.op_Implicit((Object)(object)component2))
			{
				if (!On("Food") || !component2.IsTamed() || !component2.IsHungry() || !Object.op_Implicit((Object)(object)component2.m_monsterAI) || ((BaseAI)component2.m_monsterAI).IsAlerted() || component2.m_character.IsDead() || component2.m_monsterAI.m_consumeItems == null)
				{
					return null;
				}
				string[] array3 = func(from i in component2.m_monsterAI.m_consumeItems
					where Object.op_Implicit((Object)(object)i)
					select ((Object)((Component)i).gameObject).name);
				if (array3.Length == 0)
				{
					return null;
				}
				return new Demand
				{
					Role = "Food",
					Items = array3,
					Capacity = 1
				};
			}
			Fireplace component3 = ((Component)view).GetComponent<Fireplace>();
			if (Object.op_Implicit((Object)(object)component3))
			{
				if (!On("Fire") || component3.m_infiniteFuel || !Object.op_Implicit((Object)(object)component3.m_fuelItem))
				{
					return null;
				}
				string[] array4 = func(new string[1] { ((Object)((Component)component3.m_fuelItem).gameObject).name });
				int num3 = Capacity(zDO, "Fire");
				if (num3 <= 0 || array4.Length == 0)
				{
					return null;
				}
				return new Demand
				{
					Role = "Fire",
					Items = array4,
					Capacity = num3
				};
			}
			CookingStation component4 = ((Component)view).GetComponent<CookingStation>();
			if (Object.op_Implicit((Object)(object)component4))
			{
				if (!On("Cooking") || !component4.m_useFuel || !Object.op_Implicit((Object)(object)component4.m_fuelItem))
				{
					return null;
				}
				string[] array5 = func(new string[1] { ((Object)((Component)component4.m_fuelItem).gameObject).name });
				int num4 = Capacity(zDO, "Cooking");
				if (num4 <= 0 || array5.Length == 0)
				{
					return null;
				}
				return new Demand
				{
					Role = "Cooking",
					Items = array5,
					Capacity = num4
				};
			}
			ShieldGenerator component5 = ((Component)view).GetComponent<ShieldGenerator>();
			if (Object.op_Implicit((Object)(object)component5))
			{
				if (!On("Shield"))
				{
					return null;
				}
				string[] array6 = func(from i in component5.m_fuelItems
					where Object.op_Implicit((Object)(object)i)
					select ((Object)((Component)i).gameObject).name);
				int num5 = Capacity(zDO, "Shield");
				if (num5 <= 0 || array6.Length == 0)
				{
					return null;
				}
				return new Demand
				{
					Role = "Shield",
					Items = array6,
					Capacity = num5
				};
			}
			return null;
		}

		private static IEnumerable<Container> Nearby(ZNetView view)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			float range = Settings.Get<float>("NearbyResources", "ConsumerRange");
			Vector3 at = ((Component)view).transform.position;
			return Containers.Index.Where((Container c) => Containers.Zdo(c) != null && Containers.Ordinary(c) && !Containers.InUseByOther(c) && ChestAccess.ConsumerAllowed(c) && (!Settings.Get<bool>("NearbyResources", "PlayerBuiltOnly") || (Object.op_Implicit((Object)(object)c.m_piece) && c.m_piece.GetCreator() != 0L)) && Vector3.Distance(at, ((Component)c).transform.position) <= range).OrderBy(delegate(Container c)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				Vector3 val = ((Component)c).transform.position - at;
				return ((Vector3)(ref val)).sqrMagnitude;
			}).ToArray();
		}

		internal static int BatchLimit(int requested, int available, int capacity, bool leaveOne)
		{
			return Math.Max(0, Math.Min(Math.Min(requested, capacity), available - (leaveOne ? 1 : 0)));
		}

		private static int Capacity(ZDO z, string role)
		{
			GameObject prefab = ZNetScene.instance.GetPrefab(z.GetPrefab());
			if (!Object.op_Implicit((Object)(object)prefab))
			{
				return 0;
			}
			float num = z.GetFloat(ZDOVars.s_fuel, 0f);
			Smelter component = prefab.GetComponent<Smelter>();
			switch (role)
			{
			case "Fuel":
				if (!Object.op_Implicit((Object)(object)component))
				{
					return 0;
				}
				return Math.Max(0, (int)Math.Floor((float)Production.Scaled(component.m_maxFuel, Production.Capacity) - num));
			case "Ore":
				if (!Object.op_Implicit((Object)(object)component))
				{
					return 0;
				}
				return Math.Max(0, Production.Scaled(component.m_maxOre, Production.Capacity) - z.GetInt(ZDOVars.s_queued, 0));
			case "Fire":
			{
				Fireplace component3 = prefab.GetComponent<Fireplace>();
				if (!Object.op_Implicit((Object)(object)component3))
				{
					return 0;
				}
				return Math.Max(0, (int)Math.Floor(component3.m_maxFuel - num));
			}
			case "Cooking":
			{
				CookingStation component4 = prefab.GetComponent<CookingStation>();
				if (!Object.op_Implicit((Object)(object)component4) || !component4.m_useFuel)
				{
					return 0;
				}
				return Math.Max(0, (int)Math.Floor((float)component4.m_maxFuel - num));
			}
			case "Shield":
			{
				ShieldGenerator component2 = prefab.GetComponent<ShieldGenerator>();
				if (!Object.op_Implicit((Object)(object)component2))
				{
					return 0;
				}
				return Math.Max(0, (int)Math.Floor((float)component2.m_maxFuel - z.GetFloat(ZDOVars.s_fuel, (float)component2.m_defaultFuel)));
			}
			default:
				return (role == "Food") ? 1 : 0;
			}
		}

		private static void Apply(ZNetView view, string role, string item, List<ItemData> taken)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: 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_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			int num = taken.Sum((ItemData i) => i.m_stack);
			Transform transform = ((Component)view).transform;
			switch (role)
			{
			case "Fuel":
			{
				Smelter component = ((Component)view).GetComponent<Smelter>();
				component.SetFuel(Math.Min(component.m_maxFuel, component.GetFuel() + (float)num));
				component.m_fuelAddedEffects.Create(transform.position, transform.rotation, transform, 1f, -1, default(ZDOID));
				return;
			}
			case "Ore":
			{
				Smelter component2 = ((Component)view).GetComponent<Smelter>();
				foreach (ItemData item2 in taken)
				{
					for (int num2 = 0; num2 < item2.m_stack; num2++)
					{
						component2.QueueOre(item, item2.m_cheated);
					}
				}
				component2.m_oreAddedEffects.Create(transform.position, transform.rotation, (Transform)null, 1f, -1, default(ZDOID));
				return;
			}
			case "Fire":
				((Component)view).GetComponent<Fireplace>().RPC_AddFuelAmount(ZNet.GetUID(), (float)num);
				return;
			case "Cooking":
			{
				CookingStation component4 = ((Component)view).GetComponent<CookingStation>();
				component4.SetFuel(Math.Min(component4.m_maxFuel, component4.GetFuel() + (float)num));
				component4.m_fuelAddedEffects.Create(transform.position, transform.rotation, transform, 1f, -1, default(ZDOID));
				return;
			}
			case "Shield":
			{
				ShieldGenerator component3 = ((Component)view).GetComponent<ShieldGenerator>();
				component3.SetFuel(Math.Min(component3.m_maxFuel, component3.GetFuel() + (float)num));
				component3.m_fuelAddedEffects.Create(transform.position, transform.rotation, transform, 1f, -1, default(ZDOID));
				return;
			}
			}
			Tameable component5 = ((Component)view).GetComponent<Tameable>();
			ItemDrop component6 = ObjectDB.instance.GetItemPrefab(item).GetComponent<ItemDrop>();
			component5.OnConsumedItem(component6);
			Character character = component5.m_character;
			Humanoid val = (Humanoid)(object)((character is Humanoid) ? character : null);
			if (Object.op_Implicit((Object)(object)val))
			{
				val.m_consumeItemEffects.Create(((Component)component5).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
			}
			((BaseAI)component5.m_monsterAI).m_animator.SetTrigger("consume");
		}

		private static bool Legacy(ZNetView view)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = view.GetZDO();
			string text = zDO.GetString("VU.ConsumerTicket", "");
			if (text.Length == 0)
			{
				return false;
			}
			zDO.Set("VU.ConsumerTicket", "");
			ConsumerTicket consumerTicket = JsonConvert.DeserializeObject<ConsumerTicket>(text);
			if (consumerTicket == null || consumerTicket.State == "Applied")
			{
				return true;
			}
			ZDO zDO2 = ZDOMan.instance.GetZDO(new ZDOID(consumerTicket.ContainerUser, consumerTicket.ContainerId));
			if (zDO2 == null)
			{
				return true;
			}
			string text2 = zDO2.GetString("VU.ConsumerLedger", "");
			if (text2.Length == 0)
			{
				return true;
			}
			Dictionary<string, ConsumerTicket> dictionary = JsonConvert.DeserializeObject<Dictionary<string, ConsumerTicket>>(text2);
			if (dictionary == null || !dictionary.TryGetValue(consumerTicket.MachineUser + ":" + consumerTicket.MachineId, out var value) || value.Id != consumerTicket.Id || value.State != "Reserved" || string.IsNullOrEmpty(value.Data))
			{
				return true;
			}
			List<ItemData> allItems = ExactInventory.Load(value.Data).GetAllItems();
			int num = Capacity(zDO, consumerTicket.Role);
			List<ItemData> list = new List<ItemData>();
			foreach (ItemData item in allItems)
			{
				ItemData val = item.Clone();
				val.m_stack = Math.Max(0, Math.Min(num, item.m_stack));
				num -= val.m_stack;
				if (val.m_stack > 0)
				{
					list.Add(val);
				}
				int num2 = item.m_stack - val.m_stack;
				if (num2 > 0)
				{
					ItemDrop.DropItem(item, num2, ((Component)view).transform.position + Vector3.up, Quaternion.identity);
				}
			}
			if (list.Count > 0 && On(consumerTicket.Role))
			{
				Apply(view, consumerTicket.Role, consumerTicket.Item, list);
			}
			else
			{
				foreach (ItemData item2 in list)
				{
					ItemDrop.DropItem(item2, item2.m_stack, ((Component)view).transform.position + Vector3.up, Quaternion.identity);
				}
			}
			Plugin.Log.LogWarning((object)("Legacy supply ticket " + consumerTicket.Id + " settled at " + Utils.GetPrefabName(((Component)view).gameObject)));
			return true;
		}
	}
	[HarmonyPatch]
	internal static class ConsumerHooks
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(Smelter), "Awake")]
		private static void Smelter(Smelter __instance)
		{
			Modules.Run("ConsumerTransport", delegate
			{
				AutoConsumption.Add((Component)(object)__instance);
			});
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Fireplace), "Awake")]
		private static void Fire(Fireplace __instance)
		{
			Modules.Run("ConsumerTransport", delegate
			{
				AutoConsumption.Add((Component)(object)__instance);
			});
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(CookingStation), "Awake")]
		private static void Cooking(CookingStation __instance)
		{
			Modules.Run("ConsumerTransport", delegate
			{
				AutoConsumption.Add((Component)(object)__instance);
			});
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(ShieldGenerator), "Start")]
		private static void Shield(ShieldGenerator __instance)
		{
			Modules.Run("ConsumerTransport", delegate
			{
				AutoConsumption.Add((Component)(object)__instance);
			});
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Tameable), "Awake")]
		private static void Animal(Tameable __instance)
		{
			Modules.Run("ConsumerTransport", delegate
			{
				AutoConsumption.Add((Component)(object)__instance);
			});
		}
	}
	internal static class DivingSkill
	{
		internal const int Id = 189404321;

		internal static readonly SkillType Type = (SkillType)189404321;

		internal static void Register(Skills skills)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Expected O, but got Unknown
			if (!skills.m_skills.Any((SkillDef s) => (int)s.m_skill == 189404321))
			{
				SkillDef val = ((IEnumerable<SkillDef>)skills.m_skills).FirstOrDefault((Func<SkillDef, bool>)((SkillDef s) => (int)s.m_skill == 103));
				skills.m_skills.Add(new SkillDef
				{
					m_skill = Type,
					m_icon = val?.m_icon,
					m_description = Lang.Token("vu_skill_diving_desc", () => Lang.L("Увеличивает объём лёгких. Развивается при погружении под воду.")),
					m_increseStep = 1f
				});
			}
		}

		internal static float Level(Player p)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)p))
			{
				return 0f;
			}
			return ((Character)p).GetSkills().GetSkillLevel(Type);
		}
	}
	[HarmonyPatch]
	internal static class DivingSkillHooks
	{
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		[HarmonyPatch(typeof(Skills), "Awake")]
		private static void Awake(Skills __instance)
		{
			Modules.Run("CustomSkills", delegate
			{
				DivingSkill.Register(__instance);
				ExtraSkills.Register(__instance);
			});
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Skills), "IsSkillValid")]
		private static void Valid(SkillType type, ref bool __result)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected I4, but got Unknown
			if ((int)type == 189404321 || ExtraSkills.Own((int)type))
			{
				__result = true;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Localization), "Localize", new Type[] { typeof(string) })]
		private static void Localize(ref string text)
		{
			if (text != null && text.IndexOf("$skill_18940432", StringComparison.Ordinal) >= 0)
			{
				text = text.Replace("$skill_" + 189404321, Lang.L("Подводник")).Replace("$skill_" + 189404322, Lang.L("Мореход")).Replace("$skill_" + 189404323, Lang.L("Картограф"));
			}
		}
	}
	internal static class Breath
	{
		private static Player tracked;

		private static float oxygen = -1f;

		private static float damageClock;

		private static float xpClock;

		private static GameObject bar;

		private static Hud hud;

		private static GuiBar[] bars;

		private static TMP_Text[] labels;

		private static Canvas canvas;

		private static CanvasGroup visibility;

		private static bool submerged;

		private static float maximum;

		private static int shownSeconds = -1;

		private static int shownMaximum = -1;

		internal static float Capacity(float level)
		{
			float value = Settings.Get<float>("Diving", "OxygenSeconds") + Mathf.Clamp(level, 0f, 100f) * Settings.Get<float>("Diving", "OxygenPerSkillLevel");
			return StatModifiers.Apply(Player.m_localPlayer, "Oxygen", value);
		}

		internal static void Reset()
		{
			tracked = null;
			oxygen = -1f;
			damageClock = (xpClock = 0f);
			if (Object.op_Implicit((Object)(object)bar))
			{
				Object.Destroy((Object)(object)bar);
			}
			bar = null;
			hud = null;
			bars = null;
			labels = null;
			canvas = null;
			visibility = null;
			submerged = false;
			maximum = 0f;
			shownSeconds = (shownMaximum = -1);
		}

		internal static void Tick(Player player, float dt, bool train = true)
		{
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Expected O, but got Unknown
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			if (!Settings.Get<bool>("Diving", "Breathing"))
			{
				Reset();
				return;
			}
			if ((Object)(object)tracked != (Object)(object)player)
			{
				Reset();
				tracked = player;
				DivingSkill.Register(((Character)player).GetSkills());
			}
			maximum = Capacity(DivingSkill.Level(player));
			bool num = (submerged = DivingSpace.Read(player).Underwater);
			if (oxygen < 0f)
			{
				oxygen = maximum;
			}
			oxygen = Mathf.Min(oxygen, maximum);
			if (num)
			{
				oxygen = Mathf.Max(0f, oxygen - dt);
				if (train)
				{
					xpClock += dt;
				}
				else
				{
					xpClock = 0f;
				}
				if (train && xpClock >= 1f)
				{
					float num2 = xpClock;
					xpClock = 0f;
					((Character)player).RaiseSkill(DivingSkill.Type, Settings.Get<float>("Diving", "DivingXpPerSecond") * num2);
				}
				if (!(oxygen <= 0f))
				{
					return;
				}
				damageClock += dt;
				if (damageClock >= 1f)
				{
					float num3 = Settings.Get<float>("Diving", "DrowningDamage") * damageClock;
					damageClock = 0f;
					if (num3 > 0f)
					{
						HitData val = new HitData();
						val.m_damage.m_damage = num3;
						val.m_hitType = (HitType)4;
						val.m_point = ((Character)player).GetEyePoint();
						((Character)player).Damage(val);
					}
				}
			}
			else
			{
				oxygen = Mathf.Min(maximum, oxygen + Settings.Get<float>("Diving", "OxygenRecovery") * dt);
				damageClock = (xpClock = 0f);
			}
		}

		internal static bool Visible(bool hidden, bool underwater, float air, float capacity)
		{
			if (!hidden && capacity > 0f)
			{
				if (!underwater)
				{
					return air < capacity - 0.1f;
				}
				return true;
			}
			return false;
		}

		internal static Rect Layout(Rect stamina, Rect eitr, bool hasEitr, float scale, float screenWidth, float screenHeight)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			float num = Math.Max(160f * scale, ((Rect)(ref stamina)).width);
			float num2 = Math.Max(24f * scale, ((Rect)(ref stamina)).height);
			float num3 = (hasEitr ? Math.Min(((Rect)(ref stamina)).y, ((Rect)(ref eitr)).y) : ((Rect)(ref stamina)).y);
			return new Rect(Mathf.Clamp(((Rect)(ref stamina)).center.x - num / 2f, 4f, Math.Max(4f, screenWidth - num - 4f)), Mathf.Clamp(num3 - num2 - 10f * scale, 4f, Math.Max(4f, screenHeight - num2 - 4f)), num, num2);
		}

		private static void Create(Hud current)
		{
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0309: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_0329: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)bar))
			{
				Object.Destroy((Object)(object)bar);
			}
			hud = current;
			canvas = ((Component)current.m_staminaBar2Root).GetComponentInParent<Canvas>();
			Transform val = ((Object.op_Implicit((Object)(object)current.m_rootObject) && current.m_rootObject.transform is RectTransform) ? current.m_rootObject.transform : ((Component)canvas).transform);
			bar = Object.Instantiate<GameObject>(((Component)current.m_staminaBar2Root).gameObject, val);
			((Object)bar).name = "Chistix Oxygen";
			Animator[] componentsInChildren = bar.GetComponentsInChildren<Animator>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				((Behaviour)componentsInChildren[i]).enabled = false;
			}
			Transform[] componentsInChildren2 = bar.GetComponentsInChildren<Transform>(true);
			foreach (Transform val2 in componentsInChildren2)
			{
				((Component)val2).gameObject.SetActive(true);
				Vector3 localScale = val2.localScale;
				if (((Vector3)(ref localScale)).sqrMagnitude < 0.001f)
				{
					val2.localScale = Vector3.one;
				}
			}
			RectTransform val3 = (RectTransform)bar.transform;
			((Transform)val3).localScale = Vector3.one;
			((Transform)val3).localRotation = Quaternion.identity;
			CanvasGroup[] componentsInChildren3 = bar.GetComponentsInChildren<CanvasGroup>(true);
			foreach (CanvasGroup obj in componentsInChildren3)
			{
				obj.alpha = 1f;
				obj.interactable = false;
				obj.blocksRaycasts = false;
			}
			visibility = bar.GetComponent<CanvasGroup>();
			if (!Object.op_Implicit((Object)(object)visibility))
			{
				visibility = bar.AddComponent<CanvasGroup>();
			}
			visibility.alpha = 1f;
			visibility.interactable = false;
			visibility.blocksRaycasts = false;
			visibility.ignoreParentGroups = true;
			Image[] componentsInChildren4 = bar.GetComponentsInChildren<Image>(true);
			foreach (Image val4 in componentsInChildren4)
			{
				((Graphic)val4).raycastTarget = false;
				((Behaviour)val4).enabled = true;
				if (Object.op_Implicit((Object)(object)val4.sprite) && ((Graphic)val4).color.a < 0.01f)
				{
					Color color = ((Graphic)val4).color;
					color.a = 1f;
					((Graphic)val4).color = color;
				}
			}
			bars = bar.GetComponentsInChildren<GuiBar>(true);
			GuiBar[] array = bars;
			foreach (GuiBar obj2 in array)
			{
				((Behaviour)obj2).enabled = true;
				obj2.m_smoothDrain = (obj2.m_smoothFill = false);
				obj2.SetMaxValue(1f);
				obj2.SetValue(1f);
				obj2.SetColor(new Color(0.15f, 0.65f, 0.95f, 1f));
			}
			labels = bar.GetComponentsInChildren<TMP_Text>(true);
			TMP_Text[] array2 = labels;
			foreach (TMP_Text val5 in array2)
			{
				((Behaviour)val5).enabled = true;
				((Graphic)val5).raycastTarget = false;
				Color color2 = ((Graphic)val5).color;
				color2.a = 1f;
				((Graphic)val5).color = color2;
				val5.transform.SetParent(bar.transform, false);
				RectTransform rectTransform = val5.rectTransform;
				rectTransform.anchorMin = Vector2.zero;
				rectTransform.anchorMax = Vector2.one;
				rectTransform.offsetMin = new Vector2(3f, 0f);
				rectTransform.offsetMax = new Vector2(-3f, 0f);
				val5.alignment = (TextAlignmentOptions)514;
				val5.enableAutoSizing = true;
				val5.fontSizeMin = 10f;
				val5.fontSizeMax = Math.Max(10f, val5.fontSize);
			}
			shownSeconds = (shownMaximum = -1);
		}

		internal static void Present()
		{
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Expected O, but got Unknown
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)tracked) || !Settings.Get<bool>("Diving", "Breathing"))
			{
				return;
			}
			Hud instance = Hud.instance;
			if (!Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)instance.m_staminaBar2Root))
			{
				return;
			}
			if (!Visible(Hud.IsUserHidden() || ((Character)tracked).InCutscene(), submerged, oxygen, maximum))
			{
				if (Object.op_Implicit((Object)(object)bar))
				{
					bar.SetActive(false);
				}
				return;
			}
			if ((Object)(object)hud != (Object)(object)instance || !Object.op_Implicit((Object)(object)bar))
			{
				Create(instance);
			}
			if (!bar.activeSelf)
			{
				bar.SetActive(true);
			}
			visibility.alpha = 1f;
			float scale = Mathf.Clamp((float)Screen.height / 1080f, 0.6f, 2f);
			bool flag = Object.op_Implicit((Object)(object)instance.m_eitrBarRoot) && ((Component)instance.m_eitrBarRoot).gameObject.activeInHierarchy;
			Rect stamina = InventoryPanel.Bounds(instance.m_staminaBar2Root);
			Rect val;
			Rect eitr;
			if (!flag)
			{
				val = default(Rect);
				eitr = val;
			}
			else
			{
				eitr = InventoryPanel.Bounds(instance.m_eitrBarRoot);
			}
			Rect screen = Layout(stamina, eitr, flag, scale, Screen.width, Screen.height);
			RectTransform val2 = (RectTransform)bar.transform;
			InventoryPanel.Place(val2, canvas, screen);
			float value = ((maximum > 0f) ? (oxygen / maximum) : 0f);
			val = val2.rect;
			float width = Math.Max(1f, ((Rect)(ref val)).width - instance.m_staminaBarBorderBuffer);
			GuiBar[] array = bars;
			foreach (GuiBar obj in array)
			{
				obj.SetWidth(width);
				obj.SetValue(value);
			}
			int num = Mathf.CeilToInt(oxygen);
			int num2 = Mathf.CeilToInt(maximum);
			if (num != shownSeconds || num2 != shownMaximum)
			{
				shownSeconds = num;
				shownMaximum = num2;
				string text = Lang.L("Дыхание ") + num + " / " + num2;
				TMP_Text[] array2 = labels;
				for (int i = 0; i < array2.Length; i++)
				{
					array2[i].text = text;
				}
			}
		}

		internal static void Draw()
		{
		}
	}
	internal static class Building
	{
		internal static bool NoRain;

		internal static bool Vehicles;

		private static PieceTable hammer;

		private static GameObject listed;

		private static float next;

		internal static void Tick()
		{
			NoRain = Settings.Get<bool>("Building", "NoRainDamage");
			Vehicles = Settings.Get<bool>("Building", "InstantRemoveVehicles");
			if (!(Time.unscaledTime < next))
			{
				next = Time.unscaledTime + 1f;
				List(Settings.Get<bool>("Building", "TrashCan"));
			}
		}

		internal static void Reset()
		{
			NoRain = (Vehicles = false);
			List(show: false);
			hammer = null;
			next = 0f;
		}

		private static void List(bool show)
		{
			if (!Object.op_Implicit((Object)(object)ObjectDB.instance) || !Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				hammer = null;
				listed = null;
				return;
			}
			PieceTable val = Table();
			if (!Object.op_Implicit((Object)(object)val))
			{
				return;
			}
			if (show)
			{
				GameObject val2 = CustomPrefabs.Get("VU_TrashCan");
				if (Object.op_Implicit((Object)(object)val2) && !val.m_pieces.Contains(val2))
				{
					int num = val.m_pieces.FindIndex((GameObject p) => Object.op_Implicit((Object)(object)p) && ((Object)p).name == "piece_chest_wood");
					val.m_pieces.Insert((num < 0) ? val.m_pieces.Count : (num + 1), val2);
					listed = val2;
				}
			}
			else if (Object.op_Implicit((Object)(object)listed))
			{
				val.m_pieces.Remove(listed);
				listed = null;
			}
		}

		private static PieceTable Table()
		{
			if (Object.op_Implicit((Object)(object)hammer))
			{
				return hammer;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Hammer");
			ItemDrop val = (Object.op_Implicit((Object)(object)itemPrefab) ? itemPrefab.GetComponent<ItemDrop>() : null);
			hammer = (Object.op_Implicit((Object)(object)val) ? val.m_itemData.m_shared.m_buildPieces : null);
			return hammer;
		}

		internal static Piece Target(Player p)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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)
			if (!Object.op_Implicit((Object)(object)GameCamera.instance) || !Object.op_Implicit((Object)(object)((Character)p).m_eye))
			{
				return null;
			}
			Transform transform = ((Component)GameCamera.instance).transform;
			RaycastHit val = default(RaycastHit);
			if (!Physics.Raycast(transform.position, transform.forward, ref val, 50f, p.m_removeRayMask) || Vector3.Distance(((RaycastHit)(ref val)).point, ((Character)p).m_eye.position) >= p.m_maxPlaceDistance)
			{
				return null;
			}
			return ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Piece>();
		}

		internal static bool Vehicle(Piece piece)
		{
			if (Object.op_Implicit((Object)(object)piece))
			{
				if (!Object.op_Implicit((Object)(object)((Component)piece).GetComponent<Ship>()))
				{
					return Object.op_Implicit((Object)(object)((Component)piece).GetComponent<Vagon>());
				}
				return true;
			}
			return false;
		}
	}
	internal static class TrashCan
	{
		internal const string Name = "VU_TrashCan";

		internal static bool Is(Container c)
		{
			if (Object.op_Implicit((Object)(object)c))
			{
				return Utils.GetPrefabName(((Component)c).gameObject) == "VU_TrashCan";
			}
			return false;
		}

		internal static void Define()
		{
			CustomPrefabs.Define("VU_TrashCan", Make);
		}

		private static GameObject Make()
		{
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Expected O, but got Unknown
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.GetPrefab("piece_chest_wood") : null);
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.GetComponent<Container>()))
			{
				return null;
			}
			GameObject val2 = CustomPrefabs.Clone(val, "VU_TrashCan");
			Piece component = val2.GetComponent<Piece>();
			if (Object.op_Implicit((Object)(object)component))
			{
				component.m_name = Lang.Token("vu_trashcan", () => Lang.L("Урна"));
				component.m_description = Lang.Token("vu_trashcan_desc", () => Lang.L("Всё, что осталось в урне, удаляется, когда её закрывают."));
			}
			Container component2 = val2.GetComponent<Container>();
			component2.m_name = Lang.Token("vu_trashcan", () => Lang.L("Урна"));
			component2.m_privacy = (PrivacySetting)2;
			Renderer[] componentsInChildren = val2.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val3 in componentsInChildren)
			{
				Material[] sharedMaterials = val3.sharedMaterials;
				for (int num2 = 0; num2 < sharedMaterials.Length; num2++)
				{
					if (Object.op_Implicit((Object)(object)sharedMaterials[num2]) && sharedMaterials[num2].HasProperty("_Color"))
					{
						Material val4 = new Material(sharedMaterials[num2]);
						val4.color *= new Color(0.42f, 0.42f, 0.48f, 1f);
						sharedMaterials[num2] = val4;
					}
				}
				val3.sharedMaterials = sharedMaterials;
			}
			return val2;
		}

		internal static void Empty(Container chest)
		{
			Inventory inventory = chest.GetInventory();
			int num = inventory.NrOfItems();
			if (num > 0)
			{
				inventory.RemoveAll();
				if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
				{
					((Character)Player.m_localPlayer).Message((MessageType)1, Lang.L("Урна: удалено предметов — ") + num, 0, (Sprite)null, false);
				}
			}
		}
	}
	internal static class TrashSlot
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static Func<Image, bool> <>9__10_0;

			public static UnityAction <>9__10_1;

			internal bool <Build>b__10_0(Image i)
			{
				if ((Object)(object)((Component)i).gameObject != (Object)(object)plaque)
				{
					return Object.op_Implicit((Object)(object)i.sprite);
				}
				return false;
			}

			internal void <Build>b__10_1()
			{
				Modules.Run("Building", Click);
			}
		}

		private static GameObject plaque;

		private static InventoryGui owner;

		private static TMP_Text label;

		private static Button button;

		private static UITooltip tip;

		private static Sprite bin;

		private static float armed;

		private static string shown;

		internal static void Reset()
		{
			if (Object.op_Implicit((Object)(object)plaque))
			{
				Object.Destroy((Object)(object)plaque);
			}
			plaque = null;
			owner = null;
			label = null;
			button = null;
			tip = null;
			armed = 0f;
			shown = null;
		}

		private static RectTransform Source(InventoryGui gui)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			TMP_Text weight = gui.m_weight;
			RectTransform val = (RectTransform)(Object.op_Implicit((Object)(object)weight) ? /*isinst with value type is only supported in some contexts*/: null);
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)((Component)val).GetComponent<Image>()))
			{
				return null;
			}
			Rect rect = val.rect;
			Vector2 size = ((Rect)(ref rect)).size;
			if (!(size.x > 0f) || !(size.x < 260f) || !(size.y > 0f) || !(size.y < 260f))
			{
				return null;
			}
			return val;
		}

		private static void Build(InventoryGui gui)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Expected O, but got Unknown
			Reset();
			owner = gui;
			RectTransform val = Source(gui);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return;
			}
			plaque = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Transform)val).parent, false);
			((Object)plaque).name = "VU trash plaque";
			RectTransform val2 = (RectTransform)plaque.transform;
			Vector2 anchoredPosition = val.anchoredPosition;
			Rect rect = val.rect;
			val2.anchoredPosition = anchoredPosition + new Vector2(0f, ((Rect)(ref rect)).height + 10f);
			label = plaque.GetComponentsInChildren<TMP_Text>(true).FirstOrDefault();
			Localize[] componentsInChildren = plaque.GetComponentsInChildren<Localize>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
			Image val3 = ((IEnumerable<Image>)plaque.GetComponentsInChildren<Image>(true)).FirstOrDefault((Func<Image, bool>)((Image val5) => (Object)(object)((Component)val5).gameObject != (Object)(object)plaque && Object.op_Implicit((Object)(object)val5.sprite)));
			if (Object.op_Implicit((Object)(object)val3))
			{
				val3.sprite = Bin();
				val3.preserveAspect = true;
			}
			Image component = plaque.GetComponent<Image>();
			((Graphic)component).raycastTarget = true;
			button = plaque.GetComponent<Button>() ?? plaque.AddComponent<Button>();
			((Selectable)button).targetGraphic = (Graphic)(object)component;
			((Selectable)button).transition = (Transition)1;
			ColorBlock defaultColorBlock = ColorBlock.defaultColorBlock;
			((ColorBlock)(ref defaultColorBlock)).highlightedColor = new Color(1f, 0.86f, 0.6f);
			((ColorBlock)(ref defaultColorBlock)).pressedColor = new Color(1f, 0.7f, 0.4f);
			((ColorBlock)(ref defaultColorBlock)).disabledColor = new Color(0.62f, 0.62f, 0.62f, 0.85f);
			((Selectable)button).colors = defaultColorBlock;
			Button obj = button;
			Navigation navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)0;
			((Selectable)obj).navigation = navigation;
			((UnityEventBase)button.onClick).RemoveAllListeners();
			ButtonClickedEvent onClick = button.onClick;
			object obj2 = <>c.<>9__10_1;
			if (obj2 == null)
			{
				UnityAction val4 = delegate
				{
					Modules.Run("Building", Click);
				};
				<>c.<>9__10_1 = val4;
				obj2 = (object)val4;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj2);
			tip = plaque.GetComponent<UITooltip>() ?? plaque.AddComponent<UITooltip>();
			if (!Object.op_Implicit((Object)(object)tip.m_tooltipPrefab))
			{
				tip.m_tooltipPrefab = InventoryTips.Template(gui, null);
			}
			shown = null;
		}

		private static Sprite Bin()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)bin))
			{
				return bin;
			}
			Texture2D val = new Texture2D(32, 32, (TextureFormat)4, false)
			{
				hideFlags = (HideFlags)61,
				filterMode = (FilterMode)1
			};
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(0f, 0f, 0f, 0f);
			Color ink = new Color(0.86f, 0.8f, 0.68f, 1f);
			Color[] px = (Color[])(object)new Color[1024];
			for (int i = 0; i < px.Length; i++)
			{
				px[i] = val2;
			}
			for (int j = 5; j <= 26; j++)
			{
				Dot(j, 24);
				Dot(j, 25);
			}
			for (int k = 12; k <= 19; k++)
			{
				Dot(k, 27);
				Dot(k, 28);
			}
			Dot(12, 26);
			Dot(19, 26);
			for (int l = 3; l <= 22; l++)
			{
				int num = (22 - l) / 7;
				for (int m = 0; m < 2; m++)
				{
					Dot(7 + num + m, l);
					Dot(24 - num - m, l);
				}
			}
			for (int n = 9; n <= 22; n++)
			{
				Dot(n, 3);
				Dot(n, 4);
			}
			for (int num2 = 6; num2 <= 20; num2++)
			{
				Dot(12, num2);
				Dot(15, num2);
				Dot(16, num2);
				Dot(19, num2);
			}
			val.SetPixels(px);
			val.Apply();
			bin = Sprite.Create(val, new Rect(0f, 0f, 32f, 32f), new Vector2(0.5f, 0.5f), 100f);
			return bin;
			void Dot(int x, int y)
			{
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				if (x >= 0 && y >= 0 && x < 32 && y < 32)
				{
					px[y * 32 + x] = ink;
				}
			}
		}

		internal static void Tick()
		{
			InventoryGui instance = InventoryGui.instance;
			if (!Settings.Get<bool>("Building", "TrashSlot") || !Object.op_Implicit((Object)(object)instance) || !InventoryGui.IsVisible() || ChestNames.Editing)
			{
				if (Object.op_Implicit((Object)(object)plaque) && plaque.activeSelf)
				{
					plaque.SetActive(false);
				}
				return;
			}
			if (!Object.op_Implicit((Object)(object)plaque) || (Object)(object)owner != (Object)(object)instance)
			{
				Build(instance);
			}
			if (Object.op_Implicit((Object)(object)plaque))
			{
				if (!plaque.activeSelf)
				{
					plaque.SetActive(true);
				}
				bool flag = instance.m_dragItem != null;
				bool flag2 = flag && Time.unscaledTime < armed;
				((Selectable)button).interactable = flag;
				string text = (flag2 ? Lang.L("<color=#ff6a5a>Точно?</color>") : Lang.L("Урна"));
				if (Object.op_Implicit((Object)(object)label) && text != shown)
				{
					shown = text;
					label.text = text;
				}
				if (Object.op_Implicit((Object)(object)tip))
				{
					tip.m_topic = Lang.L("Урна");
					tip.m_text = ((!flag) ? Lang.L("Возьмите предмет из ячейки и нажмите на урну, чтобы удалить его") : (flag2 ? Lang.L("Нажмите ещё раз — предмет удалится") : Lang.L("Нажмите, чтобы удалить взятый предмет. Shift — сразу")));
				}
			}
		}

		private static void Click()
		{
			InventoryGui instance = InventoryGui.instance;
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)localPlayer) || instance.m_dragItem == null || instance.m_dragInventory == null)
			{
				return;
			}
			bool flag = Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303);
			if (Settings.Get<bool>("Building", "TrashConfirm") && !flag && Time.unscaledTime >= armed)
			{
				armed = Time.unscaledTime + 3f;
				return;
			}
			armed = 0f;
			ItemData dragItem = instance.m_dragItem;
			Inventory dragInventory = instance.m_dragInventory;
			int num = Math.Max(1, Math.Min(instance.m_dragAmount, dragItem.m_stack));
			if (dragInventory == ((Humanoid)localPlayer).GetInventory() && ((Humanoid)localPlayer).IsItemEquiped(dragItem))
			{
				((Humanoid)localPlayer).UnequipItem(dragItem, true);
			}
			dragInventory.RemoveItem(dragItem, num);
			instance.SetupDragItem((ItemData)null, (Inventory)null, 1);
			((Character)localPlayer).Message((MessageType)1, Lang.L("Удалено: ") + Lang.Game(dragItem.m_shared.m_name) + ((num > 1) ? (" ×" + num) : ""), 0, (Sprite)null, false);
		}
	}
	[HarmonyPatch]
	internal static class BuildingHooks
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(WearNTear), "UpdateWear")]
		private static void Wear(WearNTear __instance, float time)
		{
			if (Building.NoRain)
			{
				__instance.m_rainTimer = time;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "RemovePiece")]
		private static void Remove(Player __instance, out Piece __state)
		{
			__state = null;
			if (!Building.Vehicles || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			try
			{
				Piece val = Building.Target(__instance);
				if (Object.op_Implicit((Object)(object)val) && !val.m_canBeRemoved && Building.Vehicle(val))
				{
					val.m_canBeRemoved = true;
					__state = val;
				}
			}
			catch (Exception ex)
			{
				Modules.Fault("Building", "Remove", ex);
			}
		}

		[HarmonyFinalizer]
		[HarmonyPatch(typeof(Player), "RemovePiece")]
		private static Exception Removed(Piece __state, Exception __exception)
		{
			if (Object.op_Implicit((Object)(object)__state))
			{
				__state.m_canBeRemoved = false;
			}
			return __exception;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Container), "SetInUse")]
		private static void Close(Container __instance, bool inUse)
		{
			if (inUse || !TrashCan.Is(__instance) || !Object.op_Implicit((Object)(object)__instance.m_nview) || !__instance.m_nview.IsValid() || !__instance.m_nview.IsOwner())
			{
				return;
			}
			Modules.Run("Building", delegate
			{
				if (Settings.Get<bool>("Building", "TrashCan"))
				{
					TrashCan.Empty(__instance);
				}
			});
		}
	}
	public static class BuildResources
	{
		public const int Version = 1;

		public static bool Reserve(Player player, Requirement[] requirements, int multiplier, Action onReady)
		{
			if (!Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer || requirements == null || requirements.Length == 0 || multiplier < 1)
			{
				return true;
			}
			if (!Modules.Active("NearbyResources") || !Settings.Get<bool>("NearbyResources", "Build") || player.NoCostCheat() || (Object.op_Implicit((Object)(object)ZoneSystem.instance) && ZoneSystem.instance.GetGlobalKey((GlobalKeys)24)))
			{
				return true;
			}
			try
			{
				List<Need> list = Resources.Requirements(player, requirements, 1, multiplier, one: false);
				return list == null || list.Count == 0 || Resources.Gate(player, list, onReady);
			}
			catch (Exception ex)
			{
				Containers.Warn("Build reserve", ex);
				Util.Message(Lang.L("Сундуки сейчас недоступны."));
				return false;
			}
		}
	}
	internal static class Cartography
	{
		private static Minimap map;

		private static float native = -1f;

		private static uint fogCount;

		private static bool tracking;

		internal static float Factor(float common, float skill, float skillBonus)
		{
			return Math.Max(0.1f, common / 100f * (1f + skill * skillBonus / 100f));
		}

		internal static float Radius(Player p)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			float num = 1f;
			if (Modules.Active("Cartography"))
			{
				num *= Factor(Settings.Get<int>("Map", "RadiusPercent"), Settings.Get<bool>("Map", "Skill") ? ExtraSkills.Factor(p, ExtraSkills.Cartography) : 0f, Settings.Get<int>("Map", "SkillRadius"));
			}
			if (Modules.Active("Sailing"))
			{
				num *= Sailing.ExploreFactor(p);
			}
			return native * num;
		}

		internal static void Before(Minimap m, Player p)
		{
			if ((Object)(object)map != (Object)(object)m)
			{
				map = m;
				native = m.m_exploreRadius;
			}
			float num = Radius(p);
			if (m.m_exploreRadius != num)
			{
				m.m_exploreRadius = num;
			}
			tracking = Object.op_Implicit((Object)(object)m.m_fogTexture);
			if (tracking)
			{
				fogCount = ((Texture)m.m_fogTexture).updateCount;
			}
		}

		internal static void After(Minimap m, Player p)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			if (tracking && Object.op_Implicit((Object)(object)m.m_fogTexture) && ((Texture)m.m_fogTexture).updateCount != fogCount && Modules.Active("Cartography") && Settings.Get<bool>("Map", "Skill"))
			{
				((Character)p).RaiseSkill(ExtraSkills.Cartography, Settings.Get<float>("Map", "SkillXp"));
			}
		}

		internal static void Reset()
		{
			if (Object.op_Implicit((Object)(object)map) && native > 0f)
			{
				map.m_exploreRadius = native;
			}
		}
	}
	[HarmonyPatch]
	internal static class CartographyHooks
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(Minimap), "UpdateExplore")]
		private static void Before(Minimap __instance, Player player)
		{
			if (!Object.op_Implicit((Object)(object)player))
			{
				return;
			}
			try
			{
				Cartography.Before(__instance, player);
			}
			catch (Exception ex)
			{
				Modules.Fault("MapRadius", "Explore", ex);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Minimap), "UpdateExplore")]
		private static void After(Minimap __instance, Player player)
		{
			if (!Object.op_Implicit((Object)(object)player))
			{
				return;
			}
			try
			{
				Cartography.After(__instance, player);
			}
			catch (Exception ex)
			{
				Modules.Fault("MapRadius", "Explore", ex);
			}
		}
	}
	internal static class CatalogBridge
	{
		private static Assembly assembly;

		private static MethodInfo items;

		private static MethodInfo creatures;

		private static MethodInfo icon;

		private static MethodInfo categoryMap;

		private static bool failed;

		private static bool Bind()
		{
			PluginInfo val = AdminMenuPlugin.Find();
			if (val == null || !Object.op_Implicit((Object)(object)val.Instance))
			{
				return false;
			}
			Assembly assembly = ((object)val.Instance).GetType().Assembly;
			if (assembly == CatalogBridge.assembly)
			{
				return !failed;
			}
			CatalogBridge.assembly = assembly;
			failed = false;
			try
			{
				Type type = assembly.GetType("AdminMenu.ModCatalogApi", throwOnError: true);
				if ((int)type.GetField("ApiVersion", BindingFlags.Static | BindingFlags.Public).GetRawConstantValue() != 1)
				{
					throw new InvalidOperationException("Unsupported catalog API");
				}
				items = type.GetMethod("GetItemPrefabs", Type.EmptyTypes);
				creatures = type.GetMethod("GetCreaturePrefabs", Type.EmptyTypes);
				icon = type.GetMethod("GetCreatureIcon", new Type[1] { typeof(string) });
				categoryMap = type.GetMethod("GetItemCategoryMap", Type.EmptyTypes);
				if (categoryMap != null && (!categoryMap.IsStatic || categoryMap.ReturnType != typeof(string)))
				{
					categoryMap = null;
				}
				if (items == null || creatures == null || icon == null || items.ReturnType != typeof(GameObject[]) || creatures.ReturnType != typeof(GameObject[]) || icon.ReturnType != typeof(Sprite) || !items.IsStatic || !creatures.IsStatic || !icon.IsStatic)
				{
					throw new MissingMethodException("Catalog contract incomplete");
				}
				return true;
			}
			catch (Exception ex)
			{
				Fail(ex);
				return false;
			}
		}

		private static void Fail(Exception ex)
		{
			failed = true;
			Plugin.Log.LogWarning((object)("AdminMenu catalog unavailable; using game registries: " + (ex.InnerException ?? ex).Message));
		}

		internal static GameObject[] Items()
		{
			if (Bind())
			{
				try
				{
					return (GameObject[])(((object)(GameObject[])items.Invoke(null, null)) ?? ((object)new GameObject[0]));
				}
				catch (Exception ex)
				{
					Fail(ex);
				}
			}
			if (!Object.op_Implicit((Object)(object)ObjectDB.instance))
			{
				return (GameObject[])(object)new GameObject[0];
			}
			return ObjectDB.instance.m_items.ToArray();
		}

		internal static string CategoryMap()
		{
			if (Bind() && categoryMap != null)
			{
				try
				{
					return (string)categoryMap.Invoke(null, null);
				}
				catch (Exception ex)
				{
					Fail(ex);
				}
			}
			return null;
		}

		internal static GameObject[] Creatures()
		{
			if (Bind())
			{
				try
				{
					return (GameObject[])(((object)(GameObject[])creatures.Invoke(null, null)) ?? ((object)new GameObject[0]));
				}
				catch (Exception ex)
				{
					Fail(ex);
				}
			}
			if (!Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				return (GameObject[])(object)new GameObject[0];
			}
			return ZNetScene.instance.m_prefabs.ToAr