Decompiled source of AIOAssembler v0.1.0

AIOAssembler.dll

Decompiled 5 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using CommonAPI;
using CommonAPI.Systems;
using CommonAPI.Systems.ModLocalization;
using HarmonyLib;
using LokiMoonLabs.HoneyIShrunkTheFactory;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;
using crecheng.DSPModSave;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace LokiMoonLabs.AIOAssembler
{
	internal sealed class AssemblyLine
	{
		private struct Slot
		{
			public BatchRecipe Recipe;

			public int RecipeId;

			public int Duration;

			public int Progress;

			public int Multiplier;

			public float Speed;

			public float RemainingWork;
		}

		private const int LegacySlotCount = 8;

		internal const int SlotCount = 10;

		internal const int InputSlotCount = 20;

		internal const int OutputSlotCount = 10;

		internal const int BufferedBatches = 9;

		internal const int OutputSlotsPerProduct = 8;

		internal readonly IngredientBuffer Ingredients = new IngredientBuffer();

		private readonly Slot[] slots = new Slot[10];

		private int firstSlot;

		private readonly List<int> logisticsItems = new List<int>();

		private bool logisticsDirty = true;

		private float assemblyWorkPerTick;

		private float smeltingWorkPerTick;

		public int Multiplier { get; private set; }

		internal bool HasPower { get; private set; }

		internal float PowerServed { get; set; }

		public int ConfiguredSlots
		{
			get
			{
				int num = 0;
				Slot[] array = slots;
				for (int i = 0; i < array.Length; i++)
				{
					Slot slot = array[i];
					if (slot.Recipe != null)
					{
						num++;
					}
				}
				return num;
			}
		}

		public AssemblyLine()
		{
			Multiplier = 1;
		}

		public void SetMultiplier(int multiplier)
		{
			if (multiplier < 1 || multiplier > 1000)
			{
				throw new ArgumentOutOfRangeException("multiplier");
			}
			Multiplier = multiplier;
		}

		public void SetRecipe(int index, int recipeId, BatchRecipe recipe, int duration)
		{
			if (recipeId <= 0 || recipe == null || duration <= 0)
			{
				throw new ArgumentException("A slot requires a valid recipe and cycle duration.");
			}
			ref Slot reference = ref slots[index];
			reference = new Slot
			{
				Recipe = recipe,
				RecipeId = recipeId,
				Duration = duration
			};
			logisticsDirty = true;
		}

		public void ClearRecipe(int index)
		{
			slots[index] = default(Slot);
			logisticsDirty = true;
		}

		public void ClearRecipes()
		{
			Array.Clear(slots, 0, slots.Length);
			logisticsDirty = true;
		}

		internal IReadOnlyList<int> LogisticsItems()
		{
			if (!logisticsDirty)
			{
				return logisticsItems;
			}
			logisticsItems.Clear();
			Slot[] array = slots;
			for (int i = 0; i < array.Length; i++)
			{
				Slot slot = array[i];
				if (slot.Recipe == null)
				{
					continue;
				}
				BatchRecipe.IngredientChange[] changes = slot.Recipe.Changes;
				for (int j = 0; j < changes.Length; j++)
				{
					BatchRecipe.IngredientChange ingredientChange = changes[j];
					if (!logisticsItems.Contains(ingredientChange.Item))
					{
						logisticsItems.Add(ingredientChange.Item);
					}
				}
			}
			logisticsDirty = false;
			return logisticsItems;
		}

		internal bool LogisticsRule(int item, out int reserve, out bool output)
		{
			long num = 0L;
			output = false;
			Slot[] array = slots;
			for (int i = 0; i < array.Length; i++)
			{
				Slot slot = array[i];
				if (slot.Recipe == null)
				{
					continue;
				}
				BatchRecipe.IngredientChange[] changes = slot.Recipe.Changes;
				for (int j = 0; j < changes.Length; j++)
				{
					BatchRecipe.IngredientChange ingredientChange = changes[j];
					if (ingredientChange.Item == item)
					{
						num += (long)ingredientChange.Input * (long)Math.Max(Multiplier, (slot.Progress > 0) ? slot.Multiplier : 0);
						output |= ingredientChange.Output > 0;
					}
				}
			}
			reserve = (int)Math.Min(num * 9, 2147483647L);
			if (reserve <= 0)
			{
				return output;
			}
			return true;
		}

		public int RecipeId(int index)
		{
			return slots[index].RecipeId;
		}

		internal BatchRecipe Recipe(int index)
		{
			return slots[index].Recipe;
		}

		internal int BatchMultiplier(int index)
		{
			if (slots[index].Progress != 0)
			{
				return slots[index].Multiplier;
			}
			return Multiplier;
		}

		internal bool WaitingForSpace(int index)
		{
			if (slots[index].Duration > 0)
			{
				return slots[index].Progress == slots[index].Duration;
			}
			return false;
		}

		internal long WorkingMachines(Func<BatchRecipe, int, bool> hasInputs)
		{
			long num = 0L;
			Slot[] array = slots;
			for (int i = 0; i < array.Length; i++)
			{
				Slot slot = array[i];
				if (slot.Recipe != null && slot.Progress != slot.Duration)
				{
					int num2 = ((slot.Progress > 0) ? slot.Multiplier : Multiplier);
					if (hasInputs(slot.Recipe, num2))
					{
						num += num2;
					}
				}
			}
			return num;
		}

		internal float CycleSeconds(int index)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			Slot slot = slots[index];
			if (slot.Recipe == null)
			{
				return 0f;
			}
			float num = (((int)slot.Recipe.Type == 1) ? smeltingWorkPerTick : assemblyWorkPerTick);
			if (!(num > 0f))
			{
				return 0f;
			}
			return (float)slot.Duration / (60f * num * Math.Max(1f, slot.Speed));
		}

		internal void AdvancePowered(float speed, Func<BatchRecipe, int, bool> hasInputs, Func<BatchRecipe, int, bool> completeBatch, Func<BatchRecipe, int, float> batchSpeed = null, float smeltingSpeed = -1f)
		{
			HasPower = speed > 0f;
			assemblyWorkPerTick = speed;
			smeltingWorkPerTick = ((smeltingSpeed < 0f) ? speed : smeltingSpeed);
			if (HasPower)
			{
				Advance(speed, completeBatch, hasInputs, batchSpeed, smeltingWorkPerTick);
			}
		}

		public float Progress(int index)
		{
			Slot slot = slots[index];
			if (slot.Duration != 0)
			{
				return (float)slot.Progress / (float)slot.Duration;
			}
			return 0f;
		}

		public void Write(BinaryWriter writer)
		{
			writer.Write(3);
			writer.Write(Multiplier);
			writer.Write(firstSlot);
			Slot[] array = slots;
			for (int i = 0; i < array.Length; i++)
			{
				Slot slot = array[i];
				writer.Write(slot.RecipeId);
				writer.Write(slot.Progress);
				writer.Write(slot.Multiplier);
			}
			Ingredients.Write(writer);
		}

		public static AssemblyLine Read(BinaryReader reader, Func<int, BatchRecipe> resolveRecipe, Func<int, int> resolveDuration)
		{
			int num = reader.ReadInt32();
			int num2;
			switch (num)
			{
			default:
				throw new InvalidDataException("Unsupported AIO Assembler save version.");
			case 3:
				num2 = 10;
				break;
			case 1:
			case 2:
				num2 = 8;
				break;
			}
			int num3 = num2;
			AssemblyLine assemblyLine = new AssemblyLine();
			assemblyLine.SetMultiplier(reader.ReadInt32());
			assemblyLine.firstSlot = reader.ReadInt32();
			if (assemblyLine.firstSlot < 0 || assemblyLine.firstSlot >= num3)
			{
				throw new InvalidDataException("Invalid saved slot cursor.");
			}
			for (int i = 0; i < num3; i++)
			{
				int num4 = reader.ReadInt32();
				int num5 = reader.ReadInt32();
				int num6 = reader.ReadInt32();
				if (num4 <= 0)
				{
					continue;
				}
				BatchRecipe batchRecipe = resolveRecipe(num4);
				int num7 = ((batchRecipe != null) ? resolveDuration(num4) : 0);
				if (num7 > 0)
				{
					assemblyLine.SetRecipe(i, num4, batchRecipe, num7);
					if (num5 > 0 && num6 >= 1 && num6 <= 1000)
					{
						assemblyLine.slots[i].Progress = Math.Min(num5, num7);
						assemblyLine.slots[i].Multiplier = num6;
					}
				}
			}
			if (num >= 2)
			{
				assemblyLine.Ingredients.Read(reader);
			}
			return assemblyLine;
		}

		public int Advance(int work, IReadOnlyDictionary<int, int> limits, Dictionary<int, int> stock)
		{
			return Advance(work, (BatchRecipe recipe, int multiplier) => recipe.TryComplete(limits, stock, multiplier));
		}

		private int Advance(float work, Func<BatchRecipe, int, bool> completeBatch, Func<BatchRecipe, int, bool> hasInputs = null, Func<BatchRecipe, int, float> batchSpeed = null, float smeltingWork = -1f)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Invalid comparison between Unknown and I4
			if (work <= 0f)
			{
				return 0;
			}
			int num = 0;
			for (int i = 0; i < 10; i++)
			{
				int num2 = (firstSlot + i) % 10;
				Slot slot = slots[num2];
				if (slot.Recipe == null)
				{
					continue;
				}
				float num3 = ((smeltingWork >= 0f && (int)slot.Recipe.Type == 1) ? smeltingWork : work);
				float num4 = num3 + slot.RemainingWork;
				int num5 = (int)num4;
				slot.RemainingWork = num4 - (float)num5;
				while (num5 > 0)
				{
					if (slot.Progress == 0)
					{
						slot.Multiplier = Multiplier;
					}
					if (hasInputs != null && !hasInputs(slot.Recipe, slot.Multiplier))
					{
						break;
					}
					if (slot.Progress == 0 || slot.Speed == 0f)
					{
						slot.Speed = batchSpeed?.Invoke(slot.Recipe, slot.Multiplier) ?? 1f;
					}
					int num6 = Math.Min((int)((float)num5 * slot.Speed), slot.Duration - slot.Progress);
					slot.Progress += num6;
					num5 -= (int)Math.Ceiling((double)num6 / (double)slot.Speed);
					if (slot.Progress < slot.Duration || !completeBatch(slot.Recipe, slot.Multiplier))
					{
						break;
					}
					num++;
					slot.Progress = 0;
				}
				slots[num2] = slot;
			}
			firstSlot = (firstSlot + 1) % 10;
			return num;
		}
	}
	internal sealed class BatchRecipe
	{
		internal struct IngredientChange
		{
			public int Item;

			public int Input;

			public int Output;
		}

		internal const int MaximumMultiplier = 1000;

		internal readonly IngredientChange[] Changes;

		internal readonly bool SpeedupOnly;

		internal readonly ERecipeType Type;

		internal static int DurationInTicks(int executionTime, int recipeTime)
		{
			if (executionTime <= 0)
			{
				return recipeTime;
			}
			return (int)(((long)executionTime + 9999L) / 10000);
		}

		public BatchRecipe(int[] inputs, int[] inputCounts, int[] outputs, int[] outputCounts, bool speedupOnly = false, ERecipeType type = (ERecipeType)4)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			SpeedupOnly = speedupOnly;
			Type = type;
			Dictionary<int, IngredientChange> dictionary = new Dictionary<int, IngredientChange>();
			Add(dictionary, inputs, inputCounts, output: false);
			Add(dictionary, outputs, outputCounts, output: true);
			Changes = new List<IngredientChange>(dictionary.Values).ToArray();
			if (!Array.Exists(Changes, (IngredientChange change) => change.Output > 0))
			{
				throw new ArgumentException("A recipe must produce at least one item.");
			}
		}

		private static void Add(Dictionary<int, IngredientChange> items, int[] ids, int[] counts, bool output)
		{
			if (ids == null || counts == null || ids.Length != counts.Length)
			{
				throw new ArgumentException("Recipe IDs and counts must align.");
			}
			for (int i = 0; i < ids.Length; i++)
			{
				checked
				{
					if (counts[i] != 0 || ids[i] < 0)
					{
						if (ids[i] <= 0 || counts[i] <= 0)
						{
							throw new ArgumentException("Recipe items and quantities must be positive.");
						}
						items.TryGetValue(ids[i], out var value);
						value.Item = ids[i];
						if (output)
						{
							value.Output += counts[i];
						}
						else
						{
							value.Input += counts[i];
						}
						items[value.Item] = value;
					}
				}
			}
		}

		public bool TryComplete(IReadOnlyDictionary<int, int> limits, Dictionary<int, int> stock, int multiplier)
		{
			if (multiplier < 1 || multiplier > 1000)
			{
				throw new ArgumentOutOfRangeException("multiplier");
			}
			IngredientChange[] changes = Changes;
			for (int i = 0; i < changes.Length; i++)
			{
				IngredientChange ingredientChange = changes[i];
				stock.TryGetValue(ingredientChange.Item, out var value);
				long num = (long)ingredientChange.Input * (long)multiplier;
				long num2 = value - num + (long)ingredientChange.Output * (long)multiplier;
				if (value < num || (ingredientChange.Output > 0 && (!limits.TryGetValue(ingredientChange.Item, out var value2) || num2 > value2)))
				{
					return false;
				}
			}
			IngredientChange[] changes2 = Changes;
			for (int j = 0; j < changes2.Length; j++)
			{
				IngredientChange ingredientChange2 = changes2[j];
				stock.TryGetValue(ingredientChange2.Item, out var value3);
				int num3 = (int)(value3 + ((long)ingredientChange2.Output - (long)ingredientChange2.Input) * multiplier);
				if (num3 == 0)
				{
					stock.Remove(ingredientChange2.Item);
				}
				else
				{
					stock[ingredientChange2.Item] = num3;
				}
			}
			return true;
		}
	}
	internal sealed class HubPanel : IDisposable
	{
		private const int RecipeColumns = 5;

		private const int InventorySlots = 30;

		private const int Width = 985;

		private const int Height = 506;

		private readonly Plugin plugin;

		private readonly Text[] recipeLabels = (Text[])(object)new Text[10];

		private readonly Image[] recipeIcons = (Image[])(object)new Image[10];

		private readonly Image[] progress = (Image[])(object)new Image[10];

		private readonly Button[] clear = (Button[])(object)new Button[10];

		private readonly Image[] items = (Image[])(object)new Image[30];

		private readonly Text[] counts = (Text[])(object)new Text[30];

		private readonly UIIncArrow[] arrows = (UIIncArrow[])(object)new UIIncArrow[30];

		private readonly List<int> inputs = new List<int>(20);

		private readonly List<int> outputs = new List<int>(10);

		private readonly Vector3[] corners = (Vector3[])(object)new Vector3[4];

		private RectTransform dockedStorage;

		private Vector2 storagePosition;

		private bool pickingRecipe;

		private float nextRefresh;

		private GameObject root;

		private RectTransform panel;

		private CanvasGroup native;

		private NativeSkin skin;

		private Font font;

		private Text footer;

		private Text powerLabel;

		private AssemblyLine line;

		private StorageComponent selectedStorage;

		private bool showStorage;

		private bool confirmClear;

		private float savedAlpha;

		private bool savedRaycasts;

		internal RectTransform MultiplierAnchor
		{
			get
			{
				if (!((Object)(object)root != (Object)null) || !root.activeSelf || UIRecipePicker.isOpened)
				{
					return null;
				}
				return panel;
			}
		}

		internal bool BlocksGamePointer
		{
			get
			{
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				RectTransform val = (((Object)(object)root != (Object)null && root.activeSelf) ? panel : null);
				if ((Object)(object)val != (Object)null)
				{
					return RectTransformUtility.RectangleContainsScreenPoint(val, Vector2.op_Implicit(Input.mousePosition), (Camera)null);
				}
				return false;
			}
		}

		internal int Multiplier
		{
			get
			{
				if (line != null)
				{
					return line.Multiplier;
				}
				return 1;
			}
		}

		internal HubPanel(Plugin plugin)
		{
			this.plugin = plugin;
		}

		internal void SetMultiplier(int value)
		{
			if (line != null)
			{
				line.SetMultiplier(value);
			}
		}

		private Image Surface(Transform parent, string name, float x, float y, float w, float h)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val.transform.SetParent(parent, false);
			Place(val.GetComponent<RectTransform>(), x, y, w, h);
			Image component = val.GetComponent<Image>();
			((Graphic)component).color = new Color(0.12f, 0.22f, 0.27f, 0.98f);
			return component;
		}

		private static void Place(RectTransform rect, float x, float y, float w, float h)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: 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_001a: 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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = (rect.pivot = new Vector2(0f, 1f));
			Vector2 anchorMin = (rect.anchorMax = val);
			rect.anchorMin = anchorMin;
			rect.anchoredPosition = new Vector2(x, 0f - y);
			rect.sizeDelta = new Vector2(w, h);
		}

		private Text Label(Transform parent, string value, float x, float y, float w, float h, int size)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Label", new Type[2]
			{
				typeof(RectTransform),
				typeof(Text)
			});
			val.transform.SetParent(parent, false);
			Place(val.GetComponent<RectTransform>(), x, y, w, h);
			Text component = val.GetComponent<Text>();
			component.font = font;
			component.text = value;
			component.fontSize = size;
			component.alignment = (TextAnchor)3;
			((Graphic)component).color = Color.white;
			((Graphic)component).raycastTarget = false;
			return component;
		}

		private Button Button(Transform parent, string label, float x, float y, float w, float h, Action action)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			Image val = Surface(parent, label, x, y, w, h);
			Button val2 = ((Component)val).gameObject.AddComponent<Button>();
			((Selectable)val2).targetGraphic = (Graphic)(object)val;
			skin.Button(val2);
			((UnityEvent)val2.onClick).AddListener((UnityAction)delegate
			{
				action();
			});
			Text val3 = Label(((Component)val).transform, label, 0f, 0f, w, h, (label == "×") ? 12 : 15);
			val3.alignment = (TextAnchor)4;
			val3.horizontalOverflow = (HorizontalWrapMode)1;
			val3.verticalOverflow = (VerticalWrapMode)1;
			return val2;
		}

		private void Create(UIGame game)
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_00f4: 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_02b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_037e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b8: Expected O, but got Unknown
			//IL_048c: Unknown result type (might be due to invalid IL or missing references)
			//IL_06e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_063b: Unknown result type (might be due to invalid IL or missing references)
			font = game.controlPanelWindow.FONT_SAIRASB;
			skin = new NativeSkin();
			root = new GameObject("AIO Assembler", new Type[3]
			{
				typeof(RectTransform),
				typeof(Canvas),
				typeof(GraphicRaycaster)
			});
			Canvas component = root.GetComponent<Canvas>();
			component.renderMode = (RenderMode)0;
			component.sortingOrder = 32740;
			panel = ((Graphic)Surface(root.transform, "Window", Mathf.Max(0f, (float)(Screen.width - 985) / 2f), 88f, 985f, 506f)).rectTransform;
			Image component2 = ((Component)panel).GetComponent<Image>();
			((Graphic)component2).color = Color.clear;
			int childCount = ((Transform)panel).childCount;
			skin.Frame(game.storageWindow.windowTrans, panel);
			if (((Transform)panel).childCount == childCount)
			{
				((Graphic)component2).color = new Color(0.045f, 0.075f, 0.105f, 0.98f);
			}
			Image val = Surface((Transform)(object)panel, "Title bar", 25f, 27f, 935f, 35f);
			((Graphic)val).color = new Color(0.041f, 0.084f, 0.11f, 0.96f);
			((Component)val).gameObject.AddComponent<WindowDrag>().Window = panel;
			Label(((Component)val).transform, "AIO Assembler", 12f, 0f, 180f, 35f, 19);
			Button(((Component)val).transform, "Storage", 667f, 4f, 90f, 27f, delegate
			{
				showStorage = !showStorage;
			});
			Button(((Component)val).transform, "Clear Recipes", 767f, 4f, 122f, 27f, ClearAll);
			Button(((Component)val).transform, "×", 898f, 4f, 30f, 27f, delegate
			{
				game.ShutStorageWindow();
			});
			Image val2 = Surface((Transform)(object)panel, "Inventory backing", 25f, 71f, 935f, 371f);
			((Graphic)val2).color = new Color(0.32f, 0.58f, 0.65f, 0.32f);
			((Graphic)val2).raycastTarget = false;
			Image val3 = Surface((Transform)(object)panel, "Inventory inset", 26f, 72f, 933f, 369f);
			((Graphic)val3).color = new Color(0.038f, 0.078f, 0.1f, 0.91f);
			((Graphic)val3).raycastTarget = false;
			for (int num = 0; num < recipeLabels.Length; num++)
			{
				int slot = num;
				Image val4 = Surface((Transform)(object)panel, "Recipe", 35 + 185 * (num % 5), 81 + 97 * (num / 5), 175f, 87f);
				((Graphic)val4).color = new Color(0.13f, 0.25f, 0.29f, 0.82f);
				Button val5 = ((Component)val4).gameObject.AddComponent<Button>();
				((Selectable)val5).targetGraphic = (Graphic)(object)val4;
				((UnityEvent)val5.onClick).AddListener((UnityAction)delegate
				{
					Choose(slot);
				});
				((Component)val4).gameObject.AddComponent<RecipeInspect>().Inspect = delegate
				{
					Inspect(slot);
				};
				recipeLabels[num] = Label(((Component)val4).transform, "", 47f, 7f, 100f, 68f, 13);
				recipeIcons[num] = Surface(((Component)val4).transform, "Recipe icon", 8f, 20f, 32f, 32f);
				((Graphic)recipeIcons[num]).raycastTarget = false;
				progress[num] = Surface(((Component)val4).transform, "Progress", 8f, 75f, 159f, 4f);
				((Graphic)progress[num]).color = new Color(0.32f, 0.8f, 0.87f);
				((Graphic)progress[num]).raycastTarget = false;
				clear[num] = Button(((Component)val4).transform, "×", 148f, 6f, 21f, 21f, delegate
				{
					ClearSlot(slot);
				});
			}
			Label((Transform)(object)panel, "Inputs", 42f, 285f, 90f, 65f, 17);
			Label((Transform)(object)panel, "Outputs", 42f, 386f, 90f, 45f, 17);
			UIIncArrow val6 = FindArrowTemplate();
			for (int num2 = 0; num2 < items.Length; num2++)
			{
				int num3 = ((num2 < 20) ? (276 + 51 * (num2 / 10)) : 385);
				Image val7 = Surface((Transform)(object)panel, "Inventory slot", 137 + 82 * (num2 % 10), num3, 63f, 45f);
				items[num2] = Surface(((Component)val7).transform, "Item icon", 4f, 2f, 31f, 31f);
				((Graphic)items[num2]).raycastTarget = false;
				if ((Object)(object)val6 != (Object)null)
				{
					Image val8 = Surface(((Component)val7).transform, "Proliferation arrows", 58f, 3f, 23f, 13f);
					NativeSkin.Copy(val8, val6.arrowImage);
					val8.preserveAspect = true;
					((Graphic)val8).rectTransform.pivot = new Vector2(1f, 1f);
					((Graphic)val8).raycastTarget = false;
					UIIncArrow val9 = (arrows[num2] = ((Component)val8).gameObject.AddComponent<UIIncArrow>());
					val9.arrowImage = val8;
					val9.arrowArray = val6.arrowArray;
					val9.incLevel = 0;
					((Behaviour)val8).enabled = false;
				}
				counts[num2] = Label(((Component)val7).transform, "", 3f, 27f, 54f, 14f, 12);
				counts[num2].alignment = (TextAnchor)5;
				((Graphic)counts[num2]).color = new Color(0.5f, 0.95f, 1f);
				counts[num2].resizeTextForBestFit = true;
				counts[num2].resizeTextMinSize = 8;
				counts[num2].resizeTextMaxSize = 12;
			}
			footer = Label((Transform)(object)panel, "Click a recipe slot to choose a recipe. Right-click for details.", 29f, 448f, 624f, 37f, 15);
			powerLabel = Label((Transform)(object)panel, "", 840f, 448f, 117f, 37f, 15);
			powerLabel.alignment = (TextAnchor)5;
		}

		private static UIIncArrow FindArrowTemplate()
		{
			UIIncArrow[] array = Resources.FindObjectsOfTypeAll<UIIncArrow>();
			foreach (UIIncArrow val in array)
			{
				if ((Object)(object)val.arrowImage != (Object)null && val.arrowArray != null && val.arrowArray.Length > 1 && (Object)(object)val.arrowArray[1] != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		private void Choose(int slot)
		{
			//IL_0031: 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)
			AssemblyLine selected = line;
			pickingRecipe = true;
			UIRecipePicker.Popup(new Vector2(0f, 0f), (Action<RecipeProto>)delegate(RecipeProto recipe)
			{
				pickingRecipe = false;
				if (recipe != null && selected == line && GameMain.history.RecipeUnlocked(((Proto)recipe).ID))
				{
					BatchRecipe batchRecipe = Plugin.ResolveRecipe(((Proto)recipe).ID);
					if (batchRecipe != null)
					{
						BatchRecipe recipe2 = selected.Recipe(slot);
						if (selected.RecipeId(slot) != ((Proto)recipe).ID)
						{
							selected.SetRecipe(slot, ((Proto)recipe).ID, batchRecipe, Plugin.ResolveDuration(((Proto)recipe).ID));
							ReturnSlotItems(recipe2);
						}
						footer.text = "Inputs show stock / delivery target (" + 9 + " batches per recipe).";
						nextRefresh = 0f;
					}
					else
					{
						footer.text = "AIO Assembler cannot run this recipe: " + ((Proto)recipe).name;
					}
				}
			}, RecipePickerFilter.Filter);
		}

		private void Inspect(int slot)
		{
			RecipeProto val = ((ProtoSet<RecipeProto>)(object)LDB.recipes).Select(line.RecipeId(slot));
			footer.text = ((val == null) ? "This slot is empty." : (((Proto)val).name + "  |  " + line.Progress(slot).ToString("P0") + " complete" + (line.HasPower ? ("  |  " + line.CycleSeconds(slot).ToString("0.##") + " s per batch at current power") : "")));
		}

		private void ClearAll()
		{
			if (confirmClear && line != null)
			{
				HashSet<int> hashSet = new HashSet<int>(line.LogisticsItems());
				hashSet.UnionWith(line.Ingredients.Items);
				line.ClearRecipes();
				Plugin.ReturnUnusedItems(line, selectedStorage, hashSet);
				nextRefresh = 0f;
			}
			confirmClear = !confirmClear;
			footer.text = (confirmClear ? "Click Clear Recipes again to confirm." : "All recipes cleared.");
		}

		private void ClearSlot(int slot)
		{
			if (line != null && line.Recipe(slot) != null)
			{
				BatchRecipe recipe = line.Recipe(slot);
				line.ClearRecipe(slot);
				ReturnSlotItems(recipe);
				footer.text = "Recipe cleared. Items shared with other recipes stay in storage.";
				nextRefresh = 0f;
			}
		}

		private void ReturnSlotItems(BatchRecipe recipe)
		{
			if (recipe != null)
			{
				List<int> list = new List<int>(recipe.Changes.Length);
				BatchRecipe.IngredientChange[] changes = recipe.Changes;
				for (int i = 0; i < changes.Length; i++)
				{
					BatchRecipe.IngredientChange ingredientChange = changes[i];
					list.Add(ingredientChange.Item);
				}
				Plugin.ReturnUnusedItems(line, selectedStorage, list);
			}
		}

		internal void Update()
		{
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			UIRoot instance = UIRoot.instance;
			UIGame val = (((Object)(object)instance == (Object)null) ? null : instance.uiGame);
			UIStorageWindow val2 = (((Object)(object)val == (Object)null) ? null : val.storageWindow);
			PlanetFactory val3 = (((Object)(object)val2 == (Object)null) ? null : val2.factory);
			StorageComponent[] array = val3?.factoryStorage.storagePool;
			StorageComponent storage = (((Object)(object)val2 != (Object)null && ((ManualBehaviour)val2).active && array != null && val2.storageId > 0 && val2.storageId < array.Length) ? array[val2.storageId] : null);
			AssemblyLine assemblyLine = plugin.Open(val3, storage);
			if (assemblyLine == null)
			{
				RestoreNative();
				RestoreStoragePosition();
				if (pickingRecipe)
				{
					UIRecipePicker.Close();
				}
				if ((Object)(object)root != (Object)null)
				{
					root.SetActive(false);
				}
				line = null;
				selectedStorage = null;
				return;
			}
			if ((Object)(object)root == (Object)null)
			{
				Create(val);
			}
			selectedStorage = storage;
			if (line != assemblyLine)
			{
				line = assemblyLine;
				showStorage = false;
				confirmClear = false;
				nextRefresh = 0f;
			}
			root.SetActive(true);
			if (showStorage)
			{
				RestoreNative();
				if ((Object)(object)dockedStorage != (Object)(object)val2.windowTrans)
				{
					RestoreStoragePosition();
					dockedStorage = val2.windowTrans;
					storagePosition = dockedStorage.anchoredPosition;
				}
				Dock(dockedStorage, right: false);
			}
			else
			{
				RestoreStoragePosition();
				HideNative(val2.windowTrans);
			}
			if (pickingRecipe && UIRecipePicker.isOpened)
			{
				Dock(val.recipePicker.pickerTrans, right: true);
			}
			if (!(Time.unscaledTime < nextRefresh))
			{
				nextRefresh = Time.unscaledTime + 0.12f;
				Refresh(storage);
			}
		}

		private void Dock(RectTransform window, bool right)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: 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_015e: 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_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)window == (Object)null)
			{
				return;
			}
			Transform parent = ((Transform)window).parent;
			RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
			if (!((Object)(object)val == (Object)null))
			{
				Canvas componentInParent = ((Component)window).GetComponentInParent<Canvas>();
				Camera val2 = (((Object)(object)componentInParent != (Object)null && (int)componentInParent.renderMode != 0) ? componentInParent.worldCamera : null);
				panel.GetWorldCorners(corners);
				Vector2 val3 = RectTransformUtility.WorldToScreenPoint((Camera)null, corners[(!right) ? 1 : 2]);
				window.GetWorldCorners(corners);
				Vector2 val4 = RectTransformUtility.WorldToScreenPoint(val2, corners[1]);
				Vector2 val5 = RectTransformUtility.WorldToScreenPoint(val2, corners[2]);
				Vector2 val6 = RectTransformUtility.WorldToScreenPoint(val2, corners[0]);
				float num = Mathf.Abs(val5.x - val4.x);
				float num2 = Mathf.Abs(val4.y - val6.y);
				float num3 = (right ? (val3.x + 6f) : (val3.x - 6f - num));
				Vector2 val7 = default(Vector2);
				((Vector2)(ref val7))..ctor(Mathf.Clamp(num3, 0f, Mathf.Max(0f, (float)Screen.width - num)), Mathf.Clamp(val3.y, Mathf.Min(num2, (float)Screen.height), (float)Screen.height));
				Vector2 val8 = default(Vector2);
				Vector2 val9 = default(Vector2);
				if (RectTransformUtility.ScreenPointToLocalPointInRectangle(val, val4, val2, ref val8) && RectTransformUtility.ScreenPointToLocalPointInRectangle(val, val7, val2, ref val9))
				{
					window.anchoredPosition += val9 - val8;
				}
			}
		}

		private void RestoreStoragePosition()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)dockedStorage == (Object)null))
			{
				dockedStorage.anchoredPosition = storagePosition;
				dockedStorage = null;
			}
		}

		private void HideNative(RectTransform window)
		{
			if (!((Object)(object)native != (Object)null))
			{
				native = ((Component)window).GetComponent<CanvasGroup>();
				if ((Object)(object)native == (Object)null)
				{
					native = ((Component)window).gameObject.AddComponent<CanvasGroup>();
				}
				savedAlpha = native.alpha;
				savedRaycasts = native.blocksRaycasts;
				native.alpha = 0f;
				native.blocksRaycasts = false;
			}
		}

		private void RestoreNative()
		{
			if (!((Object)(object)native == (Object)null))
			{
				native.alpha = savedAlpha;
				native.blocksRaycasts = savedRaycasts;
				native = null;
			}
		}

		private void Refresh(StorageComponent storage)
		{
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0327: Unknown result type (might be due to invalid IL or missing references)
			powerLabel.text = "Grid power " + line.PowerServed.ToString("P0");
			inputs.Clear();
			outputs.Clear();
			for (int i = 0; i < recipeLabels.Length; i++)
			{
				RecipeProto val = ((ProtoSet<RecipeProto>)(object)LDB.recipes).Select(line.RecipeId(i));
				BatchRecipe batchRecipe = line.Recipe(i);
				int num = line.BatchMultiplier(i);
				string text = ((batchRecipe == null) ? "" : ((!line.HasPower) ? "No power" : ((!NativeStorage.HasInputs(line.Ingredients, batchRecipe, num)) ? "Needs inputs" : (line.WaitingForSpace(i) ? "Output full" : (line.Progress(i).ToString("P0") + " · " + num + "x")))));
				recipeLabels[i].text = "Slot " + (i + 1) + "\n" + ((val == null) ? "Empty" : (((Proto)val).name + "\n" + text));
				recipeIcons[i].sprite = ((val == null) ? null : val.iconSprite);
				((Behaviour)recipeIcons[i]).enabled = val != null;
				((Graphic)recipeIcons[i]).color = Color.white;
				((Selectable)clear[i]).interactable = val != null;
				((Graphic)progress[i]).rectTransform.sizeDelta = new Vector2(159f * line.Progress(i), 4f);
				if (batchRecipe == null)
				{
					continue;
				}
				BatchRecipe.IngredientChange[] changes = batchRecipe.Changes;
				for (int j = 0; j < changes.Length; j++)
				{
					BatchRecipe.IngredientChange ingredientChange = changes[j];
					if (ingredientChange.Input > 0 && !inputs.Contains(ingredientChange.Item))
					{
						inputs.Add(ingredientChange.Item);
					}
					if (ingredientChange.Output > 0 && !outputs.Contains(ingredientChange.Item))
					{
						outputs.Add(ingredientChange.Item);
					}
				}
			}
			for (int k = 0; k < items.Length; k++)
			{
				bool flag = k < 20;
				List<int> list = (flag ? inputs : outputs);
				int num2 = (flag ? k : (k - 20));
				ItemProto val2 = ((num2 < list.Count) ? ((ProtoSet<ItemProto>)(object)LDB.items).Select(list[num2]) : null);
				items[k].sprite = ((val2 == null) ? null : val2.iconSprite);
				((Behaviour)items[k]).enabled = val2 != null;
				((Graphic)items[k]).color = Color.white;
				if (val2 == null)
				{
					counts[k].text = "";
					SetArrows(k, 0);
					continue;
				}
				int num3;
				long points2;
				if (flag)
				{
					num3 = line.Ingredients.Read(((Proto)val2).ID, out var points);
					points2 = points;
				}
				else
				{
					num3 = NativeStorage.OutputStock(storage, ((Proto)val2).ID, out points2);
				}
				SetArrows(k, (int)((num3 > 0) ? Math.Max(0L, Math.Min(10L, points2 / num3)) : 0));
				line.LogisticsRule(((Proto)val2).ID, out var reserve, out var _);
				counts[k].text = (flag ? (num3 + "/" + reserve) : num3.ToString());
			}
		}

		private void SetArrows(int index, int level)
		{
			UIIncArrow val = arrows[index];
			if (!((Object)(object)val == (Object)null) && val.incLevel != level)
			{
				val.incLevel = level;
				if (level == 0)
				{
					((Behaviour)val.arrowImage).enabled = false;
				}
			}
		}

		public void Dispose()
		{
			RestoreNative();
			RestoreStoragePosition();
			if ((Object)(object)root != (Object)null)
			{
				Object.Destroy((Object)(object)root);
			}
		}
	}
	internal sealed class RecipeInspect : MonoBehaviour, IPointerClickHandler, IEventSystemHandler
	{
		internal Action Inspect;

		public void OnPointerClick(PointerEventData e)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)e.button == 1 && Inspect != null)
			{
				Inspect();
			}
		}
	}
	internal sealed class WindowDrag : MonoBehaviour, IDragHandler, IEventSystemHandler
	{
		internal RectTransform Window;

		public void OnDrag(PointerEventData e)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			Vector2 anchoredPosition = Window.anchoredPosition + e.delta;
			float x = anchoredPosition.x;
			float num = Screen.width;
			Rect rect = Window.rect;
			anchoredPosition.x = Mathf.Clamp(x, 0f, Mathf.Max(0f, num - ((Rect)(ref rect)).width));
			float y = anchoredPosition.y;
			Rect rect2 = Window.rect;
			anchoredPosition.y = Mathf.Clamp(y, Mathf.Min(0f, ((Rect)(ref rect2)).height - (float)Screen.height), 0f);
			Window.anchoredPosition = anchoredPosition;
		}
	}
	internal sealed class IngredientBuffer
	{
		private struct Stack
		{
			public int Count;

			public int Points;
		}

		private readonly Dictionary<int, Stack> items = new Dictionary<int, Stack>();

		internal IEnumerable<int> Items => items.Keys;

		internal int Read(int item, out int points)
		{
			items.TryGetValue(item, out var value);
			points = value.Points;
			return value.Count;
		}

		internal int Count(int item)
		{
			int points;
			return Read(item, out points);
		}

		internal void Set(int item, int count, int points)
		{
			if (count == 0)
			{
				items.Remove(item);
				return;
			}
			items[item] = new Stack
			{
				Count = count,
				Points = points
			};
		}

		internal int PointsFor(int item, int count)
		{
			int points;
			int num = Read(item, out points);
			if (num != 0)
			{
				return points / num * count + Math.Max(0, points % num - (num - count));
			}
			return 0;
		}

		internal void Consume(int item, int count)
		{
			Stack stack = items[item];
			Set(item, stack.Count - count, stack.Points - PointsFor(item, count));
		}

		internal void Write(BinaryWriter writer)
		{
			writer.Write(items.Count);
			foreach (KeyValuePair<int, Stack> item in items)
			{
				writer.Write(item.Key);
				writer.Write(item.Value.Count);
				writer.Write(item.Value.Points);
			}
		}

		internal void Read(BinaryReader reader)
		{
			int num = reader.ReadInt32();
			if (num < 0 || num > 65536)
			{
				throw new InvalidDataException("Invalid AIO ingredient buffer size.");
			}
			for (int i = 0; i < num; i++)
			{
				int num2 = reader.ReadInt32();
				int num3 = reader.ReadInt32();
				int num4 = reader.ReadInt32();
				if (num2 <= 0 || num3 <= 0 || num4 < 0 || items.ContainsKey(num2))
				{
					throw new InvalidDataException("Invalid AIO ingredient buffer entry.");
				}
				Set(num2, num3, num4);
			}
		}
	}
	internal sealed class NativeStorage
	{
		private StorageComponent scratch;

		internal static int OutputStock(StorageComponent storage, int item, out long points)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			long num = 0L;
			points = 0L;
			for (int i = 0; i < storage.size; i++)
			{
				GRID val = storage.grids[i];
				if (val.itemId == item && val.count > 0)
				{
					num += val.count;
					points += val.inc;
				}
			}
			return (int)Math.Min(2147483647L, num);
		}

		internal static void RefillFromStorage(StorageComponent storage, AssemblyLine line)
		{
			IReadOnlyList<int> readOnlyList = line.LogisticsItems();
			int num5 = default(int);
			for (int i = 0; i < readOnlyList.Count; i++)
			{
				int num = readOnlyList[i];
				line.LogisticsRule(num, out var reserve, out var _);
				if (reserve <= 0)
				{
					continue;
				}
				int points;
				int num2 = line.Ingredients.Read(num, out points);
				int val = reserve - num2;
				int num3 = Math.Min(val, Math.Min(storage.GetItemCount(num), (int.MaxValue - points) / 10));
				if (num3 > 0)
				{
					int num4 = storage.TakeItem(num, num3, ref num5);
					if (num4 > 0)
					{
						line.Ingredients.Set(num, num2 + num4, points + num5);
					}
				}
			}
		}

		internal static float SpeedForBatch(IngredientBuffer buffer, BatchRecipe recipe, int multiplier)
		{
			if (!recipe.SpeedupOnly || Cargo.accTableMilli == null || Cargo.accTableMilli.Length == 0)
			{
				return 1f;
			}
			int num = Math.Min(10, Cargo.accTableMilli.Length - 1);
			bool flag = false;
			BatchRecipe.IngredientChange[] changes = recipe.Changes;
			for (int i = 0; i < changes.Length; i++)
			{
				BatchRecipe.IngredientChange ingredientChange = changes[i];
				if (ingredientChange.Input > 0)
				{
					long num2 = (long)ingredientChange.Input * (long)multiplier;
					if (num2 > buffer.Count(ingredientChange.Item))
					{
						return 1f;
					}
					flag = true;
					num = Math.Min(num, buffer.PointsFor(ingredientChange.Item, (int)num2) / (int)num2);
					if (num <= 0)
					{
						return 1f;
					}
				}
			}
			if (!flag)
			{
				return 1f;
			}
			return 1f + (float)Cargo.accTableMilli[num];
		}

		internal static bool HasInputs(IngredientBuffer buffer, BatchRecipe recipe, int multiplier)
		{
			BatchRecipe.IngredientChange[] changes = recipe.Changes;
			for (int i = 0; i < changes.Length; i++)
			{
				BatchRecipe.IngredientChange ingredientChange = changes[i];
				if (ingredientChange.Input > 0 && buffer.Count(ingredientChange.Item) < (long)ingredientChange.Input * (long)multiplier)
				{
					return false;
				}
			}
			return true;
		}

		public bool TryComplete(StorageComponent storage, BatchRecipe recipe, int multiplier, AssemblyLine line)
		{
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Expected O, but got Unknown
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			if (multiplier < 1 || multiplier > 1000)
			{
				throw new ArgumentOutOfRangeException("multiplier");
			}
			if (storage == null || storage.size <= 0 || storage.grids == null || storage.grids.Length < storage.size)
			{
				return false;
			}
			IngredientBuffer ingredients = line.Ingredients;
			BatchRecipe.IngredientChange[] changes = recipe.Changes;
			for (int i = 0; i < changes.Length; i++)
			{
				BatchRecipe.IngredientChange ingredientChange = changes[i];
				if (StorageComponent.itemStackCount == null || ingredientChange.Item >= StorageComponent.itemStackCount.Length || (long)ingredientChange.Input * (long)multiplier > int.MaxValue || (long)ingredientChange.Output * (long)multiplier > int.MaxValue || (ingredientChange.Input > 0 && ingredients.Count(ingredientChange.Item) < ingredientChange.Input * multiplier))
				{
					return false;
				}
			}
			if (scratch == null || scratch.size != storage.size)
			{
				scratch = new StorageComponent(storage.size);
			}
			scratch.type = storage.type;
			scratch.bans = storage.bans;
			Array.Copy(storage.grids, scratch.grids, storage.size);
			BatchRecipe.IngredientChange[] changes2 = recipe.Changes;
			int num2 = default(int);
			for (int j = 0; j < changes2.Length; j++)
			{
				BatchRecipe.IngredientChange ingredientChange2 = changes2[j];
				int num = ingredientChange2.Output * multiplier;
				if (num <= 0)
				{
					continue;
				}
				if (scratch.AddItem(ingredientChange2.Item, num, 0, ref num2, false) != num)
				{
					return false;
				}
				int num3 = 0;
				for (int k = 0; k < scratch.size; k++)
				{
					if (scratch.grids[k].itemId == ingredientChange2.Item && scratch.grids[k].count > 0 && ++num3 > 8)
					{
						return false;
					}
				}
			}
			BatchRecipe.IngredientChange[] changes3 = recipe.Changes;
			for (int l = 0; l < changes3.Length; l++)
			{
				BatchRecipe.IngredientChange ingredientChange3 = changes3[l];
				if (ingredientChange3.Input > 0)
				{
					ingredients.Consume(ingredientChange3.Item, ingredientChange3.Input * multiplier);
				}
			}
			Array.Copy(scratch.grids, storage.grids, storage.size);
			storage.searchStart = 0;
			storage.lastEmptyItem = (storage.lastFullItem = -1);
			storage.NotifyStorageChange();
			return true;
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInIncompatibility("org.xcm.dsp.molecularhub")]
	[CommonAPISubmoduleDependency(new string[] { "ProtoRegistry", "LocalizationModule" })]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("LokiMoonLabs.AIOAssembler", "AIO Assembler", "0.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin, IModCanSave
	{
		[HarmonyPatch(typeof(GameLogic), "OnFactoryFrameEnd")]
		private static class FactoryEnd
		{
			private static void Postfix(GameLogic __instance)
			{
				if ((Object)(object)instance != (Object)null && (Object)(object)__instance.main != (Object)null && !__instance.main.isMenuDemo)
				{
					instance.Tick(__instance.data);
				}
			}
		}

		[HarmonyPatch(typeof(PlanetFactory), "RemoveEntityWithComponents")]
		private static class RemoveEntity
		{
			private static void Prefix(PlanetFactory __instance, int __0)
			{
				if ((Object)(object)instance == (Object)null || GameMain.mainPlayer == null || __0 <= 0 || __0 >= __instance.entityPool.Length)
				{
					return;
				}
				StorageComponent[] storagePool = __instance.factoryStorage.storagePool;
				int storageId = __instance.entityPool[__0].storageId;
				if (storageId <= 0 || storageId >= storagePool.Length)
				{
					return;
				}
				AssemblyLine assemblyLine = FindLogisticsLine(__instance, storagePool[storageId]);
				if (assemblyLine == null)
				{
					return;
				}
				foreach (int item in new List<int>(assemblyLine.Ingredients.Items))
				{
					ReturnBufferedItem(assemblyLine, GameMain.mainPlayer, __0, item);
				}
			}

			private static void Postfix(PlanetFactory __instance, int __0)
			{
				if (!((Object)(object)instance == (Object)null))
				{
					long num = ((long)__instance.planetId << 32) | (uint)__0;
					if (instance.machines.Remove(num))
					{
						instance.keys.Remove(num);
					}
				}
			}
		}

		[HarmonyPatch(typeof(VFInput), "UpdateGameStates")]
		private static class InputGuard
		{
			[HarmonyPostfix]
			[HarmonyPriority(0)]
			private static void Postfix()
			{
				if (!((Object)(object)instance == (Object)null) && instance.panel != null && instance.panel.BlocksGamePointer)
				{
					VFInput.onGUI = true;
					VFInput.onGUIOperate = true;
					VFInput.inScrollView = true;
				}
			}
		}

		public const string Id = "LokiMoonLabs.AIOAssembler";

		private const int ItemId = 2907;

		private const int RecipeId = 1789;

		private const int TechId = 1989;

		private const int StorageColumns = 10;

		private const int StorageRows = 10;

		private static Plugin instance;

		private readonly Dictionary<long, AssemblyLine> machines = new Dictionary<long, AssemblyLine>();

		private readonly List<long> keys = new List<long>();

		private readonly NativeStorage transfer = new NativeStorage();

		private Harmony harmony;

		private ItemProto item;

		private ModelProto buildingModel;

		private ModelProto templateModel;

		private HubPanel panel;

		private StorageComponent currentStorage;

		private AssemblyLine currentLine;

		private Func<BatchRecipe, int, bool> complete;

		private Func<BatchRecipe, int, bool> hasInputs;

		private Func<BatchRecipe, int, float> batchSpeed;

		private float machineSpeed = 1f;

		private Func<ERecipeType, int> overclock;

		private void Awake()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			if (Chainloader.PluginInfos.ContainsKey("dsp.nebula-multiplayer"))
			{
				return;
			}
			harmony = new Harmony("LokiMoonLabs.AIOAssembler");
			using (ProtoRegistry.StartModLoad("LokiMoonLabs.AIOAssembler"))
			{
				RegisterBuilding();
			}
			if (item == null)
			{
				return;
			}
			ProtoRegistry.onLoadingFinished += ConfigurePower;
			complete = (BatchRecipe recipe, int multiplier) => transfer.TryComplete(currentStorage, recipe, multiplier, currentLine);
			hasInputs = (BatchRecipe recipe, int multiplier) => NativeStorage.HasInputs(currentLine.Ingredients, recipe, multiplier);
			batchSpeed = (BatchRecipe recipe, int multiplier) => NativeStorage.SpeedForBatch(currentLine.Ingredients, recipe, multiplier);
			instance = this;
			harmony.CreateClassProcessor(typeof(FactoryEnd)).Patch();
			harmony.CreateClassProcessor(typeof(RemoveEntity)).Patch();
			harmony.CreateClassProcessor(typeof(InputGuard)).Patch();
			harmony.CreateClassProcessor(typeof(RecipePickerFilter)).Patch();
			if (!RecipePickerFilter.Installed)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"AIO could not extend the native recipe picker. Existing smelting recipes can still run.");
			}
			panel = new HubPanel(this);
			if (Chainloader.PluginInfos.TryGetValue("LokiMoonLabs.FastNFurious", out var value) && (Object)(object)value.Instance != (Object)null)
			{
				Type type = ((object)value.Instance).GetType().Assembly.GetType("LokiMoonLabs.FastNFurious.PluginConfig");
				MethodInfo methodInfo = ((type == null) ? null : type.GetMethod("GetMultiplierByRecipe", new Type[1] { typeof(ERecipeType) }));
				if (methodInfo != null && methodInfo.IsStatic && methodInfo.ReturnType == typeof(int))
				{
					overclock = (Func<ERecipeType, int>)Delegate.CreateDelegate(typeof(Func<ERecipeType, int>), methodInfo);
				}
			}
			if (!Chainloader.PluginInfos.TryGetValue("LokiMoonLabs.HoneyIShrunkTheFactory", out var value2) || !((Object)(object)value2.Instance != (Object)null))
			{
				return;
			}
			MethodInfo method = ((object)value2.Instance).GetType().GetMethod("RegisterExternalPanel");
			if (method != null)
			{
				method.Invoke(null, new object[3]
				{
					(Func<RectTransform>)(() => panel.MultiplierAnchor),
					(Func<int>)(() => panel.Multiplier),
					new Action<int>(panel.SetMultiplier)
				});
			}
		}

		private void RegisterBuilding()
		{
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_031d: 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)
			//IL_0338: Unknown result type (might be due to invalid IL or missing references)
			//IL_0449: Unknown result type (might be due to invalid IL or missing references)
			//IL_0458: Unknown result type (might be due to invalid IL or missing references)
			//IL_045d: Unknown result type (might be due to invalid IL or missing references)
			ModelProto val = ((ProtoSet<ModelProto>)(object)LDB.models).Select(456);
			TechProto val2 = ((ProtoSet<TechProto>)(object)LDB.techs).Select(1124);
			int num = ((ProtoSet<ModelProto>)(object)LDB.models).dataArray.Length + 64;
			HashSet<int> hashSet = OccupiedIds((IEnumerable<Proto>)(object)((ProtoSet<ModelProto>)(object)LDB.models).dataArray, typeof(ModelProto));
			int i;
			for (i = 669; i < num && hashSet.Contains(i); i++)
			{
			}
			if (i >= num)
			{
				i = num - 1;
				while (i > 52 && hashSet.Contains(i))
				{
					i--;
				}
			}
			i = ((BaseUnityPlugin)this).Config.Bind<int>("Registration", "ModelId", i, "Save identity for AIO Assembler. Keep this value after placing a building.").Value;
			bool flag = hashSet.Contains(i);
			int num2 = Reserve(2907, "ItemId", OccupiedIds((IEnumerable<Proto>)(object)((ProtoSet<ItemProto>)(object)LDB.items).dataArray, typeof(ItemProto)), 11999);
			int num3 = Reserve(1789, "RecipeId", OccupiedIds((IEnumerable<Proto>)(object)((ProtoSet<RecipeProto>)(object)LDB.recipes).dataArray, typeof(RecipeProto)), 9999);
			int num4 = Reserve(1989, "TechId", OccupiedIds((IEnumerable<Proto>)(object)((ProtoSet<TechProto>)(object)LDB.techs).dataArray, typeof(TechProto)), 9999);
			if (val == null || val2 == null || i <= 52 || i >= num || flag || num2 == 0 || num3 == 0 || num4 == 0)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("AIO registration blocked. Assembler model present=" + (val != null) + ", model ID=" + i + ", model limit=" + num + ", model occupied=" + flag + ", item=" + num2 + ", recipe=" + num3 + ", tech=" + num4 + ", Structure Matrix present=" + (val2 != null) + "."));
				return;
			}
			LocalizationModule.RegisterTranslation("AIOAssembler.Name", "AIO Assembler");
			LocalizationModule.RegisterTranslation("AIOAssembler.Description", "Runs up to eight recipes using shared storage.");
			LocalizationModule.RegisterTranslation("AIOAssembler.Unlock", "Unlocks the AIO Assembler.");
			templateModel = val;
			ModelProto val3 = (buildingModel = ProtoRegistry.RegisterModel(i, val.PrefabPath, (Material[])null, 0));
			val3.HpMax = val.HpMax;
			val3.HpRecover = val.HpRecover;
			val3.HpUpgrade = val.HpUpgrade;
			val3.RendererType = val.RendererType;
			val3.ObjectType = val.ObjectType;
			val3.RotSymmetry = val.RotSymmetry;
			val3.Order = val.Order;
			item = ProtoRegistry.RegisterItem(num2, "AIOAssembler.Name", "AIOAssembler.Description", "Icons/ItemRecipe/assembler-4", ProtoRegistry.GetGridIndex(2, 14, 1), 50, (EItemType)6, ProtoRegistry.GetDefaultIconDesc(Color32.op_Implicit(new Color32((byte)11, (byte)140, (byte)122, byte.MaxValue)), Color32.op_Implicit(new Color32((byte)236, (byte)189, (byte)52, byte.MaxValue))));
			ProtoRegistry.AddModelToItemProto(val3, item, new int[1] { 1 }, 810);
			RecipeProto val4 = ProtoRegistry.RegisterRecipe(num3, (ERecipeType)4, 480, new int[3] { 2304, 1303, 2013 }, new int[3] { 8, 16, 20 }, new int[1] { ((Proto)item).ID }, new int[1] { 1 }, "AIOAssembler.Description", 0, item.GridIndex, "AIOAssembler.Name", "Icons/ItemRecipe/assembler-4");
			ProtoRegistry.RegisterTech(num4, "AIOAssembler.Name", "AIOAssembler.Description", "AIOAssembler.Unlock", "Icons/ItemRecipe/assembler-4", new int[1] { ((Proto)val2).ID }, new int[1] { 6003 }, new int[1] { 1 }, 12000L, new int[1] { ((Proto)val4).ID }, val2.Position + new Vector2(8f, -8f));
			((BaseUnityPlugin)this).Logger.LogInfo((object)("AIO IDs: item " + ((Proto)item).ID + ", model " + ((Proto)val3).ID + ", recipe " + ((Proto)val4).ID + ", tech " + num4));
		}

		private int Reserve(int preferred, string key, HashSet<int> occupied, int limit)
		{
			while (preferred <= limit && occupied.Contains(preferred))
			{
				preferred++;
			}
			ConfigEntry<int> val = ((BaseUnityPlugin)this).Config.Bind<int>("Registration", key, preferred, "Save identity for AIO Assembler. Keep this value after placing a building.");
			if (key == "ItemId" && val.Value == 12000 && preferred <= limit)
			{
				val.Value = preferred;
			}
			int value = val.Value;
			if (value <= 0 || value > limit || occupied.Contains(value))
			{
				return 0;
			}
			return value;
		}

		private static HashSet<int> OccupiedIds(IEnumerable<Proto> current, Type type)
		{
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Expected O, but got Unknown
			HashSet<int> hashSet = new HashSet<int>();
			foreach (Proto item in current)
			{
				if (item != null)
				{
					hashSet.Add(item.ID);
				}
			}
			Type type2 = AccessTools.TypeByName("xiaoye97.LDBTool");
			if (type2 == null)
			{
				return hashSet;
			}
			string[] array = new string[3] { "PreToAdd", "PostToAdd", "TotalDict" };
			foreach (string text in array)
			{
				FieldInfo fieldInfo = AccessTools.Field(type2, text);
				IEnumerable enumerable = ((fieldInfo == null) ? null : (fieldInfo.GetValue(null) as IEnumerable));
				if (enumerable == null)
				{
					continue;
				}
				foreach (IEnumerable item2 in enumerable)
				{
					foreach (Proto item3 in item2)
					{
						Proto val = item3;
						if (val != null && ((object)val).GetType() == type)
						{
							hashSet.Add(val.ID);
						}
					}
				}
			}
			return hashSet;
		}

		private void ConfigurePower()
		{
			PrefabDesc prefabDesc = buildingModel.prefabDesc;
			if (prefabDesc == null || object.ReferenceEquals(prefabDesc, templateModel.prefabDesc))
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"AIO Assembler could not initialize its independent power descriptor.");
				return;
			}
			prefabDesc.isAssembler = false;
			machineSpeed = Mathf.Max(1f, (float)prefabDesc.assemblerSpeed / 10000f);
			prefabDesc.isStorage = true;
			prefabDesc.storageCol = 10;
			prefabDesc.storageRow = 10;
			prefabDesc.isPowerConsumer = true;
			prefabDesc.workEnergyPerTick = 9000L;
			prefabDesc.idleEnergyPerTick = 300L;
			prefabDesc.multiLevel = false;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"AIO Assembler registered with native storage and power.");
		}

		internal AssemblyLine Select(PlanetFactory factory, StorageComponent storage)
		{
			if (!IsHub(factory, storage))
			{
				return null;
			}
			long key = ((long)factory.planetId << 32) | (uint)storage.entityId;
			if (!machines.TryGetValue(key, out var value))
			{
				value = new AssemblyLine();
				machines.Add(key, value);
			}
			return value;
		}

		public static IReadOnlyList<int> GetLogisticsItems(PlanetFactory factory, StorageComponent storage)
		{
			return FindLogisticsLine(factory, storage)?.LogisticsItems();
		}

		public static bool GetLogisticsRule(PlanetFactory factory, StorageComponent storage, int item, out int reserve, out bool output)
		{
			if (!GetIngredientLogisticsRule(factory, storage, item, out reserve, out output))
			{
				return false;
			}
			reserve = Math.Max(0, reserve - ReadIngredientBuffer(factory, storage, item, out var _));
			if (reserve <= 0)
			{
				return output;
			}
			return true;
		}

		public static bool GetIngredientLogisticsRule(PlanetFactory factory, StorageComponent storage, int item, out int reserve, out bool output)
		{
			reserve = 0;
			output = false;
			return FindLogisticsLine(factory, storage)?.LogisticsRule(item, out reserve, out output) ?? false;
		}

		public static int ReadIngredientBuffer(PlanetFactory factory, StorageComponent storage, int item, out int points)
		{
			AssemblyLine assemblyLine = FindLogisticsLine(factory, storage);
			points = 0;
			return assemblyLine?.Ingredients.Read(item, out points) ?? 0;
		}

		public static void WriteIngredientBuffer(PlanetFactory factory, StorageComponent storage, int item, int count, int points)
		{
			FindLogisticsLine(factory, storage)?.Ingredients.Set(item, count, points);
		}

		private static AssemblyLine FindLogisticsLine(PlanetFactory factory, StorageComponent storage)
		{
			if ((Object)(object)instance == (Object)null || !instance.IsHub(factory, storage))
			{
				return null;
			}
			instance.machines.TryGetValue(((long)factory.planetId << 32) | (uint)storage.entityId, out var value);
			return value;
		}

		private bool IsHub(PlanetFactory factory, StorageComponent storage)
		{
			if (factory != null && storage != null && storage.entityId > 0 && storage.entityId < factory.entityPool.Length && factory.entityPool[storage.entityId].id == storage.entityId && factory.entityPool[storage.entityId].protoId == ((Proto)item).ID)
			{
				return factory.entityPool[storage.entityId].storageId == storage.id;
			}
			return false;
		}

		internal static BatchRecipe ResolveRecipe(int id)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Invalid comparison between Unknown and I4
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			RecipeProto val = ((ProtoSet<RecipeProto>)(object)LDB.recipes).Select(id);
			if (val == null || ((int)val.Type != 4 && (int)val.Type != 1) || ResolveDuration(id) <= 0)
			{
				return null;
			}
			try
			{
				if (RecipeProto.recipeExecuteData != null && RecipeProto.recipeExecuteData.TryGetValue(id, out var value) && value != null)
				{
					return new BatchRecipe(value.requires, value.requireCounts, value.products, value.productCounts, !value.productive, val.Type);
				}
				return new BatchRecipe(val.Items, val.ItemCounts, val.Results, val.ResultCounts, !val.productive, val.Type);
			}
			catch (ArgumentException)
			{
				return null;
			}
			catch (OverflowException)
			{
				return null;
			}
		}

		internal static int ResolveDuration(int id)
		{
			RecipeProto val = ((ProtoSet<RecipeProto>)(object)LDB.recipes).Select(id);
			if (val == null)
			{
				return 0;
			}
			if (RecipeProto.recipeExecuteData != null && RecipeProto.recipeExecuteData.TryGetValue(id, out var value) && value != null)
			{
				return BatchRecipe.DurationInTicks(value.timeSpend, val.TimeSpend);
			}
			return val.TimeSpend;
		}

		private void Tick(GameData data)
		{
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			if (data == null || machines.Count == 0)
			{
				return;
			}
			int num = ((overclock == null) ? 1 : Mathf.Clamp(overclock((ERecipeType)4), 1, 20));
			int num2 = ((overclock == null) ? 1 : Mathf.Clamp(overclock((ERecipeType)1), 1, 20));
			foreach (long key in keys)
			{
				int num3 = (int)(key >> 32);
				int num4 = (int)key;
				PlanetFactory val = data.galaxy.PlanetById(num3)?.factory;
				if (val == null || num4 <= 0 || num4 >= val.entityPool.Length)
				{
					continue;
				}
				int storageId = val.entityPool[num4].storageId;
				StorageComponent[] storagePool = val.factoryStorage.storagePool;
				if (storageId > 0 && storageId < storagePool.Length && IsHub(val, storagePool[storageId]))
				{
					AssemblyLine assemblyLine = (currentLine = machines[key]);
					currentStorage = storagePool[storageId];
					if (currentStorage.size < 100)
					{
						currentStorage.SetSize(100);
					}
					NativeStorage.RefillFromStorage(currentStorage, assemblyLine);
					int powerConId = val.entityPool[num4].powerConId;
					PowerSystem powerSystem = val.powerSystem;
					if (powerConId <= 0 || powerConId >= powerSystem.consumerPool.Length)
					{
						assemblyLine.PowerServed = 0f;
						assemblyLine.AdvancePowered(0f, hasInputs, complete);
						Animate(val, num4, 0f, working: false);
						continue;
					}
					PowerConsumerComponent val2 = powerSystem.consumerPool[powerConId];
					int configuredSlots = assemblyLine.ConfiguredSlots;
					int networkId = val2.networkId;
					float num5 = (assemblyLine.PowerServed = ((configuredSlots > 0 && networkId > 0 && networkId < powerSystem.networkServes.Length) ? powerSystem.networkServes[networkId] : 0f));
					float num7 = ((num5 < 0.1f) ? 0f : (machineSpeed * num5));
					assemblyLine.AdvancePowered(num7 * (float)num, hasInputs, complete, batchSpeed, num7 * (float)num2);
					long num8 = assemblyLine.WorkingMachines(hasInputs);
					powerSystem.consumerPool[powerConId].requiredEnergy = ((num8 == 0) ? val2.idleEnergyPerTick : (val2.workEnergyPerTick * num8));
					Animate(val, num4, num5, assemblyLine.HasPower && num8 > 0);
				}
			}
			currentStorage = null;
			currentLine = null;
		}

		private void Animate(PlanetFactory factory, int entity, float power, bool working)
		{
			AnimData[] entityAnimPool = factory.entityAnimPool;
			if (entityAnimPool != null && entity < entityAnimPool.Length)
			{
				PrefabDesc prefabDesc = buildingModel.prefabDesc;
				entityAnimPool[entity].prepare_length = prefabDesc.anim_prepare_length;
				entityAnimPool[entity].working_length = prefabDesc.anim_working_length;
				((AnimData)(ref entityAnimPool[entity])).Step(working ? 1u : 0u, power / 60f);
				entityAnimPool[entity].power = power;
			}
		}

		internal static void ReturnUnusedItems(AssemblyLine line, StorageComponent storage, IEnumerable<int> items)
		{
			Player mainPlayer = GameMain.mainPlayer;
			if (storage == null || mainPlayer == null)
			{
				return;
			}
			int num2 = default(int);
			foreach (int item in items)
			{
				int reserve;
				bool output;
				bool flag = line.LogisticsRule(item, out reserve, out output);
				if (reserve == 0)
				{
					ReturnBufferedItem(line, mainPlayer, storage.entityId, item);
				}
				if (flag)
				{
					continue;
				}
				int itemCount = storage.GetItemCount(item);
				if (itemCount <= 0)
				{
					continue;
				}
				int num = storage.TakeItem(item, itemCount, ref num2);
				if (num > 0)
				{
					int num3 = mainPlayer.TryAddItemToPackage(item, num, num2, true, storage.entityId, false);
					if (num3 > 0)
					{
						UIItemup.Up(item, num3);
					}
				}
			}
		}

		private static void ReturnBufferedItem(AssemblyLine line, Player player, int entity, int item)
		{
			int points;
			int num = line.Ingredients.Read(item, out points);
			if (num > 0)
			{
				int num2 = player.TryAddItemToPackage(item, num, points, true, entity, false);
				line.Ingredients.Set(item, 0, 0);
				if (num2 > 0)
				{
					UIItemup.Up(item, num2);
				}
			}
		}

		internal AssemblyLine Open(PlanetFactory factory, StorageComponent storage)
		{
			AssemblyLine assemblyLine = Select(factory, storage);
			if (assemblyLine != null)
			{
				long num = ((long)factory.planetId << 32) | (uint)storage.entityId;
				if (!keys.Contains(num))
				{
					keys.Add(num);
				}
			}
			return assemblyLine;
		}

		private void LateUpdate()
		{
			if (panel != null)
			{
				panel.Update();
			}
		}

		private void OnDestroy()
		{
			ProtoRegistry.onLoadingFinished -= ConfigurePower;
			if (panel != null)
			{
				panel.Dispose();
			}
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			if ((Object)(object)instance == (Object)(object)this)
			{
				instance = null;
			}
		}

		public void Export(BinaryWriter writer)
		{
			writer.Write(machines.Count);
			foreach (KeyValuePair<long, AssemblyLine> machine in machines)
			{
				writer.Write(machine.Key);
				machine.Value.Write(writer);
			}
		}

		public void Import(BinaryReader reader)
		{
			Dictionary<long, AssemblyLine> dictionary = new Dictionary<long, AssemblyLine>();
			int num = reader.ReadInt32();
			if (num < 0 || num > 1000000)
			{
				throw new InvalidDataException("Invalid AIO Assembler count.");
			}
			for (int i = 0; i < num; i++)
			{
				dictionary.Add(reader.ReadInt64(), AssemblyLine.Read(reader, ResolveRecipe, ResolveDuration));
			}
			IntoOtherSave();
			foreach (KeyValuePair<long, AssemblyLine> item in dictionary)
			{
				machines.Add(item.Key, item.Value);
				keys.Add(item.Key);
			}
		}

		public void IntoOtherSave()
		{
			machines.Clear();
			keys.Clear();
		}
	}
	[HarmonyPatch(typeof(UIRecipePicker), "RefreshIcons")]
	internal static class RecipePickerFilter
	{
		private const ERecipeType Mixed = (ERecipeType)255;

		internal static bool Installed { get; private set; }

		internal static ERecipeType Filter
		{
			get
			{
				if (Installed)
				{
					return (ERecipeType)255;
				}
				return (ERecipeType)4;
			}
		}

		private static bool Matches(ERecipeType filter, ERecipeType type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			if ((int)filter != 255)
			{
				return filter == type;
			}
			if ((int)type != 4)
			{
				return (int)type == 1;
			}
			return true;
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			FieldInfo fieldInfo = AccessTools.Field(typeof(UIRecipePicker), "filter");
			FieldInfo fieldInfo2 = AccessTools.Field(typeof(RecipeProto), "Type");
			for (int i = 5; i + 1 < list.Count; i++)
			{
				CodeInstruction val = list[i + 1];
				if (CodeInstructionExtensions.LoadsField(list[i - 4], fieldInfo, false) && CodeInstructionExtensions.LoadsField(list[i], fieldInfo2, false) && (!(val.opcode != OpCodes.Bne_Un) || !(val.opcode != OpCodes.Bne_Un_S)))
				{
					CodeInstruction val2 = new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(RecipePickerFilter), "Matches", (Type[])null, (Type[])null));
					val2.labels.AddRange(val.labels);
					val2.blocks.AddRange(val.blocks);
					val.labels.Clear();
					val.blocks.Clear();
					val.opcode = OpCodes.Brfalse;
					list.Insert(i + 1, val2);
					Installed = true;
					break;
				}
			}
			return list;
		}
	}
}
namespace LokiMoonLabs.HoneyIShrunkTheFactory
{
	internal sealed class NativeSkin
	{
		private readonly UIComboBox combo;

		private readonly Button button;

		private readonly Slider slider;

		internal NativeSkin()
		{
			UIGame uiGame = UIRoot.instance.uiGame;
			combo = uiGame.controlPanelWindow.filterPanel.sortFilterBox;
			UIButton copyButton = uiGame.assemblerWindow.copyButton;
			if ((Object)(object)copyButton != (Object)null)
			{
				button = copyButton.button;
			}
			if (!((Object)(object)uiGame.stationWindow != (Object)null))
			{
				return;
			}
			Slider[] componentsInChildren = ((Component)uiGame.stationWindow).GetComponentsInChildren<Slider>(true);
			foreach (Slider val in componentsInChildren)
			{
				if ((Object)(object)val.handleRect != (Object)null)
				{
					slider = val;
					break;
				}
			}
		}

		internal static void Copy(Image target, Image source)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)source == (Object)null))
			{
				target.sprite = source.sprite;
				target.type = source.type;
				((Graphic)target).material = ((Graphic)source).material;
				((Graphic)target).color = ((Graphic)source).color;
				target.fillCenter = source.fillCenter;
				target.pixelsPerUnitMultiplier = source.pixelsPerUnitMultiplier;
			}
		}

		internal void Input(Image target)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			Copy(target, ((Component)combo).GetComponent<Image>());
			((Graphic)target).color = new Color(0.09f, 0.14f, 0.16f, 1f);
		}

		internal void Button(Button target)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			Copy((Image)((Selectable)target).targetGraphic, (Image)(((Object)(object)button != (Object)null) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)((Component)combo).GetComponent<Image>())));
			if ((Object)(object)button != (Object)null)
			{
				((Selectable)target).colors = ((Selectable)button).colors;
				((Selectable)target).transition = (Transition)1;
			}
		}

		internal void Popup(Image target)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			Copy(target, ((Component)combo.m_DropDownList).GetComponent<Image>());
			((Graphic)target).color = new Color(0.075f, 0.11f, 0.13f, 1f);
		}

		internal void Option(Button target)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			Image val = (Image)((Selectable)target).targetGraphic;
			val.sprite = null;
			((Graphic)val).material = null;
			((Graphic)val).color = Color.white;
			ColorBlock colors = ((Selectable)target).colors;
			((ColorBlock)(ref colors)).normalColor = new Color(0.09f, 0.14f, 0.16f, 1f);
			((ColorBlock)(ref colors)).highlightedColor = new Color(0.22f, 0.39f, 0.44f, 1f);
			((ColorBlock)(ref colors)).selectedColor = ((ColorBlock)(ref colors)).highlightedColor;
			((ColorBlock)(ref colors)).pressedColor = new Color(0.14f, 0.27f, 0.31f, 1f);
			((Selectable)target).colors = colors;
		}

		internal void Scrollbar(Scrollbar target)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)combo.m_Scrollbar == (Object)null))
			{
				Copy(((Component)target).GetComponent<Image>(), ((Component)combo.m_Scrollbar).GetComponent<Image>());
				object target2 = (object)(Image)((Selectable)target).targetGraphic;
				Graphic targetGraphic = ((Selectable)combo.m_Scrollbar).targetGraphic;
				Copy((Image)target2, (Image)(object)((targetGraphic is Image) ? targetGraphic : null));
				((Selectable)target).colors = ((Selectable)combo.m_Scrollbar).colors;
			}
		}

		internal void Slider(Slider target, Image background)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Expected O, but got Unknown
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)slider == (Object)null)
			{
				return;
			}
			Image val = ((Component)slider).GetComponent<Image>();
			if ((Object)(object)val == (Object)null)
			{
				Image[] componentsInChildren = ((Component)slider).GetComponentsInChildren<Image>(true);
				foreach (Image val2 in componentsInChildren)
				{
					if ((Object)(object)((Component)val2).transform != (Object)(object)slider.handleRect && ((Object)val2).name.IndexOf("background", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						val = val2;
						break;
					}
				}
			}
			Copy(background, val);
			((Graphic)background).color = new Color(0.07f, 0.12f, 0.14f, 1f);
			Copy((Image)((Selectable)target).targetGraphic, ((Component)slider.handleRect).GetComponent<Image>());
			((Selectable)target).colors = ((Selectable)slider).colors;
		}

		internal void Arrow(RectTransform parent, Font font)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//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_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Native dropdown arrow", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent((Transform)(object)parent, false);
			RectTransform component = val.GetComponent<RectTransform>();
			Vector2 val2 = (component.pivot = new Vector2(1f, 0.5f));
			Vector2 anchorMin = (component.anchorMax = val2);
			component.anchorMin = anchorMin;
			component.anchoredPosition = new Vector2(-8f, 0f);
			component.sizeDelta = new Vector2(12f, 14f);
			Image[] componentsInChildren = ((Component)combo).GetComponentsInChildren<Image>(true);
			foreach (Image val5 in componentsInChildren)
			{
				string text = ((Object)val5).name.ToLowerInvariant();
				if (text.Contains("arrow") || text.Contains("down"))
				{
					Copy(val.AddComponent<Image>(), val5);
					((Graphic)val.GetComponent<Image>()).raycastTarget = false;
					return;
				}
			}
			Text val6 = val.AddComponent<Text>();
			val6.font = font;
			val6.fontSize = 12;
			val6.text = "▾";
			val6.alignment = (TextAnchor)4;
			((Graphic)val6).raycastTarget = false;
		}

		internal void Frame(RectTransform source, RectTransform target)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Expected O, but got Unknown
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: 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)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Expected O, but got Unknown
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			Rect rect = source.rect;
			if (((Rect)(ref rect)).width <= 0f || ((Rect)(ref rect)).height <= 0f)
			{
				return;
			}
			Graphic[] componentsInChildren = ((Component)source).GetComponentsInChildren<Graphic>(true);
			foreach (Graphic val in componentsInChildren)
			{
				if (!((Behaviour)val).enabled || (!(val is Image) && !(val is RawImage)))
				{
					continue;
				}
				val.rectTransform.GetWorldCorners(array);
				Vector3 val2 = ((Transform)source).InverseTransformPoint(array[0]);
				Vector3 val3 = ((Transform)source).InverseTransformPoint(array[2]);
				float num = val3.x - val2.x;
				float num2 = val3.y - val2.y;
				if (!(num >= ((Rect)(ref rect)).width * 0.85f) || !(num2 >= ((Rect)(ref rect)).height * 0.8f))
				{
					continue;
				}
				bool flag = false;
				Transform val4 = ((Component)val).transform;
				while ((Object)(object)val4 != (Object)(object)source && (Object)(object)val4 != (Object)null)
				{
					if (!((Component)val4).gameObject.activeSelf)
					{
						flag = true;
						break;
					}
					val4 = val4.parent;
				}
				if (!flag)
				{
					GameObject val5 = new GameObject("Native window " + ((Object)val).name, new Type[1] { typeof(RectTransform) });
					val5.transform.SetParent((Transform)(object)target, false);
					RectTransform component = val5.GetComponent<RectTransform>();
					component.anchorMin = Vector2.zero;
					component.anchorMax = Vector2.one;
					Vector2 offsetMin = (component.offsetMax = Vector2.zero);
					component.offsetMin = offsetMin;
					Image val6 = (Image)(object)((val is Image) ? val : null);
					Graphic val8;
					if ((Object)(object)val6 != (Object)null)
					{
						Image val7 = val5.AddComponent<Image>();
						Copy(val7, val6);
						val8 = (Graphic)(object)val7;
					}
					else
					{
						RawImage val9 = (RawImage)val;
						RawImage val10 = val5.AddComponent<RawImage>();
						val10.texture = val9.texture;
						val10.uvRect = val9.uvRect;
						((Graphic)val10).material = ((Graphic)val9).material;
						((Graphic)val10).color = ((Graphic)val9).color;
						val8 = (Graphic)(object)val10;
					}
					val8.raycastTarget = false;
				}
			}
		}
	}
}