Decompiled source of ModerWarehouse v1.2.1

BepInEx/plugins/ModerWarehouse/ModerWarehouse.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using Microsoft.CodeAnalysis;
using ServersideQoL;
using ServersideQoL.Processors;
using ServersideQoL.Utilities;
using UnityEngine;
using YamlDotNet.Serialization;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("Cris Haani")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © 2026 Cris Haani")]
[assembly: AssemblyDescription("Server-only automatic warehouse for Valheim.")]
[assembly: AssemblyFileVersion("1.2.1.0")]
[assembly: AssemblyInformationalVersion("1.2.1+337a457de3bab7a934ff953ee6a1ef5071cc4acc")]
[assembly: AssemblyProduct("Moder Warehouse")]
[assembly: AssemblyTitle("ModerWarehouse")]
[assembly: AssemblyVersion("1.2.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ModerWarehouse
{
	internal static class WarehouseLocalization
	{
		public sealed class TranslationFile
		{
			public string language { get; set; }

			public string language_name { get; set; }

			public string translator { get; set; }

			public Dictionary<string, string> strings { get; set; }
		}

		private static readonly Dictionary<string, Dictionary<string, string>> Languages = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, string> Aliases = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

		private static Action<string> _log;

		public static void Initialize(Action<string> log)
		{
			_log = log;
			Languages.Clear();
			Aliases.Clear();
			AddBuiltIn("en", English());
			AddBuiltIn("de", German());
			Aliases["english"] = "en";
			Aliases["eng"] = "en";
			Aliases["german"] = "de";
			Aliases["deutsch"] = "de";
			Aliases["ger"] = "de";
			string text = Path.Combine(Paths.ConfigPath, "ModerWarehouse", "localization");
			Directory.CreateDirectory(text);
			WriteTemplate(Path.Combine(text, "TranslationTemplate.json"));
			string[] files = Directory.GetFiles(text, "*.json");
			foreach (string path in files)
			{
				if (!Path.GetFileName(path).Equals("TranslationTemplate.json", StringComparison.OrdinalIgnoreCase))
				{
					LoadFile(path);
				}
			}
			_log?.Invoke($"Moder Warehouse localization: {Languages.Count} language(s) available: " + string.Join(", ", Languages.Keys.OrderBy((string x) => x)) + ".");
		}

		public static string Resolve(string requested)
		{
			string text = (requested ?? string.Empty).Trim();
			if (Aliases.TryGetValue(text, out var value))
			{
				text = value;
			}
			text = text.Replace('_', '-').ToLowerInvariant();
			if (Languages.ContainsKey(text))
			{
				return text;
			}
			string text2 = text.Split(new char[1] { '-' })[0];
			if (Languages.ContainsKey(text2))
			{
				return text2;
			}
			return "en";
		}

		public static string Text(string language, string key)
		{
			language = Resolve(language);
			if (Languages.TryGetValue(language, out var value) && value.TryGetValue(key, out var value2) && !string.IsNullOrWhiteSpace(value2))
			{
				return value2;
			}
			if (Languages["en"].TryGetValue(key, out value2))
			{
				return value2;
			}
			return "[" + key + "]";
		}

		public static string Format(string language, string key, params object[] args)
		{
			try
			{
				return string.Format(CultureInfo.InvariantCulture, Text(language, key), args);
			}
			catch (FormatException)
			{
				string value;
				return Languages["en"].TryGetValue(key, out value) ? string.Format(CultureInfo.InvariantCulture, value, args) : ("[" + key + "]");
			}
		}

		private static void AddBuiltIn(string code, Dictionary<string, string> strings)
		{
			Languages[code] = strings;
		}

		private static void LoadFile(string path)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				TranslationFile translationFile = new DeserializerBuilder().IgnoreUnmatchedProperties().Build().Deserialize<TranslationFile>(File.ReadAllText(path));
				string text = (translationFile?.language ?? string.Empty).Trim().Replace('_', '-').ToLowerInvariant();
				if (string.IsNullOrWhiteSpace(text) || translationFile.strings == null || translationFile.strings.Count == 0)
				{
					throw new InvalidDataException("language and strings are required");
				}
				Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
				foreach (KeyValuePair<string, string> @string in translationFile.strings)
				{
					if (!string.IsNullOrWhiteSpace(@string.Key) && @string.Value != null)
					{
						dictionary[@string.Key] = @string.Value;
					}
				}
				Languages[text] = dictionary;
				Aliases[text] = text;
				if (!string.IsNullOrWhiteSpace(translationFile.language_name))
				{
					Aliases[translationFile.language_name.Trim()] = text;
				}
				_log?.Invoke($"Loaded warehouse translation '{text}' ({dictionary.Count} strings) from {Path.GetFileName(path)}." + MissingSummary(dictionary));
			}
			catch (Exception ex)
			{
				_log?.Invoke("Ignored invalid warehouse translation '" + Path.GetFileName(path) + "': " + ex.Message);
			}
		}

		private static string MissingSummary(Dictionary<string, string> strings)
		{
			List<string> list = Languages["en"].Keys.Where((string key) => !strings.ContainsKey(key)).Take(6).ToList();
			int num = Languages["en"].Keys.Count((string key) => !strings.ContainsKey(key));
			if (num != 0)
			{
				return $" Missing {num} key(s); English fallback will be used" + ((list.Count > 0) ? (": " + string.Join(", ", list)) : string.Empty) + ".";
			}
			return string.Empty;
		}

		private static void WriteTemplate(string path)
		{
			if (File.Exists(path))
			{
				return;
			}
			StringBuilder stringBuilder = new StringBuilder("{\n  \"language\": \"xx\",\n  \"language_name\": \"Your language\",\n").Append("  \"translator\": \"Your name\",\n  \"strings\": {\n");
			List<KeyValuePair<string, string>> list = (from x in English()
				orderby x.Key
				select x).ToList();
			for (int num = 0; num < list.Count; num++)
			{
				KeyValuePair<string, string> keyValuePair = list[num];
				stringBuilder.Append("    \"").Append(JsonEscape(keyValuePair.Key)).Append("\": \"")
					.Append(JsonEscape(keyValuePair.Value))
					.Append('"');
				if (num + 1 < list.Count)
				{
					stringBuilder.Append(',');
				}
				stringBuilder.AppendLine();
			}
			stringBuilder.Append("  }\n}\n");
			File.WriteAllText(path, stringBuilder.ToString(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
		}

		private static string JsonEscape(string value)
		{
			return (value ?? string.Empty).Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\r", "\\r")
				.Replace("\n", "\\n");
		}

		private static Dictionary<string, string> English()
		{
			return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
			{
				["help.title"] = "WAREHOUSE HELP",
				["help.in"] = "IN: DEPOSIT ALL",
				["help.req"] = "REQ: WOOD 100",
				["help.out"] = "OUT: COLLECT",
				["help.board"] = "BOARD: E = FILTER",
				["request.title"] = "REQUEST",
				["request.example_item"] = "Wood",
				["request.updating"] = "UPDATING",
				["request.target"] = "TARGET",
				["request.error_example"] = "ERROR: e.g. Tin 20",
				["request.done"] = "DONE {0} x{1}",
				["request.partial"] = "PARTIAL {0} x{1}/{2}",
				["request.output_full"] = "OUTPUT FULL {0}",
				["request.not_found"] = "NOT FOUND {0}",
				["request.error"] = "ERROR: {0}",
				["shopping.title"] = "NEEDED",
				["board.warehouse"] = "WAREHOUSE",
				["board.stock"] = "STOCK",
				["board.page"] = "PAGE",
				["board.chests"] = "CHESTS",
				["board.display_sleeping"] = "DISPLAY\nSLEEPING",
				["board.wake"] = "{0} METRES\nWAKE UP",
				["board.sleep_word"] = "SLEEPMODEZZZ",
				["board.expand"] = "EXPAND!",
				["board.deposited"] = "DEPOSITED",
				["board.since_visit"] = "SINCE VISIT",
				["board.rejected"] = "REJECTED AT IN",
				["board.internal_item"] = "INTERNAL / CHEAT ITEM",
				["board.positions"] = "ITEMS",
				["board.no_matches"] = "NO MATCHES",
				["info.free"] = "FREE",
				["info.empty_reserved"] = "EMPTY RESERVED",
				["info.occupied"] = "OCCUPIED",
				["stats.title"] = "STATISTICS",
				["stats.period"] = "PERIOD",
				["stats.today"] = "TODAY",
				["stats.days"] = "{0} DAYS",
				["stats.sleep_word"] = "STATSZ",
				["stats.input"] = "INPUT",
				["stats.output"] = "OUTPUT",
				["stats.balance"] = "BALANCE",
				["stats.per_day"] = "MOVES / DAY",
				["stats.top_input"] = "TOP INPUT",
				["stats.top_output"] = "TOP OUTPUT",
				["stats.current"] = "CURRENT TOTAL",
				["stats.item_types"] = "ITEM TYPES",
				["stats.chests_now"] = "CHESTS NOW",
				["stats.avg_use"] = "AVG USE",
				["stats.peak"] = "PEAK",
				["stats.low"] = "LOW",
				["stats.rising"] = "RISING",
				["stats.falling"] = "FALLING",
				["stats.empty_first"] = "EMPTY FIRST",
				["stats.ratio"] = "IN / OUT",
				["stats.busy_in"] = "BUSIEST INPUT",
				["stats.busy_out"] = "BUSIEST OUTPUT",
				["stats.tracked_since"] = "TRACKED SINCE",
				["stats.days_tracked"] = "DAYS TRACKED",
				["stats.days_short"] = "DAYS",
				["stats.eta"] = "DAYS LEFT",
				["stats.input_change"] = "INPUT VS 7D",
				["stats.output_change"] = "OUTPUT VS 7D",
				["stats.confidence"] = "DATA BASIS",
				["stats.not_enough"] = "TOO LITTLE DATA",
				["stats.net_day"] = "NET / DAY",
				["stats.date"] = "DATE",
				["stats.amount"] = "AMOUNT",
				["stats.previous"] = "PREVIOUS",
				["stats.control"] = "STAT CONTROL",
				["stats.manual"] = "MANUAL",
				["stats.auto_in"] = "AUTO IN {0}s",
				["stats.page_1"] = "OVERVIEW",
				["stats.page_2"] = "COMPARE",
				["stats.page_3"] = "TREND",
				["stats.page_4"] = "RECORDS"
			};
		}

		private static Dictionary<string, string> German()
		{
			return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
			{
				["help.title"] = "LAGERHILFE",
				["help.in"] = "IN: ALLES REIN",
				["help.req"] = "REQ: HOLZ 100",
				["help.out"] = "OUT: ABHOLEN",
				["help.board"] = "TAFEL: E = FILTER",
				["request.title"] = "BESTELLUNG",
				["request.example_item"] = "Holz",
				["request.updating"] = "WIRD AKTUALISIERT",
				["request.target"] = "SOLL",
				["request.error_example"] = "FEHLER: z.B. Zinn 20",
				["request.done"] = "FERTIG {0} x{1}",
				["request.partial"] = "TEILWEISE {0} x{1}/{2}",
				["request.output_full"] = "AUSGABE VOLL {0}",
				["request.not_found"] = "NICHT GEFUNDEN {0}",
				["request.error"] = "FEHLER: {0}",
				["shopping.title"] = "BEDARF",
				["board.warehouse"] = "LAGER",
				["board.stock"] = "BESTAND",
				["board.page"] = "SEITE",
				["board.chests"] = "KISTEN",
				["board.display_sleeping"] = "ANZEIGE\nSCHLÄFT",
				["board.wake"] = "{0} METER\nAUFWECKEN",
				["board.sleep_word"] = "RUHEMODUSZZZ",
				["board.expand"] = "AUSBAUEN!",
				["board.deposited"] = "EINGELAGERT",
				["board.since_visit"] = "SEIT BESUCH",
				["board.rejected"] = "BEI IN ABGEWIESEN",
				["board.internal_item"] = "INTERNES / CHEAT-OBJEKT",
				["board.positions"] = "POSITIONEN",
				["board.no_matches"] = "KEINE TREFFER",
				["info.free"] = "FREI",
				["info.empty_reserved"] = "LEER RESERVIERT",
				["info.occupied"] = "BELEGT",
				["stats.title"] = "STATISTIK",
				["stats.period"] = "ZEITRAUM",
				["stats.today"] = "HEUTE",
				["stats.days"] = "{0} TAGE",
				["stats.sleep_word"] = "STATSZ",
				["stats.input"] = "EINGANG",
				["stats.output"] = "AUSGANG",
				["stats.balance"] = "SALDO",
				["stats.per_day"] = "BEWEGT / TAG",
				["stats.top_input"] = "TOP EINGANG",
				["stats.top_output"] = "TOP AUSGANG",
				["stats.current"] = "BESTAND TOTAL",
				["stats.item_types"] = "ARTIKELARTEN",
				["stats.chests_now"] = "KISTEN JETZT",
				["stats.avg_use"] = "Ø AUSLASTUNG",
				["stats.peak"] = "HÖCHSTSTAND",
				["stats.low"] = "TIEFSTSTAND",
				["stats.rising"] = "STEIGEND",
				["stats.falling"] = "FALLEND",
				["stats.empty_first"] = "ZUERST LEER",
				["stats.ratio"] = "EIN / AUS",
				["stats.busy_in"] = "MAX EINGANG",
				["stats.busy_out"] = "MAX AUSGANG",
				["stats.tracked_since"] = "ERFASST SEIT",
				["stats.days_tracked"] = "TAGE ERFASST",
				["stats.days_short"] = "TAGE",
				["stats.eta"] = "NOCH TAGE",
				["stats.input_change"] = "EIN VS 7T",
				["stats.output_change"] = "AUS VS 7T",
				["stats.confidence"] = "DATENBASIS",
				["stats.not_enough"] = "ZU WENIG DATEN",
				["stats.net_day"] = "NETTO / TAG",
				["stats.date"] = "DATUM",
				["stats.amount"] = "MENGE",
				["stats.previous"] = "VORPERIODE",
				["stats.control"] = "STAT-STEUERUNG",
				["stats.manual"] = "MANUELL",
				["stats.auto_in"] = "AUTO IN {0}s",
				["stats.page_1"] = "ÜBERSICHT",
				["stats.page_2"] = "VERGLEICH",
				["stats.page_3"] = "TREND",
				["stats.page_4"] = "REKORDE"
			};
		}
	}
	[BepInPlugin("ch.cris.valheim.moderwarehouse", "Moder Warehouse", "1.2.1")]
	public sealed class WarehousePlugin : ServersideQoLPluginBase<WarehousePlugin, WarehouseConfig>
	{
		public const string Guid = "ch.cris.valheim.moderwarehouse";

		public const string Name = "Moder Warehouse";

		public const string Version = "1.2.1";

		protected override WarehouseConfig CreateConfigSingleton(ConfigFile file, Logger logger)
		{
			return new WarehouseConfig(file, logger);
		}

		protected override void RegisterProcessors(IProcessorCollection processors)
		{
			processors.Add<WarehouseProcessor>();
		}
	}
	public sealed class WarehouseConfig : ConfigBase<WarehouseConfig>
	{
		public override ConfigEntry<bool> Enabled { get; }

		public ConfigEntry<string> Language { get; }

		public ConfigEntry<float> Radius { get; }

		public ConfigEntry<float> MarkerDistance { get; }

		public ConfigEntry<float> ScanInterval { get; }

		public ConfigEntry<int> MaxMoves { get; }

		public ConfigEntry<bool> AutoCreateLabels { get; }

		public ConfigEntry<float> LabelDistance { get; }

		public ConfigEntry<float> AutoLabelDelay { get; }

		public ConfigEntry<float> RequestResultSeconds { get; }

		public ConfigEntry<float> BoardPageSeconds { get; }

		public ConfigEntry<float> BoardWakeDistance { get; }

		public ConfigEntry<float> DeliveryNoticeSeconds { get; }

		public ConfigEntry<float> VisitSummarySeconds { get; }

		public ConfigEntry<int> CapacityWarningPercent { get; }

		public ConfigEntry<int> CapacityCriticalPercent { get; }

		public WarehouseConfig(ConfigFile file, Logger logger)
			: base(file, logger)
		{
			Enabled = ConfigBase<WarehouseConfig>.BindEx<bool>(file, "Warehouse", true, "Enable the warehouse.", (AcceptableValueBase)null, (Deprecated<WarehouseConfig>)null, "Enabled");
			Language = ConfigBase<WarehouseConfig>.BindEx<string>(file, "Localization", "English", "Default display language. Built in: English, German. External JSON translations may add more.", (AcceptableValueBase)null, (Deprecated<WarehouseConfig>)null, "Language");
			Radius = ConfigBase<WarehouseConfig>.BindEx<float>(file, "Warehouse", 100f, "Storage radius around the input chest.", (AcceptableValueBase)null, (Deprecated<WarehouseConfig>)null, "Radius");
			MarkerDistance = ConfigBase<WarehouseConfig>.BindEx<float>(file, "Warehouse", 3f, "Maximum sign-to-chest distance.", (AcceptableValueBase)null, (Deprecated<WarehouseConfig>)null, "MarkerDistance");
			ScanInterval = ConfigBase<WarehouseConfig>.BindEx<float>(file, "Warehouse", 3f, "Seconds between scans.", (AcceptableValueBase)null, (Deprecated<WarehouseConfig>)null, "ScanInterval");
			MaxMoves = ConfigBase<WarehouseConfig>.BindEx<int>(file, "Safety", 250, "Maximum stack moves per scan.", (AcceptableValueBase)null, (Deprecated<WarehouseConfig>)null, "MaxMovesPerCycle");
			AutoCreateLabels = ConfigBase<WarehouseConfig>.BindEx<bool>(file, "Labels", true, "Create persistent localized white labels for homogeneous storage chests.", (AcceptableValueBase)null, (Deprecated<WarehouseConfig>)null, "AutoCreateLabels");
			LabelDistance = ConfigBase<WarehouseConfig>.BindEx<float>(file, "Labels", 1f, "Maximum distance for ordinary storage labels and blank adoption signs.", (AcceptableValueBase)null, (Deprecated<WarehouseConfig>)null, "LabelDistance");
			AutoLabelDelay = ConfigBase<WarehouseConfig>.BindEx<float>(file, "Labels", 90f, "Seconds an unlabeled homogeneous chest must remain unchanged before a sign is created.", (AcceptableValueBase)null, (Deprecated<WarehouseConfig>)null, "AutoLabelDelay");
			RequestResultSeconds = ConfigBase<WarehouseConfig>.BindEx<float>(file, "Requests", 30f, "Seconds withdrawal results remain visible before the request sign is cleared.", (AcceptableValueBase)null, (Deprecated<WarehouseConfig>)null, "ResultDisplaySeconds");
			BoardPageSeconds = ConfigBase<WarehouseConfig>.BindEx<float>(file, "Display", 7f, "Seconds each warehouse board page remains visible.", (AcceptableValueBase)null, (Deprecated<WarehouseConfig>)null, "BoardPageSeconds");
			BoardWakeDistance = ConfigBase<WarehouseConfig>.BindEx<float>(file, "Display", 5f, "Player distance in metres at which the stock board wakes up.", (AcceptableValueBase)null, (Deprecated<WarehouseConfig>)null, "BoardWakeDistance");
			DeliveryNoticeSeconds = ConfigBase<WarehouseConfig>.BindEx<float>(file, "Display", 6f, "Seconds a completed delivery remains visible on the stock board.", (AcceptableValueBase)null, (Deprecated<WarehouseConfig>)null, "DeliveryNoticeSeconds");
			VisitSummarySeconds = ConfigBase<WarehouseConfig>.BindEx<float>(file, "Display", 12f, "Seconds stock changes since the last visit remain visible after waking the board.", (AcceptableValueBase)null, (Deprecated<WarehouseConfig>)null, "VisitSummarySeconds");
			CapacityWarningPercent = ConfigBase<WarehouseConfig>.BindEx<int>(file, "Display", 80, "Occupied chest percentage at which the capacity display becomes orange.", (AcceptableValueBase)null, (Deprecated<WarehouseConfig>)null, "CapacityWarningPercent");
			CapacityCriticalPercent = ConfigBase<WarehouseConfig>.BindEx<int>(file, "Display", 95, "Occupied chest percentage at which the capacity display becomes red and requests expansion.", (AcceptableValueBase)null, (Deprecated<WarehouseConfig>)null, "CapacityCriticalPercent");
		}
	}
	[Processor("1f3823e7-1db0-4857-b8b8-e377bd8cd191")]
	[RunAfter<ContainerRegistryProcessor>]
	public sealed class WarehouseProcessor : Processor<ProcessorPrefabInfo<Sign>>
	{
		private sealed class Request
		{
			public ServersideQoLZDO Sign { get; }

			public string Payload { get; }

			public Request(ServersideQoLZDO sign, string payload)
			{
				Sign = sign;
				Payload = payload;
			}
		}

		private sealed class PendingLabel
		{
			public string ItemType { get; }

			public DateTime Since { get; }

			public PendingLabel(string itemType, DateTime since)
			{
				ItemType = itemType;
				Since = since;
			}
		}

		private sealed class StockEntry
		{
			public string Token { get; }

			public string Name { get; }

			public int Amount { get; }

			public StockEntry(string token, string name, int amount)
			{
				Token = token;
				Name = name;
				Amount = amount;
			}
		}

		private sealed class BoardControl
		{
			public string Prefix { get; set; }

			public int? Page { get; set; }

			public DateTime ChangedAt { get; set; }
		}

		private sealed class StatsControl
		{
			public int? Days { get; set; }

			public int? Page { get; set; }

			public DateTime ChangedAt { get; set; }
		}

		private sealed class TargetStatus
		{
			public string Name { get; }

			public int Current { get; }

			public int Target { get; }

			public TargetStatus(string name, int current, int target)
			{
				Name = name;
				Current = current;
				Target = target;
			}
		}

		private sealed class DeliveryNotice
		{
			public Dictionary<string, int> Items { get; }

			public DateTime Until { get; }

			public DeliveryNotice(Dictionary<string, int> items, DateTime until)
			{
				Items = items;
				Until = until;
			}
		}

		private sealed class BoardVisitState
		{
			public bool Awake { get; set; }

			public Dictionary<string, StockEntry> Baseline { get; set; } = new Dictionary<string, StockEntry>(StringComparer.OrdinalIgnoreCase);

			public List<StockChange> Changes { get; set; } = new List<StockChange>();

			public DateTime SummaryUntil { get; set; }
		}

		private sealed class StockChange
		{
			public string Name { get; }

			public int Amount { get; }

			public StockChange(string name, int amount)
			{
				Name = name;
				Amount = amount;
			}
		}

		private sealed class BoardMessage
		{
			public string Name { get; }

			public string Value { get; }

			public string Color { get; }

			public BoardMessage(string name, string value, string color)
			{
				Name = name;
				Value = value;
				Color = color;
			}
		}

		private static readonly Regex Marker = new Regex("^\\s*\\[WH:(?<id>[A-Za-z0-9_-]+):(?<role>IN|OUT|REQ|INFO|BOARD|STATS)\\](?<payload>[\\s\\S]*)$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant);

		private static readonly Regex IgnoreMarker = new Regex("^\\s*\\[WH:IGNORE\\]\\s*$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant);

		private static readonly Regex DeleteMarker = new Regex("^\\s*\\[WH:DELETE\\]\\s*$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant);

		private static readonly Regex CleanMarker = new Regex("^\\s*\\[WH:CLEAN\\]\\s*$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant);

		private const string RequestWarehouseKey = "ModerWarehouse.RequestWarehouse";

		private const string InfoWarehouseKey = "ModerWarehouse.InfoWarehouse";

		private const string BoardWarehouseKey = "ModerWarehouse.BoardWarehouse";

		private const string BoardGroupKey = "ModerWarehouse.BoardGroup";

		private const string BoardCellKey = "ModerWarehouse.BoardCell";

		private const string BoardRenderedTextKey = "ModerWarehouse.BoardRenderedText";

		private const string StatsWarehouseKey = "ModerWarehouse.StatsWarehouse";

		private const string StatsGroupKey = "ModerWarehouse.StatsGroup";

		private const string StatsCellKey = "ModerWarehouse.StatsCell";

		private const string StatsHistoryKey = "ModerWarehouse.StatsHistory";

		private const string StatsControlKey = "ModerWarehouse.StatsControl";

		private const string RequestRenderedTextKey = "ModerWarehouse.RequestRenderedText";

		private const string RequestTargetsKey = "ModerWarehouse.RequestTargets";

		private const string HelpGroupKey = "ModerWarehouse.HelpGroup";

		private const string HelpChildKey = "ModerWarehouse.HelpChild";

		private const int BoardColumns = 4;

		private const int BoardRows = 4;

		private const int BoardCellCount = 16;

		private const int BoardPageSize = 12;

		private const int BoardAnchorCell = 12;

		private const int StatsColumns = 4;

		private const int StatsRows = 4;

		private const int StatsCellCount = 16;

		private const int StatsAnchorCell = 12;

		private const string AutoChestXKey = "ModerWarehouse.AutoChestX";

		private const string AutoChestYKey = "ModerWarehouse.AutoChestY";

		private const string AutoChestZKey = "ModerWarehouse.AutoChestZ";

		private const string AutoLabelItemKey = "ModerWarehouse.AutoLabelItem";

		private const string AutoLabelManagedKey = "ModerWarehouse.AutoLabelManaged";

		private readonly HashSet<ServersideQoLZDO> _signs = new HashSet<ServersideQoLZDO>();

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

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

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

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

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

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

		private static bool _germanNamesLoaded;

		private SectorDictionary<HashSet<ServersideQoLZDO>> _containers;

		private readonly Dictionary<ServersideQoLZDO, PendingLabel> _pendingLabels = new Dictionary<ServersideQoLZDO, PendingLabel>();

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

		private readonly Dictionary<ServersideQoLZDO, DateTime> _requestClearAt = new Dictionary<ServersideQoLZDO, DateTime>();

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

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

		private readonly Dictionary<ServersideQoLZDO, DateTime> _helpPendingAt = new Dictionary<ServersideQoLZDO, DateTime>();

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

		private readonly HashSet<string> _boardReadyGroups = new HashSet<string>(StringComparer.Ordinal);

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

		private readonly HashSet<string> _statsReadyGroups = new HashSet<string>(StringComparer.Ordinal);

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

		private readonly Dictionary<string, DeliveryNotice> _deliveryNotices = new Dictionary<string, DeliveryNotice>(StringComparer.OrdinalIgnoreCase);

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

		protected override void Initialize()
		{
			_signs.Clear();
			_pendingLabels.Clear();
			_requestClearAt.Clear();
			_orphanBoardSeenAt.Clear();
			_boardControls.Clear();
			_helpPendingAt.Clear();
			_boardEnsurePendingAt.Clear();
			_boardReadyGroups.Clear();
			_statsEnsurePendingAt.Clear();
			_statsReadyGroups.Clear();
			_statsControls.Clear();
			_deliveryNotices.Clear();
			_boardVisits.Clear();
			ContainerRegistryProcessor val = Processor.Instance<ContainerRegistryProcessor>();
			_containers = val.GetContainers(100f);
			val.ContainerChanged -= OnContainerChanged;
			val.ContainerChanged += OnContainerChanged;
			WarehouseLocalization.Initialize(delegate(string message)
			{
				((Processor)this).Logger.LogInfo((object)message);
			});
			LoadGermanNames();
			((Processor)this).Logger.LogInfo((object)("Moder Warehouse 1.2.1: localization, configurable capacity alerts, player-safe input ownership, solo-friendly visit deltas, target stock shopping list, delivery confirmation, automatic IN help sign, interactive rotating 4x4 stock board, rolling 4x4 statistics board, persistent linked automatic signs, safe transfers and multi-item withdrawal initialized; " + $"{GermanNames.Count} EN/DE item names loaded."));
		}

		private void OnContainerChanged(ServersideQoLZDO changed, ContainerState state)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			foreach (ServersideQoLZDO sign in _signs)
			{
				Regex marker = Marker;
				ZDOVars vars = sign.Vars;
				if (marker.Match(PlainText(((ZDOVars)(ref vars)).GetText(""))).Success || IsRememberedInfo(sign) || IsRememberedBoard(sign) || IsRememberedStats(sign))
				{
					((Processor)this).ScheduleReprocessing(sign, 0.5f);
				}
			}
		}

		protected override bool ClaimExclusive(ServersideQoLZDO zdo)
		{
			return false;
		}

		protected override ProcessResult Process(ServersideQoLZDO zdo, IReadOnlyList<Peer> peers, ProcessorPrefabInfo<Sign> prefabInfo)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0928: Unknown result type (might be due to invalid IL or missing references)
			//IL_06bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b0c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0cc8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d2d: Unknown result type (might be due to invalid IL or missing references)
			//IL_080b: Unknown result type (might be due to invalid IL or missing references)
			//IL_07c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_08f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_08bc: Unknown result type (might be due to invalid IL or missing references)
			zdo.Fields<Piece>().Set((Func<Expression<Func<Piece, bool>>>)(() => (Piece x) => x.m_canBeRemoved), true, "D:\\Schuerch Dropbox\\Andreas Schuerch\\Dokumente\\Codex\\ModerWarehouse\\src\\WarehousePlugin.cs", 192);
			ZDOVars vars = zdo.Vars;
			string text = PlainText(((ZDOVars)(ref vars)).GetText(""));
			if (CleanMarker.IsMatch(text))
			{
				List<ServersideQoLZDO> list = _signs.Where((ServersideQoLZDO other) => other != zdo && other.IsModCreator() && Distance2(other, zdo) < 0.0025f).ToList();
				foreach (ServersideQoLZDO item in list)
				{
					item.Destroy();
				}
				_signs.Remove(zdo);
				((Processor)this).Logger.LogInfo((object)$"Cleaned warehouse sign stack: removed {list.Count + 1} sign(s).");
				return (ProcessResult)4;
			}
			if (DeleteMarker.IsMatch(text))
			{
				string boardGroup = zdo.ZDO.GetString("ModerWarehouse.BoardGroup", string.Empty);
				if (!string.IsNullOrWhiteSpace(boardGroup))
				{
					foreach (ServersideQoLZDO item2 in _signs.Where((ServersideQoLZDO x) => x.ZDO.GetString("ModerWarehouse.BoardGroup", string.Empty) == boardGroup).ToList())
					{
						_signs.Remove(item2);
						item2.Destroy();
					}
					((Processor)this).Logger.LogInfo((object)("Deleted warehouse board group '" + boardGroup + "'."));
					return (ProcessResult)4;
				}
				string statsGroup = zdo.ZDO.GetString("ModerWarehouse.StatsGroup", string.Empty);
				if (!string.IsNullOrWhiteSpace(statsGroup))
				{
					foreach (ServersideQoLZDO item3 in _signs.Where((ServersideQoLZDO x) => x.ZDO.GetString("ModerWarehouse.StatsGroup", string.Empty) == statsGroup).ToList())
					{
						_signs.Remove(item3);
						item3.Destroy();
					}
					((Processor)this).Logger.LogInfo((object)("Deleted warehouse statistics group '" + statsGroup + "'."));
					return (ProcessResult)4;
				}
				_signs.Remove(zdo);
				((Processor)this).Logger.LogInfo((object)"Deleted warehouse sign marked [WH:DELETE].");
				return (ProcessResult)4;
			}
			if (_signs.Add(zdo))
			{
				zdo.Destroyed += delegate(ServersideQoLZDO destroyed)
				{
					_signs.Remove(destroyed);
				};
			}
			Match match = Marker.Match(text);
			string text2 = zdo.ZDO.GetString("ModerWarehouse.RequestWarehouse", string.Empty);
			string text3 = zdo.ZDO.GetString("ModerWarehouse.InfoWarehouse", string.Empty);
			string text4 = zdo.ZDO.GetString("ModerWarehouse.BoardWarehouse", string.Empty);
			string text5 = zdo.ZDO.GetString("ModerWarehouse.StatsWarehouse", string.Empty);
			if (match.Success && match.Groups["role"].Value.Equals("REQ", StringComparison.OrdinalIgnoreCase))
			{
				text2 = match.Groups["id"].Value;
				zdo.ZDO.Set("ModerWarehouse.RequestWarehouse", text2);
			}
			if (match.Success && match.Groups["role"].Value.Equals("INFO", StringComparison.OrdinalIgnoreCase))
			{
				text3 = match.Groups["id"].Value;
				zdo.ZDO.Set("ModerWarehouse.InfoWarehouse", text3);
			}
			if (match.Success && match.Groups["role"].Value.Equals("BOARD", StringComparison.OrdinalIgnoreCase))
			{
				text4 = match.Groups["id"].Value;
				zdo.ZDO.Set("ModerWarehouse.BoardWarehouse", text4);
				if (string.IsNullOrWhiteSpace(zdo.ZDO.GetString("ModerWarehouse.BoardGroup", string.Empty)))
				{
					zdo.ZDO.Set("ModerWarehouse.BoardGroup", Guid.NewGuid().ToString("N"));
				}
				zdo.ZDO.Set("ModerWarehouse.BoardCell", 12);
				EnsureBoard(zdo, text4);
			}
			if (match.Success && match.Groups["role"].Value.Equals("STATS", StringComparison.OrdinalIgnoreCase))
			{
				text5 = match.Groups["id"].Value;
				zdo.ZDO.Set("ModerWarehouse.StatsWarehouse", text5);
				if (string.IsNullOrWhiteSpace(zdo.ZDO.GetString("ModerWarehouse.StatsGroup", string.Empty)))
				{
					zdo.ZDO.Set("ModerWarehouse.StatsGroup", Guid.NewGuid().ToString("N"));
				}
				zdo.ZDO.Set("ModerWarehouse.StatsCell", 12);
				EnsureStatsBoard(zdo, text5);
			}
			if (match.Success && match.Groups["role"].Value.Equals("IN", StringComparison.OrdinalIgnoreCase))
			{
				EnsureHelpSign(zdo, match.Groups["id"].Value, ResolveLanguage(match.Groups["payload"].Value));
			}
			if (!string.IsNullOrWhiteSpace(text2))
			{
				string text6 = (match.Success ? match.Groups["payload"].Value.Trim() : text.Trim());
				string text7 = zdo.ZDO.GetString("ModerWarehouse.RequestRenderedText", string.Empty);
				if (string.IsNullOrWhiteSpace(text6))
				{
					_requestClearAt.Remove(zdo);
					WriteRequestPrompt(zdo, text2, LanguageForWarehouse(text2));
					return ((Processor)this).ScheduleReprocessing(Mathf.Max(1f, ConfigBase<WarehouseConfig>.Instance.ScanInterval.Value));
				}
				if (text6.StartsWith("SOLL ", StringComparison.OrdinalIgnoreCase) || text6.StartsWith("TARGET ", StringComparison.OrdinalIgnoreCase))
				{
					int startIndex = (text6.StartsWith("SOLL ", StringComparison.OrdinalIgnoreCase) ? 5 : 7);
					if (TryParseTargets(text6.Substring(startIndex).Trim(), out var targets))
					{
						zdo.ZDO.Set("ModerWarehouse.RequestTargets", SerializeTargets(targets));
						((Processor)this).Logger.LogInfo((object)$"Warehouse '{text2}': saved {targets.Count} target stock value(s).");
						ProcessWarehouse(text2, peers);
					}
					else
					{
						string language = LanguageForWarehouse(text2);
						WriteRequestText(zdo, "<color=#ff6666>" + WarehouseLocalization.Text(language, "request.error_example") + "\n<color=white>" + WarehouseLocalization.Text(language, "request.target") + " Wood 1000");
					}
					return ((Processor)this).ScheduleReprocessing(Mathf.Max(1f, ConfigBase<WarehouseConfig>.Instance.ScanInterval.Value));
				}
				if (IsRequestPrompt(text6) || (!string.IsNullOrWhiteSpace(text7) && string.Equals(text6, text7, StringComparison.Ordinal)))
				{
					ProcessWarehouse(text2, peers);
					return ((Processor)this).ScheduleReprocessing(Mathf.Max(1f, ConfigBase<WarehouseConfig>.Instance.ScanInterval.Value));
				}
				if (IsStatus(text6))
				{
					if (!_requestClearAt.TryGetValue(zdo, out var value))
					{
						value = DateTime.UtcNow.AddSeconds(Math.Max(5f, ConfigBase<WarehouseConfig>.Instance.RequestResultSeconds.Value));
						_requestClearAt[zdo] = value;
					}
					if (DateTime.UtcNow >= value)
					{
						WriteRequestPrompt(zdo, text2, LanguageForWarehouse(text2));
						_requestClearAt.Remove(zdo);
					}
					return ((Processor)this).ScheduleReprocessing(Mathf.Max(1f, ConfigBase<WarehouseConfig>.Instance.ScanInterval.Value));
				}
				_requestClearAt.Remove(zdo);
				ProcessWarehouse(text2, peers);
				return ((Processor)this).ScheduleReprocessing(Mathf.Max(1f, ConfigBase<WarehouseConfig>.Instance.ScanInterval.Value));
			}
			if (!string.IsNullOrWhiteSpace(text3))
			{
				ProcessWarehouse(text3, peers);
				return ((Processor)this).ScheduleReprocessing(Mathf.Max(1f, ConfigBase<WarehouseConfig>.Instance.ScanInterval.Value));
			}
			if (!string.IsNullOrWhiteSpace(text4))
			{
				string group = zdo.ZDO.GetString("ModerWarehouse.BoardGroup", string.Empty);
				int num = zdo.ZDO.GetInt("ModerWarehouse.BoardCell", -1);
				CaptureBoardControlInput(zdo, group, num);
				if (!string.IsNullOrWhiteSpace(group))
				{
					DateTime value2;
					if (_signs.Any((ServersideQoLZDO sign) => sign.ZDO.GetString("ModerWarehouse.BoardGroup", string.Empty) == group && sign.ZDO.GetInt("ModerWarehouse.BoardCell", -1) == 12))
					{
						_orphanBoardSeenAt.Remove(group);
					}
					else if (!_orphanBoardSeenAt.TryGetValue(group, out value2))
					{
						_orphanBoardSeenAt[group] = DateTime.UtcNow;
					}
					else if ((DateTime.UtcNow - value2).TotalSeconds >= 10.0)
					{
						List<ServersideQoLZDO> list2 = _signs.Where((ServersideQoLZDO sign) => sign.ZDO.GetString("ModerWarehouse.BoardGroup", string.Empty) == group).ToList();
						foreach (ServersideQoLZDO item4 in list2)
						{
							_signs.Remove(item4);
							item4.Destroy();
						}
						_orphanBoardSeenAt.Remove(group);
						((Processor)this).Logger.LogInfo((object)$"Removed {list2.Count} orphaned stock-board sign(s) from group '{group}'.");
						return (ProcessResult)4;
					}
				}
				if (num == 12)
				{
					EnsureBoard(zdo, text4);
				}
				ProcessWarehouse(text4, peers);
				return ((Processor)this).ScheduleReprocessing(Mathf.Min(1f, Mathf.Max(0.5f, ConfigBase<WarehouseConfig>.Instance.BoardPageSeconds.Value / 2f)));
			}
			if (!string.IsNullOrWhiteSpace(text5))
			{
				int num2 = zdo.ZDO.GetInt("ModerWarehouse.StatsCell", -1);
				string statsGroup2 = zdo.ZDO.GetString("ModerWarehouse.StatsGroup", string.Empty);
				if (num2 == 6 && !string.IsNullOrWhiteSpace(zdo.ZDO.GetString("ModerWarehouse.StatsHistory", string.Empty)))
				{
					foreach (ServersideQoLZDO item5 in _signs.Where((ServersideQoLZDO x) => x != zdo && x.ZDO.GetString("ModerWarehouse.StatsGroup", string.Empty) == statsGroup2).ToList())
					{
						_signs.Remove(item5);
						item5.Destroy();
					}
					zdo.ZDO.Set("ModerWarehouse.StatsCell", 12);
					_statsReadyGroups.Remove(statsGroup2);
					_statsEnsurePendingAt.Remove(statsGroup2);
					((Processor)this).Logger.LogInfo((object)("Warehouse '" + text5 + "': migrated 3x3 statistics board to 4x4."));
					num2 = 12;
				}
				if (num2 == 12)
				{
					EnsureStatsBoard(zdo, text5);
				}
				ProcessWarehouse(text5, peers);
				return ((Processor)this).ScheduleReprocessing(Mathf.Min(1f, Mathf.Max(0.5f, ConfigBase<WarehouseConfig>.Instance.BoardPageSeconds.Value / 2f)));
			}
			if (match.Success || IgnoreMarker.IsMatch(text))
			{
				WriteWhite(zdo, text);
			}
			if (match.Success)
			{
				ProcessWarehouse(match.Groups["id"].Value, peers);
			}
			return ((Processor)this).ScheduleReprocessing(Mathf.Max(1f, ConfigBase<WarehouseConfig>.Instance.ScanInterval.Value));
		}

		private string LanguageForWarehouse(string id)
		{
			//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)
			foreach (ServersideQoLZDO sign in _signs)
			{
				Regex marker = Marker;
				ZDOVars vars = sign.Vars;
				Match match = marker.Match(PlainText(((ZDOVars)(ref vars)).GetText("")));
				if (match.Success && match.Groups["id"].Value.Equals(id, StringComparison.OrdinalIgnoreCase) && match.Groups["role"].Value.Equals("IN", StringComparison.OrdinalIgnoreCase))
				{
					return ResolveLanguage(match.Groups["payload"].Value);
				}
			}
			return ResolveLanguage(string.Empty);
		}

		private static string ResolveLanguage(string payload)
		{
			Match match = Regex.Match(payload ?? string.Empty, "(?:^|[\\r\\n])\\s*LANG(?:UAGE)?\\s*=\\s*(?<language>[A-Za-z][A-Za-z0-9_-]*)\\s*(?:$|[\\r\\n])", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
			return WarehouseLocalization.Resolve(match.Success ? match.Groups["language"].Value : ConfigBase<WarehouseConfig>.Instance.Language.Value);
		}

		private void ProcessWarehouse(string id, IReadOnlyList<Peer> peers)
		{
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_063b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0640: Unknown result type (might be due to invalid IL or missing references)
			string language = LanguageForWarehouse(id);
			List<ServersideQoLZDO> list = AllContainers();
			HashSet<ServersideQoLZDO> endpoints = new HashSet<ServersideQoLZDO>();
			ServersideQoLZDO input = null;
			ServersideQoLZDO val = null;
			List<Request> list2 = new List<Request>();
			List<ServersideQoLZDO> list3 = new List<ServersideQoLZDO>();
			List<ServersideQoLZDO> list4 = new List<ServersideQoLZDO>();
			List<ServersideQoLZDO> list5 = new List<ServersideQoLZDO>();
			float range = ConfigBase<WarehouseConfig>.Instance.MarkerDistance.Value * ConfigBase<WarehouseConfig>.Instance.MarkerDistance.Value;
			float num = ConfigBase<WarehouseConfig>.Instance.LabelDistance.Value * ConfigBase<WarehouseConfig>.Instance.LabelDistance.Value;
			ZDOVars vars;
			foreach (ServersideQoLZDO sign in _signs)
			{
				Regex marker = Marker;
				vars = sign.Vars;
				Match match = marker.Match(PlainText(((ZDOVars)(ref vars)).GetText("")));
				string text = sign.ZDO.GetString("ModerWarehouse.RequestWarehouse", string.Empty);
				string text2 = sign.ZDO.GetString("ModerWarehouse.InfoWarehouse", string.Empty);
				string text3 = sign.ZDO.GetString("ModerWarehouse.BoardWarehouse", string.Empty);
				string text4 = sign.ZDO.GetString("ModerWarehouse.StatsWarehouse", string.Empty);
				bool flag = !match.Success && text.Equals(id, StringComparison.OrdinalIgnoreCase);
				bool flag2 = !match.Success && text2.Equals(id, StringComparison.OrdinalIgnoreCase);
				bool flag3 = !match.Success && text3.Equals(id, StringComparison.OrdinalIgnoreCase);
				bool flag4 = !match.Success && text4.Equals(id, StringComparison.OrdinalIgnoreCase);
				if (!flag && !flag2 && !flag3 && !flag4 && (!match.Success || !match.Groups["id"].Value.Equals(id, StringComparison.OrdinalIgnoreCase)))
				{
					continue;
				}
				string text5 = (flag ? "REQ" : (flag2 ? "INFO" : (flag3 ? "BOARD" : (flag4 ? "STATS" : match.Groups["role"].Value.ToUpperInvariant()))));
				switch (text5)
				{
				case "REQ":
				{
					string text6;
					if (!flag)
					{
						text6 = match.Groups["payload"].Value.Trim();
					}
					else
					{
						vars = sign.Vars;
						text6 = PlainText(((ZDOVars)(ref vars)).GetText("")).Trim();
					}
					string payload = text6;
					list2.Add(new Request(sign, payload));
					continue;
				}
				case "INFO":
					list3.Add(sign);
					continue;
				case "BOARD":
					list4.Add(sign);
					continue;
				case "STATS":
					list5.Add(sign);
					continue;
				}
				ServersideQoLZDO val2 = NearestContainer(sign, list, range);
				if (val2 != null)
				{
					endpoints.Add(val2);
					if (text5 == "IN")
					{
						input = val2;
					}
					if (text5 == "OUT")
					{
						val = val2;
					}
				}
			}
			if (input == null)
			{
				return;
			}
			ContainerRegistryProcessor registry = Processor.Instance<ContainerRegistryProcessor>();
			ContainerState state = registry.GetState(input);
			if (state == null)
			{
				return;
			}
			IInventory inventory = state.GetInventory();
			float radius2 = ConfigBase<WarehouseConfig>.Instance.Radius.Value * ConfigBase<WarehouseConfig>.Instance.Radius.Value;
			HashSet<ServersideQoLZDO> ignored = DiscoverIgnored(list, range);
			List<ServersideQoLZDO> targets = (from x in list.Where(delegate(ServersideQoLZDO x)
				{
					//IL_002b: Unknown result type (might be due to invalid IL or missing references)
					//IL_0030: Unknown result type (might be due to invalid IL or missing references)
					if (!endpoints.Contains(x) && !ignored.Contains(x) && !IsPrivateContainer(x))
					{
						ZDOVars vars2 = x.Vars;
						return !((ZDOVars)(ref vars2)).GetInUse(false);
					}
					return false;
				})
				where Distance2(x, input) <= radius2
				select x).ToList();
			int num2 = SanitizeForbiddenItems(targets, registry, list, num);
			if (num2 > 0)
			{
				((Processor)this).Logger.LogWarning((object)($"Warehouse '{id}' janitor purged {num2} forbidden internal item(s) " + "from managed storage; IN was left untouched."));
			}
			RefreshAutomaticLabels(list, num, registry, language);
			Dictionary<ServersideQoLZDO, string> labels = DiscoverLabels(list, num);
			Dictionary<ServersideQoLZDO, ServersideQoLZDO> blankSigns = DiscoverBlankSigns(list, num);
			if (RemoveSupersededGeneratedLabels(blankSigns, list, num))
			{
				labels = DiscoverLabels(list, num);
				blankSigns = DiscoverBlankSigns(list, num);
			}
			RepairGeneratedLabelPlacement(list, num);
			List<ServersideQoLZDO> list6 = (from x in list.Where(delegate(ServersideQoLZDO x)
				{
					//IL_002b: Unknown result type (might be due to invalid IL or missing references)
					//IL_0030: Unknown result type (might be due to invalid IL or missing references)
					if (!endpoints.Contains(x) && !ignored.Contains(x) && !IsPrivateContainer(x))
					{
						ZDOVars vars2 = x.Vars;
						return !((ZDOVars)(ref vars2)).GetInUse(false);
					}
					return false;
				}).Where(delegate(ServersideQoLZDO x)
				{
					ContainerState state3 = registry.GetState(x);
					return ContainsOnlyWarehouseItems((state3 != null) ? state3.GetInventory() : null);
				})
				where Distance2(x, input) <= radius2
				orderby Distance2(x, input)
				select x).ToList();
			int moves = Math.Max(1, ConfigBase<WarehouseConfig>.Instance.MaxMoves.Value);
			int num3 = CorrectMisfiledItems(id, list6, labels, registry, ref moves);
			if (num3 > 0)
			{
				((Processor)this).Logger.LogInfo((object)$"Warehouse '{id}' janitor refiled {num3} valid misplaced item(s) in total.");
			}
			ServersideQoLZDO val3 = ((IEnumerable<ServersideQoLZDO>)list5).FirstOrDefault((Func<ServersideQoLZDO, bool>)((ServersideQoLZDO sign) => sign.ZDO.GetInt("ModerWarehouse.StatsCell", -1) == 12));
			WarehouseStatsHistory warehouseStatsHistory = ((val3 == null) ? null : WarehouseStatsHistory.Parse(val3.ZDO.GetString("ModerWarehouse.StatsHistory", string.Empty)));
			warehouseStatsHistory?.SetSnapshot(list6, registry);
			WhitenWarehouseLabels(list6.Concat(endpoints).Concat(ignored).Distinct()
				.ToList(), list, num);
			LabelHomogeneousStores(list6, labels, blankSigns, registry, language);
			WriteWarehouseInfo(id, language, list3, list6, labels, registry);
			WriteShoppingLists(id, language, list2.Select((Request x) => x.Sign), list6, registry);
			WriteWarehouseBoard(id, language, list4, list6, registry, peers);
			int num4 = 0;
			HashSet<ServersideQoLZDO> hashSet = new HashSet<ServersideQoLZDO>();
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.CurrentCultureIgnoreCase);
			if (inventory.Items.Any((ItemData val4) => IsWarehouseItem(val4) && val4.m_stack > 0))
			{
				vars = input.Vars;
				if (!((ZDOVars)(ref vars)).GetInUse(false) && Own(state))
				{
					foreach (ItemData item in inventory.Items.ToList())
					{
						if (moves <= 0 || item == null || item.m_stack <= 0)
						{
							break;
						}
						if (!IsWarehouseItem(item))
						{
							continue;
						}
						int num5 = item.m_stack;
						string value3;
						foreach (ServersideQoLZDO item2 in from x in list6.Where(delegate(ServersideQoLZDO x)
							{
								if (!labels.TryGetValue(x, out value3))
								{
									ContainerState state3 = registry.GetState(x);
									return IsSingleItemType((state3 != null) ? state3.GetInventory() : null, item);
								}
								return LabelMatches(x, value3, item, registry);
							})
							orderby (!HasItem(registry.GetState(x), item)) ? ((labels.TryGetValue(x, out value3) && LabelMatches(x, value3, item, registry)) ? 1 : 0) : 2 descending
							select x)
						{
							if (moves <= 0 || num5 <= 0)
							{
								break;
							}
							ContainerState state2 = registry.GetState(item2);
							if (state2 == null || !Own(state2))
							{
								continue;
							}
							IInventory inventory2 = state2.GetInventory();
							bool flag5 = !labels.ContainsKey(item2) && IsSingleItemType(inventory2, item);
							int num6 = Move(inventory, inventory2, item, num5);
							if (num6 <= 0)
							{
								continue;
							}
							string key = LocalizedItemName(item, language);
							dictionary[key] = (dictionary.TryGetValue(key, out var value) ? (value + num6) : num6);
							num4 += num6;
							warehouseStatsHistory?.AddInput(item.m_shared.m_name, num6);
							num5 -= num6;
							moves--;
							hashSet.Add(item2);
							if (flag5 && ConfigBase<WarehouseConfig>.Instance.AutoCreateLabels.Value)
							{
								string value2 = CreateAutomaticLabel(item2, item, blankSigns, language);
								if (!string.IsNullOrEmpty(value2))
								{
									labels[item2] = value2;
								}
							}
						}
					}
				}
			}
			if (num4 > 0)
			{
				_deliveryNotices[id] = new DeliveryNotice(dictionary, DateTime.UtcNow.AddSeconds(Math.Max(2f, ConfigBase<WarehouseConfig>.Instance.DeliveryNoticeSeconds.Value)));
				((Processor)this).Logger.LogInfo((object)($"Warehouse '{id}': stored {num4} item(s) into " + $"{hashSet.Count} chest(s); {list6.Count} candidate chest(s) scanned."));
			}
			if (val != null)
			{
				foreach (Request item3 in list2)
				{
					ProcessRequest(id, language, item3, val, list6, registry, warehouseStatsHistory, ref moves);
				}
			}
			if (warehouseStatsHistory != null)
			{
				if (warehouseStatsHistory.Changed)
				{
					val3.ZDO.Set("ModerWarehouse.StatsHistory", warehouseStatsHistory.Serialize());
				}
				WriteStatisticsBoard(id, language, list5, warehouseStatsHistory, list6, registry, peers);
			}
		}

		private Dictionary<ServersideQoLZDO, string> DiscoverLabels(List<ServersideQoLZDO> containers, float range2)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<ServersideQoLZDO, string> dictionary = new Dictionary<ServersideQoLZDO, string>();
			_labelItemTokens.Clear();
			foreach (ServersideQoLZDO sign in _signs)
			{
				if (IsRememberedRequest(sign) || IsRememberedInfo(sign) || IsRememberedBoard(sign) || IsRememberedStats(sign) || sign.ZDO.GetBool("ModerWarehouse.HelpChild", false))
				{
					continue;
				}
				ZDOVars vars = sign.Vars;
				string text = ((ZDOVars)(ref vars)).GetText("") ?? string.Empty;
				string text2 = PlainText(text);
				if (IsBlankLabel(text2) || Marker.IsMatch(text2) || IgnoreMarker.IsMatch(text2))
				{
					continue;
				}
				ServersideQoLZDO val = LinkedOrNearestContainer(sign, containers, range2);
				if (val != null)
				{
					dictionary[val] = (dictionary.TryGetValue(val, out var value) ? (value + " " + text) : text);
					string value2 = sign.ZDO.GetString("ModerWarehouse.AutoLabelItem", string.Empty);
					if (!string.IsNullOrWhiteSpace(value2))
					{
						_labelItemTokens[val] = value2;
					}
				}
			}
			return dictionary;
		}

		private Dictionary<ServersideQoLZDO, ServersideQoLZDO> DiscoverBlankSigns(List<ServersideQoLZDO> containers, float range2)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<ServersideQoLZDO, ServersideQoLZDO> dictionary = new Dictionary<ServersideQoLZDO, ServersideQoLZDO>();
			foreach (ServersideQoLZDO sign in _signs)
			{
				if (IsRememberedRequest(sign) || IsRememberedInfo(sign) || IsRememberedBoard(sign) || IsRememberedStats(sign) || sign.ZDO.GetBool("ModerWarehouse.HelpChild", false))
				{
					continue;
				}
				ZDOVars vars = sign.Vars;
				if (IsBlankLabel(PlainText(((ZDOVars)(ref vars)).GetText(""))))
				{
					ServersideQoLZDO val = NearestContainer(sign, containers, range2);
					if (val != null && !dictionary.ContainsKey(val))
					{
						dictionary.Add(val, sign);
					}
				}
			}
			return dictionary;
		}

		private bool RemoveSupersededGeneratedLabels(Dictionary<ServersideQoLZDO, ServersideQoLZDO> blankSigns, List<ServersideQoLZDO> containers, float range2)
		{
			bool result = false;
			foreach (KeyValuePair<ServersideQoLZDO, ServersideQoLZDO> pair in blankSigns)
			{
				List<ServersideQoLZDO> list = _signs.Where((ServersideQoLZDO sign) => sign != pair.Value && sign.IsModCreator() && sign.ZDO.GetBool("ModerWarehouse.AutoLabelManaged", false) && LinkedOrNearestContainer(sign, containers, range2) == pair.Key).ToList();
				foreach (ServersideQoLZDO item in list)
				{
					_signs.Remove(item);
					item.Destroy();
					result = true;
				}
				if (list.Count > 0)
				{
					((Processor)this).Logger.LogInfo((object)$"Removed {list.Count} generated label(s) superseded by a blank sign at the same chest.");
				}
			}
			return result;
		}

		private HashSet<ServersideQoLZDO> DiscoverIgnored(List<ServersideQoLZDO> containers, float range2)
		{
			//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)
			HashSet<ServersideQoLZDO> hashSet = new HashSet<ServersideQoLZDO>();
			foreach (ServersideQoLZDO sign in _signs)
			{
				Regex ignoreMarker = IgnoreMarker;
				ZDOVars vars = sign.Vars;
				if (ignoreMarker.IsMatch(PlainText(((ZDOVars)(ref vars)).GetText(""))))
				{
					ServersideQoLZDO val = NearestContainer(sign, containers, range2);
					if (val != null)
					{
						hashSet.Add(val);
					}
				}
			}
			return hashSet;
		}

		private static ServersideQoLZDO NearestContainer(ServersideQoLZDO sign, List<ServersideQoLZDO> containers, float range2)
		{
			return (from x in containers
				where Distance2(x, sign) <= range2
				orderby Distance2(x, sign)
				select x).FirstOrDefault();
		}

		private string CreateAutomaticLabel(ServersideQoLZDO chest, ItemData item, Dictionary<ServersideQoLZDO, ServersideQoLZDO> blankSigns, string language)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: 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)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			string text = LocalizedItemName(item, language);
			ZDOVars vars;
			if (blankSigns.TryGetValue(chest, out var value))
			{
				if (!value.IsOwnerOrUnassigned())
				{
					value.ClaimOwnership();
				}
				vars = value.Vars;
				((ZDOVars)(ref vars)).SetText("<color=white>" + text, "D:\\Schuerch Dropbox\\Andreas Schuerch\\Dokumente\\Codex\\ModerWarehouse\\src\\WarehousePlugin.cs", 686);
				MarkAutomaticLabel(value, chest, item?.m_shared?.m_name);
				((Processor)this).Logger.LogInfo((object)("Reused blank sign and labeled chest '" + text + "'."));
				_pendingLabels.Remove(chest);
				return text;
			}
			DateTime utcNow = DateTime.UtcNow;
			string text2 = item?.m_shared?.m_name ?? string.Empty;
			if (!_pendingLabels.TryGetValue(chest, out var value2) || value2.ItemType != text2)
			{
				_pendingLabels[chest] = new PendingLabel(text2, utcNow);
				return null;
			}
			if ((utcNow - value2.Since).TotalSeconds < (double)Math.Max(5f, ConfigBase<WarehouseConfig>.Instance.AutoLabelDelay.Value))
			{
				return null;
			}
			Vector3 val = AutomaticLabelPosition(chest);
			ServersideQoLZDO val2 = ((Processor)this).PlacePiece(val, Prefabs.Sign, chest.ZDO.GetRotation(), (CreatorMarkers)2);
			if (val2 == null)
			{
				return null;
			}
			val2.Fields<Piece>().Set((Func<Expression<Func<Piece, bool>>>)(() => (Piece x) => x.m_canBeRemoved), true, "D:\\Schuerch Dropbox\\Andreas Schuerch\\Dokumente\\Codex\\ModerWarehouse\\src\\WarehousePlugin.cs", 708);
			vars = val2.Vars;
			((ZDOVars)(ref vars)).SetText("<color=white>" + text, "D:\\Schuerch Dropbox\\Andreas Schuerch\\Dokumente\\Codex\\ModerWarehouse\\src\\WarehousePlugin.cs", 709);
			Vector3 position = chest.ZDO.GetPosition();
			val2.ZDO.Set("ModerWarehouse.AutoChestX", position.x);
			val2.ZDO.Set("ModerWarehouse.AutoChestY", position.y);
			val2.ZDO.Set("ModerWarehouse.AutoChestZ", position.z);
			val2.ZDO.Set("ModerWarehouse.AutoLabelManaged", true);
			val2.ZDO.Set("ModerWarehouse.AutoLabelItem", item?.m_shared?.m_name ?? string.Empty);
			if (_signs.Add(val2))
			{
				val2.Destroyed += delegate(ServersideQoLZDO destroyed)
				{
					_signs.Remove(destroyed);
				};
			}
			_pendingLabels.Remove(chest);
			((Processor)this).Logger.LogInfo((object)("Created persistent automatic label '" + text + "'."));
			return text;
		}

		private void RepairGeneratedLabelPlacement(List<ServersideQoLZDO> containers, float range2)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: 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)
			foreach (ServersideQoLZDO item in _signs.Where((ServersideQoLZDO x) => x.IsModCreator() && x.ZDO.GetBool("ModerWarehouse.AutoLabelManaged", false)).ToList())
			{
				ServersideQoLZDO val = LinkedOrNearestContainer(item, containers, range2);
				if (val == null)
				{
					continue;
				}
				Vector3 val2 = AutomaticLabelPosition(val);
				Vector3 val3 = item.ZDO.GetPosition() - val2;
				if (((Vector3)(ref val3)).sqrMagnitude <= 0.0225f)
				{
					continue;
				}
				ServersideQoLZDO val4 = ((Processor)this).PlacePiece(val2, Prefabs.Sign, val.ZDO.GetRotation(), (CreatorMarkers)2);
				if (val4 == null)
				{
					continue;
				}
				val4.Fields<Piece>().Set((Func<Expression<Func<Piece, bool>>>)(() => (Piece x) => x.m_canBeRemoved), true, "D:\\Schuerch Dropbox\\Andreas Schuerch\\Dokumente\\Codex\\ModerWarehouse\\src\\WarehousePlugin.cs", 735);
				ZDOVars vars = val4.Vars;
				ZDOVars vars2 = item.Vars;
				((ZDOVars)(ref vars)).SetText(((ZDOVars)(ref vars2)).GetText("") ?? string.Empty, "D:\\Schuerch Dropbox\\Andreas Schuerch\\Dokumente\\Codex\\ModerWarehouse\\src\\WarehousePlugin.cs", 736);
				MarkAutomaticLabel(val4, val, item.ZDO.GetString("ModerWarehouse.AutoLabelItem", string.Empty));
				if (_signs.Add(val4))
				{
					val4.Destroyed += delegate(ServersideQoLZDO destroyed)
					{
						_signs.Remove(destroyed);
					};
				}
				_signs.Remove(item);
				item.Destroy();
				((Processor)this).Logger.LogInfo((object)"Moved a generated storage label from the back to the decorated front of its chest.");
			}
		}

		private static Vector3 AutomaticLabelPosition(ServersideQoLZDO chest)
		{
			//IL_0006: 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_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			return chest.ZDO.GetPosition() + chest.ZDO.GetRotation() * new Vector3(0f, 0.35f, 0.65f);
		}

		private static void MarkAutomaticLabel(ServersideQoLZDO sign, ServersideQoLZDO chest, string itemToken)
		{
			//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_0017: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = chest.ZDO.GetPosition();
			sign.ZDO.Set("ModerWarehouse.AutoChestX", position.x);
			sign.ZDO.Set("ModerWarehouse.AutoChestY", position.y);
			sign.ZDO.Set("ModerWarehouse.AutoChestZ", position.z);
			sign.ZDO.Set("ModerWarehouse.AutoLabelManaged", true);
			sign.ZDO.Set("ModerWarehouse.AutoLabelItem", itemToken ?? string.Empty);
		}

		private void RefreshAutomaticLabels(List<ServersideQoLZDO> containers, float range2, ContainerRegistryProcessor registry, string language)
		{
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			foreach (ServersideQoLZDO sign in _signs)
			{
				string text = sign.ZDO.GetString("ModerWarehouse.AutoLabelItem", string.Empty);
				bool num = sign.ZDO.GetBool("ModerWarehouse.AutoLabelManaged", false);
				bool flag = !float.IsNaN(sign.ZDO.GetFloat("ModerWarehouse.AutoChestX", float.NaN));
				if (!num && !flag)
				{
					continue;
				}
				ServersideQoLZDO val = LinkedOrNearestContainer(sign, containers, range2);
				if (val == null)
				{
					continue;
				}
				ZDOVars vars;
				if (string.IsNullOrWhiteSpace(text))
				{
					ContainerState state = registry.GetState(val);
					object obj;
					if (state == null)
					{
						obj = null;
					}
					else
					{
						IInventory inventory = state.GetInventory();
						obj = ((inventory != null) ? ((IEnumerable<ItemData>)inventory.Items).FirstOrDefault((Func<ItemData, bool>)((ItemData x) => x != null && x.m_stack > 0 && x.m_shared != null)) : null);
					}
					text = ((ItemData)(obj?)).m_shared?.m_name;
					if (string.IsNullOrWhiteSpace(text))
					{
						vars = sign.Vars;
						text = FindTokenByDisplayName(PlainText(((ZDOVars)(ref vars)).GetText("")));
					}
					if (string.IsNullOrWhiteSpace(text))
					{
						continue;
					}
					MarkAutomaticLabel(sign, val, text);
				}
				string text2 = LocalizedTokenName(text, language);
				string text3 = "<color=white>" + text2;
				vars = sign.Vars;
				if (!string.Equals(((ZDOVars)(ref vars)).GetText(""), text3, StringComparison.Ordinal))
				{
					if (!sign.IsOwnerOrUnassigned())
					{
						sign.ClaimOwnership();
					}
					vars = sign.Vars;
					((ZDOVars)(ref vars)).SetText(text3, "D:\\Schuerch Dropbox\\Andreas Schuerch\\Dokumente\\Codex\\ModerWarehouse\\src\\WarehousePlugin.cs", 786);
				}
			}
		}

		private static string FindTokenByDisplayName(string displayName)
		{
			string normalized = Normalize(displayName);
			return (from x in GermanDisplayNames.Concat(EnglishDisplayNames)
				where Normalize(x.Value) == normalized
				select x.Key).FirstOrDefault();
		}

		private static string LocalizedTokenName(string token, string language)
		{
			Dictionary<string, string> dictionary = ((WarehouseLocalization.Resolve(language) == "de") ? GermanDisplayNames : EnglishDisplayNames);
			if (!string.IsNullOrWhiteSpace(token) && dictionary.TryGetValue(token, out var value) && !string.IsNullOrWhiteSpace(value))
			{
				return value;
			}
			if (!string.IsNullOrWhiteSpace(token) && PrefabNames.TryGetValue(token, out var value2) && !string.IsNullOrWhiteSpace(value2))
			{
				return value2;
			}
			return token ?? string.Empty;
		}

		private void LabelHomogeneousStores(List<ServersideQoLZDO> stores, Dictionary<ServersideQoLZDO, string> labels, Dictionary<ServersideQoLZDO, ServersideQoLZDO> blankSigns, ContainerRegistryProcessor registry, string language)
		{
			//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)
			if (!ConfigBase<WarehouseConfig>.Instance.AutoCreateLabels.Value)
			{
				return;
			}
			foreach (ServersideQoLZDO store in stores)
			{
				if (!labels.ContainsKey(store))
				{
					ZDOVars vars = store.Vars;
					if (!((ZDOVars)(ref vars)).GetInUse(false))
					{
						ContainerState state = registry.GetState(store);
						if (state == null)
						{
							continue;
						}
						List<ItemData> list = state.GetInventory().Items.Where((ItemData x) => x != null && x.m_stack > 0 && x.m_shared != null).ToList();
						if (list.Count == 0)
						{
							_pendingLabels.Remove(store);
							continue;
						}
						string itemType = list[0].m_shared.m_name;
						if (list.Any((ItemData x) => x.m_shared.m_name != itemType))
						{
							_pendingLabels.Remove(store);
							continue;
						}
						string value = CreateAutomaticLabel(store, list[0], blankSigns, language);
						if (!string.IsNullOrEmpty(value))
						{
							labels[store] = value;
						}
						continue;
					}
				}
				_pendingLabels.Remove(store);
			}
		}

		private bool IsPrivateContainer(ServersideQoLZDO chest)
		{
			string text = Processor.GetPrefabInfo(chest).PrefabName.ToLowerInvariant();
			if (!text.Contains("chest_private"))
			{
				return text.Contains("personal");
			}
			return true;
		}

		private void WhitenWarehouseLabels(List<ServersideQoLZDO> managed, List<ServersideQoLZDO> containers, float range2)
		{
			//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)
			HashSet<ServersideQoLZDO> hashSet = new HashSet<ServersideQoLZDO>(managed);
			foreach (ServersideQoLZDO sign in _signs)
			{
				if (IsRememberedInfo(sign) || IsRememberedBoard(sign) || IsRememberedStats(sign))
				{
					continue;
				}
				ZDOVars vars = sign.Vars;
				string text = PlainText(((ZDOVars)(ref vars)).GetText(""));
				if (!IsBlankLabel(text) && !DeleteMarker.IsMatch(text) && !CleanMarker.IsMatch(text))
				{
					ServersideQoLZDO val = NearestContainer(sign, containers, range2);
					if (val != null && hashSet.Contains(val))
					{
						WriteWhite(sign, text);
					}
				}
			}
		}

		private static void WriteWhite(ServersideQoLZDO sign, string plain)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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)
			ZDOVars vars = sign.Vars;
			if (!(((ZDOVars)(ref vars)).GetText("") ?? string.Empty).StartsWith("<color=white>", StringComparison.OrdinalIgnoreCase))
			{
				if (!sign.IsOwnerOrUnassigned())
				{
					sign.ClaimOwnership();
				}
				vars = sign.Vars;
				((ZDOVars)(ref vars)).SetText("<color=white>" + plain, "D:\\Schuerch Dropbox\\Andreas Schuerch\\Dokumente\\Codex\\ModerWarehouse\\src\\WarehousePlugin.cs", 869);
			}
		}

		private static bool IsSingleItemType(IInventory inventory, ItemData incoming)
		{
			if (inventory != null)
			{
				if (inventory.Items.Count != 0)
				{
					return inventory.Items.All((ItemData x) => x?.m_shared?.m_name == incoming?.m_shared?.m_name);
				}
				return true;
			}
			return false;
		}

		private static bool ContainsOnlyWarehouseItems(IInventory inventory)
		{
			if (inventory != null)
			{
				return inventory.Items.All((ItemData item) => item == null || item.m_stack <= 0 || IsWarehouseItem(item));
			}
			return false;
		}

		private int CorrectMisfiledItems(string warehouseId, List<ServersideQoLZDO> stores, Dictionary<ServersideQoLZDO, string> labels, ContainerRegistryProcessor registry, ref int moves)
		{
			int num = 0;
			foreach (ServersideQoLZDO sourceZdo in stores.ToList())
			{
				if (moves <= 0 || !labels.TryGetValue(sourceZdo, out var value))
				{
					continue;
				}
				ContainerState state = registry.GetState(sourceZdo);
				IInventory val = ((state != null) ? state.GetInventory() : null);
				if (val == null)
				{
					continue;
				}
				foreach (ItemData item in val.Items.ToList())
				{
					if (moves <= 0)
					{
						break;
					}
					if (item == null || item.m_stack <= 0 || !IsWarehouseItem(item) || LabelMatches(sourceZdo, value, item, registry))
					{
						continue;
					}
					if (!Own(state))
					{
						break;
					}
					int num2 = item.m_stack;
					string value3;
					foreach (ServersideQoLZDO item2 in from targetZdo in stores.Where((ServersideQoLZDO targetZdo) => targetZdo != sourceZdo).Where(delegate(ServersideQoLZDO targetZdo)
						{
							if (!labels.TryGetValue(targetZdo, out value3))
							{
								ContainerState state3 = registry.GetState(targetZdo);
								return IsSingleItemType((state3 != null) ? state3.GetInventory() : null, item);
							}
							return LabelMatches(targetZdo, value3, item, registry);
						})
						orderby (!HasItem(registry.GetState(targetZdo), item)) ? ((labels.TryGetValue(targetZdo, out value3) && LabelMatches(targetZdo, value3, item, registry)) ? 1 : 0) : 2 descending, Distance2(targetZdo, sourceZdo)
						select targetZdo)
					{
						if (moves <= 0 || num2 <= 0)
						{
							break;
						}
						ContainerState state2 = registry.GetState(item2);
						if (state2 != null && Own(state2))
						{
							int num3 = Move(val, state2.GetInventory(), item, num2);
							if (num3 > 0)
							{
								string value2;
								string text = (labels.TryGetValue(item2, out value2) ? PlainText(value2).Trim() : "(free/unlabelled)");
								((Processor)this).Logger.LogInfo((object)($"Warehouse '{warehouseId}' janitor moved {num3} x " + "'" + item.m_shared.m_name + "' from '" + PlainText(value).Trim() + "' to '" + text + "'."));
								num += num3;
								num2 -= num3;
								moves--;
							}
						}
					}
				}
			}
			return num;
		}

		private int SanitizeForbiddenItems(IEnumerable<ServersideQoLZDO> targets, ContainerRegistryProcessor registry, List<ServersideQoLZDO> allContainers, float markerRange2)
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: 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)
			int num = 0;
			foreach (ServersideQoLZDO chest in targets.Where((ServersideQoLZDO x) => x != null).Distinct())
			{
				ContainerState state = registry.GetState(chest);
				IInventory val = ((state != null) ? state.GetInventory() : null);
				if (val == null)
				{
					continue;
				}
				ZDOVars vars = chest.Vars;
				if (((ZDOVars)(ref vars)).GetInUse(false))
				{
					continue;
				}
				List<ItemData> list = val.Items.Where((ItemData item) => item != null && item.m_stack > 0 && !IsWarehouseItem(item)).ToList();
				if (list.Count == 0 || !Own(state))
				{
					continue;
				}
				int num2 = 0;
				foreach (ItemData item in list)
				{
					int stack = item.m_stack;
					if (val.Inventory.RemoveItem(item, stack))
					{
						num2 += stack;
					}
				}
				if (num2 == 0)
				{
					continue;
				}
				val.Save();
				num += num2;
				if (val.Items.Any((ItemData item) => item != null && item.m_stack > 0))
				{
					continue;
				}
				foreach (ServersideQoLZDO item2 in _signs.Where((ServersideQoLZDO sign) => sign.ZDO.GetBool("ModerWarehouse.AutoLabelManaged", false) && LinkedOrNearestContainer(sign, allContainers, markerRange2) == chest))
				{
					if (!item2.IsOwnerOrUnassigned())
					{
						item2.ClaimOwnership();
					}
					item2.ZDO.Set("ModerWarehouse.AutoLabelItem", string.Empty);
					vars = item2.Vars;
					((ZDOVars)(ref vars)).SetText("<color=white>-", "D:\\Schuerch Dropbox\\Andreas Schuerch\\Dokumente\\Codex\\ModerWarehouse\\src\\WarehousePlugin.cs", 962);
				}
				_pendingLabels.Remove(chest);
			}
			return num;
		}

		private static bool IsWarehouseItem(ItemData item)
		{
			if (item?.m_shared == null || item.m_cheated)
			{
				return false;
			}
			string text = item.m_shared.m_name ?? string.Empty;
			if (text.StartsWith("$item_", StringComparison.OrdinalIgnoreCase) || text.StartsWith("$animal_fish", StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			return string.Equals(((object)Unsafe.As<ItemType, ItemType>(ref item.m_shared.m_itemType)/*cast due to .constrained prefix*/).ToString(), "Trophy", StringComparison.OrdinalIgnoreCase);
		}

		private static string LocalizedItemName(ItemData item, string language)
		{
			string text = item?.m_shared?.m_name;
			Dictionary<string, string> dictionary = ((WarehouseLocalization.Resolve(language) == "de") ? GermanDisplayNames : EnglishDisplayNames);
			if (string.IsNullOrEmpty(text) || !dictionary.TryGetValue(text, out var value))
			{
				return ItemName(item);
			}
			return value;
		}

		private void ProcessRequest(string id, string language, Request request, ServersideQoLZDO outputZdo, List<ServersideQoLZDO> stores, ContainerRegistryProcessor registry, WarehouseStatsHistory stats, ref int moves)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrWhiteSpace(request.Payload) || IsStatus(request.Payload) || IsRequestPrompt(request.Payload) || request.Payload.StartsWith("SOLL ", StringComparison.OrdinalIgnoreCase) || string.Equals(request.Payload, request.Sign.ZDO.GetString("ModerWarehouse.RequestRenderedText", string.Empty), StringComparison.Ordinal))
			{
				return;
			}
			ZDOVars vars = outputZdo.Vars;
			if (((ZDOVars)(ref vars)).GetInUse(false))
			{
				return;
			}
			ContainerState state = registry.GetState(outputZdo);
			if (state == null || !Own(state))
			{
				return;
			}
			IInventory inventory = state.GetInventory();
			string[] array = (from x in request.Payload.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries)
				select x.Trim() into x
				where x.Length > 0
				select x).Take(10).ToArray();
			if (array.Length == 0)
			{
				WriteStatus(id, request.Sign, WarehouseLocalization.Text(language, "request.error_example"));
				return;
			}
			List<string> list = new List<string>();
			string[] array2 = array;
			foreach (string text in array2)
			{
				if (!TryParseRequest(text, out var query, out var amount))
				{
					list.Add(WarehouseLocalization.Format(language, "request.error", text));
				}
				else
				{
					list.Add(ProcessSingleRequest(id, language, query, amount, inventory, stores, registry, stats, ref moves));
				}
			}
			WriteStatus(id, request.Sign, string.Join("\n", list));
		}

		private string ProcessSingleRequest(string id, string language, string query, int amount, IInventory output, List<ServersideQoLZDO> stores, ContainerRegistryProcessor registry, WarehouseStatsHistory stats, ref int moves)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			int num = amount;
			int num2 = 0;
			string text = query;
			bool flag = false;
			foreach (ServersideQoLZDO store in stores)
			{
				if (moves <= 0 || num <= 0)
				{
					break;
				}
				ZDOVars vars = store.Vars;
				if (((ZDOVars)(ref vars)).GetInUse(false))
				{
					continue;
				}
				ContainerState state = registry.GetState(store);
				if (state == null || !Own(state))
				{
					continue;
				}
				IInventory inventory = state.GetInventory();
				foreach (ItemData item in inventory.Items.Where((ItemData x) => ItemMatchesQuery(x, query)).ToList())
				{
					if (moves <= 0 || num <= 0)
					{
						break;
					}
					flag = true;
					text = LocalizedItemName(item, language);
					int num3 = Move(inventory, output, item, num);
					if (num3 > 0)
					{
						num2 += num3;
						num -= num3;
						moves--;
						stats?.AddOutput(item.m_shared.m_name, num3);
					}
				}
			}
			string result = ((num2 == amount) ? WarehouseLocalization.Format(language, "request.done", text, num2) : ((num2 > 0) ? WarehouseLocalization.Format(language, "request.partial", text, num2, amount) : (flag ? WarehouseLocalization.Format(language, "request.output_full", text) : WarehouseLocalization.Format(language, "request.not_found", query))));
			((Processor)this).Logger.LogInfo((object)$"Warehouse '{id}': withdrawal '{query}' moved {num2}/{amount} item(s).");
			return result;
		}

		private static bool TryParseRequest(string payload, out string query, out int amount)
		{
			query = string.Empty;
			amount = 0;
			Match match = Regex.Match(payload.Replace("\r", string.Empty).Split(new char[1] { '\n' })[0].Trim(), "^(?<item>.+?)\\s+(?:x)?(?<amount>\\d+)$", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
			if (!match.Success || !int.TryParse(match.Groups["amount"].Value, NumberStyles.None, CultureInfo.InvariantCulture, out amount) || amount <= 0 || amount > 10000)
			{
				return false;
			}
			query = match.Groups["item"].Value.Trim();
			return query.Length > 0;
		}

		private static bool IsStatus(string payload)
		{
			string text = payload.TrimStart(Array.Empty<char>()).ToUpperInvariant();
			if (!text.StartsWith("FERTIG ") && !text.StartsWith("TEILWEISE ") && !text.StartsWith("AUSGABE VOLL ") && !text.StartsWith("NICHT GEFUNDEN ") && !text.StartsWith("FEHLER:") && !text.StartsWith("DONE ") && !text.StartsWith("PARTIAL ") && !text.StartsWith("OUTPUT FULL ") && !text.StartsWith("NOT FOUND "))
			{
				return text.StartsWith("ERROR:");
			}
			return true;
		}

		private static bool IsRequestPrompt(string payload)
		{
			string text = payload.Trim().ToUpperInvariant();
			if (!text.StartsWith("BESTELLUNG"))
			{
				return text.StartsWith("REQUEST");
			}
			return true;
		}

		private static void WriteRequestPrompt(ServersideQoLZDO sign, string id, string language)
		{
			string value = sign.ZDO.GetString("ModerWarehouse.RequestTargets", string.Empty);
			string text = WarehouseLocalization.Text(language, "request.example_item");
			string text2 = (string.IsNullOrWhiteSpace(value) ? ("<color=#80ffff>" + WarehouseLocalization.Text(language, "request.title") + "\n<color=white>" + text + " 100\n" + WarehouseLocalization.Text(language, "request.target") + " " + text + " 1000") : ("<color=#80ffff>" + WarehouseLocalization.Text(language, "request.title") + "\n<color=white>" + WarehouseLocalization.Text(language, "request.updating")));
			WriteRequestText(sign, text2);
		}

		private static void WriteRequestText(ServersideQoLZDO sign, string text)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			string text2 = PlainText(text).Trim();
			sign.ZDO.Set("ModerWarehouse.RequestRenderedText", text2);
			ZDOVars vars = sign.Vars;
			if (!string.Equals(((ZDOVars)(ref vars)).GetText(""), text, StringComparison.Ordinal))
			{
				if (!sign.IsOwnerOrUnassigned())
				{
					sign.ClaimOwnership();
				}
				vars = sign.Vars;
				((ZDOVars)(ref vars)).SetText(text, "D:\\Schuerch Dropbox\\Andreas Schuerch\\Dokumente\\Codex\\ModerWarehouse\\src\\WarehousePlugin.cs", 1118);
			}
		}

		private static void WriteStatus(string id, ServersideQoLZDO sign, string status)
		{
			//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)
			if (!sign.IsOwnerOrUnassigned())
			{
				sign.ClaimOwnership();
			}
			string text = "<color=white>" + status;
			sign.ZDO.Set("ModerWarehouse.RequestRenderedText", PlainText(text).Trim());
			ZDOVars vars = sign.Vars;
			((ZDOVars)(ref vars)).SetText(text, "D:\\Schuerch Dropbox\\Andreas Schuerch\\Dokumente\\Codex\\ModerWarehouse\\src\\WarehousePlugin.cs", 1126);
		}

		private static bool TryParseTargets(string payload, out Dictionary<string, int> targets)
		{
			targets = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
			foreach (string item in (from x in (payload ?? string.Empty).Split(new char[4] { ',', ';', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries)
				select x.Trim() into x
				where x.Length > 0
				select x).Take(20))
			{
				if (!TryParseRequest(item, out var query, out var amount))
				{
					return false;
				}
				targets[query] = amount;
			}
			return targets.Count > 0;
		}

		private static string SerializeTargets(Dictionary<string, int> targets)
		{
			return string.Join("\n", targets.Select((KeyValuePair<string, int> x) => x.Key + "\t" + x.Value.ToString(CultureInfo.InvariantCulture)));
		}

		private static Dictionary<string, int> DeserializeTargets(string value)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
			string[] array = (value ?? string.Empty).Split(new char[1] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { '\t' });
				if (array2.Length == 2 && int.TryParse(array2[1], NumberStyles.None, CultureInfo.InvariantCulture, out var result) && result > 0)
				{
					dictionary[array2[0]] = result;
				}
			}
			return dictionary;
		}

		private void EnsureHelpSign(ServersideQoLZDO inputSign, string id, string language)
		{
			//IL_0109: 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_0196: 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_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			string group = inputSign.ZDO.GetString("ModerWarehouse.HelpGroup", string.Empty);
			if (string.IsNullOrWhiteSpace(group))
			{
				group = Guid.NewGuid().ToString("N");
				inputSign.ZDO.Set("ModerWarehouse.HelpGroup", group);
			}
			ServersideQoLZDO val = ((IEnumerable<ServersideQoLZDO>)_signs).FirstOrDefault((Func<ServersideQoLZDO, bool>)((ServersideQoLZDO sign) => sign.ZDO.GetBool("ModerWarehouse.HelpChild", false) && sign.ZDO.GetString("ModerWarehouse.HelpGroup", string.Empty) == group));
			string text = "<size=70%><color=#80ffff>" + WarehouseLocalization.Text(language, "help.title") + "\n<color=white>" + WarehouseLocalization.Text(language, "help.in") + "\n" + WarehouseLocalization.Text(language, "help.req") + "\n" + WarehouseLocalization.Text(language, "help.out") + "\n" + WarehouseLocalization.Text(language, "help.board");
			ZDOVars vars;
			DateTime value;
			if (val != null)
			{
				_helpPendingAt.Remove(inputSign);
				vars = val.Vars;
				if (!string.Equals(((ZDOVars)(ref vars)).GetText(""), text, StringComparison.Ordinal))
				{
					if (!val.IsOwnerOrUnassigned())
					{
						val.ClaimOwnership();
					}
					vars = val.Vars;
					((ZDOVars)(ref vars)).SetText(text, "D:\\Schuerch Dropbox\\Andreas Schuerch\\Dokumente\\Codex\\ModerWarehouse\\src\\WarehousePlugin.cs", 1181);
				}
			}
			else if (!_helpPendingAt.TryGetValue(inputSign, out value))
			{
				_helpPendingAt[inputSign] = DateTime.UtcNow;
			}
			else
			{
				if ((DateTime.UtcNow - value).TotalSeconds < 5.0)
				{
					return;
				}
				Quaternion rotation = inputSign.ZDO.GetRotation();
				Vector3 val2 = inputSign.ZDO.GetPosition() + rotation * new Vector3(1.2f, 0f, 0f);
				ServersideQoLZDO val3 = ((Processor)this).PlacePiece(val2, Prefabs.Sign, rotation, (CreatorMarkers)2);
				if (val3 == null)
				{
					return;
				}
				val3.Fields<Piece>().Set((Func<Expression<Func<Piece, bool>>>)(() => (Piece x) => x.m_canBeRemoved), true, "D:\\Schuerch Dropbox\\Andreas Schuerch\\Dokumente\\Codex\\ModerWarehouse\\src\\WarehousePlugin.cs", 1198);
				val3.ZDO.Set("ModerWarehouse.HelpGroup", group);
				val3.ZDO.Set("ModerWarehouse.HelpChild", true);
				vars = val3.Vars;
				((ZDOVars)(ref vars)).SetText(text, "D:\\Schuerch Dropbox\\Andreas Schuerch\\Dokumente\\Codex\\ModerWarehouse\\src\\WarehousePlugin.cs", 1201);
				if (_signs.Add(val3))
				{
					val3.Destroyed += delegate(ServersideQoLZDO destroyed)
					{
						_signs.Remove(destroyed);
					};
				}
				_helpPendingAt.Remove(inputSign);
				((Processor)this).Logger.LogInfo((object)("Warehouse '" + id + "': created automatic help sign left of IN marker."));
			}
		}

		private void EnsureBoard(ServersideQoLZDO anchor, string id)
		{
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: 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_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: 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_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0371: Unknown result type (might be due to invalid IL or missing references)
			//IL_0376: Unknown result type (might be due to invalid IL or missing references)
			string group = anchor.ZDO.GetString("ModerWarehouse.BoardGroup", string.Empty);
			if (string.IsNullOrWhiteSpace(group))
			{
				return;
			}
			if (!_boardReadyGroups.Contains(group))
			{
				if (!_boardEnsurePendingAt.TryGetValue(group, out var value))
				{
					_boardEnsurePendingAt[group] = DateTime.UtcNow;
					return;
				}
				if ((DateTime.UtcNow - value).TotalSeconds < 5.0)
				{
					return;
				}
				_boardEnsurePendingAt.Remove(group);
				_boardReadyGroups.Add(group);
			}
			List<ServersideQoLZDO> source = _signs.Where((ServersideQoLZDO x) => x.ZDO.GetString("ModerWarehouse.BoardGroup", string.Empty) == group).ToList();
			int num = 0;
			foreach (IGrouping<int, ServersideQoLZDO> item in from x in source
				group x by x.ZDO.GetInt("ModerWarehouse.BoardCell", -1))
			{
				ServersideQoLZDO keep = ((item.Key == 12 && item.Contains(anchor)) ? anchor : item.First());
				foreach (ServersideQoLZDO item2 in item.Where((ServersideQoLZDO x) => x != keep).ToList())
				{
					_signs.Remove(item2);
					item2.Destroy();
					num++;
				}
			}
			if (num > 0)
			{
				((Processor)this).Logger.LogInfo((object)$"Warehouse '{id}': removed {num} duplicate stock-board sign layer(s) from '{group}'.");
			}
			Dictionary<int, ServersideQoLZDO> dictionary = (from x in _signs
				where x.ZDO.GetString("ModerWarehouse.BoardGroup", string.Empty) == @group
				group x by x.ZDO.GetInt("ModerWarehouse.BoardCell", -1)).ToDictionary((IGrouping<int, ServersideQoLZDO> x) => x.Key, (IGrouping<int, ServersideQoLZDO> x) => x.First());
			Quaternion rotation = anchor.ZDO.GetRotation();
			Vector3 position = anchor.ZDO.GetPosition();
			int num2 = 0;
			for (int num3 = 0; num3 < 16; num3++)
			{
				if (num3 == 12 || dictionary.ContainsKey(num3))
				{
					continue;
				}
				int num4 = num3 % 4;
				int num5 = num3 / 4;
				Vector3 val = position + rotation * new Vector3((float)num4 * -1.12f, (float)(3 - num5) * 0.5f, 0f);
				ServersideQoLZDO val2 = ((Processor)this).PlacePiece(val, Prefabs.Sign, rotation, (CreatorMarkers)2);
				if (val2 == null)
				{
					continue;
				}
				val2.Fields<Piece>().Set((Func<Expression<Func<Piece, bool>>>)(() => (Piece x) => x.m_canBeRemoved), true, "D:\\Schuerch Dropbox\\Andreas Schuerch\\Dokumente\\Codex\\ModerWarehouse\\src\\WarehousePlugin.cs", 1259);
				val2.ZDO.Set("ModerWarehouse.BoardWarehouse", id);
				val2.ZDO.Set("ModerWarehouse.BoardGroup", group);
				val2.ZDO.Set("ModerWarehouse.BoardCell", num3);
				ZDOVars vars = val2.Vars;
				((ZDOVars)(ref vars)).SetText("<color=white>...", "D:\\Schuerch Dropbox\\Andreas Schuerch\\Dokumente\\Codex\\ModerWarehouse\\src\\WarehousePlugin.cs", 1263);
				if (_signs.Add(val2))
				{
					val2.Destroyed += delegate(ServersideQoLZDO destroyed)
					{
						_signs.Remove(destroyed);
					};
				}
				num2++;
			}
			if (num2 > 0)
			{
				((Processor)this).Logger.LogInfo((object)$"Warehouse '{id}': created {num2} sign(s) for 4x4 stock board '{group}'.");
			}
		}

		private void EnsureStatsBoard(ServersideQoLZDO anchor, string id)
		{
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: 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_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: 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_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0390: Unknown result type (might be due to invalid IL or missing references)
			//IL_0395: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
			string group = anchor.ZDO.GetString("ModerWarehouse.StatsGroup", string.Empty);
			if (string.IsNullOrWhiteSpace(group))
			{
				return;
			}
			if (!_statsReadyGroups.Contains(group))
			{
				if (!_statsEnsurePendingAt.TryGetValue(group, out var value))
				{
					_statsEnsurePendingAt[group] = DateTime.UtcNow;
					return;
				}
				if ((DateTime.UtcNow - value).TotalSeconds < 5.0)
				{
					return;
				}
				_statsEnsurePendingAt.Remove(group);
				_statsReadyGroups.Add(group);
			}
			Dictionary<int, ServersideQoLZDO> dictionary = (from x in _signs
				where x.ZDO.GetString("ModerWarehouse.StatsGroup", string.Empty) == @group
				group x by x.ZDO.GetInt("ModerWarehouse.StatsCell", -1)).ToDictionary((IGrouping<int, ServersideQoLZDO> x) => x.Key, (IGrouping<int, ServersideQoLZDO> x) => x.First());
			Quaternion rotation = anchor.ZDO.GetRotation();
			Vector3 position = anchor.ZDO.GetPosition();
			int num = 0;
			ZDOVars vars;
			for (int num2 = 0; num2 < 16; num2++)
			{
				if (num2 == 12 || dictionary.ContainsKey(num2))
				{
					continue;
				}
				int num3 = num2 % 4;
				int num4 = num2 / 4;
				Vector3 val = position + rotation * new Vector3((float)num3 * -1.02f, (float)(3 - num4) * 0.5f, 0f);
				ServersideQoLZDO val2 = ((Processor)this).PlacePiece(val, Prefabs.Sign, rotation, (CreatorMarkers)2);
				if (val2 == null)
				{
					continue;
				}
				val2.Fields<Piece>().Set((Func<Expression<Func<Piece, bool>>>)(() => (Piece x) => x.m_canBeRemoved), true, "D:\\Schuerch Dropbox\\Andreas Schuerch\\Dokumente\\Codex\\ModerWarehouse\\src\\WarehousePlugin.cs", 1302);
				val2.ZDO.Set("ModerWarehouse.StatsWarehouse", id);
				val2.ZDO.Set("ModerWarehouse.StatsGroup", group);
				val2.ZDO.Set("ModerWarehouse.StatsCell", num2);
				vars = val2.Vars;
				((ZDOVars)(ref vars)).SetText("<color=white>...", "D:\\Schuerch Dropbox\\Andreas Schuerch\\Dokumente\\Codex\\ModerWarehouse\\src\\WarehousePlugin.cs", 1306);
				if (_signs.Add(val2))
				{
					val2.Destroyed += delegate(ServersideQoLZDO destroyed)
					{
						_signs.Remove(destroyed);
					};
				}
				num++;
			}
			if (!dictionary.Values.Any((ServersideQoLZDO x) => x.ZDO.GetBool("ModerWarehouse.StatsControl", false)))
			{
				Vector3 val3 = position + rotation * new Vector3(-1.53f, -0.55f, 0f);
				ServersideQoLZDO val4 = ((Processor)this).PlacePiece(val3, Prefabs.Sign, rotation, (CreatorMarkers)2);
				if (val4 != null)
				{
					val4.Fields<Piece>().Set((Func<Expression<Func<Piece, bool>>>)(() => (Piece x) => x.m_canBeRemoved), true, "D:\\Schuerch Dropbox\\Andreas Schuerch\\Dokumente\\Codex\\ModerWarehouse\\src\\WarehousePlugin.cs", 1317);
					val4.ZDO.Set("ModerWarehouse.StatsWarehouse", id);
					val4.ZDO.Set("ModerWarehouse.StatsGroup", group);
					val4.ZDO.Set("ModerWarehouse.StatsCell", -2);
					val4.ZDO.Set("ModerWarehouse.StatsControl", true);
					vars = val4.Vars;
					((ZDOVars)(ref vars)).SetText("<color=#80ffff>CONTROL\n<color=white>E: 1-90 AUTO", "D:\\Schuerch Dropbox\\Andreas Schuerch\\Dokumente\\Codex\\ModerWarehouse\\src\\WarehousePlugin.cs", 1322);
					ZDO zDO = val4.ZDO;
					vars = val4.Vars;
					zDO.Set("ModerWarehouse.BoardRenderedText", PlainText(((ZDOVars)(ref vars)).GetText("")).Trim());
					if (_signs.Add(val4))
					{
						val4.Destroyed += delegate(ServersideQoLZDO destroyed)
						{
							_signs.Remove(destroyed);
						};
					}
					num++;
				}
			}
			if (num > 0)
			{
				((Processor)this).Logger.LogInfo((object)$"Warehouse '{id}': created {num} sign/control(s) for 4x4 statistics board '{group}'.");
			}
		}

		private void CaptureBoardControlInput(ServersideQoLZDO sign, string group, int cell)
		{
			//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)
			if (string.IsNullOrWhiteSpace(group) || (cell != 1 && cell != 2))
			{
				return;
			}
			string text = sign.ZDO.GetString("ModerWarehouse.BoardRenderedText", string.Empty);
			if (string.IsNullOrEmpty(text))
			{
				return;
			}
			ZDOVars vars = sign.Vars;
			string text2 = PlainText(((ZDOVars)(ref vars)).GetText("")).Trim();
			if (string.Equals(text2, text, StringComparison.Ordinal))
			{
				return;
			}
			string text3 = text2;
			int num = text3.LastIndexOf('\n');
			if (num >= 0)
			{
				text3 = text3.Substring(num + 1);
			}
			text3 = text3.Trim();
			if (string.IsNullOrWhiteSpace(text3) || text3.Equals("AUTO", StringComparison.OrdinalIgnoreCase))
			{
				_boardControls.Remove(group);
				((Processor)this).Logger.LogInfo((object)("Stock board '" + group + "': returned to automatic rotation."));
				return;
			}
			if (!_boardControls.TryGetValue(group, out var value))
			{
				value = new BoardControl();
			}
			if (cell == 1)
			{
				value.Prefix = text3;
				value.Page = null;
			}
			else
			{
				Match match = Regex.Match(text3, "\\d+");
				if (!match.Success || !int.TryParse(match.Value, out var result))
				{
					return;
				}
				value.Page = Math.Max(1, result);
			}
			value.ChangedAt = DateTime.UtcNow;
			_boardControls[group] = value;
			((Processor)this).Logger.LogInfo((object)("Stock board '" + group + "': filter='" + (value.Prefix ?? "ALLE") + "', page=" + (value.Page.HasValue ? value.Page.Value.ToString() : "1") + " for 60 seconds."));
		}

		private void WriteShoppingLists(string id, string language, IEnumerable<ServersideQoLZDO> requestSigns, List<ServersideQoLZDO> stores, ContainerRegistryProcessor registry)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			List<ItemData> items = (from item in stores.SelectMany(delegate(ServersideQoLZDO store)
				{
					ContainerState state = registry.GetState(store);
					object obj;
					if (state == null)
					{
						obj = null;
					}
					else
					{
						IInventory inventory = state.GetInventory();
						obj = ((inventory != null) ? inventory.Items : null);
					}
					IEnumerable<ItemData> enumerable = (IEnumerable<ItemData>)obj;
					return enumerable ?? Enumerable.Empty<ItemData>();
				})
				where item != null && item.m_stack > 0 && item.m_shared != null
				select item).ToList();
			foreach (ServersideQoLZDO item in requestSigns.Distinct())
			{
				Dictionary<string, int> dictionary = DeserializeTargets(item.ZDO.GetString("ModerWarehouse.RequestTargets", string.Empty));
				if (dictionary.Count == 0)
				{
					continue;
				}
				ZDOVars vars = item.Vars;
				string text = PlainText(((ZDOVars)(ref vars)).GetText("")).Trim();
				string b = item.ZDO.GetString("ModerWarehouse.RequestRenderedText", string.Empty);
				bool flag = text.StartsWith("SOLL ", StringComparison.OrdinalIgnoreCase) || text.StartsWith("TARGET ", StringComparison.OrdinalIgnoreCase);
				if ((!string.Equals(text, b, StringComparison.Ordinal) && !flag) || IsStatus(text))
				{
					continue;
				}
				List<TargetStatus> list = (from x in dictionary.Select(delegate(KeyValuePair<string, int> target)
					{
						int current3 = items.Where((ItemData item) => ItemMatchesQuery(item, target.Key)).Sum((ItemData item) => item.m_stack);