Decompiled source of RestlessWorkshop v0.1.1

RestlessWorks.dll

Decompiled 8 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using RestlessQoL.Api;
using RestlessQoL.Core;
using RestlessQoL.HudTweaks;
using RestlessQoL.Storage;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("RestlessWorks")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.1.0")]
[assembly: AssemblyInformationalVersion("0.1.1+7bfda291f4bc832729cd62f1737852295c0f93ae")]
[assembly: AssemblyProduct("RestlessWorks")]
[assembly: AssemblyTitle("RestlessWorks")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace RestlessWorks
{
	public class Board : MonoBehaviour, Hoverable, Interactable
	{
		public string GetHoverName()
		{
			return Localization.instance.Localize("Work-order board");
		}

		public string GetHoverText()
		{
			return Localization.instance.Localize("[<color=yellow><b>$KEY_Use</b></color>] Work orders");
		}

		public float GetHoverOffset()
		{
			return 0.4f;
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			if (!(hold || alt))
			{
				Player val = (Player)(object)((user is Player) ? user : null);
				if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer))
				{
					ZNetView component = ((Component)this).GetComponent<ZNetView>();
					if ((Object)(object)component != (Object)null && component.IsValid() && !component.IsOwner())
					{
						component.ClaimOwnership();
					}
					Piece component2 = ((Component)this).GetComponent<Piece>();
					if ((Object)(object)component2 != (Object)null)
					{
						Works.Raise(component2);
					}
					return true;
				}
			}
			return false;
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			return false;
		}
	}
	internal static class BoardArt
	{
		public const string Id = "board";

		public const string UnityId = "board.from-unity";

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

		private static Texture2D? _albedo;

		private static Sprite? _icon;

		private static string? _folder;

		private static MethodInfo? _loadImage;

		private static bool _searched;

		public static Mesh? Mesh()
		{
			return Mesh("board");
		}

		public static Mesh? Mesh(string id)
		{
			if (Meshes.TryGetValue(id, out Mesh value))
			{
				return value;
			}
			string text = Path.Combine(Folder(), id + ".rcm");
			if (!File.Exists(text))
			{
				Plugin.Log.LogWarning((object)("board mesh missing " + text));
				return null;
			}
			Mesh val = ReadRcm(File.ReadAllBytes(text), id);
			if ((Object)(object)val != (Object)null)
			{
				Meshes[id] = val;
			}
			return val;
		}

		public static Texture2D? Albedo()
		{
			if ((Object)(object)_albedo != (Object)null)
			{
				return _albedo;
			}
			string text = Path.Combine(Folder(), "board.png");
			if (!File.Exists(text))
			{
				Plugin.Log.LogWarning((object)("board picture missing " + text));
				return null;
			}
			_albedo = DecodePng(File.ReadAllBytes(text), "board");
			return _albedo;
		}

		public static Sprite? Icon()
		{
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_icon != (Object)null)
			{
				return _icon;
			}
			Stream manifestResourceStream = typeof(BoardArt).Assembly.GetManifestResourceStream("RestlessWorks.Assets.board.png");
			if (manifestResourceStream == null)
			{
				Plugin.Log.LogWarning((object)"board icon missing");
				return null;
			}
			using (manifestResourceStream)
			{
				byte[] array = new byte[manifestResourceStream.Length];
				int num;
				for (int i = 0; i < array.Length; i += num)
				{
					num = manifestResourceStream.Read(array, i, array.Length - i);
					if (num <= 0)
					{
						break;
					}
				}
				Texture2D val = DecodePng(array, "board.icon");
				if ((Object)(object)val == (Object)null)
				{
					return null;
				}
				_icon = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
				((Object)_icon).name = "board";
				return _icon;
			}
		}

		private static string Folder()
		{
			if (_folder != null)
			{
				return _folder;
			}
			List<string> list = new List<string>();
			Plugin instance = Plugin.Instance;
			object file;
			if (instance == null)
			{
				file = null;
			}
			else
			{
				PluginInfo info = ((BaseUnityPlugin)instance).Info;
				file = ((info != null) ? info.Location : null);
			}
			AddRoot(list, (string?)file);
			AddRoot(list, typeof(BoardArt).Assembly.Location);
			foreach (string item in list)
			{
				string text = Path.Combine(item, "mesh");
				if (File.Exists(Path.Combine(text, "board.rcm")))
				{
					return Remember(text);
				}
				if (File.Exists(Path.Combine(item, "board.rcm")))
				{
					return Remember(item);
				}
			}
			_folder = Path.Combine((list.Count > 0) ? list[0] : ".", "mesh");
			Plugin.Log.LogWarning((object)("board mesh folder missing, looking in " + _folder));
			return _folder;
		}

		private static void AddRoot(List<string> roots, string? file)
		{
			string text = (string.IsNullOrEmpty(file) ? "" : (Path.GetDirectoryName(file) ?? ""));
			if (text.Length == 0)
			{
				return;
			}
			foreach (string root in roots)
			{
				if (string.Equals(root, text, StringComparison.OrdinalIgnoreCase))
				{
					return;
				}
			}
			roots.Add(text);
		}

		private static string Remember(string dir)
		{
			_folder = dir;
			Plugin.Log.LogInfo((object)("board mesh folder " + dir));
			return dir;
		}

		private static Mesh? ReadRcm(byte[] data, string id)
		{
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: 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_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: 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_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: 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_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Expected O, but got Unknown
			if (data.Length < 12 || data[0] != 82 || data[1] != 67 || data[2] != 77 || (data[3] != 49 && data[3] != 50))
			{
				Plugin.Log.LogWarning((object)"board mesh bad header");
				return null;
			}
			bool flag = data[3] == 49;
			int num = 4;
			int num2 = BitConverter.ToInt32(data, num);
			num += 4;
			int num3 = BitConverter.ToInt32(data, num);
			num += 4;
			if (num2 <= 0 || num3 <= 0 || num + num2 * 32 + num3 * 4 > data.Length)
			{
				Plugin.Log.LogWarning((object)"board mesh truncated");
				return null;
			}
			Vector3[] array = (Vector3[])(object)new Vector3[num2];
			Vector3[] array2 = (Vector3[])(object)new Vector3[num2];
			Vector2[] array3 = (Vector2[])(object)new Vector2[num2];
			for (int i = 0; i < num2; i++)
			{
				array[i] = new Vector3(BitConverter.ToSingle(data, num), BitConverter.ToSingle(data, num + 4), BitConverter.ToSingle(data, num + 8));
				array2[i] = new Vector3(BitConverter.ToSingle(data, num + 12), BitConverter.ToSingle(data, num + 16), BitConverter.ToSingle(data, num + 20));
				float num4 = BitConverter.ToSingle(data, num + 28);
				array3[i] = new Vector2(BitConverter.ToSingle(data, num + 24), flag ? (1f - num4) : num4);
				num += 32;
			}
			int[] array4 = new int[num3];
			for (int j = 0; j < num3; j++)
			{
				array4[j] = BitConverter.ToInt32(data, num);
				num += 4;
			}
			Mesh val = new Mesh
			{
				name = id,
				indexFormat = (IndexFormat)(num2 > 65000)
			};
			val.SetVertices(array);
			val.SetNormals(array2);
			val.SetUVs(0, array3);
			val.SetTriangles(array4, 0);
			val.RecalculateBounds();
			return val;
		}

		private static Texture2D? DecodePng(byte[] bytes, string name)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true);
			MethodInfo methodInfo = LoadImage();
			if (methodInfo == null || !(bool)methodInfo.Invoke(null, new object[2] { val, bytes }))
			{
				Object.Destroy((Object)(object)val);
				Plugin.Log.LogWarning((object)("board png decode failed " + name));
				return null;
			}
			((Object)val).name = name;
			((Texture)val).wrapMode = (TextureWrapMode)1;
			((Texture)val).filterMode = (FilterMode)1;
			((Texture)val).anisoLevel = 4;
			val.Apply(true, false);
			return val;
		}

		private static MethodInfo? LoadImage()
		{
			if (_searched)
			{
				return _loadImage;
			}
			_searched = true;
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			for (int i = 0; i < assemblies.Length; i++)
			{
				Type type = assemblies[i].GetType("UnityEngine.ImageConversion");
				if (!(type == null))
				{
					_loadImage = type.GetMethod("LoadImage", new Type[2]
					{
						typeof(Texture2D),
						typeof(byte[])
					});
					if (_loadImage != null)
					{
						return _loadImage;
					}
				}
			}
			return null;
		}
	}
	internal static class BoardPiece
	{
		public const string PrefabName = "piece_restless_works";

		public const string DisplayName = "Work-order board";

		public const string Blurb = "Hang it on a wall. Standing orders for the kilns and smelters nearby.";

		private const string Donor = "piece_chest_wood";

		private static bool _added;

		public static void Load()
		{
			PrefabManager.OnVanillaPrefabsAvailable += Add;
		}

		private static void Add()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= Add;
			if (!_added)
			{
				_added = true;
				if ((Object)(object)PrefabManager.Instance.GetPrefab("piece_chest_wood") == (Object)null)
				{
					Plugin.Log.LogWarning((object)"RestlessWorks skipped the board (no piece_chest_wood).");
					return;
				}
				Register("piece_restless_works", "Work-order board", "Hang it on a wall. Standing orders for the kilns and smelters nearby.", "board.from-unity");
				Plugin.Log.LogInfo((object)"RestlessWorks added the work-order board.");
			}
		}

		private static void Register(string prefabName, string displayName, string blurb, string meshId)
		{
			//IL_0093: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: 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_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Expected O, but got Unknown
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Expected O, but got Unknown
			GameObject val = PrefabManager.Instance.CreateClonedPrefab(prefabName, "piece_chest_wood");
			if (!((Object)(object)val == (Object)null))
			{
				Container component = val.GetComponent<Container>();
				if ((Object)(object)component != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)component);
				}
				BoardVisual.Apply(val, meshId);
				Piece val2 = val.GetComponent<Piece>() ?? val.AddComponent<Piece>();
				Sprite icon = (val2.m_icon = BoardArt.Icon() ?? val2.m_icon);
				val2.m_name = displayName;
				val2.m_description = blurb;
				val2.m_groundOnly = false;
				val2.m_groundPiece = false;
				val2.m_clipGround = false;
				val2.m_notOnTiltingSurface = false;
				val2.m_notOnFloor = true;
				val2.m_category = (PieceCategory)4;
				SitAsFurniture(val);
				if ((Object)(object)val.GetComponent<Board>() == (Object)null)
				{
					val.AddComponent<Board>();
				}
				PieceConfig val3 = new PieceConfig
				{
					Name = displayName,
					Description = blurb,
					PieceTable = PieceTables.Hammer,
					Category = PieceCategories.Furniture,
					CraftingStation = "piece_workbench",
					Icon = icon
				};
				val3.AddRequirement("Wood", 10, true);
				val3.AddRequirement("Coal", 4, true);
				val3.AddRequirement("BronzeNails", 4, true);
				PieceManager.Instance.AddPiece(new CustomPiece(val, true, val3));
			}
		}

		private static void SitAsFurniture(GameObject prefab)
		{
			WearNTear component = prefab.GetComponent<WearNTear>();
			if (!((Object)(object)component == (Object)null))
			{
				component.m_noSupportWear = false;
				component.m_supports = true;
				AccessTools.Method(typeof(WearNTear), "SetupColliders", (Type[])null, (Type[])null)?.Invoke(component, null);
			}
		}
	}
	internal static class BoardVisual
	{
		public const string ChildName = "RestlessWorksMesh";

		public const float ModelScale = 2f;

		public static void Apply(GameObject prefab, string meshId)
		{
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Expected O, but got Unknown
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: 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_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: 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_01a7: 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_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			Mesh val = BoardArt.Mesh(meshId);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"RestlessWorks: no custom model, leaving the chest look.");
				return;
			}
			Material mat = CopyLit(prefab);
			LODGroup[] componentsInChildren = prefab.GetComponentsInChildren<LODGroup>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
			int layer = prefab.layer;
			Collider componentInChildren = prefab.GetComponentInChildren<Collider>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				layer = ((Component)componentInChildren).gameObject.layer;
			}
			Collider[] componentsInChildren2 = prefab.GetComponentsInChildren<Collider>(true);
			foreach (Collider val2 in componentsInChildren2)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)val2);
				}
			}
			GameObject val3 = new GameObject("RestlessWorksMesh");
			val3.layer = layer;
			val3.transform.SetParent(prefab.transform, false);
			val3.transform.localPosition = Vector3.zero;
			val3.transform.localRotation = Quaternion.identity;
			val3.transform.localScale = Vector3.one * 2f;
			val3.AddComponent<MeshFilter>().sharedMesh = val;
			MeshRenderer val4 = val3.AddComponent<MeshRenderer>();
			Paint((Renderer)(object)val4, BoardArt.Albedo(), mat);
			Renderer[] componentsInChildren3 = prefab.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val5 in componentsInChildren3)
			{
				if (!((Object)(object)val5 == (Object)null) && !((Object)(object)val5 == (Object)(object)val4) && ((val5 is MeshRenderer || val5 is SkinnedMeshRenderer) ? true : false))
				{
					val5.enabled = false;
				}
			}
			BoxCollider obj = val3.AddComponent<BoxCollider>();
			Bounds bounds = val.bounds;
			obj.center = ((Bounds)(ref bounds)).center;
			bounds = val.bounds;
			obj.size = Vector3.Max(((Bounds)(ref bounds)).size, new Vector3(0.2f, 0.2f, 0.2f));
		}

		private static void Paint(Renderer renderer, Texture2D? albedo, Material? mat)
		{
			//IL_000b: 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_0045: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)mat == (Object)null)
			{
				return;
			}
			mat.color = Color.white;
			if (mat.HasProperty("_Color"))
			{
				mat.SetColor("_Color", Color.white);
			}
			if (mat.HasProperty("_BaseColor"))
			{
				mat.SetColor("_BaseColor", Color.white);
			}
			if ((Object)(object)albedo != (Object)null)
			{
				if (mat.HasProperty("_MainTex"))
				{
					mat.SetTexture("_MainTex", (Texture)(object)albedo);
				}
				if (mat.HasProperty("_BaseMap"))
				{
					mat.SetTexture("_BaseMap", (Texture)(object)albedo);
				}
			}
			renderer.sharedMaterial = mat;
		}

		private static Material? CopyLit(GameObject prefab)
		{
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Expected O, but got Unknown
			//IL_00ca: 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_00d3: 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_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Expected O, but got Unknown
			Renderer val = null;
			float num = -1f;
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				if ((Object)(object)val2 == (Object)null || (!(val2 is MeshRenderer) && !(val2 is SkinnedMeshRenderer)))
				{
					continue;
				}
				Material sharedMaterial = val2.sharedMaterial;
				if ((Object)(object)((sharedMaterial != null) ? sharedMaterial.shader : null) == (Object)null || ((Object)sharedMaterial.shader).name == "Standard")
				{
					continue;
				}
				string text = ((Object)sharedMaterial).name + " " + ((Object)sharedMaterial.shader).name;
				if (!Has(text, "snow") && !Has(text, "particle") && !Has(text, "glow"))
				{
					Bounds bounds = val2.bounds;
					float x = ((Bounds)(ref bounds)).size.x;
					bounds = val2.bounds;
					float num2 = x * ((Bounds)(ref bounds)).size.y;
					bounds = val2.bounds;
					float num3 = num2 * ((Bounds)(ref bounds)).size.z;
					if (!(num3 <= num))
					{
						num = num3;
						val = val2;
					}
				}
			}
			if ((Object)(object)((val != null) ? val.sharedMaterial : null) != (Object)null)
			{
				return new Material(val.sharedMaterial);
			}
			PrefabManager instance = PrefabManager.Instance;
			GameObject val3 = ((instance != null) ? instance.GetPrefab("piece_chest_wood") : null);
			MeshRenderer val4 = (((Object)(object)val3 != (Object)null) ? val3.GetComponentInChildren<MeshRenderer>(true) : null);
			if ((Object)(object)((val4 != null) ? ((Renderer)val4).sharedMaterial : null) != (Object)null && ((Object)((Renderer)val4).sharedMaterial.shader).name != "Standard")
			{
				return new Material(((Renderer)val4).sharedMaterial);
			}
			Plugin.Log.LogWarning((object)"RestlessWorks shader missing");
			return null;
		}

		private static bool Has(string text, string token)
		{
			return text.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0;
		}
	}
	[BepInPlugin("restless.works", "RestlessWorkshop", "0.1.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "restless.works";

		public const string PluginName = "RestlessWorkshop";

		public const string PluginVersion = "0.1.1";

		internal static ConfigEntry<bool> BoardEnabled;

		private float _clock;

		private Harmony? _uiPatches;

		private IDisposable? _page;

		private IDisposable? _settings;

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			BoardEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Interface", "Work orders", true, "Open the work-order board. Local preference; does not stop orders already placed.");
			_page = SettingsPageApi.Register(new SettingsPage("restless.works", "RestlessWorkshop", "Standing orders for the kilns and smelters.", "A work-order board queues the production machines nearby. The Cookbook stays the kitchen.", (Sprite)null, (string)null, (Action)null));
			_settings = SettingsPageApi.RegisterSettings("restless.works", (SettingsSection[])(object)new SettingsSection[1]
			{
				new SettingsSection("Work orders", (SettingsOption[])(object)new SettingsOption[1]
				{
					new SettingsOption("Open the board", (ConfigEntryBase)(object)BoardEnabled, false, "", false)
				})
			});
			BoardPiece.Load();
			Works.Opened += WorkshopWindow.Open;
			_uiPatches = new Harmony("restless.works.ui");
			_uiPatches.PatchAll(typeof(WorkshopWindow).Assembly);
			Log.LogInfo((object)"RestlessWorkshop 0.1.1 loaded.");
		}

		private void OnDestroy()
		{
			Works.Opened -= WorkshopWindow.Open;
			WorkshopWindow.Close();
			Harmony? uiPatches = _uiPatches;
			if (uiPatches != null)
			{
				uiPatches.UnpatchSelf();
			}
			_settings?.Dispose();
			_page?.Dispose();
		}

		private void Update()
		{
			_clock += Time.deltaTime;
			if (!(_clock < 1f))
			{
				float clock = _clock;
				_clock = 0f;
				WorksRun.TickOwned(clock);
			}
		}
	}
	public enum WorksOrderMode
	{
		Make,
		Keep
	}
	public sealed class WorksRecipe
	{
		public string Output = "";

		public string OutputName = "";

		public string Input = "";

		public string InputName = "";

		public string Station = "";

		public string StationName = "";

		public string Fuel = "";

		public string FuelName = "";
	}
	public sealed class WorksUse
	{
		public string Item = "";

		public string Name = "";

		public int Amount;

		public int Available;
	}
	public sealed class WorksStep
	{
		public string Output = "";

		public string Name = "";

		public string Parent = "";

		public int Depth;

		public int Need;

		public int Available;

		public string Station = "";

		public string Note = "";

		public readonly List<WorksUse> Uses = new List<WorksUse>();
	}
	public sealed class WorksOrder
	{
		public int Id;

		public string Output = "";

		public string Name = "";

		public WorksOrderMode Mode;

		public int Count;

		public long PlayerId;

		public int Ready;

		public int Collected;

		public int InProduction;

		public int Available;

		public int Remaining;
	}
	public sealed class WorksMachine
	{
		public string Name = "";

		public string Prefab = "";

		public Vector3 Position;

		public int Free;

		public int Cooking;

		public int Ready;

		public int Fuel;

		public int FuelMax;

		public string FuelItem = "";

		public string Block = "";
	}
	public sealed class WorksStock
	{
		public string Prefab = "";

		public string Name = "";

		public int Count;

		public int Reserved;
	}
	public static class Works
	{
		public static event Action<Piece>? Opened;

		public static IReadOnlyList<WorksRecipe> Recipes()
		{
			return WorksRun.Recipes();
		}

		public static WorksRecipe? Find(string output)
		{
			return WorksRun.Find(output);
		}

		public static IReadOnlyList<WorksStep> Plan(Piece board, string output, int count)
		{
			return WorksRun.Plan(board, output, count);
		}

		public static IReadOnlyList<WorksOrder> Orders(Piece board)
		{
			return WorksRun.ReadOrders(board);
		}

		public static IReadOnlyList<WorksMachine> Machines(Piece board)
		{
			return WorksRun.Machines(board);
		}

		public static IReadOnlyList<WorksStock> Pantry(Piece board)
		{
			return WorksRun.Pantry(board);
		}

		public static bool Place(Piece board, string output, WorksOrderMode mode, int count)
		{
			return WorksRun.Place(board, output, mode, count);
		}

		public static void Cancel(Piece board, int orderId)
		{
			WorksRun.Cancel(board, orderId);
		}

		public static int Collect(Piece board, int orderId)
		{
			return WorksRun.Collect(board, orderId);
		}

		public static int Take(Piece board, string prefab, int count)
		{
			return WorksRun.Take(board, prefab, count);
		}

		internal static void Raise(Piece board)
		{
			if (!Plugin.BoardEnabled.Value)
			{
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer != null)
				{
					((Character)localPlayer).Message((MessageType)2, "Enable the work-order board in F8 · RestlessWorkshop.", 0, (Sprite)null, false);
				}
			}
			else if (Works.Opened != null)
			{
				Works.Opened(board);
			}
			else
			{
				Player localPlayer2 = Player.m_localPlayer;
				if (localPlayer2 != null)
				{
					((Character)localPlayer2).Message((MessageType)2, "Work-order board is not in yet.", 0, (Sprite)null, false);
				}
			}
		}
	}
	internal sealed class WorkshopWindow : MonoBehaviour
	{
		[HarmonyPatch(typeof(Menu), "Update")]
		private static class MenuInput
		{
			private static bool Prefix()
			{
				if ((Object)(object)_current == (Object)null)
				{
					return Time.frameCount != _closedFrame;
				}
				return false;
			}
		}

		private sealed class Card
		{
			internal readonly GameObject Root;

			private readonly Image _icon;

			private readonly Image _done;

			private readonly Image _running;

			private readonly Text _name;

			private readonly Text _summary;

			private readonly GameObject _track;

			private Action? _click;

			internal Card(Transform parent)
			{
				//IL_0059: Unknown result type (might be due to invalid IL or missing references)
				//IL_0063: Expected O, but got Unknown
				//IL_0074: 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_0147: Unknown result type (might be due to invalid IL or missing references)
				//IL_017c: Unknown result type (might be due to invalid IL or missing references)
				Root = RestlessUi.Chip(parent, "work-card");
				RestlessUi.PaperControl(Root, (Color?)null);
				Button obj = Root.AddComponent<Button>();
				((Selectable)obj).targetGraphic = (Graphic)(object)Root.GetComponent<Image>();
				RestlessUi.PaperSelectable((Selectable)(object)obj);
				((UnityEvent)obj.onClick).AddListener((UnityAction)delegate
				{
					_click?.Invoke();
				});
				_icon = RestlessUi.Graphic(Root.transform, "item", Color.white, false).GetComponent<Image>();
				_icon.preserveAspect = true;
				_name = Label(Root.transform, "", 21, 0f, 0f, 100f, 50f);
				RestlessUi.BoundedLabel(_name, 21, 17);
				_summary = Label(Root.transform, "", 17, 0f, 0f, 100f, 40f);
				RestlessUi.BoundedLabel(_summary, 17, 14);
				_track = RestlessUi.Graphic(Root.transform, "coverage-track", RestlessUi.Ink, false);
				_running = RestlessUi.Graphic(_track.transform, "in-production", RestlessUi.Accent, false).GetComponent<Image>();
				_done = RestlessUi.Graphic(_track.transform, "finished", new Color(0.58f, 0.76f, 0.56f), false).GetComponent<Image>();
			}

			internal void Set(string name, string summary, Sprite? icon, Action click, bool selected = false, bool compact = false)
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//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_00a4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f4: 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_014a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0156: Unknown result type (might be due to invalid IL or missing references)
				//IL_0113: Unknown result type (might be due to invalid IL or missing references)
				//IL_0122: Unknown result type (might be due to invalid IL or missing references)
				//IL_0185: Unknown result type (might be due to invalid IL or missing references)
				//IL_01d4: 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)
				Rect rect = ((RectTransform)Root.transform).rect;
				Vector2 size = ((Rect)(ref rect)).size;
				_click = click;
				Portrait(((Component)_icon).gameObject, 12f, compact ? 12 : 18, compact ? 40 : 62, compact ? 40 : 62);
				_icon.sprite = icon;
				((Behaviour)_icon).enabled = (Object)(object)icon != (Object)null;
				int num = (((Object)(object)icon == (Object)null) ? 14 : (compact ? 62 : 88));
				Place(((Component)_name).gameObject, num, 8f, size.x - (float)num - 18f, compact ? 46 : 52);
				if (compact)
				{
					Place(((Component)_summary).gameObject, 12f, 58f, size.x - 24f, 26f);
				}
				else if (size.y <= 116f)
				{
					Place(((Component)_summary).gameObject, num, 62f, size.x - (float)num - 18f, size.y - 72f);
				}
				else
				{
					Place(((Component)_summary).gameObject, 12f, 80f, size.x - 24f, size.y - 96f);
				}
				_name.text = name;
				_summary.text = summary;
				((Graphic)_summary).color = RestlessUi.PaperMuted;
				((Component)_summary).gameObject.SetActive(!string.IsNullOrEmpty(summary));
				_track.SetActive(false);
				RestlessUi.PaperControl(Root, (Color?)(Color)(selected ? RestlessUi.Accent : new Color(0.32f, 0.29f, 0.24f)));
			}

			internal void Coverage(int completed, int running, int target)
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//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_0036: 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_008e: 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)
				Rect rect = ((RectTransform)Root.transform).rect;
				Vector2 size = ((Rect)(ref rect)).size;
				_track.SetActive(true);
				Place(_track, 14f, size.y - 12f, size.x - 28f, 5f);
				int num = Math.Max(1, target);
				float num2 = Mathf.Clamp01((float)completed / (float)num);
				float num3 = Mathf.Clamp01(((float)completed + (float)running) / (float)num);
				Place(((Component)_running).gameObject, 0f, 0f, (size.x - 28f) * num3, 5f);
				Place(((Component)_done).gameObject, 0f, 0f, (size.x - 28f) * num2, 5f);
			}
		}

		private static WorkshopWindow? _current;

		private static int _closedFrame = -1;

		private Piece _board;

		private RectTransform _sheet;

		private RestlessScrollRect _list;

		private RestlessScrollRect _body;

		private RestlessScrollRect _details;

		private readonly List<Card> _choices = new List<Card>();

		private readonly List<Card> _cards = new List<Card>();

		private readonly List<Button> _tabs = new List<Button>();

		private readonly Dictionary<string, Sprite?> _icons = new Dictionary<string, Sprite>();

		private GameObject _controls;

		private InputField _search;

		private InputField _amount;

		private Text _modeHelp;

		private Text _detailText;

		private Text _hint;

		private Text _status;

		private Button _make;

		private Button _keep;

		private Button _stationFilter;

		private Button _action;

		private Button _secondary;

		private IReadOnlyList<WorksRecipe> _recipes = Array.Empty<WorksRecipe>();

		private IReadOnlyList<WorksOrder> _orders = Array.Empty<WorksOrder>();

		private IReadOnlyList<WorksMachine> _machines = Array.Empty<WorksMachine>();

		private IReadOnlyList<WorksStock> _stock = Array.Empty<WorksStock>();

		private IReadOnlyList<WorksStep> _plan = Array.Empty<WorksStep>();

		private WorksOrderMode _mode;

		private int _tab;

		private int _count = 30;

		private int _order;

		private int _machine;

		private string _output = "";

		private string _stockItem = "";

		private string _query = "";

		private string _station = "";

		private string _stamp = "";

		private string _lastError = "";

		private bool _blocked;

		private bool _confirmCancel;

		private float _next;

		private float _messageUntil;

		private Vector2 _canvas;

		internal static void Open(Piece board)
		{
			//IL_0059: 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_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_0074: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.BoardEnabled.Value || (Object)(object)board == (Object)null || (Object)(object)GUIManager.CustomGUIFront == (Object)null || SettingsUi.IsOpen || InventoryGui.IsVisible())
			{
				return;
			}
			Close();
			GameObject obj = RestlessUi.Graphic(GUIManager.CustomGUIFront.transform, "RestlessWorkshop", new Color(0f, 0f, 0f, 0.28f), true);
			RestlessUi.Stretch(obj, Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero);
			WorkshopWindow workshopWindow = (_current = obj.AddComponent<WorkshopWindow>());
			workshopWindow._board = board;
			try
			{
				workshopWindow.Build();
				LookHints.SetSuppressed((object)workshopWindow, true);
				workshopWindow._blocked = true;
				GUIManager.BlockInput(true);
				workshopWindow.Refresh(force: true);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)ex);
				Close();
			}
		}

		internal static void Close()
		{
			if (!((Object)(object)_current == (Object)null))
			{
				WorkshopWindow? current = _current;
				_current = null;
				_closedFrame = Time.frameCount;
				((Component)current).gameObject.SetActive(false);
				Object.Destroy((Object)(object)((Component)current).gameObject);
			}
		}

		private void OnDisable()
		{
			LookHints.SetSuppressed((object)this, false);
			if ((Object)(object)_current == (Object)(object)this)
			{
				_current = null;
			}
			if (_blocked && !SettingsUi.IsOpen)
			{
				GUIManager.BlockInput(false);
			}
			_blocked = false;
		}

		private void Update()
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!Input.GetKeyDown((KeyCode)27) && Plugin.BoardEnabled.Value && !((Object)(object)_board == (Object)null) && !((Object)(object)localPlayer == (Object)null) && !((Character)localPlayer).IsDead() && !SettingsUi.IsOpen && !InventoryGui.IsVisible())
			{
				Vector3 val = ((Component)_board).transform.position - ((Component)localPlayer).transform.position;
				if (!(((Vector3)(ref val)).sqrMagnitude > 25f))
				{
					Fit();
					if (Time.unscaledTime >= _next)
					{
						Refresh(force: false);
					}
					return;
				}
			}
			Close();
		}

		private void SelectTab(int tab)
		{
			_tab = tab;
			_confirmCancel = false;
			_query = "";
			_search.SetTextWithoutNotify("");
			Refresh(force: true);
			Reset(_list);
			Reset(_body);
			Reset(_details);
		}

		private void SetMode(WorksOrderMode mode)
		{
			_mode = mode;
			Refresh(force: true);
		}

		private void Quantity(int delta)
		{
			_count = Mathf.Clamp(_count + delta, 1, 999);
			_amount.SetTextWithoutNotify(_count.ToString());
			Refresh(force: true);
		}

		private void CycleStation()
		{
			List<WorksRecipe> list = (from r in _recipes
				group r by r.Station into g
				select g.First() into r
				orderby r.StationName
				select r).ToList();
			int num = list.FindIndex((WorksRecipe r) => r.Station == _station);
			_station = ((num + 1 < list.Count) ? list[num + 1].Station : "");
			Refresh(force: true);
			Reset(_list);
		}

		private bool Control()
		{
			if ((Object)(object)_board != (Object)null)
			{
				ZNetView component = ((Component)_board).GetComponent<ZNetView>();
				if (component != null && component.IsValid())
				{
					return component.IsOwner();
				}
			}
			return false;
		}

		private bool Matches(string name)
		{
			if (!string.IsNullOrWhiteSpace(_query))
			{
				return Local(name).IndexOf(_query.Trim(), StringComparison.CurrentCultureIgnoreCase) >= 0;
			}
			return true;
		}

		private void Refresh(bool force)
		{
			//IL_038e: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b3: Unknown result type (might be due to invalid IL or missing references)
			_next = Time.unscaledTime + 1f;
			try
			{
				_recipes = Works.Recipes();
				_orders = Works.Orders(_board);
				_machines = Works.Machines(_board);
				if (_tab == 3)
				{
					_stock = Works.Pantry(_board);
				}
				if (_tab == 0)
				{
					List<WorksRecipe> source = _recipes.Where((WorksRecipe r) => Matches(r.OutputName) && (_station.Length == 0 || r.Station == _station)).ToList();
					if (!source.Any((WorksRecipe r) => r.Output == _output))
					{
						_output = source.FirstOrDefault()?.Output ?? "";
					}
				}
				if (_tab == 1 && !_orders.Any((WorksOrder o) => o.Id == _order && Matches(o.Name)))
				{
					_order = _orders.FirstOrDefault((WorksOrder o) => Matches(o.Name))?.Id ?? 0;
					_confirmCancel = false;
				}
				if (_tab == 2)
				{
					_machine = Mathf.Clamp(_machine, 0, Math.Max(0, _machines.Count - 1));
				}
				if (_tab == 3 && !_stock.Any((WorksStock s) => s.Prefab == _stockItem && Matches(s.Name)))
				{
					_stockItem = _stock.FirstOrDefault((WorksStock s) => Matches(s.Name))?.Prefab ?? "";
				}
				if (_tab == 0)
				{
					IReadOnlyList<WorksStep> plan;
					if (_output.Length != 0)
					{
						plan = Works.Plan(_board, _output, _count);
					}
					else
					{
						IReadOnlyList<WorksStep> readOnlyList = Array.Empty<WorksStep>();
						plan = readOnlyList;
					}
					_plan = plan;
				}
				StringBuilder stringBuilder = new StringBuilder().Append(_tab).Append(_mode).Append(_count)
					.Append(_query)
					.Append(_station)
					.Append(_output)
					.Append(_order)
					.Append(_machine)
					.Append(_stockItem)
					.Append(Control())
					.Append(_confirmCancel);
				foreach (WorksRecipe recipe in _recipes)
				{
					stringBuilder.Append('|').Append(recipe.Output);
				}
				foreach (WorksOrder order in _orders)
				{
					stringBuilder.Append('|').Append(order.Id).Append(':')
						.Append(order.Count)
						.Append(':')
						.Append(order.Mode)
						.Append(':')
						.Append(order.Ready)
						.Append(':')
						.Append(order.Collected)
						.Append(':')
						.Append(order.Available)
						.Append(':')
						.Append(order.InProduction)
						.Append(':')
						.Append(order.Remaining);
				}
				foreach (WorksMachine machine in _machines)
				{
					stringBuilder.Append('|').Append(machine.Prefab).Append(machine.Position)
						.Append(':')
						.Append(machine.Fuel)
						.Append(':')
						.Append(machine.Free)
						.Append(':')
						.Append(machine.Cooking)
						.Append(':')
						.Append(machine.Ready)
						.Append(machine.Block);
				}
				if (_tab == 0)
				{
					foreach (WorksStep item in _plan)
					{
						stringBuilder.Append('|').Append(item.Output).Append(':')
							.Append(item.Available)
							.Append(':')
							.Append(item.Need);
						foreach (WorksUse use in item.Uses)
						{
							stringBuilder.Append(use.Item).Append(':').Append(use.Available)
								.Append(':')
								.Append(use.Amount);
						}
					}
				}
				if (_tab == 3)
				{
					foreach (WorksStock item2 in _stock)
					{
						stringBuilder.Append('|').Append(item2.Prefab).Append(':')
							.Append(item2.Count)
							.Append(':')
							.Append(item2.Reserved);
					}
				}
				string text = stringBuilder.ToString();
				if (force || text != _stamp)
				{
					_stamp = text;
					for (int num = 0; num < _tabs.Count; num++)
					{
						RestlessUi.PaperControl(((Component)_tabs[num]).gameObject, (num == _tab) ? new Color?(RestlessUi.Accent) : ((Color?)null));
					}
					_controls.SetActive(_tab == 0);
					ResizeReader(_list, 28f, (_tab == 0) ? 396 : 190, 252f, (_tab == 0) ? 338 : 544);
					((Component)_secondary).gameObject.SetActive(false);
					((Component)_action).gameObject.SetActive(true);
					Place(((Component)_hint).gameObject, 918f, 596f, 324f, (_tab == 1) ? 36 : 72);
					if (_tab == 0)
					{
						PaintProduction();
					}
					else if (_tab == 1)
					{
						PaintOrders();
					}
					else if (_tab == 2)
					{
						PaintMachines();
					}
					else
					{
						PaintOutput();
					}
					if (!Control())
					{
						((Selectable)_action).interactable = false;
						((Selectable)_secondary).interactable = false;
						_hint.text = "Board control changed. Reopen it to manage orders.";
					}
				}
				if (Time.unscaledTime >= _messageUntil)
				{
					_status.text = "Finished output stays on this board · " + _orders.Count + " / 8 orders · " + _machines.Count + " machines in range";
				}
				_lastError = "";
			}
			catch (Exception ex)
			{
				if (_lastError != ex.Message)
				{
					Plugin.Log.LogError((object)ex);
					_lastError = ex.Message;
				}
				((Selectable)_action).interactable = false;
				((Selectable)_secondary).interactable = false;
				Message("Workshop data unavailable. Close and reopen the board.");
			}
		}

		private void Detail(string text)
		{
			_detailText.text = text;
			float num = Mathf.Max(60f, _detailText.preferredHeight);
			Place(((Component)_detailText).gameObject, 0f, 0f, 304f, num);
			Size(_details, num + 16f);
		}

		private void Message(string text)
		{
			_status.text = text;
			_messageUntil = Time.unscaledTime + 5f;
		}

		private static string Local(string text)
		{
			if (Localization.instance != null)
			{
				return Localization.instance.Localize(text);
			}
			return text;
		}

		private Sprite? Icon(string prefab)
		{
			if (_icons.TryGetValue(prefab, out Sprite value))
			{
				return value;
			}
			ObjectDB instance = ObjectDB.instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				GameObject itemPrefab = instance.GetItemPrefab(prefab);
				obj = ((itemPrefab == null) ? null : itemPrefab.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_icons);
			}
			Sprite[] array = (Sprite[])obj;
			value = ((array != null && array.Length != 0) ? array[0] : null);
			_icons[prefab] = value;
			return value;
		}

		private void PickOutput(string output)
		{
			_output = output;
			_station = "";
			_query = "";
			_search.SetTextWithoutNotify("");
			_tab = 0;
			Refresh(force: true);
			Reset(_body);
			Reset(_details);
		}

		private void Act()
		{
			if (!((Selectable)_action).interactable || !Control())
			{
				return;
			}
			try
			{
				if (_tab == 0)
				{
					if (_amount.isFocused && int.TryParse(_amount.text, out var result))
					{
						_count = Mathf.Clamp(result, 1, 999);
						_amount.SetTextWithoutNotify(_count.ToString());
					}
					IReadOnlyList<WorksOrder> source = Works.Orders(_board);
					if (_mode == WorksOrderMode.Keep && source.Any((WorksOrder o) => o.Output == _output && o.Mode == WorksOrderMode.Keep))
					{
						Message("A Keep target already exists for this item. Manage it in Orders.");
						Refresh(force: true);
						return;
					}
					HashSet<int> ids = new HashSet<int>(source.Select((WorksOrder o) => o.Id));
					if (!Works.Place(_board, _output, _mode, _count))
					{
						Message("Order could not be placed. Check the board and queue capacity.");
						return;
					}
					_order = Works.Orders(_board).FirstOrDefault((WorksOrder o) => !ids.Contains(o.Id))?.Id ?? 0;
					SelectTab(1);
					Message("Order placed. Machines keep working after this window closes.");
				}
				else if (_tab == 1)
				{
					if (!_confirmCancel)
					{
						_confirmCancel = true;
						Refresh(force: true);
						Message("Remove this order? Material already in machines keeps processing.");
					}
					else
					{
						Works.Cancel(_board, _order);
						_confirmCancel = false;
						Refresh(force: true);
						Message("Order removed. Finished stock can be taken from Output.");
					}
				}
				else
				{
					if (_tab != 3)
					{
						return;
					}
					WorksStock worksStock = Works.Pantry(_board).FirstOrDefault((WorksStock s) => s.Prefab == _stockItem);
					if (worksStock != null)
					{
						ObjectDB instance = ObjectDB.instance;
						int? obj;
						if (instance == null)
						{
							obj = null;
						}
						else
						{
							GameObject itemPrefab = instance.GetItemPrefab(worksStock.Prefab);
							obj = ((itemPrefab == null) ? ((int?)null) : itemPrefab.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_maxStackSize);
						}
						int val = obj ?? 1;
						int num = Works.Take(_board, worksStock.Prefab, Math.Min(val, Math.Max(0, worksStock.Count - worksStock.Reserved)));
						Refresh(force: true);
						Message((num > 0) ? ("Collected " + num + " " + Local(worksStock.Name)) : "Nothing collected. Check inventory space and reservations.");
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)ex);
				Message("Action failed. Check Orders before retrying.");
			}
		}

		private void Secondary()
		{
			if (!((Selectable)_secondary).interactable || !Control())
			{
				return;
			}
			try
			{
				int num = Works.Collect(_board, _order);
				Refresh(force: true);
				Message((num > 0) ? ("Collected " + num + ". Any remaining output stays on the board.") : "Nothing collected. Check inventory space and order ownership.");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)ex);
				Message("Collection failed. Check your inventory.");
			}
		}

		private void Build()
		{
			//IL_003a: 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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = RestlessUi.Tray(((Component)this).transform, "Workshop", true);
			RestlessUi.PaperSurface(val, false, (Color?)null);
			((Graphic)val.GetComponent<Image>()).raycastTarget = true;
			_sheet = RestlessUi.Pin(val, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, new Vector2(1280f, 800f));
			RestlessUi.PaperCorner(val);
			Place(RestlessUi.Picture((Transform)(object)_sheet, "workshop-mark", "craft-hammer", false), 26f, 22f, 52f, 62f);
			Label((Transform)(object)_sheet, "Workshop", 36, 92f, 22f, 430f, 50f);
			Label((Transform)(object)_sheet, "Set the work. Keep the stores supplied.", 17, 30f, 78f, 530f, 26f);
			string[] array = new string[4] { "Production", "Orders", "Machines", "Output" };
			for (int i = 0; i < array.Length; i++)
			{
				int tab = i;
				_tabs.Add(Button((Transform)(object)_sheet, array[i], 590 + i * 142, 34f, 132f, 38f, delegate
				{
					SelectTab(tab);
				}));
			}
			Button((Transform)(object)_sheet, "ESC", 1174f, 34f, 70f, 38f, Close);
			Rule((Transform)(object)_sheet, 28f, 112f, 1220f, 1f);
			Rule((Transform)(object)_sheet, 298f, 132f, 1f, 602f);
			Rule((Transform)(object)_sheet, 894f, 132f, 1f, 602f);
			_search = Field((Transform)(object)_sheet, "Search…", 28f, 132f, 252f, 40f, number: false);
			((UnityEvent<string>)(object)_search.onValueChanged).AddListener((UnityAction<string>)delegate(string value)
			{
				_query = value;
				_stamp = "";
				Refresh(force: true);
				Reset(_list);
			});
			_controls = RestlessUi.Node((Transform)(object)_sheet, "production-controls");
			RestlessUi.Stretch(_controls, Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero);
			_make = Button(_controls.transform, "Make", 28f, 186f, 122f, 36f, delegate
			{
				SetMode(WorksOrderMode.Make);
			});
			_keep = Button(_controls.transform, "Keep", 158f, 186f, 122f, 36f, delegate
			{
				SetMode(WorksOrderMode.Keep);
			});
			Button(_controls.transform, "−", 28f, 236f, 52f, 38f, delegate
			{
				Quantity(-1);
			});
			_amount = Field(_controls.transform, "30", 90f, 236f, 128f, 38f, number: true);
			_amount.SetTextWithoutNotify("30");
			((UnityEvent<string>)(object)_amount.onEndEdit).AddListener((UnityAction<string>)delegate(string value)
			{
				if (int.TryParse(value, out var result))
				{
					_count = Mathf.Clamp(result, 1, 999);
				}
				_amount.SetTextWithoutNotify(_count.ToString());
				Refresh(force: true);
			});
			Button(_controls.transform, "+", 228f, 236f, 52f, 38f, delegate
			{
				Quantity(1);
			});
			_modeHelp = Label(_controls.transform, "", 17, 30f, 286f, 246f, 62f);
			_stationFilter = Button(_controls.transform, "All machines", 28f, 350f, 252f, 34f, CycleStation);
			_list = Reader((Transform)(object)_sheet, "selection", 28f, 396f, 252f, 338f, 78f);
			_body = Reader((Transform)(object)_sheet, "work-plan", 318f, 132f, 560f, 602f, 112f);
			_details = Reader((Transform)(object)_sheet, "inspector", 916f, 132f, 328f, 450f, 40f);
			_detailText = Label((Transform)(object)((ScrollRect)_details).content, "", 18, 0f, 0f, 304f, 100f);
			_detailText.alignment = (TextAnchor)0;
			_detailText.verticalOverflow = (VerticalWrapMode)1;
			_hint = Label((Transform)(object)_sheet, "", 17, 918f, 596f, 324f, 72f);
			RestlessUi.BoundedLabel(_hint, 17, 14);
			_secondary = Button((Transform)(object)_sheet, "", 916f, 636f, 328f, 40f, Secondary);
			_action = Button((Transform)(object)_sheet, "", 916f, 684f, 328f, 50f, Act);
			RestlessUi.ForgedSurface(((Component)_action).gameObject, true, true);
			_status = Label((Transform)(object)_sheet, "", 16, 28f, 752f, 1216f, 30f);
			RestlessUi.BoundedLabel(_status, 16, 13);
			Fit();
		}

		private static void Place(GameObject go, float x, float y, float w, float h)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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)
			RestlessUi.Pin(go, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(x, 0f - y), new Vector2(w, h));
		}

		private static void Portrait(GameObject go, float x, float y, float w, float h)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			RestlessUi.Pin(go, new Vector2(0f, 1f), new Vector2(0.5f, 0.5f), new Vector2(x + w / 2f, 0f - y - h / 2f), new Vector2(w, h));
		}

		private static Text Label(Transform p, string value, int size, float x, float y, float w, float h)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			Text obj = RestlessUi.Label(p, value, size, RestlessUi.Text, (TextAnchor)3);
			Place(((Component)obj).gameObject, x, y, w, h);
			obj.horizontalOverflow = (HorizontalWrapMode)0;
			return obj;
		}

		private static void Rule(Transform p, float x, float y, float w, float h)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			Place(RestlessUi.Graphic(p, "rule", new Color(0.5f, 0.43f, 0.32f, 0.5f), false), x, y, w, h);
		}

		private static Button Button(Transform p, string title, float x, float y, float w, float h, Action action)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			GameObject val = RestlessUi.Chip(p, "button");
			RestlessUi.PaperControl(val, (Color?)null);
			Place(val, x, y, w, h);
			Button obj = val.AddComponent<Button>();
			((Selectable)obj).targetGraphic = (Graphic)(object)val.GetComponent<Image>();
			RestlessUi.PaperSelectable((Selectable)(object)obj);
			Text obj2 = Label(val.transform, title, 18, 8f, 3f, w - 16f, h - 6f);
			obj2.alignment = (TextAnchor)4;
			RestlessUi.BoundedLabel(obj2, 18, 14);
			((UnityEvent)obj.onClick).AddListener((UnityAction)delegate
			{
				action();
			});
			return obj;
		}

		private static InputField Field(Transform p, string placeholder, float x, float y, float w, float h, bool number)
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = RestlessUi.Chip(p, "input");
			RestlessUi.PaperControl(val, (Color?)null);
			Place(val, x, y, w, h);
			InputField val2 = val.AddComponent<InputField>();
			((Selectable)val2).targetGraphic = (Graphic)(object)val.GetComponent<Image>();
			val2.textComponent = Label(val.transform, "", 18, 10f, 3f, w - 20f, h - 6f);
			val2.placeholder = (Graphic)(object)Label(val.transform, placeholder, 18, 10f, 3f, w - 20f, h - 6f);
			val2.placeholder.color = RestlessUi.PaperMuted;
			val2.lineType = (LineType)0;
			val2.characterLimit = (number ? 3 : 80);
			if (number)
			{
				val2.contentType = (ContentType)2;
				val2.textComponent.alignment = (TextAnchor)4;
			}
			RestlessUi.PaperSelectable((Selectable)(object)val2);
			return val2;
		}

		private static RestlessScrollRect Reader(Transform p, string name, float x, float y, float w, float h, float row)
		{
			//IL_0040: 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_007e: Expected O, but got Unknown
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Expected O, but got Unknown
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Expected O, but got Unknown
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: 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)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: 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)
			GameObject val = RestlessUi.Node(p, name);
			Place(val, x, y, w, h);
			RestlessScrollRect val2 = val.AddComponent<RestlessScrollRect>();
			((ScrollRect)val2).horizontal = false;
			val2.RowHeight = row;
			val2.RowsPerNotch = 2f;
			GameObject val3 = RestlessUi.Graphic(val.transform, "viewport", Color.clear, true);
			Place(val3, 0f, 0f, w - 24f, h);
			val3.AddComponent<RectMask2D>();
			((ScrollRect)val2).viewport = (RectTransform)val3.transform;
			GameObject val4 = RestlessUi.Node(val3.transform, "content");
			Place(val4, 0f, 0f, w - 24f, h);
			((ScrollRect)val2).content = (RectTransform)val4.transform;
			if ((Object)(object)InventoryGui.instance?.m_recipeListScroll != (Object)null)
			{
				Scrollbar val5 = Object.Instantiate<Scrollbar>(InventoryGui.instance.m_recipeListScroll, val.transform, false);
				val5.onValueChanged = new ScrollEvent();
				Place(((Component)val5).gameObject, w - 6f, 0f, 6f, h);
				((Component)val5).transform.localScale = Vector3.one;
				if ((Object)(object)val5.handleRect != (Object)null)
				{
					Transform parent = ((Transform)val5.handleRect).parent;
					RectTransform val6 = (RectTransform)(object)((parent is RectTransform) ? parent : null);
					if ((Object)(object)val6 != (Object)null && (Object)(object)val6 != (Object)(object)((Component)val5).transform)
					{
						RestlessUi.Stretch(((Component)val6).gameObject, Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero);
					}
					val5.handleRect.sizeDelta = new Vector2(0f, val5.handleRect.sizeDelta.y);
					val5.handleRect.anchoredPosition = new Vector2(0f, val5.handleRect.anchoredPosition.y);
				}
				((ScrollRect)val2).verticalScrollbar = val5;
				((ScrollRect)val2).verticalScrollbarVisibility = (ScrollbarVisibility)1;
			}
			return val2;
		}

		private static void ResizeReader(RestlessScrollRect s, float x, float y, float w, float h)
		{
			Place(((Component)s).gameObject, x, y, w, h);
			((ScrollRect)s).viewport.SetSizeWithCurrentAnchors((Axis)1, h);
			if ((Object)(object)((ScrollRect)s).verticalScrollbar != (Object)null)
			{
				Place(((Component)((ScrollRect)s).verticalScrollbar).gameObject, w - 6f, 0f, 6f, h);
			}
		}

		private static void Size(RestlessScrollRect s, float height)
		{
			//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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: 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_005f: 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)
			Rect rect = ((ScrollRect)s).viewport.rect;
			height = Mathf.Max(((Rect)(ref rect)).height, height);
			((ScrollRect)s).content.SetSizeWithCurrentAnchors((Axis)1, height);
			float y = ((ScrollRect)s).content.anchoredPosition.y;
			float num = height;
			rect = ((ScrollRect)s).viewport.rect;
			float num2 = Mathf.Clamp(y, 0f, num - ((Rect)(ref rect)).height);
			if (!Mathf.Approximately(num2, ((ScrollRect)s).content.anchoredPosition.y))
			{
				s.CancelWheel();
				((ScrollRect)s).content.anchoredPosition = new Vector2(0f, num2);
			}
		}

		private static void Reset(RestlessScrollRect s)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			s.CancelWheel();
			((ScrollRect)s).content.anchoredPosition = Vector2.zero;
		}

		private void Fit()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: 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_006e: 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)
			Rect rect = ((RectTransform)((Component)this).transform).rect;
			Vector2 size = ((Rect)(ref rect)).size;
			if (!(size == _canvas))
			{
				_canvas = size;
				((Transform)_sheet).localScale = Vector3.one * Mathf.Min(new float[3]
				{
					1f,
					Mathf.Max(0.1f, (size.x - 24f) / 1280f),
					Mathf.Max(0.1f, (size.y - 24f) / 800f)
				});
			}
		}

		private static void Caption(Button b, string caption)
		{
			((Component)b).GetComponentInChildren<Text>().text = caption;
		}

		private static Card Get(List<Card> pool, int index, Transform parent)
		{
			if (index == pool.Count)
			{
				pool.Add(new Card(parent));
			}
			pool[index].Root.SetActive(true);
			return pool[index];
		}

		private static void Hide(List<Card> pool, int from)
		{
			for (int i = from; i < pool.Count; i++)
			{
				pool[i].Root.SetActive(false);
			}
		}

		private void PaintProduction()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			RestlessUi.PaperControl(((Component)_make).gameObject, (_mode == WorksOrderMode.Make) ? new Color?(RestlessUi.Accent) : ((Color?)null));
			RestlessUi.PaperControl(((Component)_keep).gameObject, (_mode == WorksOrderMode.Keep) ? new Color?(RestlessUi.Accent) : ((Color?)null));
			_modeHelp.text = ((_mode == WorksOrderMode.Make) ? "Produce this many additional units, then stop." : "Maintain this much usable stock. Refill as supplies are used.");
			Caption(_stationFilter, (_station.Length == 0) ? "All machines" : Local(_recipes.FirstOrDefault((WorksRecipe r) => r.Station == _station)?.StationName ?? _station));
			List<WorksRecipe> list = (from r in _recipes
				where Matches(r.OutputName) && (_station.Length == 0 || r.Station == _station)
				orderby r.OutputName
				select r).ToList();
			for (int num = 0; num < list.Count; num++)
			{
				WorksRecipe recipe = list[num];
				Card card = Get(_choices, num, (Transform)(object)((ScrollRect)_list).content);
				Place(card.Root, 0f, num * 78, 228f, 70f);
				card.Set(Local(recipe.OutputName), "", Icon(recipe.Output), delegate
				{
					_output = recipe.Output;
					Refresh(force: true);
					Reset(_body);
					Reset(_details);
				}, recipe.Output == _output, compact: true);
			}
			Hide(_choices, list.Count);
			Size(_list, list.Count * 78);
			WorksRecipe selected = _recipes.FirstOrDefault((WorksRecipe r) => r.Output == _output);
			if (selected == null || _plan.Count == 0)
			{
				Empty("No matching production", "Try another search or machine filter. Machine recipes become available when the world is loaded.");
				return;
			}
			WorksStep worksStep = _plan[0];
			int num2 = Math.Max(0, worksStep.Available - _orders.Where((WorksOrder o) => o.Output == _output && o.Mode == WorksOrderMode.Make).Sum((WorksOrder o) => o.Ready));
			int num3 = ((_mode == WorksOrderMode.Make) ? _count : Math.Max(0, _count - num2));
			string name = ((_mode == WorksOrderMode.Make) ? "Make " : "Keep ") + _count + " · " + Local(selected.OutputName);
			Card card2 = Get(_cards, 0, (Transform)(object)((ScrollRect)_body).content);
			Place(card2.Root, 0f, 4f, 536f, 148f);
			card2.Set(name, (_mode == WorksOrderMode.Make) ? "Additional output · existing finished stock is kept" : (num2 + " usable now · target " + _count), Icon(_output), delegate
			{
			}, selected: true);
			if (_mode == WorksOrderMode.Keep)
			{
				card2.Coverage(num2, 0, _count);
			}
			int num4 = 1;
			for (int num5 = 0; num5 < worksStep.Uses.Count; num5++)
			{
				WorksUse use = worksStep.Uses[num5];
				int num6 = (int)Math.Ceiling((double)use.Amount * (double)num3 / (double)Math.Max(1, worksStep.Need));
				bool flag = use.Item == selected.Fuel;
				bool craftable = _recipes.Any((WorksRecipe r) => r.Output == use.Item);
				Card card3 = Get(_cards, num4++, (Transform)(object)((ScrollRect)_body).content);
				Place(card3.Root, 0f, 176 + num5 * 128, 536f, 116f);
				card3.Set(Local(use.Name) + (craftable ? "  ›" : ""), (flag ? "Fuel estimate: " : "Input: ") + num6 + " needed · " + use.Available + " available" + (craftable ? "\nSelect to order this separately" : ""), Icon(use.Item), delegate
				{
					if (craftable)
					{
						PickOutput(use.Item);
					}
				});
			}
			Hide(_cards, num4);
			Size(_body, 176 + worksStep.Uses.Count * 128);
			List<WorksMachine> list2 = _machines.Where((WorksMachine m) => m.Prefab == selected.Station).ToList();
			StringBuilder stringBuilder = new StringBuilder("PRODUCTION REQUIREMENTS\n\n").AppendLine(Local(selected.StationName)).AppendLine(list2.Count + " machines in range").AppendLine(list2.Sum((WorksMachine m) => m.Free) + " free input slots")
				.AppendLine()
				.AppendLine((_mode == WorksOrderMode.Make) ? "Make produces additional units." : "Keep counts usable stock after Make reservations, plus incoming production when the order is running.")
				.AppendLine()
				.AppendLine("OUTPUT DESTINATION")
				.AppendLine("Collected onto this board. Use Orders to collect Make output, or Output for unreserved stock.")
				.AppendLine()
				.AppendLine("DEPENDENCIES")
				.AppendLine("Input and fuel recipes can be ordered separately. This plan does not automatically queue them.");
			if (!string.IsNullOrEmpty(selected.Fuel))
			{
				stringBuilder.AppendLine().AppendLine("Fuel quantities are estimates. Machines retain their normal fuel use and processing time.");
			}
			Detail(stringBuilder.ToString());
			bool flag2 = _orders.Any((WorksOrder o) => o.Output == _output && o.Mode == WorksOrderMode.Keep);
			_hint.text = ((_mode == WorksOrderMode.Keep && flag2) ? "A Keep target already exists. Manage it in Orders." : ((_orders.Count >= 8) ? "The board has eight orders. Remove or finish one first." : ((list2.Count == 0) ? "No matching machine nearby. This order will wait." : ((_mode == WorksOrderMode.Keep && num3 == 0) ? "Target already met. The order will monitor stock." : "Machines use available inputs and fuel. Missing supplies can be added later."))));
			Caption(_action, ((_mode == WorksOrderMode.Make) ? "Make " : "Keep ") + _count);
			((Selectable)_action).interactable = _orders.Count < 8 && !(_mode == WorksOrderMode.Keep && flag2);
		}

		private void PaintOrders()
		{
			List<WorksOrder> list = _orders.Where((WorksOrder worksOrder) => Matches(worksOrder.Name)).ToList();
			for (int num = 0; num < list.Count; num++)
			{
				WorksOrder o = list[num];
				Card card = Get(_choices, num, (Transform)(object)((ScrollRect)_list).content);
				Place(card.Root, 0f, num * 100, 228f, 92f);
				card.Set(Local(o.Name), o.Mode.ToString() + " " + o.Count, Icon(o.Output), delegate
				{
					_order = o.Id;
					_confirmCancel = false;
					Refresh(force: true);
					Reset(_details);
				}, o.Id == _order, compact: true);
			}
			Hide(_choices, list.Count);
			Size(_list, list.Count * 100);
			WorksOrder order = list.FirstOrDefault((WorksOrder worksOrder) => worksOrder.Id == _order);
			if (order == null)
			{
				Empty("No orders selected", "Place a Make order for a finite amount, or a Keep target to replenish stock automatically.");
				return;
			}
			Card card2 = Get(_cards, 0, (Transform)(object)((ScrollRect)_body).content);
			Place(card2.Root, 0f, 4f, 536f, 160f);
			card2.Set(order.Mode.ToString() + " " + order.Count + " · " + Local(order.Name), (order.Mode == WorksOrderMode.Keep) ? "Stock coverage · green available, amber incoming" : "Order completion · green finished, amber incoming", Icon(order.Output), delegate
			{
			}, selected: true);
			card2.Coverage(order.Available, order.InProduction, order.Count);
			string[] array = ((order.Mode != WorksOrderMode.Keep) ? new string[3] { "Finished", "In production", "Still to load" } : new string[3] { "Available stock", "In production", "Remaining shortage" });
			int[] array2 = new int[3] { order.Available, order.InProduction, order.Remaining };
			for (int num2 = 0; num2 < 3; num2++)
			{
				Card card3 = Get(_cards, num2 + 1, (Transform)(object)((ScrollRect)_body).content);
				Place(card3.Root, 0f, 186 + num2 * 112, 536f, 104f);
				card3.Set(array[num2] + "  " + array2[num2], (num2 == 0 && order.Mode == WorksOrderMode.Make) ? (order.Ready + " ready on board · " + order.Collected + " collected") : "", null, delegate
				{
				});
			}
			Hide(_cards, 4);
			Size(_body, 532f);
			WorksRecipe recipe = _recipes.FirstOrDefault((WorksRecipe r) => r.Output == order.Output);
			List<WorksMachine> list2 = _machines.Where((WorksMachine m) => m.Prefab == recipe?.Station).ToList();
			string value = ((order.Mode == WorksOrderMode.Keep && order.Available >= order.Count) ? "Target met · monitoring stock" : ((order.InProduction > 0) ? "Production underway" : ((order.Ready > 0 && order.Remaining == 0) ? "Ready to collect" : ((list2.Count == 0) ? "Waiting for a matching machine" : "Waiting for inputs, fuel or a free machine slot"))));
			StringBuilder stringBuilder = new StringBuilder("ORDER #").Append(order.Id).Append("\n\n").AppendLine(value)
				.AppendLine()
				.AppendLine((order.Mode == WorksOrderMode.Keep) ? "This target stays active and replenishes supplies as stock falls." : "This order stops after its requested additional output is made and collected.")
				.AppendLine()
				.AppendLine("MACHINES")
				.AppendLine((recipe == null) ? "Recipe unavailable" : Local(recipe.StationName))
				.AppendLine(list2.Count + " in range")
				.AppendLine()
				.AppendLine("Stopping an order removes its instruction. Material already inside machines continues processing.");
			Detail(stringBuilder.ToString());
			_hint.text = "";
			Caption(_action, _confirmCancel ? "Confirm removal" : ((order.Mode == WorksOrderMode.Keep) ? "Stop keeping stock" : "Cancel order"));
			((Selectable)_action).interactable = true;
			((Component)_secondary).gameObject.SetActive(order.Mode == WorksOrderMode.Make);
			Caption(_secondary, "Collect " + order.Ready + " ready");
			((Selectable)_secondary).interactable = order.Ready > 0 && (Object)(object)Player.m_localPlayer != (Object)null && Player.m_localPlayer.GetPlayerID() == order.PlayerId;
			if (order.Mode == WorksOrderMode.Make && (Object)(object)Player.m_localPlayer != (Object)null && order.PlayerId != Player.m_localPlayer.GetPlayerID())
			{
				_hint.text = "Only the player who placed this Make order can collect it.";
			}
		}

		private void PaintMachines()
		{
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_032d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			var list = (from x in _machines.Select((WorksMachine m, int i) => new
				{
					Machine = m,
					Index = i
				})
				where Matches(x.Machine.Name)
				select x).ToList();
			if (!list.Any(x => x.Index == _machine))
			{
				_machine = list.FirstOrDefault()?.Index ?? 0;
			}
			for (int num = 0; num < list.Count; num++)
			{
				var row = list[num];
				Card card = Get(_choices, num, (Transform)(object)((ScrollRect)_list).content);
				Place(card.Root, 0f, num * 100, 228f, 92f);
				card.Set(Local(row.Machine.Name), Mathf.RoundToInt(Vector3.Distance(((Component)_board).transform.position, row.Machine.Position)) + " m from board", null, delegate
				{
					_machine = row.Index;
					Refresh(force: true);
					Reset(_details);
				}, _machine == row.Index, compact: true);
			}
			Hide(_choices, list.Count);
			Size(_list, list.Count * 100);
			WorksMachine worksMachine = list.FirstOrDefault(x => x.Index == _machine)?.Machine;
			if (worksMachine == null)
			{
				Empty("No machines in range", "Build a kiln, smelter or another supported production machine near the board.");
				return;
			}
			Card card2 = Get(_cards, 0, (Transform)(object)((ScrollRect)_body).content);
			Place(card2.Root, 0f, 4f, 536f, 148f);
			card2.Set(Local(worksMachine.Name), string.IsNullOrEmpty(worksMachine.Block) ? "Machine connected" : worksMachine.Block, null, delegate
			{
			}, selected: true);
			string[] array = new string[3]
			{
				worksMachine.Cooking + " inputs queued",
				worksMachine.Ready + " processed output waiting",
				worksMachine.Free + " free input slots"
			};
			for (int num2 = 0; num2 < array.Length; num2++)
			{
				Card card3 = Get(_cards, num2 + 1, (Transform)(object)((ScrollRect)_body).content);
				Place(card3.Root, 0f, 170 + num2 * 112, 536f, 104f);
				card3.Set(array[num2], "", null, delegate
				{
				});
			}
			Hide(_cards, 4);
			Size(_body, 506f);
			float num3 = Vector3.Distance(((Component)_board).transform.position, worksMachine.Position);
			Detail("MACHINE STATUS\n\n" + Local(worksMachine.Name) + "\n" + num3.ToString("0.0") + " m from board\n\n" + ((worksMachine.FuelMax > 0) ? ("FUEL\n" + worksMachine.Fuel + " / " + worksMachine.FuelMax) : "No fuel required") + "\n\n" + (string.IsNullOrEmpty(worksMachine.Block) ? "No reported block." : worksMachine.Block) + "\n\nCounts are live machine queues. Processing time and machine conditions remain native.\n\nFinished output for active orders is collected onto the board.");
			_hint.text = "Manage what this machine makes through Production and Orders.";
			((Component)_action).gameObject.SetActive(false);
		}

		private void PaintOutput()
		{
			List<WorksStock> list = (from s in _stock
				where Matches(s.Name)
				orderby s.Name
				select s).ToList();
			for (int num = 0; num < list.Count; num++)
			{
				WorksStock item = list[num];
				Card card = Get(_choices, num, (Transform)(object)((ScrollRect)_list).content);
				Place(card.Root, 0f, num * 100, 228f, 92f);
				card.Set(Local(item.Name), Math.Max(0, item.Count - item.Reserved) + " available", Icon(item.Prefab), delegate
				{
					_stockItem = item.Prefab;
					Refresh(force: true);
					Reset(_details);
				}, item.Prefab == _stockItem, compact: true);
			}
			Hide(_choices, list.Count);
			Size(_list, list.Count * 100);
			WorksStock worksStock = list.FirstOrDefault((WorksStock s) => s.Prefab == _stockItem);
			if (worksStock == null)
			{
				Empty("Board output is empty", "Processed output collected for orders appears here. Make reservations are collected from Orders.");
				return;
			}
			int num2 = Math.Max(0, worksStock.Count - worksStock.Reserved);
			Card card2 = Get(_cards, 0, (Transform)(object)((ScrollRect)_body).content);
			Place(card2.Root, 0f, 4f, 536f, 148f);
			card2.Set(Local(worksStock.Name), worksStock.Count + " stored on this board", Icon(worksStock.Prefab), delegate
			{
			}, selected: true);
			Card card3 = Get(_cards, 1, (Transform)(object)((ScrollRect)_body).content);
			Place(card3.Root, 0f, 176f, 536f, 116f);
			card3.Set(num2 + " available to take", worksStock.Reserved + " reserved for Make orders", Icon(worksStock.Prefab), delegate
			{
			});
			Hide(_cards, 2);
			Size(_body, 312f);
			Detail("BOARD OUTPUT\n\nUnreserved materials can be taken into your inventory.\n\nMake output is reserved for its order. Collect it from Orders.\n\nKeep output is unreserved. Taking it into your bag may still count towards the Keep target while you remain nearby.\n\nAutomatic delivery to a designated chest is not connected yet.");
			_hint.text = ((num2 > 0) ? "Take up to one stack. Anything that does not fit stays here." : "All of this item is reserved. Open its Make order to collect it.");
			Caption(_action, "Take a stack");
			((Selectable)_action).interactable = num2 > 0;
		}

		private void Empty(string title, string description)
		{
			Card card = Get(_cards, 0, (Transform)(object)((ScrollRect)_body).content);
			Place(card.Root, 0f, 4f, 536f, 168f);
			card.Set(title, description, null, delegate
			{
			});
			Hide(_cards, 1);
			Size(_body, 180f);
			Detail(description);
			_hint.text = "";
			((Component)_action).gameObject.SetActive(false);
			((Component)_secondary).gameObject.SetActive(false);
		}
	}
	internal static class WorksRun
	{
		private sealed class Hit
		{
			public Smelter? Station;

			public WorksMachine Info = new WorksMachine();
		}

		private sealed class Ledger
		{
			public readonly List<WorksOrder> Orders = new List<WorksOrder>();

			public readonly Dictionary<string, int> Pantry = new Dictionary<string, int>(StringComparer.Ordinal);
		}

		private const string Key = "RestlessWorks";

		private const int MaxOrders = 8;

		private const int LoadsPerTick = 4;

		private static List<WorksRecipe>? _recipes;

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

		internal static void TickOwned(float elapsed)
		{
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				return;
			}
			Board[] array = Object.FindObjectsByType<Board>((FindObjectsInactive)0, (FindObjectsSortMode)0);
			foreach (Board board in array)
			{
				if (!((Object)(object)board == (Object)null))
				{
					ZNetView component = ((Component)board).GetComponent<ZNetView>();
					Piece component2 = ((Component)board).GetComponent<Piece>();
					if (!((Object)(object)component == (Object)null) && !((Object)(object)component2 == (Object)null) && component.IsValid() && component.IsOwner())
					{
						Tick(component2, component);
					}
				}
			}
		}

		internal static IReadOnlyList<WorksRecipe> Recipes()
		{
			Discover();
			return _recipes ?? new List<WorksRecipe>();
		}

		internal static WorksRecipe? Find(string output)
		{
			Discover();
			if (_recipes == null || string.IsNullOrEmpty(output))
			{
				return null;
			}
			foreach (WorksRecipe recipe in _recipes)
			{
				if (recipe.Output == output || recipe.OutputName == output)
				{
					return recipe;
				}
			}
			return null;
		}

		internal static IReadOnlyList<WorksStep> Plan(Piece board, string output, int count)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			List<WorksStep> list = new List<WorksStep>();
			WorksRecipe worksRecipe = Find(output);
			if (worksRecipe == null || (Object)(object)board == (Object)null)
			{
				return list;
			}
			Vector3 position = ((Component)board).transform.position;
			long playerId = (((Object)(object)Player.m_localPlayer != (Object)null) ? Player.m_localPlayer.GetPlayerID() : 0);
			Dictionary<string, int> stock = Stock(position, playerId, Read(View(board)));
			AddStep(list, worksRecipe, Math.Max(1, count), "", 0, stock, new HashSet<string>(StringComparer.Ordinal));
			return list;
		}

		internal static IReadOnlyList<WorksOrder> ReadOrders(Piece board)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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)
			ZNetView val = View(board);
			if ((Object)(object)val == (Object)null)
			{
				return Array.Empty<WorksOrder>();
			}
			Ledger ledger = Read(val);
			Vector3 position = ((Component)board).transform.position;
			long playerId = (((Object)(object)Player.m_localPlayer != (Object)null) ? Player.m_localPlayer.GetPlayerID() : 0);
			Describe(ledger, Stock(position, playerId, ledger), Production(Scan(position, claim: false)));
			return ledger.Orders;
		}

		internal static IReadOnlyList<WorksMachine> Machines(Piece board)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)board == (Object)null)
			{
				return Array.Empty<WorksMachine>();
			}
			List<WorksMachine> list = new List<WorksMachine>();
			foreach (Hit item in Scan(((Component)board).transform.position, claim: false))
			{
				list.Add(item.Info);
			}
			return list;
		}

		internal static IReadOnlyList<WorksStock> Pantry(Piece board)
		{
			ZNetView val = View(board);
			if ((Object)(object)val == (Object)null)
			{
				return Array.Empty<WorksStock>();
			}
			Ledger ledger = Read(val);
			List<WorksStock> list = new List<WorksStock>();
			foreach (KeyValuePair<string, int> item in ledger.Pantry)
			{
				int num = 0;
				foreach (WorksOrder order in ledger.Orders)
				{
					if (order.Mode == WorksOrderMode.Make && order.Output == item.Key)
					{
						num += order.Ready;
					}
				}
				list.Add(new WorksStock
				{
					Prefab = item.Key,
					Name = Label(item.Key),
					Count = item.Value,
					Reserved = Math.Min(item.Value, num)
				});
			}
			return list;
		}

		internal static bool Place(Piece board, string output, WorksOrderMode mode, int count)
		{
			ZNetView val = View(board);
			WorksRecipe worksRecipe = Find(output);
			if ((Object)(object)val == (Object)null || worksRecipe == null || count < 1)
			{
				return false;
			}
			Ledger ledger = Read(val);
			if (ledger.Orders.Count >= 8)
			{
				return false;
			}
			int num = 1;
			foreach (WorksOrder order in ledger.Orders)
			{
				num = Math.Max(num, order.Id + 1);
			}
			ledger.Orders.Add(new WorksOrder
			{
				Id = num,
				Output = worksRecipe.Output,
				Name = worksRecipe.OutputName,
				Mode = mode,
				Count = Math.Min(count, 999),
				PlayerId = (((Object)(object)Player.m_localPlayer != (Object)null) ? Player.m_localPlayer.GetPlayerID() : 0)
			});
			Write(val, ledger);
			return true;
		}

		internal static void Cancel(Piece board, int orderId)
		{
			ZNetView val = View(board);
			if (!((Object)(object)val == (Object)null))
			{
				Ledger ledger = Read(val);
				ledger.Orders.RemoveAll((WorksOrder order) => order.Id == orderId);
				Write(val, ledger);
			}
		}

		internal static int Collect(Piece board, int orderId)
		{
			ZNetView val = View(board);
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)val == (Object)null || (Object)(object)localPlayer == (Object)null)
			{
				return 0;
			}
			Ledger ledger = Read(val);
			WorksOrder worksOrder = null;
			foreach (WorksOrder order in ledger.Orders)
			{
				if (order.Id == orderId)
				{
					worksOrder = order;
				}
			}
			if (worksOrder == null || worksOrder.Mode != WorksOrderMode.Make || worksOrder.Ready < 1 || localPlayer.GetPlayerID() != worksOrder.PlayerId)
			{
				return 0;
			}
			int num = Give(localPlayer, ledger, worksOrder.Output, worksOrder.Ready);
			if (num < 1)
			{
				return 0;
			}
			worksOrder.Ready -= num;
			worksOrder.Collected += num;
			if (worksOrder.Collected >= worksOrder.Count && worksOrder.Ready < 1)
			{
				ledger.Orders.Remove(worksOrder);
			}
			Write(val, ledger);
			return num;
		}

		internal static int Take(Piece board, string prefab, int count)
		{
			ZNetView val = View(board);
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)val == (Object)null || (Object)(object)localPlayer == (Object)null || count < 1 || string.IsNullOrEmpty(prefab))
			{
				return 0;
			}
			Ledger ledger = Read(val);
			if (!ledger.Pantry.TryGetValue(prefab, out var value) || value < 1)
			{
				return 0;
			}
			int num = 0;
			foreach (WorksOrder order in ledger.Orders)
			{
				if (order.Mode == WorksOrderMode.Make && order.Output == prefab)
				{
					num += order.Ready;
				}
			}
			int val2 = Math.Max(0, value - num);
			int num2 = Give(localPlayer, ledger, prefab, Math.Min(count, val2));
			if (num2 > 0)
			{
				Write(val, ledger);
			}
			return num2;
		}

		private static void Tick(Piece board, ZNetView view)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			Ledger ledger = Read(view);
			if (ledger.Orders.Count == 0)
			{
				return;
			}
			Vector3 position = ((Component)board).transform.position;
			long playerId = (((Object)(object)Player.m_localPlayer != (Object)null) ? Player.m_localPlayer.GetPlayerID() : 0);
			List<Hit> hits = Scan(position, claim: true);
			CollectFinished(hits, ledger);
			int num = 0;
			Describe(ledger, Stock(position, playerId, ledger), Production(hits));
			foreach (WorksOrder order in ledger.Orders)
			{
				if (num >= 4 || order.Remaining < 1)
				{
					continue;
				}
				WorksRecipe worksRecipe = Find(order.Output);
				if (worksRecipe != null)
				{
					while (num < 4 && order.Remaining > 0 && LoadOne(worksRecipe, hits, ledger, position, playerId))
					{
						num++;
						order.Remaining--;
						order.InProduction++;
					}
				}
			}
			Write(view, ledger);
		}

		private static void Describe(Ledger ledger, Dictionary<string, int> stock, Dictionary<string, int> machines)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>(machines, StringComparer.Ordinal);
			foreach (WorksOrder order in ledger.Orders)
			{
				dictionary.TryGetValue(order.Output, out var value);
				if (order.Mode == WorksOrderMode.Make)
				{
					int num = Math.Max(0, order.Count - order.Ready - order.Collected);
					int num2 = Math.Min(num, value);
					dictionary[order.Output] = value - num2;
					order.InProduction = num2;
					order.Available = order.Ready + order.Collected;
					order.Remaining = num - num2;
				}
				else
				{
					stock.TryGetValue(order.Output, out var value2);
					value2 = Math.Max(0, value2 - Reserved(ledger, order.Output));
					int num3 = Math.Max(0, order.Count - value2);
					int num4 = Math.Min(num3, value);
					dictionary[order.Output] = value - num4;
					order.InProduction = num4;
					order.Available = value2;
					order.Remaining = num3 - num4;
				}
			}
		}

		private static int Reserved(Ledger ledger, string output)
		{
			int num = 0;
			foreach (WorksOrder order in ledger.Orders)
			{
				if (order.Mode == WorksOrderMode.Make && order.Output == output)
				{
					num += order.Ready;
				}
			}
			return num;
		}

		private static bool LoadOne(WorksRecipe recipe, List<Hit> hits, Ledger ledger, Vector3 origin, long playerId)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			if (!ledger.Pantry.TryGetValue(recipe.Input, out var value) || value < 1)
			{
				PullInto(ledger, recipe.Input, 1, origin, playerId);
				if (!ledger.Pantry.TryGetValue(recipe.Input, out value) || value < 1)
				{
					return false;
				}
			}
			foreach (Hit hit in hits)
			{
				Smelter station = hit.Station;
				if ((Object)(object)station?.m_nview == (Object)null || !station.m_nview.IsOwner() || station.GetQueueSize() >= station.m_maxOre || !station.IsItemAllowed(recipe.Input))
				{
					continue;
				}
				string text = station.m_nview.GetZDO().GetString(ZDOVars.s_spawnOre, "");
				if ((string.IsNullOrEmpty(text) || !(text != recipe.Input) || !(Clean(text) != recipe.Input)) && Fuel(station, recipe, ledger, origin, playerId))
				{
					ledger.Pantry[recipe.Input] = value - 1;
					if (ledger.Pantry[recipe.Input] <= 0)
					{
						ledger.Pantry.Remove(recipe.Input);
					}
					station.QueueOre(recipe.Input, false);
					hit.Info.Free = Math.Max(0, hit.Info.Free - 1);
					return true;
				}
			}
			return false;
		}

		private static bool Fuel(Smelter station, WorksRecipe recipe, Ledger ledger, Vector3 origin, long playerId)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)station.m_fuelItem == (Object)null || station.m_maxFuel <= 0 || station.GetFuel() >= 1f)
			{
				return true;
			}
			string text = (string.IsNullOrEmpty(recipe.Fuel) ? Clean(((Object)((Component)station.m_fuelItem).gameObject).name) : recipe.Fuel);
			if (!ledger.Pantry.TryGetValue(text, out var value) || value < 1)
			{
				PullInto(ledger, text, 1, origin, playerId);
				if (!ledger.Pantry.TryGetValue(text, out value) || value < 1)
				{
					return false;
				}
			}
			ledger.Pantry[text] = value - 1;
			if (ledger.Pantry[text] <= 0)
			{
				ledger.Pantry.Remove(text);
			}
			station.SetFuel(Math.Min(station.m_maxFuel, station.GetFuel() + 1f));
			return station.GetFuel() >= 1f;
		}

		private static void CollectFinished(List<Hit> hits, Ledger ledger)
		{
			foreach (Hit hit in hits)
			{
				Smelter station = hit.Station;
				if ((Object)(object)station?.m_nview == (Object)null || !station.m_nview.IsOwner() || station.GetProcessedQueueSize() <= 0)
				{
					continue;
				}
				string text = station.m_nview.GetZDO().GetString(ZDOVars.s_spawnOre, "");
				ItemConversion itemConversion = station.GetItemConversion(text);
				if ((Object)(object)itemConversion?.m_to == (Object)null)
				{
					continue;
				}
				string text2 = Clean(((Object)((Component)itemConversion.m_to).gameObject).name);
				if (!Wanted(ledger, text2))
				{
					continue;
				}
				int processedQueueSize = station.GetProcessedQueueSize();
				Add(ledger, text2, processedQueueSize);
				int num = processedQueueSize;
				foreach (WorksOrder order in ledger.Orders)
				{
					if (num >= 1 && order.Mode == WorksOrderMode.Make && !(order.Output != text2))
					{
						int num2 = Math.Min(Math.Max(0, order.Count - order.Ready - order.Collected), num);
						order.Ready += num2;
						num -= num2;
					}
				}
				station.m_nview.GetZDO().Set(ZDOVars.s_spawnOre, "");
				station.m_nview.GetZDO().Set(ZDOVars.s_spawnAmount, 0, false);
			}
		}

		private static bool Wanted(Ledger ledger, string output)
		{
			foreach (WorksOrder order in ledger.Orders)
			{
				if (!(order.Output != output))
				{
					if (order.Mode == WorksOrderMode.Keep)
					{
						return true;
					}
					if (order.Ready + order.Collected < order.Count)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static void AddStep(List<WorksStep> steps, WorksRecipe recipe, int count, string parent, int depth, Dictionary<string, int> stock, HashSet<string> guard)
		{
			if (!guard.Add(recipe.Output) || depth > 6)
			{
				return;
			}
			stock.TryGetValue(recipe.Output, out var value);
			WorksStep worksStep = new WorksStep
			{
				Output = recipe.Output,
				Name = recipe.OutputName,
				Parent = parent,
				Depth = depth,
				Need = count,
				Available = value,
				Station = recipe.Station
			};
			stock.TryGetValue(recipe.Input, out var value2);
			worksStep.Uses.Add(new WorksUse
			{
				Item = recipe.Input,
				Name = recipe.InputName,
				Amount = count,
				Available = value2
			});
			if (!string.IsNullOrEmpty(recipe.Fuel))
			{
				stock.TryGetValue(recipe.Fuel, out var value3);
				worksStep.Uses.Add(new WorksUse
				{
					Item = recipe.Fuel,
					Name = recipe.FuelName,
					Amount = count,
					Available = value3
				});
				worksStep.Note = "Fuel is a planning estimate of one per product.";
			}
			steps.Add(worksStep);
			WorksRecipe worksRecipe = Find(recipe.Input);
			if (worksRecipe != null)
			{
				AddStep(steps, worksRecipe, count, recipe.Output, depth + 1, stock, guard);
			}
			if (!string.IsNullOrEmpty(recipe.Fuel))
			{
				WorksRecipe worksRecipe2 = Find(recipe.Fuel);
				if (worksRecipe2 != null)
				{
					AddStep(steps, worksRecipe2, count, recipe.Output, depth + 1, stock, guard);
				}
			}
		}

		private static List<Hit> Scan(Vector3 origin, bool claim)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			List<Hit> list = new List<Hit>();
			HashSet<int> hashSet = new HashSet<int>();
			Collider[] array = Physics.OverlapSphere(origin, Range(), -1, (QueryTriggerInteraction)2);
			foreach (Collider val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					Smelter componentInParent = ((Component)val).GetComponentInParent<Smelter>();
					if (!((Object)(object)componentInParent == (Object)null) && hashSet.Add(((Object)componentInParent).GetInstanceID()) && !FoodOven(Utils.GetPrefabName(((Component)componentInParent).gameObject)))
					{
						list.Add(Describe(componentInParent, claim));
					}
				}
			}
			return list;
		}

		private static Hit Describe(Smelter station, bool claim)
		{
			//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)
			WorksMachine worksMachine = new WorksMachine
			{
				Name = LabelToken(station.m_name),
				Prefab = Utils.GetPrefabName(((Component)station).gameObject),
				Position = ((Component)station).transform.position,
				FuelMax = station.m_maxFuel,
				FuelItem = (((Object)(object)station.m_fuelItem != (Object)null) ? Clean(((Object)((Component)station.m_fuelItem).gameObject).name) : "")
			};
			if ((Object)(object)station.m_nview != (Object)null && station.m_nview.IsValid())
			{
				worksMachine.Fuel = ((station.m_maxFuel > 0) ? Mathf.FloorToInt(station.GetFuel()) : 0);
				worksMachine.Cooking = station.GetQueueSize();
				worksMachine.Ready = station.GetProcessedQueueSize();
				worksMachine.Free = Math.Max(0, station.m_maxOre - station.GetQueueSize());
				if (claim && !station.m_nview.IsOwner())
				{
					station.m_nview.ClaimOwnership();
				}
			}
			if (station.m_maxFuel > 0 && worksMachine.Fuel < 1)
			{
				worksMachine.Block = "Needs fuel";
			}
			return new Hit
			{
				Station = station,
				Info = worksMachine
			};
		}

		private static Dictionary<string, int> Production(List<Hit> hits)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal);
			foreach (Hit hit in hits)
			{
				Smelter station = hit.Station;
				if (!((Object)(object)station?.m_nview == (Object)null) && station.m_nview.IsValid())
				{
					string text = station.m_nview.GetZDO().GetString(ZDOVars.s_spawnOre, "");
					ItemConversion val = (string.IsNullOrEmpty(text) ? null : station.GetItemConversion(text));
					if (!((Object)(object)val?.m_to == (Object)null))
					{
						string key = Clean(((Object)((Component)val.m_to).gameObject).name);
						int val2 = station.GetQueueSize() + station.GetProcessedQueueSize();
						dictionary.TryGetValue(key, out var value);
						dictionary[key] = value + Math.Max(0, val2);
					}
				}
			}
			return dictionary;
		}

		private static Dictionary<string, int> Stock(Vector3 origin, long playerId, Ledger ledger)
		{
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, int> free = new Dictionary<string, int>(ledger.Pantry, StringComparer.Ordinal);
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null && (playerId == 0L || localPlayer.GetPlayerID() == playerId))
			{
				foreach (ItemData allItem in ((Humanoid)localPlayer).GetInventory().GetAllItems())
				{
					if (!((Object)(object)allItem?.m_dropPrefab == (Object)null))
					{
						AddStock(Clean(((Object)allItem.m_dropPrefab).name), allItem.m_stack);
					}
				}
			}
			foreach (Container item in NearbyStorage.Around(origin, Range(), playerId))
			{
				ZNetView nview = item.m_nview;
				if ((Object)(object)nview == (Object)null || !nview.IsOwner() || item.GetInventory() == null)
				{
					continue;
				}
				foreach (ItemData allItem2 in item.GetInventory().GetAllItems())
				{
					if (!((Object)(object)allItem2?.m_dropPrefab == (Object)null))
					{
						int num = allItem2.m_stack;
						if (ModConfig.LeaveOne.Value && num > 0)
						{
							num--;
						}
						AddStock(Clean(((Object)allItem2.m_dropPrefab).name), num);
					}
				}
			}
			List<NearbyLot> list = new List<NearbyLot>();
			NearbyLots.CollectAround(origin, Range(), list);
			foreach (NearbyLot item2 in list)
			{
				if (!((Object)(object)item2.Item?.m_dropPrefab == (Object)null))
				{
					AddStock(Clean(((Object)item2.Item.m_dropPrefab).name), item2.Count);
				}
			}
			return free;
			void AddStock(string prefab, int count)
			{
				if (count > 0 && !string.IsNullOrEmpty(prefab))
				{
					free.TryGetValue(prefab, out var value);
					free[prefab] = value + count;
				}
			}
		}

		private static void PullInto(Ledger ledger, string prefab, int count, Vector3 origin, long playerId)
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			if (count < 1)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null && (playerId == 0L || localPlayer.GetPlayerID() == playerId))
			{
				string text = Shared(prefab);
				Inventory inventory = ((Humanoid)localPlayer).GetInventory();
				int num = Math.Min((!string.IsNullOrEmpty(text)) ? inventory.CountItems(text, -1, true) : 0, count);
				if (num > 0)
				{
					inventory.RemoveItem(text, num, -1, true);
					Add(ledger, prefab, num);
					count -= num;
				}
			}
			if (count < 1)
			{
				return;
			}
			string text2 = Shared(prefab);
			if (string.IsNullOrEmpty(text2))
			{
				return;
			}
			foreach (Container item in NearbyStorage.Around(origin, Range(), playerId))
			{
				ZNetView nview = item.m_nview;
				Inventory inventory2 = item.GetInventory();
				if ((Object)(object)nview == (Object)null || !nview.IsOwner() || inventory2 == null)
				{
					continue;
				}
				int num2 = inventory2.CountItems(text2, -1, true);
				if (ModConfig.LeaveOne.Value && num2 > 0)
				{
					num2--;
				}
				int num3 = Math.Min(num2, count);
				if (num3 >= 1)
				{
					inventory2.RemoveItem(text2, num3, -1, true);
					item.Save();
					Add(ledger, prefab, num3);
					count -= num3;
					if (count < 1)
					{