Decompiled source of NishinkusSmelterLink v0.3.0

NishinkusSmelterLink.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SmelterLink
{
	[BepInPlugin("nishinku.smelterlink", "Nishinku's SmelterLink", "0.3.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginId = "nishinku.smelterlink";

		public const string Version = "0.3.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<KeyboardShortcut> LinkKey;

		internal static ConfigEntry<float> TickInterval;

		internal static ConfigEntry<float> MaxCatchupSeconds;

		internal static ConfigEntry<bool> OfflineSmelting;

		internal static ConfigEntry<float> ToolRange;

		internal static ConfigEntry<bool> BlockInputWhileMarking;

		internal static ConfigEntry<bool> CancelMarkingOnDamage;

		internal static ConfigEntry<bool> Verbose;

		private Harmony _harmony;

		private static readonly List<ZDOID> _tickBuffer = new List<ZDOID>();

		private void Awake()
		{
			//IL_0022: 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_006e: Expected O, but got Unknown
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Expected O, but got Unknown
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Expected O, but got Unknown
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			LinkKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "LinkKey", new KeyboardShortcut((KeyCode)103, Array.Empty<KeyCode>()), "Look at a smelter and press this to start marking storage; then look at a chest and press it again.");
			TickInterval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "TickInterval", 2f, new ConfigDescription("Seconds between background passes over linked smelters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 30f), Array.Empty<object>()));
			OfflineSmelting = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "OfflineSmelting", true, "Keep linked smelters running while you are away from them. Requires an output chest to be linked.");
			MaxCatchupSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "MaxCatchupSeconds", 86400f, new ConfigDescription("Most in-game seconds of production a single smelter can catch up at once. Vanilla clamps this to 3600, which is why smelters appear to stall when you travel.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(60f, 604800f), Array.Empty<object>()));
			ToolRange = ((BaseUnityPlugin)this).Config.Bind<float>("Linker rod", "Range", 64f, new ConfigDescription("How far the linker rod reveals links, in metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 256f), Array.Empty<object>()));
			BlockInputWhileMarking = ((BaseUnityPlugin)this).Config.Bind<bool>("Marking", "BlockInputWhileMarking", true, "While marking storage, allow only movement. The marking keys otherwise also trigger hotbar slots, sitting down and the menu.");
			CancelMarkingOnDamage = ((BaseUnityPlugin)this).Config.Bind<bool>("Marking", "CancelOnDamage", true, "Stop marking when you take damage.");
			Verbose = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Verbose", false, "Log every transfer.");
			LinkerTool.Register();
			_harmony = new Harmony("nishinku.smelterlink");
			_harmony.PatchAll();
			((MonoBehaviour)this).StartCoroutine(TickLoop());
			Log.LogInfo((object)"Nishinku's SmelterLink 0.3.0 loaded.");
		}

		private void OnDestroy()
		{
			((MonoBehaviour)this).StopAllCoroutines();
			LinkMode.Shutdown();
			LinkLines.Shutdown();
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}

		private void Update()
		{
			LinkMode.Update();
			LinkLines.Begin();
			LinkerTool.Draw();
			LinkMode.Draw();
			LinkLines.End();
		}

		private void OnGUI()
		{
			LinkMode.DrawGui();
		}

		private IEnumerator TickLoop()
		{
			while (true)
			{
				yield return (object)new WaitForSeconds(TickInterval.Value);
				if (!InWorld())
				{
					if (Registry.Ready)
					{
						Registry.Reset();
					}
					continue;
				}
				if (!Registry.Ready)
				{
					Registry.Rebuild();
				}
				if (ZNet.instance.IsServer())
				{
					try
					{
						Tick();
					}
					catch (Exception ex)
					{
						Log.LogError((object)("Tick failed: " + ex));
					}
				}
			}
		}

		private static bool InWorld()
		{
			if ((Object)(object)ZNet.instance != (Object)null && ZDOMan.instance != null && (Object)(object)ZNetScene.instance != (Object)null && (Object)(object)ObjectDB.instance != (Object)null)
			{
				return (Object)(object)Player.m_localPlayer != (Object)null;
			}
			return false;
		}

		private static void Tick()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_0036: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			Registry.CopyInto(_tickBuffer);
			List<ZDOID> tickBuffer = _tickBuffer;
			for (int i = 0; i < tickBuffer.Count; i++)
			{
				ZDOID val = tickBuffer[i];
				ZDO zDO = ZDOMan.instance.GetZDO(val);
				if (zDO == null || !zDO.IsValid())
				{
					Registry.Forget(val);
					continue;
				}
				Smelter val2 = Registry.PrefabFor(zDO);
				if ((Object)(object)val2 == (Object)null)
				{
					Registry.Forget(val);
				}
				else if (!Links.HasAny(zDO))
				{
					Registry.Forget(val);
				}
				else if (!ZNetScene.instance.m_instances.ContainsKey(zDO) && !Links.OwnedByOther(zDO))
				{
					int num = SmelterOps.FeedFuel(zDO, val2);
					int num2 = SmelterOps.FeedOre(zDO, val2);
					SmelterOps.FlushPendingOutput(zDO, val2);
					int num3 = 0;
					if (OfflineSmelting.Value)
					{
						num3 = SmelterOps.Simulate(zDO, val2);
					}
					if (Verbose.Value && (num > 0 || num2 > 0 || num3 > 0))
					{
						ManualLogSource log = Log;
						string[] obj = new string[10] { val2.m_name, " @ ", null, null, null, null, null, null, null, null };
						Vector3 position = zDO.GetPosition();
						obj[2] = ((Vector3)(ref position)).ToString("0");
						obj[3] = " +";
						obj[4] = num.ToString();
						obj[5] = " fuel, +";
						obj[6] = num2.ToString();
						obj[7] = " ore, ";
						obj[8] = num3.ToString();
						obj[9] = " produced";
						log.LogInfo((object)string.Concat(obj));
					}
				}
			}
		}
	}
	internal static class ChestIndex
	{
		private static readonly Dictionary<long, ZDOID> _byCid = new Dictionary<long, ZDOID>();

		private static float _nextScan;

		public static int Count => _byCid.Count;

		public static void Reset()
		{
			_byCid.Clear();
			_nextScan = 0f;
		}

		public static void Register(long cid, ZDOID id)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (cid != 0L)
			{
				_byCid[cid] = id;
			}
		}

		public static ZDO Find(long cid)
		{
			//IL_0020: 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)
			if (cid == 0L || ZDOMan.instance == null)
			{
				return null;
			}
			if (_byCid.TryGetValue(cid, out var value))
			{
				ZDO zDO = ZDOMan.instance.GetZDO(value);
				if (zDO != null && zDO.IsValid() && zDO.GetLong("slink_cid", 0L) == cid)
				{
					return zDO;
				}
				_byCid.Remove(cid);
			}
			Rescan();
			if (!_byCid.TryGetValue(cid, out value))
			{
				return null;
			}
			return ZDOMan.instance.GetZDO(value);
		}

		public static void Rescan(bool force = false)
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			if (ZDOMan.instance == null || (!force && Time.time < _nextScan))
			{
				return;
			}
			_nextScan = Time.time + 10f;
			_byCid.Clear();
			foreach (KeyValuePair<ZDOID, ZDO> item in ZDOMan.instance.m_objectsByID)
			{
				ZDO value = item.Value;
				if (value != null && value.IsValid())
				{
					long num = value.GetLong("slink_cid", 0L);
					if (num != 0L)
					{
						_byCid[num] = item.Key;
					}
				}
			}
		}
	}
	internal static class ContainerIO
	{
		private struct Cached
		{
			public uint Revision;

			public Inventory Inventory;
		}

		private static readonly Dictionary<ZDOID, Cached> _cache = new Dictionary<ZDOID, Cached>();

		private static readonly Dictionary<int, Container> _prefabs = new Dictionary<int, Container>();

		public static void Reset()
		{
			_cache.Clear();
			_prefabs.Clear();
		}

		public static Container PrefabFor(ZDO zdo)
		{
			if (zdo == null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return null;
			}
			int prefab = zdo.GetPrefab();
			if (_prefabs.TryGetValue(prefab, out var value))
			{
				return value;
			}
			GameObject prefab2 = ZNetScene.instance.GetPrefab(prefab);
			if ((Object)(object)prefab2 == (Object)null)
			{
				return null;
			}
			value = prefab2.GetComponent<Container>();
			if ((Object)(object)value != (Object)null)
			{
				_prefabs[prefab] = value;
			}
			return value;
		}

		public static Container LiveInstance(ZDO zdo)
		{
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				return null;
			}
			if (!ZNetScene.instance.m_instances.TryGetValue(zdo, out var value))
			{
				return null;
			}
			if (!((Object)(object)value == (Object)null))
			{
				return ((Component)value).GetComponentInChildren<Container>();
			}
			return null;
		}

		public static bool Open(ZDO zdo, bool forPut, out Inventory inventory, out Action commit)
		{
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Expected O, but got Unknown
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Expected O, but got Unknown
			inventory = null;
			commit = null;
			if (zdo == null || !zdo.IsValid())
			{
				return false;
			}
			if (Links.OwnedByOther(zdo))
			{
				return false;
			}
			Container live = LiveInstance(zdo);
			if ((Object)(object)live != (Object)null)
			{
				if (live.IsInUse() && (!forPut || !zdo.IsOwner()))
				{
					return false;
				}
				Inventory inventory2 = live.GetInventory();
				if (inventory2 == null)
				{
					return false;
				}
				inventory = inventory2;
				commit = delegate
				{
					//IL_0016: Unknown result type (might be due to invalid IL or missing references)
					live.Save();
					_cache.Remove(zdo.m_uid);
				};
				return true;
			}
			Container val = PrefabFor(zdo);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			if (zdo.GetInt(ZDOVars.s_inUse, 0) == 1)
			{
				return false;
			}
			if (_cache.TryGetValue(zdo.m_uid, out var value) && value.Revision == zdo.DataRevision)
			{
				inventory = value.Inventory;
			}
			else
			{
				inventory = new Inventory(val.m_name, val.m_bkg, val.m_width, val.m_height);
				byte[] byteArray = zdo.GetByteArray(ZDOVars.s_items, (byte[])null);
				if (byteArray != null)
				{
					inventory.Load(new ZPackage(byteArray));
				}
				_cache[zdo.m_uid] = new Cached
				{
					Revision = zdo.DataRevision,
					Inventory = inventory
				};
			}
			Inventory toSave = inventory;
			commit = delegate
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Expected O, but got Unknown
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				ZPackage val2 = new ZPackage();
				toSave.Save(val2);
				Links.Claim(zdo);
				zdo.Set(ZDOVars.s_items, val2.GetArray());
				_cache[zdo.m_uid] = new Cached
				{
					Revision = zdo.DataRevision,
					Inventory = toSave
				};
			};
			return true;
		}

		public static int Take(ZDO zdo, string prefabName, int want)
		{
			if (want <= 0)
			{
				return 0;
			}
			if (!Open(zdo, forPut: false, out var inventory, out var commit))
			{
				return 0;
			}
			int num = 0;
			List<ItemData> allItems = inventory.GetAllItems();
			int num2 = allItems.Count - 1;
			while (num2 >= 0 && num < want)
			{
				ItemData val = allItems[num2];
				if (val != null && !((Object)(object)val.m_dropPrefab == (Object)null) && !(((Object)val.m_dropPrefab).name != prefabName))
				{
					int num3 = Mathf.Min(val.m_stack, want - num);
					inventory.RemoveItem(val, num3);
					num += num3;
				}
				num2--;
			}
			if (num > 0)
			{
				commit();
			}
			return num;
		}

		public static bool Put(ZDO zdo, string prefabName, int amount)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			if (amount <= 0)
			{
				return true;
			}
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				return false;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefabName);
			if ((Object)(object)itemPrefab == (Object)null)
			{
				return false;
			}
			if (!Open(zdo, forPut: true, out var inventory, out var commit))
			{
				return false;
			}
			if (!inventory.CanAddItem(itemPrefab, amount))
			{
				return false;
			}
			if (inventory.AddItem(prefabName, amount, 1, 0, 0L, "", new Vector2i(-1, -1), false, false, false) == null)
			{
				return false;
			}
			commit();
			return true;
		}
	}
	internal static class LinkerTool
	{
		public const string PrefabName = "SmelterLinkRod";

		private static readonly List<ZDOID> _nearby = new List<ZDOID>();

		private static readonly List<ZDOID> _usage = new List<ZDOID>();

		public static void Register()
		{
			PrefabManager.OnVanillaPrefabsAvailable += Create;
		}

		private static void Create()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected O, but got Unknown
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			PrefabManager.OnVanillaPrefabsAvailable -= Create;
			ItemConfig val = new ItemConfig();
			val.Name = "Linking Rod";
			val.Description = "Reveals smelter storage links. Point at a smelter and press " + LinkMode.KeyName() + " to change them.";
			val.CraftingStation = CraftingStations.Workbench;
			val.Requirements = (RequirementConfig[])(object)new RequirementConfig[3]
			{
				new RequirementConfig("Wood", 5, 0, true),
				new RequirementConfig("SurtlingCore", 1, 0, true),
				new RequirementConfig("Resin", 2, 0, true)
			};
			ItemConfig val2 = val;
			CustomItem val3 = new CustomItem("SmelterLinkRod", "Club", val2);
			if ((Object)(object)val3.ItemDrop == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Could not clone the base prefab; linker rod unavailable.");
				return;
			}
			SharedData shared = val3.ItemDrop.m_itemData.m_shared;
			shared.m_maxStackSize = 1;
			shared.m_weight = 1f;
			shared.m_maxQuality = 1;
			shared.m_useDurability = false;
			shared.m_damages = default(DamageTypes);
			shared.m_toolTier = 0;
			ItemManager.Instance.AddItem(val3);
			Plugin.Log.LogInfo((object)"Registered linker rod.");
		}

		public static bool InHand()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return false;
			}
			ItemData rightItem = ((Humanoid)localPlayer).GetRightItem();
			if (rightItem != null && (Object)(object)rightItem.m_dropPrefab != (Object)null)
			{
				return ((Object)rightItem.m_dropPrefab).name == "SmelterLinkRod";
			}
			return false;
		}

		public static void Draw()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: 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_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: 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_0091: 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_00c2: 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)
			//IL_0105: 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_010f: Unknown result type (might be due to invalid IL or missing references)
			if (!InHand() || ZDOMan.instance == null || !Registry.Ready)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			Vector3 position = ((Component)localPlayer).transform.position;
			float value = Plugin.ToolRange.Value;
			float num = value * value;
			long num2 = FocusedChest(localPlayer);
			Registry.CopyInto(_nearby);
			for (int i = 0; i < _nearby.Count; i++)
			{
				ZDO zDO = ZDOMan.instance.GetZDO(_nearby[i]);
				if (zDO == null || !zDO.IsValid())
				{
					continue;
				}
				Vector3 val = zDO.GetPosition() + Vector3.up;
				Vector3 val2 = val - position;
				if (((Vector3)(ref val2)).sqrMagnitude > num)
				{
					continue;
				}
				for (int j = 0; j < 3; j++)
				{
					Slot slot = (Slot)j;
					ZDO val3 = Links.Resolve(zDO, slot);
					if (val3 != null)
					{
						Color colour = Links.Tint(slot);
						bool flag = num2 != 0L && Links.GetCid(zDO, slot) != num2;
						colour.a = (flag ? 0.12f : 0.85f);
						LinkLines.Add(val, val3.GetPosition() + Vector3.up * 0.5f, colour, flag ? 0.05f : 0.1f);
					}
				}
			}
		}

		private static long FocusedChest(Player player)
		{
			GameObject hoverObject = ((Humanoid)player).GetHoverObject();
			if ((Object)(object)hoverObject == (Object)null)
			{
				return 0L;
			}
			Container componentInParent = hoverObject.GetComponentInParent<Container>();
			if ((Object)(object)componentInParent == (Object)null)
			{
				return 0L;
			}
			ZDO val = Links.ZdoOf(componentInParent);
			if (val != null)
			{
				return val.GetLong("slink_cid", 0L);
			}
			return 0L;
		}

		public static string DescribeChestUsage(long chest)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			if (chest == 0L || !Registry.Ready || ZDOMan.instance == null)
			{
				return null;
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			Registry.CopyInto(_usage);
			for (int i = 0; i < _usage.Count; i++)
			{
				ZDO zDO = ZDOMan.instance.GetZDO(_usage[i]);
				if (zDO != null && zDO.IsValid())
				{
					if (Links.GetCid(zDO, Slot.Input) == chest)
					{
						num++;
					}
					if (Links.GetCid(zDO, Slot.Fuel) == chest)
					{
						num2++;
					}
					if (Links.GetCid(zDO, Slot.Output) == chest)
					{
						num3++;
					}
				}
			}
			if (num == 0 && num2 == 0 && num3 == 0)
			{
				return null;
			}
			List<string> list = new List<string>();
			if (num > 0)
			{
				list.Add(Part(num, Slot.Input));
			}
			if (num2 > 0)
			{
				list.Add(Part(num2, Slot.Fuel));
			}
			if (num3 > 0)
			{
				list.Add(Part(num3, Slot.Output));
			}
			return string.Join("  ", list.ToArray());
		}

		private static string Part(int count, Slot slot)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			return "<color=#" + ColorUtility.ToHtmlStringRGB(Links.Tint(slot)) + ">" + count + " " + Links.Label(slot) + "</color>";
		}
	}
	internal static class LinkLines
	{
		private static readonly List<LineRenderer> _pool = new List<LineRenderer>();

		private static GameObject _root;

		private static Material _material;

		private static int _used;

		public static void Begin()
		{
			_used = 0;
		}

		public static void Add(Vector3 from, Vector3 to, Color colour, float width)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			LineRenderer val = Rent();
			if (!((Object)(object)val == (Object)null))
			{
				((Renderer)val).enabled = true;
				val.startColor = colour;
				val.endColor = colour;
				val.widthMultiplier = width;
				val.SetPosition(0, from);
				val.SetPosition(1, to);
			}
		}

		public static void End()
		{
			for (int i = _used; i < _pool.Count; i++)
			{
				if ((Object)(object)_pool[i] != (Object)null)
				{
					((Renderer)_pool[i]).enabled = false;
				}
			}
		}

		private static LineRenderer Rent()
		{
			//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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			if (_used < _pool.Count)
			{
				LineRenderer result = _pool[_used];
				_used++;
				return result;
			}
			if ((Object)(object)_root == (Object)null)
			{
				_root = new GameObject("SmelterLinkLines");
				Object.DontDestroyOnLoad((Object)(object)_root);
				_material = new Material(Shader.Find("Sprites/Default"));
			}
			GameObject val = new GameObject("link" + _pool.Count);
			val.transform.SetParent(_root.transform);
			LineRenderer val2 = val.AddComponent<LineRenderer>();
			((Renderer)val2).material = _material;
			val2.positionCount = 2;
			val2.useWorldSpace = true;
			val2.numCapVertices = 4;
			val2.textureMode = (LineTextureMode)1;
			((Renderer)val2).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)val2).receiveShadows = false;
			((Renderer)val2).enabled = false;
			_pool.Add(val2);
			_used++;
			return val2;
		}

		public static void Shutdown()
		{
			_pool.Clear();
			_used = 0;
			if ((Object)(object)_root != (Object)null)
			{
				Object.Destroy((Object)(object)_root);
				_root = null;
			}
		}
	}
	internal static class LinkMode
	{
		private static ZDOID _smelter = ZDOID.None;

		private static string _smelterName = "";

		private static Slot _slot = Slot.Input;

		private static string _flash = "";

		private static float _flashUntil;

		private static GUIStyle _panel;

		private static GUIStyle _title;

		private static GUIStyle _line;

		public static bool Selecting => !((ZDOID)(ref _smelter)).IsNone();

		public static Slot ActiveSlot => _slot;

		public static string SmelterName => _smelterName;

		public static void Update()
		{
			//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)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)ZNetScene.instance == (Object)null || ZDOMan.instance == null)
			{
				if (Selecting)
				{
					Cancel();
				}
			}
			else
			{
				if (TypingOrInMenu())
				{
					return;
				}
				if (Selecting)
				{
					if (Input.GetKeyDown((KeyCode)27))
					{
						Cancel();
						return;
					}
					if (Input.GetKeyDown((KeyCode)49))
					{
						SetSlot(Slot.Input);
					}
					if (Input.GetKeyDown((KeyCode)50))
					{
						SetSlot(Slot.Fuel);
					}
					if (Input.GetKeyDown((KeyCode)51))
					{
						SetSlot(Slot.Output);
					}
					if (Input.GetKeyDown((KeyCode)120))
					{
						ClearSlot();
					}
				}
				KeyboardShortcut value = Plugin.LinkKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					HandleKey(localPlayer);
				}
			}
		}

		public static void Draw()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			if (!Selecting || ZDOMan.instance == null)
			{
				return;
			}
			ZDO zDO = ZDOMan.instance.GetZDO(_smelter);
			if (zDO == null || !zDO.IsValid())
			{
				Cancel();
				return;
			}
			Vector3 val = zDO.GetPosition() + Vector3.up;
			for (int i = 0; i < 3; i++)
			{
				Slot slot = (Slot)i;
				ZDO val2 = Links.Resolve(zDO, slot);
				if (val2 != null)
				{
					Color colour = Links.Tint(slot);
					colour.a = ((slot == _slot) ? 1f : 0.3f);
					LinkLines.Add(val, val2.GetPosition() + Vector3.up * 0.5f, colour, (slot == _slot) ? 0.14f : 0.08f);
				}
			}
		}

		private static bool TypingOrInMenu()
		{
			if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())
			{
				return true;
			}
			if (Menu.IsVisible())
			{
				return true;
			}
			if (InventoryGui.IsVisible())
			{
				return true;
			}
			if (TextInput.IsVisible())
			{
				return true;
			}
			return false;
		}

		private static void HandleKey(Player player)
		{
			//IL_005b: 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)
			GameObject hoverObject = ((Humanoid)player).GetHoverObject();
			if (Selecting)
			{
				if ((Object)(object)hoverObject != (Object)null)
				{
					Container componentInParent = hoverObject.GetComponentInParent<Container>();
					if ((Object)(object)componentInParent != (Object)null)
					{
						Bind(componentInParent);
						return;
					}
				}
				Cancel();
			}
			else
			{
				if ((Object)(object)hoverObject == (Object)null)
				{
					return;
				}
				Smelter componentInParent2 = hoverObject.GetComponentInParent<Smelter>();
				if (!((Object)(object)componentInParent2 == (Object)null))
				{
					ZDO val = Links.ZdoOf(componentInParent2);
					if (val != null)
					{
						_smelter = val.m_uid;
						_smelterName = Localization.instance.Localize(componentInParent2.m_name);
						_slot = SlotForHover(componentInParent2, hoverObject);
						Flash("Select " + Links.Label(_slot).ToUpper() + " chest");
					}
				}
			}
		}

		public static Slot SlotForHover(Smelter smelter, GameObject hovering)
		{
			Switch val = (((Object)(object)hovering == (Object)null) ? null : hovering.GetComponentInParent<Switch>());
			if ((Object)(object)val != (Object)null)
			{
				if ((Object)(object)smelter.m_addWoodSwitch != (Object)null && (Object)(object)val == (Object)(object)smelter.m_addWoodSwitch)
				{
					return Slot.Fuel;
				}
				if ((Object)(object)smelter.m_emptyOreSwitch != (Object)null && (Object)(object)val == (Object)(object)smelter.m_emptyOreSwitch)
				{
					return Slot.Output;
				}
			}
			return Slot.Input;
		}

		private static void Bind(Container container)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = ZDOMan.instance.GetZDO(_smelter);
			if (zDO == null || !zDO.IsValid())
			{
				Cancel();
				return;
			}
			ZDO val = Links.ZdoOf(container);
			if (val != null && !(val.m_uid == _smelter))
			{
				Links.Set(zDO, _slot, val);
				Registry.Track(zDO);
				Patches.CacheEnvironment(zDO);
				float num = Vector3.Distance(zDO.GetPosition(), val.GetPosition());
				string text = Localization.instance.Localize(container.m_name);
				Message(Links.Label(_slot).ToUpper() + " set to " + text + " (" + num.ToString("0") + "m)");
				Flash(Links.Label(_slot).ToUpper() + " set");
			}
		}

		private static void SetSlot(Slot slot)
		{
			_slot = slot;
			Flash("Select " + Links.Label(slot).ToUpper() + " chest");
		}

		private static void ClearSlot()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = ZDOMan.instance.GetZDO(_smelter);
			if (zDO != null)
			{
				Links.Clear(zDO, _slot);
				if (!Links.HasAny(zDO))
				{
					Registry.Forget(zDO.m_uid);
				}
				Message(Links.Label(_slot).ToUpper() + " cleared");
				Flash(Links.Label(_slot).ToUpper() + " cleared");
			}
		}

		private static void Cancel()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			_smelter = ZDOID.None;
			_smelterName = "";
		}

		public static void CancelFromOutside()
		{
			if (Selecting)
			{
				Cancel();
				Message("Marking cancelled");
			}
		}

		public static string KeyName()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: 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_0012: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = Plugin.LinkKey.Value;
			return ((object)((KeyboardShortcut)(ref value)).MainKey/*cast due to .constrained prefix*/).ToString();
		}

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

		private static void Flash(string text)
		{
			_flash = text;
			_flashUntil = Time.time + 2f;
		}

		public static void DrawGui()
		{
			//IL_0019: 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_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: 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_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			if (!Selecting)
			{
				return;
			}
			EnsureStyles();
			ZDO val = ((ZDOMan.instance == null) ? null : ZDOMan.instance.GetZDO(_smelter));
			if (val == null)
			{
				return;
			}
			float num = 520f;
			float num2 = 150f;
			float num3 = ((float)Screen.width - num) * 0.5f;
			Rect val2 = default(Rect);
			((Rect)(ref val2))..ctor(num3, 60f, num, num2);
			GUI.Box(val2, GUIContent.none, _panel);
			GUILayout.BeginArea(new Rect(((Rect)(ref val2)).x + 16f, ((Rect)(ref val2)).y + 12f, ((Rect)(ref val2)).width - 32f, ((Rect)(ref val2)).height - 24f));
			GUILayout.Label("Marking storage for " + _smelterName, _title, Array.Empty<GUILayoutOption>());
			for (int i = 0; i < 3; i++)
			{
				Slot slot = (Slot)i;
				ZDO val3 = Links.Resolve(val, slot);
				string text;
				if (val3 == null)
				{
					text = "not set";
				}
				else
				{
					Container val4 = ContainerIO.PrefabFor(val3);
					text = (((Object)(object)val4 == (Object)null) ? "chest" : Localization.instance.Localize(val4.m_name)) + " (" + Vector3.Distance(val.GetPosition(), val3.GetPosition()).ToString("0") + "m)";
				}
				string text2 = ((slot == _slot) ? "> " : "   ");
				Color textColor = Links.Tint(slot);
				if (slot != _slot)
				{
					textColor.a = 0.55f;
				}
				_line.normal.textColor = textColor;
				GUILayout.Label(text2 + "[" + (i + 1) + "] " + Links.Label(slot) + ": " + text, _line, Array.Empty<GUILayoutOption>());
			}
			_line.normal.textColor = new Color(0.85f, 0.85f, 0.85f);
			string text3 = "Look at a chest and press " + KeyName() + "   ·   [X] clear   ·   [Esc] cancel";
			if (Time.time < _flashUntil)
			{
				text3 = _flash + "   —   " + text3;
			}
			GUILayout.Label(text3, _line, Array.Empty<GUILayoutOption>());
			GUILayout.EndArea();
		}

		private static void EnsureStyles()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0027: 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_004b: Expected O, but got Unknown
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			//IL_0090: 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_00ae: Expected O, but got Unknown
			if (_panel == null)
			{
				Texture2D val = new Texture2D(1, 1);
				val.SetPixel(0, 0, new Color(0f, 0f, 0f, 0.75f));
				val.Apply();
				_panel = new GUIStyle(GUI.skin.box);
				_panel.normal.background = val;
				_title = new GUIStyle(GUI.skin.label);
				_title.fontSize = 16;
				_title.fontStyle = (FontStyle)1;
				_title.normal.textColor = Color.white;
				_line = new GUIStyle(GUI.skin.label);
				_line.fontSize = 14;
			}
		}

		public static void Shutdown()
		{
			Cancel();
		}
	}
	internal enum Slot
	{
		Input,
		Fuel,
		Output
	}
	internal static class Links
	{
		public const string ChestId = "slink_cid";

		public const string HaveRoof = "slink_roof";

		public const string BlockedSmoke = "slink_smoke";

		public const string WindPower = "slink_wind";

		private const string LegacyInput = "slink_in";

		private const string LegacyFuel = "slink_fuel";

		private const string LegacyOutput = "slink_out";

		public static string Label(Slot slot)
		{
			return slot switch
			{
				Slot.Input => "input", 
				Slot.Fuel => "fuel", 
				_ => "output", 
			};
		}

		public static Color Tint(Slot slot)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			return (Color)(slot switch
			{
				Slot.Input => new Color(0.35f, 0.75f, 1f), 
				Slot.Fuel => new Color(1f, 0.6f, 0.2f), 
				_ => new Color(0.45f, 0.95f, 0.5f), 
			});
		}

		private static string CidKey(Slot slot)
		{
			return slot switch
			{
				Slot.Input => "slink_in_cid", 
				Slot.Fuel => "slink_fuel_cid", 
				_ => "slink_out_cid", 
			};
		}

		public static bool OwnedByOther(ZDO zdo)
		{
			if (zdo != null && zdo.HasOwner())
			{
				return !zdo.IsOwner();
			}
			return false;
		}

		public static void Claim(ZDO zdo)
		{
			if (zdo != null && !zdo.IsOwner() && !zdo.HasOwner())
			{
				zdo.SetOwner(ZDOMan.instance.m_sessionID);
			}
		}

		public static long GetCid(ZDO smelter, Slot slot)
		{
			if (smelter != null)
			{
				return smelter.GetLong(CidKey(slot), 0L);
			}
			return 0L;
		}

		public static bool HasAny(ZDO zdo)
		{
			if (zdo == null)
			{
				return false;
			}
			if (GetCid(zdo, Slot.Input) == 0L && GetCid(zdo, Slot.Fuel) == 0L)
			{
				return GetCid(zdo, Slot.Output) != 0;
			}
			return true;
		}

		public static bool HasLegacyOnly(ZDO zdo)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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)
			if (zdo == null || HasAny(zdo))
			{
				return false;
			}
			ZDOID zDOID = zdo.GetZDOID("slink_in");
			if (((ZDOID)(ref zDOID)).IsNone())
			{
				zDOID = zdo.GetZDOID("slink_fuel");
				if (((ZDOID)(ref zDOID)).IsNone())
				{
					zDOID = zdo.GetZDOID("slink_out");
					return !((ZDOID)(ref zDOID)).IsNone();
				}
			}
			return true;
		}

		public static long EnsureChestId(ZDO chest)
		{
			//IL_0013: 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)
			long num = chest.GetLong("slink_cid", 0L);
			if (num != 0L)
			{
				ChestIndex.Register(num, chest.m_uid);
				return num;
			}
			num = Utils.GenerateUID();
			if (num == 0L)
			{
				num = 1L;
			}
			if (!chest.IsOwner())
			{
				chest.SetOwner(ZDOMan.instance.m_sessionID);
			}
			chest.Set("slink_cid", num);
			ChestIndex.Register(num, chest.m_uid);
			return num;
		}

		public static void Set(ZDO smelter, Slot slot, ZDO chest)
		{
			if (smelter != null && chest != null)
			{
				long num = EnsureChestId(chest);
				Claim(smelter);
				smelter.Set(CidKey(slot), num);
			}
		}

		public static void Clear(ZDO smelter, Slot slot)
		{
			if (smelter != null)
			{
				Claim(smelter);
				smelter.Set(CidKey(slot), 0L);
			}
		}

		public static ZDO Resolve(ZDO smelter, Slot slot)
		{
			long cid = GetCid(smelter, slot);
			if (cid == 0L)
			{
				return null;
			}
			ZDO val = ChestIndex.Find(cid);
			if (val == null)
			{
				return null;
			}
			if (!((Object)(object)ContainerIO.PrefabFor(val) == (Object)null))
			{
				return val;
			}
			return null;
		}

		public static ZDO ZdoOf(Container container)
		{
			if ((Object)(object)container == (Object)null || (Object)(object)container.m_nview == (Object)null)
			{
				return null;
			}
			if (!container.m_nview.IsValid())
			{
				return null;
			}
			return container.m_nview.GetZDO();
		}

		public static ZDO ZdoOf(Smelter smelter)
		{
			if ((Object)(object)smelter == (Object)null || (Object)(object)smelter.m_nview == (Object)null)
			{
				return null;
			}
			if (!smelter.m_nview.IsValid())
			{
				return null;
			}
			return smelter.m_nview.GetZDO();
		}
	}
	[HarmonyPatch]
	internal static class Patches
	{
		public static void CacheEnvironment(ZDO zdo)
		{
			if (ZNetScene.instance.m_instances.TryGetValue(zdo, out var value) && !((Object)(object)value == (Object)null))
			{
				Smelter componentInChildren = ((Component)value).GetComponentInChildren<Smelter>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					CacheEnvironment(componentInChildren, zdo);
				}
			}
		}

		private static void CacheEnvironment(Smelter smelter, ZDO zdo)
		{
			zdo.Set("slink_roof", smelter.m_haveRoof);
			zdo.Set("slink_smoke", smelter.m_blockedSmoke);
			if ((Object)(object)smelter.m_windmill != (Object)null)
			{
				zdo.Set("slink_wind", smelter.m_windmill.GetPowerOutput());
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Smelter), "UpdateSmelter")]
		private static void SmelterTicked(Smelter __instance)
		{
			ZNetView nview = __instance.m_nview;
			if (!((Object)(object)nview == (Object)null) && nview.IsValid() && nview.IsOwner())
			{
				ZDO zDO = nview.GetZDO();
				if (Links.HasAny(zDO))
				{
					Registry.Track(zDO);
					CacheEnvironment(__instance, zDO);
					SmelterOps.FeedFuel(zDO, __instance);
					SmelterOps.FeedOre(zDO, __instance);
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Smelter), "Spawn")]
		private static bool SmelterSpawn(Smelter __instance, string ore, int stack)
		{
			//IL_006e: 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_0087: 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)
			ZNetView nview = __instance.m_nview;
			if ((Object)(object)nview == (Object)null || !nview.IsValid())
			{
				return true;
			}
			ZDO val = Links.Resolve(nview.GetZDO(), Slot.Output);
			if (val == null)
			{
				return true;
			}
			ItemConversion val2 = SmelterOps.ConversionFor(__instance, ore);
			if (val2 == null || (Object)(object)val2.m_to == (Object)null)
			{
				return true;
			}
			if (!ContainerIO.Put(val, ((Object)((Component)val2.m_to).gameObject).name, stack))
			{
				return true;
			}
			__instance.m_produceEffects.Create(((Component)__instance).transform.position, ((Component)__instance).transform.rotation, (Transform)null, 1f, -1, default(ZDOID));
			return false;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Smelter), "OnHoverAddOre")]
		private static void HoverOre(Smelter __instance, ref string __result)
		{
			__result = Append(__instance, __result, Slot.Input);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Smelter), "OnHoverAddFuel")]
		private static void HoverFuel(Smelter __instance, ref string __result)
		{
			__result = Append(__instance, __result, Slot.Fuel);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Smelter), "OnHoverEmptyOre")]
		private static void HoverEmpty(Smelter __instance, ref string __result)
		{
			__result = Append(__instance, __result, Slot.Output);
		}

		private static string Append(Smelter smelter, string text, Slot slot)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			ZNetView nview = smelter.m_nview;
			if ((Object)(object)nview == (Object)null || !nview.IsValid())
			{
				return text;
			}
			ZDO zDO = nview.GetZDO();
			ZDO val = Links.Resolve(zDO, slot);
			string text2 = LinkMode.KeyName();
			string text3 = Links.Label(slot);
			string text4 = ColorUtility.ToHtmlStringRGB(Links.Tint(slot));
			if (val == null)
			{
				return text + "\n[<color=yellow><b>" + text2 + "</b></color>] Select " + text3 + " chest";
			}
			Container val2 = ContainerIO.PrefabFor(val);
			string text5 = (((Object)(object)val2 == (Object)null) ? "chest" : Localization.instance.Localize(val2.m_name));
			float num = Vector3.Distance(zDO.GetPosition(), val.GetPosition());
			string text6 = "\n<color=#" + text4 + ">" + text3 + ": " + text5 + " (" + num.ToString("0") + "m)</color>";
			text6 = text6 + "\n[<color=yellow><b>" + text2 + "</b></color>] Change " + text3 + " chest";
			if (slot == Slot.Output)
			{
				return text + text6;
			}
			if (Links.Resolve(zDO, Slot.Output) == null)
			{
				text6 += "\n<color=#b0b0b0>No output chest — will not run while you are away</color>";
			}
			return text + text6;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Container), "GetHoverText")]
		private static void HoverContainer(Container __instance, ref string __result)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (LinkMode.Selecting)
			{
				string text = Links.Label(LinkMode.ActiveSlot).ToUpper();
				string text2 = ColorUtility.ToHtmlStringRGB(Links.Tint(LinkMode.ActiveSlot));
				__result = __result + "\n[<color=yellow><b>" + LinkMode.KeyName() + "</b></color>] Set as <color=#" + text2 + ">" + text + "</color> for " + LinkMode.SmelterName;
			}
			else if (LinkerTool.InHand())
			{
				ZDO val = Links.ZdoOf(__instance);
				if (val != null)
				{
					string text3 = LinkerTool.DescribeChestUsage(val.GetLong("slink_cid", 0L));
					__result += ((text3 == null) ? "\n<color=#808080>Not linked to any smelter</color>" : ("\nFeeds: " + text3));
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "TakeInput")]
		private static void BlockActionsWhileMarking(ref bool __result)
		{
			if (Plugin.BlockInputWhileMarking.Value && LinkMode.Selecting)
			{
				__result = false;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Menu), "Update")]
		private static bool BlockMenuWhileMarking()
		{
			if (Plugin.BlockInputWhileMarking.Value)
			{
				return !LinkMode.Selecting;
			}
			return true;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Character), "Damage")]
		private static void CancelMarkingOnDamage(Character __instance)
		{
			if (Plugin.CancelMarkingOnDamage.Value && LinkMode.Selecting && (Object)(object)__instance != (Object)null && (Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				LinkMode.CancelFromOutside();
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(ZNet), "Shutdown")]
		private static void NetShutdown()
		{
			Registry.Reset();
			LinkMode.Shutdown();
		}
	}
	internal static class Registry
	{
		private static readonly HashSet<ZDOID> _linked = new HashSet<ZDOID>();

		private static readonly Dictionary<int, Smelter> _smelterPrefabs = new Dictionary<int, Smelter>();

		public static bool Ready { get; private set; }

		public static int Count => _linked.Count;

		public static void Reset()
		{
			_linked.Clear();
			_smelterPrefabs.Clear();
			ContainerIO.Reset();
			ChestIndex.Reset();
			Ready = false;
		}

		public static Smelter PrefabFor(ZDO zdo)
		{
			if (zdo == null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return null;
			}
			int prefab = zdo.GetPrefab();
			if (_smelterPrefabs.TryGetValue(prefab, out var value))
			{
				return value;
			}
			GameObject prefab2 = ZNetScene.instance.GetPrefab(prefab);
			if ((Object)(object)prefab2 == (Object)null)
			{
				return null;
			}
			value = prefab2.GetComponent<Smelter>();
			if ((Object)(object)value != (Object)null)
			{
				_smelterPrefabs[prefab] = value;
			}
			return value;
		}

		public static void Track(ZDO zdo)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			if (zdo != null && zdo.IsValid())
			{
				_linked.Add(zdo.m_uid);
			}
		}

		public static void Forget(ZDOID id)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			_linked.Remove(id);
		}

		public static void Rebuild()
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			_linked.Clear();
			ContainerIO.Reset();
			if (ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return;
			}
			ChestIndex.Rescan(force: true);
			int num = 0;
			int num2 = 0;
			foreach (KeyValuePair<ZDOID, ZDO> item in ZDOMan.instance.m_objectsByID)
			{
				ZDO value = item.Value;
				if (value == null || !value.IsValid())
				{
					continue;
				}
				num++;
				if (!((Object)(object)PrefabFor(value) == (Object)null))
				{
					if (Links.HasAny(value))
					{
						_linked.Add(item.Key);
					}
					else if (Links.HasLegacyOnly(value))
					{
						num2++;
					}
				}
			}
			Ready = true;
			Plugin.Log.LogInfo((object)("Scanned " + num + " ZDOs: " + _linked.Count + " linked smelter(s), " + ChestIndex.Count + " marked chest(s)."));
			if (num2 > 0)
			{
				Plugin.Log.LogWarning((object)(num2 + " smelter(s) still carry 0.2.0 links. Those were stored in a form that does not survive a world reload and cannot be converted safely — mark those smelters again."));
			}
		}

		public static void CopyInto(List<ZDOID> target)
		{
			target.Clear();
			target.AddRange(_linked);
		}
	}
	internal static class SmelterOps
	{
		public static int QueueSize(ZDO zdo)
		{
			return zdo.GetInt(ZDOVars.s_queued, 0);
		}

		public static string QueuedOre(ZDO zdo)
		{
			if (QueueSize(zdo) != 0)
			{
				return zdo.GetString(ZDOVars.s_item0, "");
			}
			return "";
		}

		public static void QueueOre(ZDO zdo, string prefabName)
		{
			int num = QueueSize(zdo);
			zdo.Set("item" + num, prefabName);
			zdo.Set(ZDOVars.s_queued, num + 1, false);
		}

		public static void RemoveOneOre(ZDO zdo)
		{
			int num = QueueSize(zdo);
			if (num != 0)
			{
				for (int i = 0; i < num; i++)
				{
					zdo.Set("item" + i, zdo.GetString("item" + (i + 1), ""));
				}
				zdo.Set(ZDOVars.s_queued, num - 1, false);
			}
		}

		public static ItemConversion ConversionFor(Smelter prefab, string oreName)
		{
			for (int i = 0; i < prefab.m_conversion.Count; i++)
			{
				ItemConversion val = prefab.m_conversion[i];
				if ((Object)(object)val.m_from != (Object)null && ((Object)((Component)val.m_from).gameObject).name == oreName)
				{
					return val;
				}
			}
			return null;
		}

		public static int FeedFuel(ZDO zdo, Smelter prefab)
		{
			if (prefab.m_maxFuel <= 0 || (Object)(object)prefab.m_fuelItem == (Object)null)
			{
				return 0;
			}
			ZDO val = Links.Resolve(zdo, Slot.Fuel);
			if (val == null)
			{
				return 0;
			}
			float num = zdo.GetFloat(ZDOVars.s_fuel, 0f);
			int num2 = Mathf.FloorToInt((float)prefab.m_maxFuel - num);
			if (num2 <= 0)
			{
				return 0;
			}
			int num3 = ContainerIO.Take(val, ((Object)((Component)prefab.m_fuelItem).gameObject).name, num2);
			if (num3 > 0)
			{
				Links.Claim(zdo);
				zdo.Set(ZDOVars.s_fuel, num + (float)num3);
			}
			return num3;
		}

		public static int FeedOre(ZDO zdo, Smelter prefab)
		{
			if (prefab.m_maxOre <= 0)
			{
				return 0;
			}
			ZDO val = Links.Resolve(zdo, Slot.Input);
			if (val == null)
			{
				return 0;
			}
			int num = prefab.m_maxOre - QueueSize(zdo);
			if (num <= 0)
			{
				return 0;
			}
			int num2 = 0;
			for (int i = 0; i < prefab.m_conversion.Count; i++)
			{
				if (num <= 0)
				{
					break;
				}
				ItemConversion val2 = prefab.m_conversion[i];
				if ((Object)(object)val2.m_from == (Object)null)
				{
					continue;
				}
				string name = ((Object)((Component)val2.m_from).gameObject).name;
				int num3 = ContainerIO.Take(val, name, num);
				if (num3 > 0)
				{
					Links.Claim(zdo);
					for (int j = 0; j < num3; j++)
					{
						QueueOre(zdo, name);
					}
					num -= num3;
					num2 += num3;
				}
			}
			return num2;
		}

		public static bool FlushPendingOutput(ZDO zdo, Smelter prefab)
		{
			int num = zdo.GetInt(ZDOVars.s_spawnAmount, 0);
			if (num <= 0)
			{
				return false;
			}
			ZDO val = Links.Resolve(zdo, Slot.Output);
			if (val == null)
			{
				return false;
			}
			string oreName = zdo.GetString(ZDOVars.s_spawnOre, "");
			ItemConversion val2 = ConversionFor(prefab, oreName);
			if (val2 == null || (Object)(object)val2.m_to == (Object)null)
			{
				return false;
			}
			if (!ContainerIO.Put(val, ((Object)((Component)val2.m_to).gameObject).name, num))
			{
				return false;
			}
			Links.Claim(zdo);
			zdo.Set(ZDOVars.s_spawnOre, "");
			zdo.Set(ZDOVars.s_spawnAmount, 0, false);
			return true;
		}

		public static int Simulate(ZDO zdo, Smelter prefab)
		{
			if (prefab.m_secPerProduct <= 0f)
			{
				return 0;
			}
			ZDO val = Links.Resolve(zdo, Slot.Output);
			if (val == null)
			{
				return 0;
			}
			DateTime time = ZNet.instance.GetTime();
			long ticks = zdo.GetLong(ZDOVars.s_startTime, time.Ticks);
			double totalSeconds = (time - new DateTime(ticks)).TotalSeconds;
			if (totalSeconds <= 0.0)
			{
				return 0;
			}
			Links.Claim(zdo);
			zdo.Set(ZDOVars.s_startTime, time.Ticks);
			float num = zdo.GetFloat(ZDOVars.s_accTime, 0f) + (float)totalSeconds;
			float value = Plugin.MaxCatchupSeconds.Value;
			if (num > value)
			{
				num = value;
			}
			bool flag = zdo.GetBool("slink_roof", true);
			bool flag2 = zdo.GetBool("slink_smoke", false);
			float num2 = (Object.op_Implicit((Object)(object)prefab.m_windmill) ? zdo.GetFloat("slink_wind", 1f) : 1f);
			int num3 = 0;
			while (num >= 1f)
			{
				num -= 1f;
				float num4 = zdo.GetFloat(ZDOVars.s_fuel, 0f);
				string text = QueuedOre(zdo);
				if ((prefab.m_maxFuel != 0 && !(num4 > 0f)) || (prefab.m_maxOre != 0 && text == "") || (prefab.m_requiresRoof && !flag) || flag2)
				{
					continue;
				}
				ItemConversion val2 = ConversionFor(prefab, text);
				if (val2 == null || (Object)(object)val2.m_to == (Object)null)
				{
					num += 1f;
					break;
				}
				float num5 = 1f * num2;
				float num6 = zdo.GetFloat(ZDOVars.s_bakeTimer, 0f) + num5;
				if (num6 >= prefab.m_secPerProduct)
				{
					if (!ContainerIO.Put(val, ((Object)((Component)val2.m_to).gameObject).name, 1))
					{
						num += 1f;
						break;
					}
					zdo.Set(ZDOVars.s_bakeTimer, 0f);
					RemoveOneOre(zdo);
					num3++;
				}
				else
				{
					zdo.Set(ZDOVars.s_bakeTimer, num6);
				}
				if (prefab.m_maxFuel > 0)
				{
					float num7 = prefab.m_secPerProduct / (float)prefab.m_fuelPerProduct;
					num4 -= num5 / num7;
					if (num4 < 0.0001f)
					{
						num4 = 0f;
					}
					zdo.Set(ZDOVars.s_fuel, num4);
				}
			}
			zdo.Set(ZDOVars.s_accTime, num);
			return num3;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		internal IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}