Decompiled source of BudylivProduction v1.2.0

plugins/BudylivProduction.dll

Decompiled an hour ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BudylivProduction
{
	internal static class ClientLinker
	{
		internal sealed class Links
		{
			public List<ZDOID>[] Lists;

			public float At;

			public int Total => Lists[0].Count + Lists[1].Count + Lists[2].Count;

			public int Count(LinkRole role)
			{
				return Lists[(int)role].Count;
			}
		}

		private const float SelectionSeconds = 30f;

		private const float LinksTtl = 5f;

		private const float LinksRequestGap = 2f;

		private static ZDOID _station = ZDOID.None;

		private static LinkRole _role;

		private static bool _unlink;

		private static float _selectedAt;

		private static bool _captured;

		private static readonly Dictionary<ZDOID, Links> StationCache = new Dictionary<ZDOID, Links>();

		private static readonly Dictionary<ZDOID, float> StationRequested = new Dictionary<ZDOID, float>();

		private static readonly Dictionary<ZDOID, Links> ChestCache = new Dictionary<ZDOID, Links>();

		private static readonly Dictionary<ZDOID, float> ChestRequested = new Dictionary<ZDOID, float>();

		private const float NearRefreshSeconds = 3f;

		internal static List<(ZDOID Station, List<ZDOID>[] Lists)> NearLinks = new List<(ZDOID, List<ZDOID>[])>();

		private static float _nearRequested = -1000f;

		internal static bool AltHeld
		{
			get
			{
				if (!Input.GetKey((KeyCode)308))
				{
					return Input.GetKey((KeyCode)307);
				}
				return true;
			}
		}

		private static bool ShiftHeld
		{
			get
			{
				if (!Input.GetKey((KeyCode)304))
				{
					return Input.GetKey((KeyCode)303);
				}
				return true;
			}
		}

		private static bool CtrlHeld
		{
			get
			{
				if (!Input.GetKey((KeyCode)306))
				{
					return Input.GetKey((KeyCode)305);
				}
				return true;
			}
		}

		private static bool SelectionActive
		{
			get
			{
				if (!((ZDOID)(ref _station)).IsNone())
				{
					return Time.time - _selectedAt <= 30f;
				}
				return false;
			}
		}

		internal static bool GesturesAllowed
		{
			get
			{
				if (AltHeld && !CtrlHeld)
				{
					return !IsTyping();
				}
				return false;
			}
		}

		internal static bool ShowAll { get; private set; }

		internal static void SetNearLinks(List<(ZDOID Station, List<ZDOID>[] Lists)> stations)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			NearLinks = stations;
			foreach (var station in stations)
			{
				SetLinks(chest: false, station.Station, station.Lists);
			}
		}

		private unsafe static void UpdateShowAll()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			if (!IsTyping())
			{
				KeyboardShortcut value = Plugin.ShowAllLinksKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					ShowAll = !ShowAll;
					string text;
					if (!ShowAll)
					{
						text = L.T("msg.show_all_off");
					}
					else
					{
						object[] array = new object[1];
						value = Plugin.ShowAllLinksKey.Value;
						array[0] = ((object)(*(KeyboardShortcut*)(&value))/*cast due to .constrained prefix*/).ToString();
						text = L.T("msg.show_all_on", array);
					}
					Show(text);
					_nearRequested = -1000f;
					if (!ShowAll)
					{
						NearLinks = new List<(ZDOID, List<ZDOID>[])>();
					}
				}
			}
			if (ShowAll && Time.time - _nearRequested >= 3f)
			{
				_nearRequested = Time.time;
				Net.SendRequest(LinkOp.NearInfo, ZDOID.None, ZDOID.None, LinkRole.Input);
			}
		}

		internal static void Update()
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			UpdateShowAll();
			if (_captured && !Input.GetKey((KeyCode)323) && !Input.GetKey((KeyCode)324) && !Input.GetKey((KeyCode)325))
			{
				_captured = false;
			}
			if (!GesturesAllowed)
			{
				return;
			}
			bool keyDown = Input.GetKeyDown((KeyCode)323);
			bool keyDown2 = Input.GetKeyDown((KeyCode)324);
			bool keyDown3 = Input.GetKeyDown((KeyCode)325);
			if ((keyDown ? 1 : 0) + (keyDown2 ? 1 : 0) + (keyDown3 ? 1 : 0) != 1)
			{
				return;
			}
			StationInfo info;
			bool fuelControl;
			Container container;
			ZNetView val = HoverTarget(out info, out fuelControl, out container);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			_captured = true;
			bool shiftHeld = ShiftHeld;
			ZDOID uid = val.GetZDO().m_uid;
			if (keyDown3)
			{
				if (!shiftHeld)
				{
					Show(L.T((info != null) ? "msg.wheel_station" : "msg.wheel_chest", L.T("btn.wheel")));
					return;
				}
				if (info != null)
				{
					Net.SendRequest(LinkOp.UnlinkAll, uid, ZDOID.None, LinkRole.Input);
					if (_station == uid)
					{
						_station = ZDOID.None;
					}
				}
				else
				{
					Net.SendRequest(LinkOp.ChestUnlinkAll, ZDOID.None, uid, LinkRole.Input);
				}
				ForgetLinks();
			}
			else if (info != null)
			{
				LinkRole? linkRole = ((!keyDown2) ? Stations.LeftRole(info, fuelControl) : (info.HasOutput ? new LinkRole?(LinkRole.Output) : ((LinkRole?)null)));
				if (!linkRole.HasValue)
				{
					Show(L.T(keyDown2 ? "msg.no_output" : "msg.no_input"));
					return;
				}
				_station = uid;
				_role = linkRole.Value;
				_unlink = shiftHeld;
				_selectedAt = Time.time;
				Show(L.T(_unlink ? "msg.unlinking" : "msg.linking", RoleName(_role), Button(_role)));
			}
			else
			{
				if (!((Object)(object)container != (Object)null))
				{
					return;
				}
				if (!SelectionActive)
				{
					Show(L.T("msg.pick_station", L.T("btn.left"), L.T("btn.right")));
					return;
				}
				bool flag = _role == LinkRole.Output;
				if (keyDown2 != flag || shiftHeld != _unlink)
				{
					Show(L.T("msg.wrong_button", RoleName(_role), (_unlink ? "Shift+" : "") + "Alt+" + Button(_role)));
				}
				else
				{
					Net.SendRequest((!_unlink) ? LinkOp.Link : LinkOp.Unlink, _station, uid, _role);
					ForgetLinks();
					_station = ZDOID.None;
				}
			}
		}

		internal static bool ShouldSuppressCombat()
		{
			if (_captured)
			{
				return true;
			}
			if (!GesturesAllowed)
			{
				return false;
			}
			StationInfo info;
			bool fuelControl;
			Container container;
			return (Object)(object)HoverTarget(out info, out fuelControl, out container) != (Object)null;
		}

		internal static void Show(string text)
		{
			if ((Object)(object)MessageHud.instance != (Object)null)
			{
				MessageHud.instance.ShowMessage((MessageType)2, text, 0, (Sprite)null, false, true);
			}
		}

		internal static void SetLinks(bool chest, ZDOID id, List<ZDOID>[] lists)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			(chest ? ChestCache : StationCache)[id] = new Links
			{
				Lists = lists,
				At = Time.time
			};
		}

		private static void ForgetLinks()
		{
			_nearRequested = -1000f;
			StationCache.Clear();
			ChestCache.Clear();
			StationRequested.Clear();
			ChestRequested.Clear();
		}

		internal static Links StationLinks(ZDOID id)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			return Cached(StationCache, StationRequested, id, chest: false);
		}

		internal static Links ChestLinks(ZDOID id)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			return Cached(ChestCache, ChestRequested, id, chest: true);
		}

		private static Links Cached(Dictionary<ZDOID, Links> cache, Dictionary<ZDOID, float> requested, ZDOID id, bool chest)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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)
			cache.TryGetValue(id, out var value);
			if ((value == null || Time.time - value.At > 5f) && (!requested.TryGetValue(id, out var value2) || Time.time - value2 > 2f))
			{
				requested[id] = Time.time;
				if (chest)
				{
					Net.SendRequest(LinkOp.ChestInfo, ZDOID.None, id, LinkRole.Input);
				}
				else
				{
					Net.SendRequest(LinkOp.Info, id, ZDOID.None, LinkRole.Input);
				}
			}
			return value;
		}

		internal static string StationHint(GameObject hovered)
		{
			//IL_0020: 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_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_032b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0330: Unknown result type (might be due to invalid IL or missing references)
			StationInfo info;
			bool fuelControl;
			ZNetView val = Stations.FindStation(hovered, out info, out fuelControl);
			if ((Object)(object)val == (Object)null)
			{
				return "";
			}
			ZDOID uid = val.GetZDO().m_uid;
			string text = "";
			LinkRole? linkRole = Stations.LeftRole(info, fuelControl);
			if (linkRole.HasValue)
			{
				text = text + "\n" + Key("Alt+" + L.T("btn.left")) + " " + L.T((linkRole.Value == LinkRole.Fuel) ? "hint.link.fuel" : "hint.link.input");
			}
			if (info.HasOutput)
			{
				text = text + "\n" + Key("Alt+" + L.T("btn.right")) + " " + L.T("hint.link.output");
			}
			text = text + "\n" + Key("Shift+Alt+" + L.T("btn.left") + "/" + L.T("btn.right")) + " " + L.T("hint.unlink");
			text = text + "\n" + Key("Shift+Alt+" + L.T("btn.wheel")) + " " + L.T("hint.unlink_all");
			text = text + "\n" + Key(((object)Plugin.ShowAllLinksKey.Value/*cast due to .constrained prefix*/).ToString()) + " " + L.T(ShowAll ? "hint.hide_all" : "hint.show_all");
			Links links = StationLinks(uid);
			if (links != null)
			{
				List<string> list = new List<string>();
				if (info.HasInput)
				{
					list.Add($"{RoleName(LinkRole.Input)} {links.Count(LinkRole.Input)}");
				}
				if (info.HasFuel)
				{
					list.Add($"{RoleName(LinkRole.Fuel)} {links.Count(LinkRole.Fuel)}");
				}
				if (info.HasOutput)
				{
					list.Add($"{RoleName(LinkRole.Output)} {links.Count(LinkRole.Output)}");
				}
				text = text + "\n" + L.T("hint.chests", string.Join(" · ", list));
				if (links.Total > 0 && !AltHeld && !ShowAll)
				{
					text = text + "  <color=#aaaaaa>" + L.T("hint.alt_show") + "</color>";
				}
			}
			if (SelectionActive && _station == uid)
			{
				text = text + "\n<color=orange>" + L.T(_unlink ? "hint.selected_unlink" : "hint.selected_link", RoleName(_role)) + "</color>";
			}
			return text;
		}

		internal static string ContainerHint(Container container)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			string text = "";
			ZNetView val = ValidView((Component)(object)container);
			if ((Object)(object)val != (Object)null)
			{
				Links links = ChestLinks(val.GetZDO().m_uid);
				if (links != null && links.Total > 0)
				{
					List<string> list = new List<string>();
					LinkRole[] array = new LinkRole[3]
					{
						LinkRole.Input,
						LinkRole.Fuel,
						LinkRole.Output
					};
					foreach (LinkRole role in array)
					{
						if (links.Count(role) > 0)
						{
							list.Add($"{RoleName(role)} {links.Count(role)}");
						}
					}
					text = text + "\n" + L.T("hint.chest_stations", string.Join(" · ", list));
					if (!AltHeld && !ShowAll)
					{
						text = text + "  <color=#aaaaaa>" + L.T("hint.alt_show") + "</color>";
					}
					text = text + "\n" + Key("Shift+Alt+" + L.T("btn.wheel")) + " " + L.T("hint.chest_unlink_all");
				}
			}
			if (SelectionActive)
			{
				text = text + "\n" + Key((_unlink ? "Shift+" : "") + "Alt+" + Button(_role)) + " " + L.T(_unlink ? "hint.chest_unlink_as" : "hint.chest_link_as", RoleName(_role));
			}
			return text;
		}

		internal static string RoleName(LinkRole role)
		{
			return L.Role(role);
		}

		private static string Button(LinkRole role)
		{
			return L.T((role == LinkRole.Output) ? "btn.right" : "btn.left");
		}

		private static string Key(string key)
		{
			return "[<color=yellow><b>" + key + "</b></color>]";
		}

		internal static ZNetView HoverTarget(out StationInfo info, out bool fuelControl, out Container container)
		{
			info = null;
			fuelControl = false;
			container = null;
			Player localPlayer = Player.m_localPlayer;
			GameObject val = (((Object)(object)localPlayer != (Object)null) ? ((Humanoid)localPlayer).GetHoverObject() : null);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			ZNetView val2 = Stations.FindStation(val, out info, out fuelControl);
			if ((Object)(object)val2 != (Object)null)
			{
				return val2;
			}
			container = val.GetComponentInParent<Container>();
			if ((Object)(object)container == (Object)null)
			{
				return null;
			}
			ZNetView val3 = ValidView((Component)(object)container);
			if (!((Object)(object)val3 == (Object)null))
			{
				GameObject prefab = ZNetScene.instance.GetPrefab(val3.GetZDO().GetPrefab());
				if (!((Object)(object)((prefab != null) ? prefab.GetComponent<Container>() : null) == (Object)null))
				{
					return val3;
				}
			}
			container = null;
			return null;
		}

		private static ZNetView ValidView(Component component)
		{
			ZNetView componentInParent = component.GetComponentInParent<ZNetView>();
			if (!((Object)(object)componentInParent != (Object)null) || !componentInParent.IsValid())
			{
				return null;
			}
			return componentInParent;
		}

		internal static bool IsTyping()
		{
			if ((!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !Menu.IsVisible() && !InventoryGui.IsVisible() && !TextInput.IsVisible())
			{
				return Minimap.IsOpen();
			}
			return true;
		}
	}
	[HarmonyPatch]
	internal static class Station_GetHoverText_Patch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			Type[] array = new Type[9]
			{
				typeof(Switch),
				typeof(Fireplace),
				typeof(Beehive),
				typeof(SapCollector),
				typeof(Fermenter),
				typeof(CookingStation),
				typeof(ShieldGenerator),
				typeof(Turret),
				typeof(WispSpawner)
			};
			for (int i = 0; i < array.Length; i++)
			{
				MethodInfo methodInfo = AccessTools.Method(array[i], "GetHoverText", Type.EmptyTypes, (Type[])null);
				if (methodInfo != null)
				{
					yield return methodInfo;
				}
			}
		}

		[HarmonyPriority(0)]
		[HarmonyAfter(new string[] { "shudnal.MyLittleUI" })]
		private static void Postfix(Component __instance, ref string __result)
		{
			if (Plugin.ShowControlHints.Value && !((Object)(object)ZNet.instance == (Object)null) && !((Object)(object)__instance == (Object)null) && !string.IsNullOrEmpty(__result))
			{
				__result += ClientLinker.StationHint(__instance.gameObject);
			}
		}
	}
	[HarmonyPatch(typeof(Container), "GetHoverText")]
	internal static class Container_GetHoverText_Patch
	{
		[HarmonyPriority(0)]
		[HarmonyAfter(new string[] { "shudnal.MyLittleUI" })]
		private static void Postfix(Container __instance, ref string __result)
		{
			if (Plugin.ShowControlHints.Value && (Object)(object)ZNet.instance != (Object)null)
			{
				__result += ClientLinker.ContainerHint(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "SetControls")]
	internal static class Player_SetControls_Patch
	{
		private static void Prefix(Player __instance, ref bool attack, ref bool attackHold, ref bool secondaryAttack, ref bool secondaryAttackHold, ref bool block, ref bool blockHold)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && ClientLinker.ShouldSuppressCombat())
			{
				attack = (attackHold = (secondaryAttack = (secondaryAttackHold = (block = (blockHold = false)))));
			}
		}
	}
	internal sealed class StationLinks
	{
		public ZDOID Station;

		public readonly List<ZDOID>[] Chests = new List<ZDOID>[3]
		{
			new List<ZDOID>(),
			new List<ZDOID>(),
			new List<ZDOID>()
		};

		public bool IsEmpty => Chests.All((List<ZDOID> c) => c.Count == 0);

		public List<ZDOID> Of(LinkRole role)
		{
			return Chests[(int)role];
		}
	}
	internal static class LinkStore
	{
		private const string HeaderV1 = "# Budyliv Production links v1";

		private const string HeaderV2 = "# Budyliv Production links v2";

		internal static readonly Dictionary<ZDOID, StationLinks> All = new Dictionary<ZDOID, StationLinks>();

		private static readonly Dictionary<ZDOID, ObjKey> Keys = new Dictionary<ZDOID, ObjKey>();

		private static readonly List<string> Unresolved = new List<string>();

		private static string _path;

		private static bool _dirty;

		internal static bool Loaded => _path != null;

		internal static int UnresolvedCount => Unresolved.Count;

		internal static void Load(string worldName)
		{
			All.Clear();
			Keys.Clear();
			Unresolved.Clear();
			_dirty = false;
			_path = Path.Combine(Path.Combine(Utils.GetSaveDataPath((FileSource)2), "worlds_local"), worldName + ".budylivproduction.txt");
			if (!File.Exists(_path))
			{
				Plugin.Log.LogInfo((object)("No link file yet: " + _path));
				return;
			}
			string[] array = File.ReadAllLines(_path);
			if (array.Length != 0 && array[0].Trim() == "# Budyliv Production links v1")
			{
				string text = _path + ".v1.bak";
				File.Copy(_path, text, overwrite: true);
				Plugin.Log.LogWarning((object)$"Link file is v1 (ZDOIDs, not stable across restarts): {array.Length - 1} lines moved to {text}; links must be made again.");
				_dirty = true;
				return;
			}
			int num = 0;
			string[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				string text2 = array2[i].Trim();
				if (text2.Length == 0 || text2.StartsWith("#"))
				{
					continue;
				}
				bool? flag = TryResolve(text2);
				if (flag.HasValue)
				{
					if (flag == true)
					{
						num++;
					}
					else
					{
						Unresolved.Add(text2);
					}
				}
				else
				{
					Plugin.Log.LogWarning((object)("Skipping bad link line: " + text2));
				}
			}
			_dirty = false;
			Plugin.Log.LogInfo((object)($"Loaded {num} links for {All.Count} stations from {_path}" + ((Unresolved.Count > 0) ? $"; {Unresolved.Count} links point to objects not found (kept, retried)" : "")));
		}

		private static bool? TryResolve(string line)
		{
			string[] array = line.Split('\t');
			if (array.Length != 3 || !ObjKey.TryParse(array[0], out var key) || !ObjKey.TryParse(array[2], out var key2) || !int.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || result < 0 || result > 2)
			{
				return null;
			}
			ZDO val = Zdos.Find(key);
			ZDO val2 = Zdos.Find(key2);
			if (val == null || val2 == null)
			{
				return false;
			}
			Add(val, (LinkRole)result, val2);
			return true;
		}

		internal static void RetryUnresolved()
		{
			if (Unresolved.Count == 0)
			{
				return;
			}
			int num = 0;
			foreach (string item in Unresolved.ToList())
			{
				if (TryResolve(item) != false)
				{
					Unresolved.Remove(item);
					num++;
					_dirty = true;
				}
			}
			if (num > 0)
			{
				Plugin.Log.LogInfo((object)$"Resolved {num} links that were missing at load; {Unresolved.Count} still missing.");
			}
		}

		internal static bool Add(ZDO station, LinkRole role, ZDO chest)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_007d: Unknown result type (might be due to invalid IL or missing references)
			Keys[station.m_uid] = ObjKey.Of(station);
			Keys[chest.m_uid] = ObjKey.Of(chest);
			if (!All.TryGetValue(station.m_uid, out var value))
			{
				Dictionary<ZDOID, StationLinks> all = All;
				ZDOID uid = station.m_uid;
				StationLinks obj = new StationLinks
				{
					Station = station.m_uid
				};
				value = obj;
				all[uid] = obj;
			}
			List<ZDOID> list = value.Of(role);
			if (list.Contains(chest.m_uid))
			{
				return false;
			}
			list.Add(chest.m_uid);
			_dirty = true;
			return true;
		}

		internal static bool Remove(ZDOID station, LinkRole role, ZDOID chest)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (!All.TryGetValue(station, out var value) || !value.Of(role).Remove(chest))
			{
				return false;
			}
			if (value.IsEmpty)
			{
				All.Remove(station);
			}
			_dirty = true;
			return true;
		}

		internal static void RemoveStation(ZDOID station)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			if (All.Remove(station))
			{
				_dirty = true;
			}
		}

		internal static void RemoveChestEverywhere(ZDOID chest)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			foreach (StationLinks item in All.Values.ToList())
			{
				List<ZDOID>[] chests = item.Chests;
				for (int i = 0; i < chests.Length; i++)
				{
					if (chests[i].Remove(chest))
					{
						_dirty = true;
					}
				}
			}
			foreach (ZDOID item2 in (from kv in All
				where kv.Value.IsEmpty
				select kv.Key).ToList())
			{
				All.Remove(item2);
			}
		}

		internal static void SaveIfDirty()
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			if (!_dirty || _path == null)
			{
				return;
			}
			_dirty = false;
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("# Budyliv Production links v2").Append('\n');
			foreach (StationLinks value3 in All.Values)
			{
				if (!Keys.TryGetValue(value3.Station, out var value))
				{
					continue;
				}
				for (int i = 0; i < 3; i++)
				{
					foreach (ZDOID item in value3.Chests[i])
					{
						if (Keys.TryGetValue(item, out var value2))
						{
							stringBuilder.Append(value).Append('\t').Append(i.ToString(CultureInfo.InvariantCulture))
								.Append('\t')
								.Append(value2)
								.Append('\n');
						}
					}
				}
			}
			foreach (string item2 in Unresolved)
			{
				stringBuilder.Append(item2).Append('\n');
			}
			try
			{
				string text = _path + ".tmp";
				File.WriteAllText(text, stringBuilder.ToString());
				if (File.Exists(_path))
				{
					File.Replace(text, _path, null);
				}
				else
				{
					File.Move(text, _path);
				}
			}
			catch (Exception ex)
			{
				_dirty = true;
				Plugin.Log.LogError((object)("Could not save links to " + _path + ": " + ex.Message));
			}
		}

		internal static void Unload()
		{
			SaveIfDirty();
			All.Clear();
			Keys.Clear();
			Unresolved.Clear();
			_path = null;
		}
	}
	internal static class LinkVisuals
	{
		private struct Strand
		{
			public LinkRole Role;

			public bool Implicit;
		}

		private static readonly Color InputColor = new Color(0.25f, 0.6f, 1f);

		private static readonly Color FuelColor = new Color(1f, 0.55f, 0.1f);

		private static readonly Color OutputColor = new Color(0.3f, 1f, 0.35f);

		private static readonly int EmissionId = Shader.PropertyToID("_EmissionColor");

		private static GameObject _root;

		private static Material _material;

		private static Material _slowMaterial;

		private const int TexW = 32;

		private const int TexH = 16;

		private const int Phases = 16;

		private const float ChevronPitch = 0.22f;

		private const float LineWidth = 0.08f;

		private static Texture2D[] _phaseTex;

		private static float _phase;

		private static float _slowPhase;

		private static readonly List<LineRenderer> Lines = new List<LineRenderer>();

		private static readonly HashSet<GameObject> Highlighted = new HashSet<GameObject>();

		private static readonly HashSet<GameObject> WantedHighlight = new HashSet<GameObject>();

		private const float StrandGap = 0.09f;

		private static readonly Dictionary<GameObject, List<Strand>> GlowWanted = new Dictionary<GameObject, List<Strand>>();

		private static readonly Dictionary<GameObject, (Vector3 Pos, float At)> AnchorCache = new Dictionary<GameObject, (Vector3, float)>();

		internal static Color RoleColor(LinkRole role)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return (Color)(role switch
			{
				LinkRole.Fuel => FuelColor, 
				LinkRole.Input => InputColor, 
				_ => OutputColor, 
			});
		}

		internal static void Update()
		{
			int used = 0;
			GlowWanted.Clear();
			if (Plugin.ShowLinkLines.Value && (Object)(object)ZNetScene.instance != (Object)null && ZDOMan.instance != null)
			{
				if (ClientLinker.ShowAll)
				{
					DrawAll(ref used);
				}
				else if (ClientLinker.GesturesAllowed)
				{
					DrawHovered(ref used);
				}
			}
			if (used > 0)
			{
				Animate();
			}
			for (int i = used; i < Lines.Count; i++)
			{
				if ((Object)(object)Lines[i] != (Object)null && ((Renderer)Lines[i]).enabled)
				{
					((Renderer)Lines[i]).enabled = false;
				}
			}
			foreach (KeyValuePair<GameObject, List<Strand>> item in GlowWanted)
			{
				item.Value.Sort(Order);
				Glow(item.Key, item.Value);
			}
			foreach (GameObject item2 in new List<GameObject>(Highlighted))
			{
				if (!((Object)(object)item2 != (Object)null) || !GlowWanted.ContainsKey(item2))
				{
					Unglow(item2);
					Highlighted.Remove(item2);
				}
			}
			if (AnchorCache.Count > 512)
			{
				AnchorCache.Clear();
			}
		}

		private static void DrawHovered(ref int used)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			StationInfo info;
			bool fuelControl;
			Container container;
			ZNetView val = ClientLinker.HoverTarget(out info, out fuelControl, out container);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Dictionary<ZDOID, List<Strand>> dictionary = Collect(val.GetZDO().m_uid, info);
			if (dictionary == null)
			{
				return;
			}
			Vector3 val2 = Anchor(((Component)val).gameObject);
			bool fromIsStation = info != null;
			foreach (KeyValuePair<ZDOID, List<Strand>> item in dictionary)
			{
				if (Endpoint(item.Key, out var pos, out var go))
				{
					DrawStrands(ref used, val2, pos, fromIsStation, item.Value);
					AddGlow(go, item.Value);
				}
			}
		}

		private static void DrawAll(ref int used)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			foreach (var (val, array) in ClientLinker.NearLinks)
			{
				if (!Endpoint(val, out var pos, out var go))
				{
					continue;
				}
				StationInfo stationInfo = Stations.Get(ZDOMan.instance.GetZDO(val).GetPrefab());
				Dictionary<ZDOID, List<Strand>> perChest = new Dictionary<ZDOID, List<Strand>>();
				for (int i = 0; i < 3; i++)
				{
					foreach (ZDOID item in array[i])
					{
						Add(item, (LinkRole)i, isImplicit: false);
					}
				}
				if (stationInfo != null && stationInfo.HasFuel && array[1].Count == 0)
				{
					foreach (ZDOID item2 in array[0])
					{
						Add(item2, LinkRole.Fuel, isImplicit: true);
					}
				}
				foreach (KeyValuePair<ZDOID, List<Strand>> item3 in perChest)
				{
					if (Endpoint(item3.Key, out var pos2, out var go2))
					{
						item3.Value.Sort(Order);
						DrawStrands(ref used, pos, pos2, fromIsStation: true, item3.Value);
						AddGlow(go2, item3.Value);
						AddGlow(go, item3.Value);
					}
				}
				void Add(ZDOID chest, LinkRole role, bool isImplicit)
				{
					//IL_001a: 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)
					if (!perChest.TryGetValue(chest, out var value))
					{
						value = (perChest[chest] = new List<Strand>());
					}
					if (!value.Exists((Strand x) => x.Role == role && x.Implicit == isImplicit))
					{
						value.Add(new Strand
						{
							Role = role,
							Implicit = isImplicit
						});
					}
				}
			}
		}

		private static int Order(Strand a, Strand b)
		{
			if (a.Implicit == b.Implicit)
			{
				return a.Role.CompareTo(b.Role);
			}
			if (!a.Implicit)
			{
				return -1;
			}
			return 1;
		}

		private static bool Endpoint(ZDOID id, out Vector3 pos, out GameObject go)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			pos = default(Vector3);
			go = null;
			ZDO zDO = ZDOMan.instance.GetZDO(id);
			if (zDO == null)
			{
				return false;
			}
			ZNetView val = ZNetScene.instance.FindInstance(zDO);
			if ((Object)(object)val != (Object)null)
			{
				go = ((Component)val).gameObject;
				pos = Anchor(go);
			}
			else
			{
				pos = zDO.GetPosition() + Vector3.up * 0.5f;
			}
			return true;
		}

		private static void DrawStrands(ref int used, Vector3 from, Vector3 to, bool fromIsStation, List<Strand> list)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_0039: 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)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = (fromIsStation ? from : to);
			Vector3 val2 = (fromIsStation ? to : from);
			Vector3 val3 = Vector3.Cross(val2 - val, Vector3.up);
			val3 = ((((Vector3)(ref val3)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val3)).normalized : Vector3.right);
			for (int i = 0; i < list.Count; i++)
			{
				Vector3 val4 = val3 * (((float)i - (float)(list.Count - 1) * 0.5f) * 0.09f);
				Color color = RoleColor(list[i].Role);
				if (list[i].Implicit)
				{
					color.a = 0.35f;
				}
				bool num = list[i].Role == LinkRole.Output;
				Vector3 val5 = (num ? val : val2) + val4;
				Vector3 to2 = (num ? val2 : val) + val4;
				Draw(used++, val5, to2, color, list[i].Implicit ? 0.6f : 1f, list[i].Implicit);
			}
		}

		private static void AddGlow(GameObject go, List<Strand> strands)
		{
			if ((Object)(object)go == (Object)null)
			{
				return;
			}
			if (!GlowWanted.TryGetValue(go, out var value))
			{
				value = (GlowWanted[go] = new List<Strand>());
			}
			foreach (Strand s in strands)
			{
				if (!value.Exists((Strand x) => x.Role == s.Role && x.Implicit == s.Implicit))
				{
					value.Add(s);
				}
			}
		}

		private static Dictionary<ZDOID, List<Strand>> Collect(ZDOID id, StationInfo info)
		{
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: 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_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<ZDOID, List<Strand>> result = new Dictionary<ZDOID, List<Strand>>();
			if (info != null)
			{
				ClientLinker.Links links = ClientLinker.StationLinks(id);
				if (links == null)
				{
					return null;
				}
				for (int i = 0; i < 3; i++)
				{
					foreach (ZDOID item in links.Lists[i])
					{
						Add(item, (LinkRole)i, isImplicit: false);
					}
				}
				if (info.HasFuel && links.Count(LinkRole.Fuel) == 0)
				{
					foreach (ZDOID item2 in links.Lists[0])
					{
						Add(item2, LinkRole.Fuel, isImplicit: true);
					}
				}
			}
			else
			{
				ClientLinker.Links links2 = ClientLinker.ChestLinks(id);
				if (links2 == null)
				{
					return null;
				}
				for (int j = 0; j < 3; j++)
				{
					foreach (ZDOID item3 in links2.Lists[j])
					{
						Add(item3, (LinkRole)j, isImplicit: false);
					}
				}
				foreach (ZDOID item4 in links2.Lists[0])
				{
					ZDO zDO = ZDOMan.instance.GetZDO(item4);
					StationInfo stationInfo = ((zDO != null) ? Stations.Get(zDO.GetPrefab()) : null);
					if (stationInfo != null && stationInfo.HasFuel)
					{
						ClientLinker.Links links3 = ClientLinker.StationLinks(item4);
						if (links3 != null && links3.Count(LinkRole.Fuel) == 0)
						{
							Add(item4, LinkRole.Fuel, isImplicit: true);
						}
					}
				}
			}
			foreach (List<Strand> value2 in result.Values)
			{
				value2.Sort(Order);
			}
			return result;
			void Add(ZDOID other, LinkRole role, bool isImplicit)
			{
				//IL_001a: 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)
				if (!result.TryGetValue(other, out var value))
				{
					value = (result[other] = new List<Strand>());
				}
				if (!value.Exists((Strand s) => s.Role == role && s.Implicit == isImplicit))
				{
					value.Add(new Strand
					{
						Role = role,
						Implicit = isImplicit
					});
				}
			}
		}

		internal static void Clear()
		{
			foreach (GameObject item in Highlighted)
			{
				Unglow(item);
			}
			Highlighted.Clear();
			foreach (LineRenderer line in Lines)
			{
				if ((Object)(object)line != (Object)null)
				{
					((Renderer)line).enabled = false;
				}
			}
		}

		private static Vector3 Anchor(GameObject go)
		{
			//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)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (AnchorCache.TryGetValue(go, out (Vector3, float) value) && Time.time - value.Item2 < 1f)
			{
				return value.Item1;
			}
			Vector3 val = ComputeAnchor(go);
			AnchorCache[go] = (val, Time.time);
			return val;
		}

		private static Vector3 ComputeAnchor(GameObject go)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			Bounds? val = null;
			MeshRenderer[] componentsInChildren = go.GetComponentsInChildren<MeshRenderer>();
			foreach (MeshRenderer val2 in componentsInChildren)
			{
				if (!val.HasValue)
				{
					val = ((Renderer)val2).bounds;
					continue;
				}
				Bounds value = val.Value;
				((Bounds)(ref value)).Encapsulate(((Renderer)val2).bounds);
				val = value;
			}
			if (!val.HasValue)
			{
				return go.transform.position + Vector3.up * 0.5f;
			}
			Bounds valueOrDefault = val.GetValueOrDefault();
			return ((Bounds)(ref valueOrDefault)).center;
		}

		private static void Draw(int index, Vector3 from, Vector3 to, Color color, float width, bool slow)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: 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_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00e8: Expected O, but got Unknown
			if ((Object)(object)_root == (Object)null)
			{
				_root = new GameObject("BudylivProduction_Links");
				Object.DontDestroyOnLoad((Object)(object)_root);
				Lines.Clear();
				Shader val = Shader.Find("Sprites/Default") ?? Shader.Find("Legacy Shaders/Particles/Alpha Blended") ?? Shader.Find("Unlit/Color");
				_material = ((!((Object)(object)val != (Object)null)) ? ((Material)null) : new Material(val));
				if ((Object)(object)_material != (Object)null)
				{
					_phaseTex = (Texture2D[])(object)new Texture2D[16];
					for (int i = 0; i < 16; i++)
					{
						_phaseTex[i] = MakeChevrons((float)i / 16f);
					}
					_material.mainTexture = (Texture)(object)_phaseTex[0];
					((Object)_material).hideFlags = (HideFlags)32;
					_slowMaterial = new Material(_material)
					{
						hideFlags = (HideFlags)32
					};
				}
			}
			while (Lines.Count <= index)
			{
				GameObject val2 = new GameObject("link");
				val2.transform.SetParent(_root.transform, false);
				LineRenderer val3 = val2.AddComponent<LineRenderer>();
				val3.positionCount = 2;
				val3.useWorldSpace = true;
				val3.startWidth = 0.08f;
				val3.endWidth = 0.08f;
				val3.numCapVertices = 0;
				val3.textureMode = (LineTextureMode)1;
				val3.textureScale = new Vector2(4.5454545f, 1f);
				((Renderer)val3).shadowCastingMode = (ShadowCastingMode)0;
				((Renderer)val3).receiveShadows = false;
				Lines.Add(val3);
			}
			LineRenderer val4 = Lines[index];
			val4.SetPosition(0, from);
			val4.SetPosition(1, to);
			Color val5 = color;
			if (val5.a > 0.9f)
			{
				val5.a = 0.9f;
			}
			val4.startColor = val5;
			val4.endColor = val5;
			val4.startWidth = 0.08f * width;
			val4.endWidth = 0.08f * width;
			Material val6 = (slow ? _slowMaterial : _material);
			if ((Object)(object)val6 != (Object)null && (Object)(object)((Renderer)val4).sharedMaterial != (Object)(object)val6)
			{
				((Renderer)val4).sharedMaterial = val6;
			}
			((Renderer)val4).enabled = true;
		}

		private static void Animate()
		{
			if (_phaseTex != null)
			{
				float num = Mathf.Max(0f, Plugin.LinkFlowSpeed.Value) / 0.22f;
				_phase = Mathf.Repeat(_phase + num * Time.deltaTime, 1f);
				_slowPhase = Mathf.Repeat(_slowPhase + num * 0.5f * Time.deltaTime, 1f);
				_material.mainTexture = (Texture)(object)_phaseTex[(int)(_phase * 16f) % 16];
				_slowMaterial.mainTexture = (Texture)(object)_phaseTex[(int)(_slowPhase * 16f) % 16];
			}
		}

		private static Texture2D MakeChevrons(float phase)
		{
			//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_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(32, 16, (TextureFormat)4, false)
			{
				wrapMode = (TextureWrapMode)0,
				filterMode = (FilterMode)1,
				hideFlags = (HideFlags)32,
				name = "BudylivProduction_Chevrons"
			};
			Color32[] array = (Color32[])(object)new Color32[512];
			for (int i = 0; i < 16; i++)
			{
				float num = Mathf.Abs(((float)i + 0.5f) / 16f - 0.5f) * 2f;
				for (int j = 0; j < 32; j++)
				{
					float num2 = Mathf.Repeat(((float)j + 0.5f) / 32f - phase + 0.45f * num, 1f);
					float num3 = 1f - Mathf.Clamp01((Mathf.Abs(num2 - 0.55f) - 0.13f) / (3f / 64f));
					float num4 = 1f - Mathf.Clamp01((num - 0.85f) / 0.15f);
					float num5 = Mathf.Max(0.3f, num3) * num4;
					array[i * 32 + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)Mathf.RoundToInt(num5 * 255f));
				}
			}
			val.SetPixels32(array);
			val.Apply(false, true);
			return val;
		}

		private static void Glow(GameObject go, List<Strand> strands)
		{
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)MaterialMan.instance == (Object)null) && strands.Count != 0)
			{
				Color val;
				if (strands.Count == 1)
				{
					val = RoleColor(strands[0].Role) * (strands[0].Implicit ? 0.6f : 1f);
				}
				else
				{
					float num = Time.time * 1.5f;
					int num2 = Mathf.FloorToInt(num) % strands.Count;
					float num3 = Mathf.SmoothStep(0f, 1f, num - Mathf.Floor(num));
					Color val2 = RoleColor(strands[num2].Role) * (strands[num2].Implicit ? 0.6f : 1f);
					Strand strand = strands[(num2 + 1) % strands.Count];
					Color val3 = RoleColor(strand.Role) * (strand.Implicit ? 0.6f : 1f);
					val = Color.Lerp(val2, val3, num3);
				}
				float num4 = 0.35f + 0.15f * Mathf.Sin(Time.time * 4f);
				MaterialMan.instance.SetValue<Color>(go, EmissionId, val * num4, false);
				Highlighted.Add(go);
			}
		}

		private static void Unglow(GameObject go)
		{
			if ((Object)(object)go != (Object)null && (Object)(object)MaterialMan.instance != (Object)null)
			{
				MaterialMan.instance.ResetValue(go, EmissionId);
			}
		}
	}
	internal enum LinkRole
	{
		Input,
		Fuel,
		Output
	}
	internal enum LinkOp
	{
		Link = 1,
		Unlink,
		Info,
		UnlinkAll,
		ChestInfo,
		ChestUnlinkAll,
		NearInfo
	}
	internal static class Net
	{
		internal const int Protocol = 4;

		internal const int TextFeature = 1;

		internal const string RequestRpc = "BudylivProduction_Request";

		internal const string MessageRpc = "BudylivProduction_Message";

		internal const string TextRpc = "BudylivProduction_Text";

		internal const string CountsRpc = "BudylivProduction_Links";

		internal const string NearRpc = "BudylivProduction_Near";

		private static ZRoutedRpc _registeredOn;

		private static readonly Dictionary<long, bool> TextPeers = new Dictionary<long, bool>();

		internal static void Register()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null && instance != _registeredOn)
			{
				_registeredOn = instance;
				instance.Register<ZPackage>("BudylivProduction_Request", (Action<long, ZPackage>)OnRequest);
				instance.Register<string>("BudylivProduction_Message", (Action<long, string>)OnMessage);
				instance.Register<ZPackage>("BudylivProduction_Text", (Action<long, ZPackage>)OnText);
				instance.Register<ZPackage>("BudylivProduction_Links", (Action<long, ZPackage>)OnCounts);
				instance.Register<ZPackage>("BudylivProduction_Near", (Action<long, ZPackage>)OnNear);
			}
		}

		internal static void SendRequest(LinkOp op, ZDOID station, ZDOID chest, LinkRole role)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			ZPackage val = new ZPackage();
			val.Write(4);
			val.Write((int)op);
			val.Write(station);
			val.Write(chest);
			val.Write((int)role);
			val.Write(1);
			ZRoutedRpc.instance.InvokeRoutedRPC("BudylivProduction_Request", new object[1] { val });
		}

		internal static void SendMessage(long peer, string key, params string[] args)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			bool value;
			if (peer == ZDOMan.GetSessionID())
			{
				object[] args2 = args;
				ClientLinker.Show(L.T(key, args2));
			}
			else if (TextPeers.TryGetValue(peer, out value) && value)
			{
				ZPackage val = new ZPackage();
				val.Write(key);
				val.Write(args.Length);
				foreach (string text in args)
				{
					val.Write(text ?? "");
				}
				ZRoutedRpc.instance.InvokeRoutedRPC(peer, "BudylivProduction_Text", new object[1] { val });
			}
			else
			{
				ZRoutedRpc instance = ZRoutedRpc.instance;
				object[] array = new object[1];
				object[] args2 = args;
				array[0] = L.Format(ukrainian: true, key, args2);
				instance.InvokeRoutedRPC(peer, "BudylivProduction_Message", array);
			}
		}

		internal static void SendLinks(long peer, bool chest, ZDOID id, List<ZDOID>[] lists)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			if (peer == ZDOMan.GetSessionID())
			{
				ClientLinker.SetLinks(chest, id, lists);
				return;
			}
			ZPackage val = new ZPackage();
			val.Write(chest);
			val.Write(id);
			foreach (List<ZDOID> list in lists)
			{
				val.Write(list.Count);
				foreach (ZDOID item in list)
				{
					val.Write(item);
				}
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(peer, "BudylivProduction_Links", new object[1] { val });
		}

		internal static void SendNearLinks(long peer, List<(ZDOID Station, List<ZDOID>[] Lists)> stations)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			//IL_0034: 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)
			//IL_006f: 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)
			if (peer == ZDOMan.GetSessionID())
			{
				ClientLinker.SetNearLinks(stations);
				return;
			}
			ZPackage val = new ZPackage();
			val.Write(stations.Count);
			foreach (var station in stations)
			{
				val.Write(station.Station);
				List<ZDOID>[] item = station.Lists;
				foreach (List<ZDOID> list in item)
				{
					val.Write(list.Count);
					foreach (ZDOID item2 in list)
					{
						val.Write(item2);
					}
				}
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(peer, "BudylivProduction_Near", new object[1] { val });
		}

		private static void OnNear(long sender, ZPackage pkg)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			if (!FromServer(sender))
			{
				return;
			}
			try
			{
				int num = pkg.ReadInt();
				if (num < 0 || num > 5000)
				{
					return;
				}
				List<(ZDOID, List<ZDOID>[])> list = new List<(ZDOID, List<ZDOID>[])>(num);
				for (int i = 0; i < num; i++)
				{
					ZDOID item = pkg.ReadZDOID();
					List<ZDOID>[] array = new List<ZDOID>[3];
					for (int j = 0; j < 3; j++)
					{
						int num2 = pkg.ReadInt();
						if (num2 < 0 || num2 > 1000)
						{
							return;
						}
						array[j] = new List<ZDOID>(num2);
						for (int k = 0; k < num2; k++)
						{
							array[j].Add(pkg.ReadZDOID());
						}
					}
					list.Add((item, array));
				}
				ClientLinker.SetNearLinks(list);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Bad near-links package: " + ex.Message));
			}
		}

		private static bool FromServer(long sender)
		{
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return false;
			}
			long num = (ZNet.instance.IsServer() ? ZDOMan.GetSessionID() : (ZNet.instance.GetServerPeer()?.m_uid ?? 0));
			return sender == num;
		}

		private static void OnCounts(long sender, ZPackage pkg)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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)
			if (!FromServer(sender))
			{
				return;
			}
			try
			{
				bool chest = pkg.ReadBool();
				ZDOID id = pkg.ReadZDOID();
				List<ZDOID>[] array = new List<ZDOID>[3];
				for (int i = 0; i < 3; i++)
				{
					int num = pkg.ReadInt();
					if (num < 0 || num > 1000)
					{
						return;
					}
					array[i] = new List<ZDOID>(num);
					for (int j = 0; j < num; j++)
					{
						array[i].Add(pkg.ReadZDOID());
					}
				}
				ClientLinker.SetLinks(chest, id, array);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Bad counts package: " + ex.Message));
			}
		}

		private static void OnRequest(long sender, ZPackage pkg)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return;
			}
			try
			{
				int num = pkg.ReadInt();
				if (num != 4)
				{
					TextPeers.Remove(sender);
					SendMessage(sender, "srv.version", num.ToString(), 4.ToString());
					return;
				}
				LinkOp op = (LinkOp)pkg.ReadInt();
				ZDOID stationId = pkg.ReadZDOID();
				ZDOID chestId = pkg.ReadZDOID();
				LinkRole role = (LinkRole)pkg.ReadInt();
				int num2 = ((pkg.GetPos() < pkg.Size()) ? pkg.ReadInt() : 0);
				TextPeers[sender] = (num2 & 1) != 0;
				if (TextPeers.Count > 256)
				{
					TextPeers.Clear();
				}
				ServerEngine.HandleRequest(sender, op, stationId, chestId, role);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Bad request from " + sender + ": " + ex.Message));
			}
		}

		private static void OnText(long sender, ZPackage pkg)
		{
			if (!FromServer(sender))
			{
				return;
			}
			try
			{
				string key = pkg.ReadString();
				int num = pkg.ReadInt();
				if (num >= 0 && num <= 16)
				{
					object[] array = new object[num];
					for (int i = 0; i < num; i++)
					{
						array[i] = pkg.ReadString();
					}
					ClientLinker.Show(L.T(key, array));
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Bad text package: " + ex.Message));
			}
		}

		private static void OnMessage(long sender, string text)
		{
			if (FromServer(sender))
			{
				ClientLinker.Show(text);
			}
		}
	}
	[BepInPlugin("com.budyliv.production", "Budyliv Production", "1.2.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.budyliv.production";

		public const string Name = "Budyliv Production";

		public const string Version = "1.2.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<float> TickSeconds;

		internal static ConfigEntry<float> ClaimWaitSeconds;

		internal static ConfigEntry<float> QuietSeconds;

		internal static ConfigEntry<float> MaxLinkRange;

		internal static ConfigEntry<float> RefillFraction;

		internal static ConfigEntry<float> DeliveryCooldownSeconds;

		internal static ConfigEntry<float> OutputRadius;

		internal static ConfigEntry<float> MinDropAgeSeconds;

		internal static ConfigEntry<float> OutputScanSeconds;

		internal static ConfigEntry<float> FullRetrySeconds;

		internal static ConfigEntry<int> RevisionBump;

		internal static ConfigEntry<bool> VerboseLogging;

		internal static ConfigEntry<string> Language;

		internal static ConfigEntry<bool> ShowControlHints;

		internal static ConfigEntry<bool> ShowLinkLines;

		internal static ConfigEntry<float> LinkFlowSpeed;

		internal static ConfigEntry<KeyboardShortcut> ShowAllLinksKey;

		private Harmony _harmony;

		internal static void Verbose(string text)
		{
			if (VerboseLogging != null && VerboseLogging.Value)
			{
				Log.LogInfo((object)text);
			}
		}

		private void Awake()
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Expected O, but got Unknown
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Expected O, but got Unknown
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Expected O, but got Unknown
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Expected O, but got Unknown
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Expected O, but got Unknown
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Expected O, but got Unknown
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Expected O, but got Unknown
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Expected O, but got Unknown
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Expected O, but got Unknown
			//IL_03a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ac: Expected O, but got Unknown
			//IL_03cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ef: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Server", "Enabled", true, "Server: run automatic fuel/input/output for linked stations.");
			TickSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "TickSeconds", 2f, new ConfigDescription("Server: how often stations are checked.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 30f), Array.Empty<object>()));
			ClaimWaitSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "ClaimWaitSeconds", 0.5f, new ConfigDescription("Server: after taking a chest/drop over, wait this long for in-flight player changes before editing it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 5f), Array.Empty<object>()));
			QuietSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "QuietSeconds", 2f, new ConfigDescription("Server: a chest whose contents changed within this time is left alone this tick.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), Array.Empty<object>()));
			MaxLinkRange = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "MaxLinkRange", 30f, new ConfigDescription("Server: maximum station-chest distance for a link (m).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			RefillFraction = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "RefillFraction", 0.5f, new ConfigDescription("Server: refill fuel/input when at least this fraction of capacity is free (or it ran out). Bigger = fewer, larger transfers.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 1f), Array.Empty<object>()));
			DeliveryCooldownSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "DeliveryCooldownSeconds", 5f, new ConfigDescription("Server: after a delivery, wait this long for the station owner to report the new state.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), Array.Empty<object>()));
			OutputRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "OutputRadius", 2f, new ConfigDescription("Server: products lying within this distance of a station's output point go to its output chest (m).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 6f), Array.Empty<object>()));
			MinDropAgeSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "MinDropAgeSeconds", 0.2f, new ConfigDescription("Server: only collect products at least this old.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), Array.Empty<object>()));
			OutputScanSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "OutputScanSeconds", 0.5f, new ConfigDescription("Server: how often products near stations are looked for (faster than TickSeconds).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 10f), Array.Empty<object>()));
			FullRetrySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "FullRetrySeconds", 5f, new ConfigDescription("Server: a full output chest is skipped this long (or until a player changes it); the next output chest is used meanwhile.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 120f), Array.Empty<object>()));
			RevisionBump = ((BaseUnityPlugin)this).Config.Bind<int>("Server", "RevisionBump", 10, new ConfigDescription("Server: extra data revisions added to a chest the server writes, so a late player write cannot leave server and client with different contents.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000), Array.Empty<object>()));
			VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Server", "VerboseLogging", false, "Server: also log every transfer and station type (for debugging). Links, unlinks and problems are always logged.");
			Language = ((BaseUnityPlugin)this).Config.Bind<string>("Client", "Language", "Auto", new ConfigDescription("Client: language of hints and messages. Auto = Ukrainian when the game is in Ukrainian, English otherwise.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[3] { "Auto", "English", "Ukrainian" }), Array.Empty<object>()));
			ShowControlHints = ((BaseUnityPlugin)this).Config.Bind<bool>("Client", "ShowControlHints", true, "Client: show link gestures (Alt+mouse) and linked chest counts on station and chest hover text.");
			ShowLinkLines = ((BaseUnityPlugin)this).Config.Bind<bool>("Client", "ShowLinkLines", true, "Client: while Alt is held over a station or chest, draw lines to its linked chests/stations and make them glow (blue input, orange fuel, green output).");
			LinkFlowSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Client", "LinkFlowSpeed", 0.6f, new ConfigDescription("Client: how fast the arrows on link lines move toward where the items go (chest to station for input and fuel, station to chest for output), in metres per second. 0 = arrows stand still.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
			ShowAllLinksKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Client", "ShowAllLinksKey", new KeyboardShortcut((KeyCode)281, Array.Empty<KeyCode>()), "Client: toggles showing every link around you at once (lines and glow, no Alt needed).");
			_harmony = new Harmony("com.budyliv.production");
			_harmony.PatchAll();
			Log.LogInfo((object)"Budyliv Production 1.2.0 loaded.");
		}

		private void Update()
		{
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return;
			}
			try
			{
				if (ZNet.instance.IsServer())
				{
					ServerEngine.Tick();
				}
				if ((Object)(object)Player.m_localPlayer != (Object)null)
				{
					ClientLinker.Update();
					LinkVisuals.Update();
				}
				else
				{
					LinkVisuals.Clear();
				}
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Update failed: " + ex));
			}
		}

		private void OnDestroy()
		{
			ServerEngine.Shutdown();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "Awake")]
	internal static class ZNet_Awake_Patch
	{
		private static void Postfix()
		{
			Net.Register();
		}
	}
	[HarmonyPatch(typeof(ZDOMan), "ReleaseZDOS")]
	internal static class ZDOMan_ReleaseZDOS_Patch
	{
		private static void Prefix()
		{
			ServerEngine.BeforeVanillaRelease();
		}

		private static void Postfix()
		{
			ServerEngine.AfterVanillaRelease();
		}
	}
	[HarmonyPatch(typeof(ZNet), "Shutdown")]
	internal static class ZNet_Shutdown_Patch
	{
		private static void Prefix()
		{
			ServerEngine.Shutdown();
		}
	}
	internal static class ServerEngine
	{
		private sealed class Claim
		{
			public ZDOID Id;

			public long PrevOwner;

			public float At;

			public ZDOID Station;

			public ZDOID Chest;
		}

		private sealed class OutChest
		{
			public ZDO Zdo;

			public bool Full;

			public bool Usable;

			private Inventory _inv;

			private bool _read;

			public Inventory Inv
			{
				get
				{
					if (!_read)
					{
						_read = true;
						_inv = ReadInventory(Zdo);
					}
					return _inv;
				}
			}
		}

		private sealed class Consumer
		{
			public StationLinks Links;

			public ZDO Station;

			public StationInfo Info;

			public long Owner;

			public float Level;

			public float Capacity;

			public int StartRoom;

			public List<string> Accepts;

			public int Given;

			public readonly Dictionary<string, int> Items = new Dictionary<string, int>();

			public float Fill => (Level + (float)Given) / Capacity;

			public int Room => StartRoom - Given;
		}

		private static readonly Dictionary<ZDOID, Claim> ChestClaims = new Dictionary<ZDOID, Claim>();

		private static readonly Dictionary<ZDOID, Claim> DropClaims = new Dictionary<ZDOID, Claim>();

		private static readonly Dictionary<ZDOID, float> FuelReady = new Dictionary<ZDOID, float>();

		private static readonly Dictionary<ZDOID, float> InputReady = new Dictionary<ZDOID, float>();

		private static readonly Dictionary<ZDOID, float> PullReady = new Dictionary<ZDOID, float>();

		private static readonly Dictionary<(ZDOID, LinkRole), (float MinLevel, float Until)> InFlight = new Dictionary<(ZDOID, LinkRole), (float, float)>();

		private static readonly Dictionary<ZDOID, (uint Rev, float Until)> ChestFull = new Dictionary<ZDOID, (uint, float)>();

		private static readonly Dictionary<ZDOID, (uint Rev, float ChangedAt)> ChestActivity = new Dictionary<ZDOID, (uint, float)>();

		private static float _nextPlan;

		private static float _nextOutput;

		private static string _world;

		private const float NearRadius = 80f;

		private static readonly Dictionary<ZDOID, float> MissingSince = new Dictionary<ZDOID, float>();

		private static float _nextSweep;

		private static readonly Dictionary<ZDOID, float> WispPicked = new Dictionary<ZDOID, float>();

		private static readonly List<ZDO> HeldBeforeRelease = new List<ZDO>();

		private static long Self => ZDOMan.GetSessionID();

		private static void Verbose(string text)
		{
			Plugin.Verbose(text);
		}

		internal static void Tick()
		{
			if (!Plugin.Enabled.Value || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			string worldName = ZNet.instance.GetWorldName();
			if (string.IsNullOrEmpty(worldName))
			{
				return;
			}
			if (_world != worldName)
			{
				if (ZDOMan.instance.NrOfObjects() == 0)
				{
					return;
				}
				ReleaseAll();
				LinkStore.Unload();
				LinkStore.Load(worldName);
				_world = worldName;
				_nextPlan = (_nextOutput = Time.time + 10f);
			}
			float time = Time.time;
			ExecuteReadyChests(time);
			if (time >= _nextPlan)
			{
				_nextPlan = time + Plugin.TickSeconds.Value;
				_nextOutput = time + Plugin.OutputScanSeconds.Value;
				ExpireClaims(time);
				SweepDestroyed(time);
				Plan(time, supplies: true);
			}
			else if (time >= _nextOutput)
			{
				_nextOutput = time + Plugin.OutputScanSeconds.Value;
				Plan(time, supplies: false);
			}
			LinkStore.SaveIfDirty();
		}

		internal static void Shutdown()
		{
			try
			{
				ReleaseAll();
				LinkStore.Unload();
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Shutdown cleanup failed: " + ex.Message));
				}
			}
			_world = null;
		}

		private static void ReleaseAll()
		{
			if (ZDOMan.instance != null)
			{
				foreach (Claim item in ChestClaims.Values.ToList())
				{
					Release(item);
				}
				foreach (Claim item2 in DropClaims.Values.ToList())
				{
					Release(item2);
				}
			}
			ChestClaims.Clear();
			DropClaims.Clear();
		}

		private static string RoleArg(LinkRole role)
		{
			return L.Ref(L.RoleKey(role));
		}

		private static string Num(float v)
		{
			return v.ToString("0", CultureInfo.InvariantCulture);
		}

		internal static void HandleRequest(long sender, LinkOp op, ZDOID stationId, ZDOID chestId, LinkRole role)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: 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_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c9: 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_0362: Unknown result type (might be due to invalid IL or missing references)
			//IL_036b: Unknown result type (might be due to invalid IL or missing references)
			bool flag = op == LinkOp.Info || op == LinkOp.ChestInfo || op == LinkOp.NearInfo;
			if (!LinkStore.Loaded)
			{
				if (!flag)
				{
					Net.SendMessage(sender, "srv.loading");
				}
				return;
			}
			switch (op)
			{
			case LinkOp.NearInfo:
				SendNearLinks(sender);
				return;
			case LinkOp.ChestInfo:
			case LinkOp.ChestUnlinkAll:
				HandleChestRequest(sender, op, chestId);
				return;
			}
			ZDO zDO = ZDOMan.instance.GetZDO(stationId);
			StationInfo stationInfo = ((zDO != null) ? Stations.Get(zDO.GetPrefab()) : null);
			if (stationInfo == null)
			{
				if (!flag)
				{
					Net.SendMessage(sender, "srv.unsupported");
				}
				return;
			}
			switch (op)
			{
			case LinkOp.Info:
				SendStationLinks(sender, stationId);
				return;
			case LinkOp.UnlinkAll:
			{
				int num = 0;
				if (LinkStore.All.TryGetValue(stationId, out var value))
				{
					num = value.Chests.Sum((List<ZDOID> list) => list.Count);
				}
				LinkStore.RemoveStation(stationId);
				if (num > 0)
				{
					Net.SendMessage(sender, "srv.unlinked_all", num.ToString());
				}
				else
				{
					Net.SendMessage(sender, "srv.no_links");
				}
				if (num > 0)
				{
					Plugin.Log.LogInfo((object)$"Unlink all ({num}) station {stationInfo.Prefab} {stationId} by {sender}");
				}
				SendStationLinks(sender, stationId);
				return;
			}
			}
			ZDO zDO2 = ZDOMan.instance.GetZDO(chestId);
			object obj;
			if (zDO2 == null)
			{
				obj = null;
			}
			else
			{
				GameObject prefab = ZNetScene.instance.GetPrefab(zDO2.GetPrefab());
				obj = ((prefab != null) ? prefab.GetComponent<Container>() : null);
			}
			if ((Object)obj == (Object)null)
			{
				Net.SendMessage(sender, "srv.not_chest");
				return;
			}
			if (op == LinkOp.Unlink)
			{
				bool flag2 = LinkStore.Remove(stationId, role, chestId);
				Net.SendMessage(sender, flag2 ? "srv.unlinked" : "srv.was_not_linked", RoleArg(role));
				if (flag2)
				{
					Plugin.Log.LogInfo((object)$"Unlink {role} station {stationInfo.Prefab} {stationId} chest {chestId} by {sender}");
				}
				SendStationLinks(sender, stationId);
				return;
			}
			if (!stationInfo.Has(role))
			{
				Net.SendMessage(sender, "srv.no_role", L.Ref(stationInfo.KindKey), RoleArg(role));
				return;
			}
			float num2 = Vector3.Distance(zDO.GetPosition(), zDO2.GetPosition());
			if (num2 > Plugin.MaxLinkRange.Value)
			{
				Net.SendMessage(sender, "srv.too_far", Num(num2), Num(Plugin.MaxLinkRange.Value));
				return;
			}
			bool flag3 = LinkStore.Add(zDO, role, zDO2);
			StationLinks value2;
			bool flag4 = flag3 && stationInfo.Kind == StationKind.Cooking && role == LinkRole.Input && LinkStore.All.TryGetValue(stationId, out value2) && value2.Of(LinkRole.Output).Count == 0;
			if (flag3)
			{
				Net.SendMessage(sender, flag4 ? "srv.linked_cooking" : "srv.linked", RoleArg(role), Num(num2));
			}
			else
			{
				Net.SendMessage(sender, "srv.already_linked", RoleArg(role));
			}
			if (flag3)
			{
				Plugin.Log.LogInfo((object)$"Link {role} station {stationInfo.Prefab} {stationId} chest {chestId} ({num2:0.0} m) by {sender}");
			}
			SendStationLinks(sender, stationId);
		}

		private static void SendStationLinks(long peer, ZDOID stationId)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			LinkStore.All.TryGetValue(stationId, out var value);
			List<ZDOID>[] array = new List<ZDOID>[3];
			for (int i = 0; i < 3; i++)
			{
				array[i] = ((value != null) ? value.Chests[i].ToList() : new List<ZDOID>());
			}
			Net.SendLinks(peer, chest: false, stationId, array);
		}

		private static void SendNearLinks(long peer)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val;
			if (peer == Self)
			{
				val = ZNet.instance.GetReferencePosition();
			}
			else
			{
				ZNetPeer peer2 = ZNet.instance.GetPeer(peer);
				if (peer2 == null)
				{
					return;
				}
				val = peer2.m_refPos;
			}
			List<(ZDOID, List<ZDOID>[])> list = new List<(ZDOID, List<ZDOID>[])>();
			foreach (StationLinks value in LinkStore.All.Values)
			{
				ZDO zDO = ZDOMan.instance.GetZDO(value.Station);
				if (zDO != null && !(Vector3.Distance(zDO.GetPosition(), val) > 80f))
				{
					List<ZDOID>[] array = new List<ZDOID>[3];
					for (int i = 0; i < 3; i++)
					{
						array[i] = value.Chests[i].ToList();
					}
					list.Add((value.Station, array));
				}
			}
			Net.SendNearLinks(peer, list);
		}

		private static void SendChestLinks(long peer, ZDOID chestId)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			List<ZDOID>[] array = new List<ZDOID>[3]
			{
				new List<ZDOID>(),
				new List<ZDOID>(),
				new List<ZDOID>()
			};
			foreach (StationLinks value in LinkStore.All.Values)
			{
				for (int i = 0; i < 3; i++)
				{
					if (value.Chests[i].Contains(chestId))
					{
						array[i].Add(value.Station);
					}
				}
			}
			Net.SendLinks(peer, chest: true, chestId, array);
		}

		private static void HandleChestRequest(long sender, LinkOp op, ZDOID chestId)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			if (op == LinkOp.ChestInfo)
			{
				SendChestLinks(sender, chestId);
				return;
			}
			int num = LinkStore.All.Values.Count((StationLinks l) => l.Chests.Any((List<ZDOID> list) => list.Contains(chestId)));
			if (num > 0)
			{
				LinkStore.RemoveChestEverywhere(chestId);
				Plugin.Log.LogInfo((object)$"Unlink chest {chestId} from all {num} stations by {sender}");
			}
			if (num > 0)
			{
				Net.SendMessage(sender, "srv.chest_unlinked_all", num.ToString());
			}
			else
			{
				Net.SendMessage(sender, "srv.chest_not_linked");
			}
			SendChestLinks(sender, chestId);
		}

		private static void SweepDestroyed(float now)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			if (now < _nextSweep)
			{
				return;
			}
			_nextSweep = now + 10f;
			LinkStore.RetryUnresolved();
			HashSet<ZDOID> hashSet = new HashSet<ZDOID>();
			foreach (StationLinks item in LinkStore.All.Values.ToList())
			{
				foreach (ZDOID item2 in ((IEnumerable<ZDOID>)(object)new ZDOID[1] { item.Station }).Concat(item.Chests.SelectMany((List<ZDOID> l) => l)).ToList())
				{
					if (!hashSet.Add(item2))
					{
						continue;
					}
					float value;
					if (ZDOMan.instance.GetZDO(item2) != null)
					{
						MissingSince.Remove(item2);
					}
					else if (!MissingSince.TryGetValue(item2, out value))
					{
						MissingSince[item2] = now;
					}
					else
					{
						if (now - value < 30f)
						{
							continue;
						}
						MissingSince.Remove(item2);
						if (item2 == item.Station && LinkStore.All.ContainsKey(item2))
						{
							int num = LinkStore.All[item2].Chests.Sum((List<ZDOID> l) => l.Count);
							LinkStore.RemoveStation(item2);
							Plugin.Log.LogInfo((object)$"Station {item2} is gone (destroyed): removed its {num} links.");
						}
						else
						{
							LinkStore.RemoveChestEverywhere(item2);
							Plugin.Log.LogInfo((object)$"Chest {item2} is gone (destroyed): removed it from all stations.");
						}
					}
				}
			}
		}

		private static void Plan(float now, bool supplies)
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<Vector2s, List<ZDO>> zoneCache = new Dictionary<Vector2s, List<ZDO>>();
			foreach (StationLinks item in LinkStore.All.Values.ToList())
			{
				if (!supplies && item.Of(LinkRole.Output).Count == 0)
				{
					continue;
				}
				ZDO zDO = ZDOMan.instance.GetZDO(item.Station);
				if (zDO == null)
				{
					continue;
				}
				long owner = zDO.GetOwner();
				if (owner == 0L || !Online(owner))
				{
					continue;
				}
				StationInfo stationInfo = Stations.Get(zDO.GetPrefab());
				if (stationInfo == null)
				{
					continue;
				}
				try
				{
					if (supplies)
					{
						PlanSupply(item, zDO, stationInfo, LinkRole.Fuel, now);
						PlanSupply(item, zDO, stationInfo, LinkRole.Input, now);
					}
					PlanOutput(item, zDO, stationInfo, owner, now, zoneCache);
				}
				catch (Exception arg)
				{
					Plugin.Log.LogWarning((object)$"Planning failed for station {item.Station}: {arg}");
				}
			}
		}

		private static List<ZDOID> Sources(StationLinks links, LinkRole role)
		{
			if (role == LinkRole.Input)
			{
				return links.Of(LinkRole.Input);
			}
			if (links.Of(LinkRole.Fuel).Count <= 0)
			{
				return links.Of(LinkRole.Input);
			}
			return links.Of(LinkRole.Fuel);
		}

		private static Dictionary<ZDOID, float> ReadyMap(LinkRole role)
		{
			if (role != LinkRole.Fuel)
			{
				return InputReady;
			}
			return FuelReady;
		}

		private static bool Settled(ZDOID station, LinkRole role, float level, float now)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if (!InFlight.TryGetValue((station, role), out (float, float) value))
			{
				return true;
			}
			if (level >= value.Item1 || now >= value.Item2)
			{
				InFlight.Remove((station, role));
				return true;
			}
			return false;
		}

		private static bool Eager(StationInfo info, LinkRole role)
		{
			return role switch
			{
				LinkRole.Fuel => info.EagerFuel, 
				LinkRole.Input => info.EagerInput, 
				_ => false, 
			};
		}

		private static int MinRoom(StationInfo info, LinkRole role, float capacity)
		{
			if (!Eager(info, role))
			{
				return Math.Max(1, Mathf.CeilToInt(capacity * Plugin.RefillFraction.Value * 0.5f));
			}
			return 1;
		}

		private static void PlanSupply(StationLinks links, ZDO station, StationInfo info, LinkRole role, float now)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			if (!info.Has(role) || !Ready(ReadyMap(role), links.Station, now))
			{
				return;
			}
			List<ZDOID> list = Sources(links, role);
			if (list.Count == 0)
			{
				return;
			}
			int num;
			float num2;
			float num3;
			IList<string> list2;
			if (role == LinkRole.Fuel)
			{
				num = info.FuelRoom(station);
				num2 = info.FuelLevel(station);
				num3 = info.FuelCapacity;
				list2 = info.FuelNames;
			}
			else
			{
				num = info.InputRoom(station);
				num2 = info.InputLevel(station);
				num3 = info.InputCapacity;
				list2 = info.InputAccepts(station);
			}
			if (num > 0 && list2.Count != 0 && Settled(links.Station, role, num2, now))
			{
				bool num4 = Eager(info, role);
				int num5 = Math.Max(1, Mathf.CeilToInt(num3 * Plugin.RefillFraction.Value));
				if (num4 || num >= num5 || !(num2 > 0f))
				{
					ClaimSourceWith(list, list2, now);
				}
			}
		}

		private static void ClaimSourceWith(List<ZDOID> chests, IList<string> wanted, float now)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			foreach (ZDOID chest in chests)
			{
				if (ChestClaims.ContainsKey(chest))
				{
					break;
				}
				ZDO zDO = ZDOMan.instance.GetZDO(chest);
				if (zDO != null && CanClaim(zDO, now))
				{
					Inventory inv = ReadInventory(zDO);
					if (inv != null && wanted.Any((string name) => Count(inv, name) > 0))
					{
						ClaimChest(zDO, now);
						break;
					}
				}
			}
		}

		private static bool MarkedFull(ZDO chest, float now)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if (!ChestFull.TryGetValue(chest.m_uid, out (uint, float) value))
			{
				return false;
			}
			if (value.Item1 != chest.DataRevision || now >= value.Item2)
			{
				ChestFull.Remove(chest.m_uid);
				return false;
			}
			return true;
		}

		private static void PlanOutput(StationLinks links, ZDO station, StationInfo info, long owner, float now, Dictionary<Vector2s, List<ZDO>> zoneCache)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: 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_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_0309: Unknown result type (might be due to invalid IL or missing references)
			//IL_0316: Unknown result type (might be due to invalid IL or missing references)
			//IL_031b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			//IL_0344: Unknown result type (might be due to invalid IL or missing references)
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			if (links.Of(LinkRole.Output).Count == 0 || !info.HasOutput)
			{
				return;
			}
			List<OutChest> list = new List<OutChest>();
			foreach (ZDOID item in links.Of(LinkRole.Output))
			{
				ZDO zDO = ZDOMan.instance.GetZDO(item);
				if (zDO != null)
				{
					bool flag = MarkedFull(zDO, now);
					list.Add(new OutChest
					{
						Zdo = zDO,
						Full = flag,
						Usable = (!flag && (ChestClaims.ContainsKey(item) || CanClaim(zDO, now)))
					});
				}
			}
			if (list.Count == 0)
			{
				return;
			}
			bool flag2 = list.Any((OutChest c) => !c.Full);
			int num = info.PullCount(station);
			if (num > 0 && Ready(PullReady, links.Station, now) && (info.Kind == StationKind.Cooking || flag2))
			{
				PullReady[links.Station] = now + info.PullCooldown;
				Vector3 position = (list.FirstOrDefault((OutChest c) => c.Usable) ?? list[0]).Zdo.GetPosition();
				info.Pull(owner, station, num, position);
				Verbose($"Pull x{num} -> {info.Prefab} {links.Station}");
			}
			if (info.Kind == StationKind.Wisp && flag2 && Ready(PullReady, links.Station, now))
			{
				PullReady[links.Station] = now + info.PullCooldown;
				PickWisps(links, station, info, now, zoneCache);
			}
			ClaimAwaitedChests(links.Station, now);
			if (!list.Any((OutChest c) => c.Usable))
			{
				return;
			}
			foreach (ZDO item2 in FindDrops(station, info, zoneCache))
			{
				ItemData val = LoadDropItem(item2);
				if (val == null)
				{
					continue;
				}
				OutChest outChest = PickOutputChest(list, val);
				if (outChest == null)
				{
					continue;
				}
				if (!outChest.Usable)
				{
					Verbose($"{((Object)val.m_dropPrefab).name} from {info.Prefab} {links.Station} waits for chest {outChest.Zdo.m_uid} that already holds it (busy).");
					continue;
				}
				outChest.Inv.AddItem(val);
				if (!ChestClaims.ContainsKey(outChest.Zdo.m_uid))
				{
					ClaimChest(outChest.Zdo, now);
				}
				long owner2 = item2.GetOwner();
				if (owner2 != Self)
				{
					item2.SetOwner(Self);
				}
				DropClaims[item2.m_uid] = new Claim
				{
					Id = item2.m_uid,
					PrevOwner = owner2,
					At = now,
					Station = links.Station,
					Chest = outChest.Zdo.m_uid
				};
			}
		}

		private static OutChest PickOutputChest(List<OutChest> chests, ItemData item)
		{
			string name = ((Object)item.m_dropPrefab).name;
			foreach (OutChest chest in chests)
			{
				if (!chest.Full && chest.Inv != null && Count(chest.Inv, name) > 0 && chest.Inv.CanAddItem(item, -1))
				{
					return chest;
				}
			}
			foreach (OutChest chest2 in chests)
			{
				if (chest2.Usable && chest2.Inv != null && chest2.Inv.CanAddItem(item, -1))
				{
					return chest2;
				}
			}
			return null;
		}

		private static void ClaimAwaitedChests(ZDOID station, float now)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			foreach (ZDOID item in (from d in DropClaims.Values
				where d.Station == station && !ChestClaims.ContainsKey(d.Chest)
				select d.Chest).Distinct().ToList())
			{
				ZDO zDO = ZDOMan.instance.GetZDO(item);
				if (zDO != null && CanClaim(zDO, now))
				{
					ClaimChest(zDO, now);
				}
			}
		}

		private static void PickWisps(StationLinks links, ZDO station, StationInfo info, float now, Dictionary<Vector2s, List<ZDO>> zoneCache)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = info.OutputPoint(station);
			float wispRadius = info.WispRadius;
			foreach (ZDO item in Nearby(val, wispRadius, zoneCache))
			{
				if (item.GetPrefab() != info.WispHash)
				{
					continue;
				}
				Vector3 val2 = item.GetPosition() - val;
				if (!(val2.x * val2.x + val2.z * val2.z > wispRadius * wispRadius) && !(Mathf.Abs(val2.y) > wispRadius) && (!WispPicked.TryGetValue(item.m_uid, out var value) || !(now < value)))
				{
					long owner = item.GetOwner();
					if (owner != 0L && owner != Self && Online(owner))
					{
						ZRoutedRpc.instance.InvokeRoutedRPC(owner, item.m_uid, "RPC_Pick", new object[1] { 0 });
						WispPicked[item.m_uid] = now + 10f;
						Verbose($"Pick wisp {item.m_uid} (owner {owner}) at {info.Prefab} {links.Station}");
					}
				}
			}
		}

		private static IEnumerable<ZDO> Nearby(Vector3 pos, float radius, Dictionary<Vector2s, List<ZDO>> zoneCache)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (!Zdos.Available)
			{
				yield break;
			}
			HashSet<Vector2s> hashSet = new HashSet<Vector2s>();
			for (int i = -1; i <= 1; i += 2)
			{
				for (int j = -1; j <= 1; j += 2)
				{
					hashSet.Add(ZoneSystem.GetZone(pos + new Vector3((float)i * radius, 0f, (float)j * radius)));
				}
			}
			foreach (Vector2s item in hashSet)
			{
				if (!zoneCache.TryGetValue(item, out var value))
				{
					value = new List<ZDO>();
					Zdos.InZone(item, value);
					zoneCache[item] = value;
				}
				foreach (ZDO item2 in value)
				{
					yield return item2;
				}
			}
		}

		private static List<ZDO> FindDrops(ZDO station, StationInfo info, Dictionary<Vector2s, List<ZDO>> zoneCache)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: 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_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (