Decompiled source of DSPCompleteReplicatorQueue v1.0.4

DSPCompleteReplicatorQueue.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("1.0.4.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace DSPCompleteReplicatorQueue
{
	public static class InstantCraft
	{
		public static void CompleteAllTasks(MechaForge forge)
		{
			if ((Object)(object)Main.Instance != (Object)null)
			{
				Main.Instance.Request(forge);
			}
		}
	}
	[BepInPlugin("Appun.DSP.plugin.DSPCompleteReplicatorQueue", "DSPCompleteReplicatorQueue", "1.0.4")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Main : BaseUnityPlugin
	{
		public const string Guid = "Appun.DSP.plugin.DSPCompleteReplicatorQueue";

		internal static Main Instance;

		private Harmony harmony;

		private QueueCompletion completion;

		internal bool Busy
		{
			get
			{
				if (completion != null)
				{
					return completion.Active;
				}
				return false;
			}
		}

		private void Awake()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			Instance = this;
			harmony = new Harmony("Appun.DSP.plugin.DSPCompleteReplicatorQueue");
			harmony.PatchAll(typeof(WindowUI));
		}

		internal void Request(MechaForge forge)
		{
			if (!Busy)
			{
				completion = new QueueCompletion(forge);
				if (!completion.Active && completion.StopReason != null)
				{
					ReportStop(completion.StopReason);
				}
			}
		}

		private void Update()
		{
			if (!Busy)
			{
				return;
			}
			if (!GameMain.isRunning || GameMain.isLoading || GameMain.mainPlayer == null || completion.Forge.player != GameMain.mainPlayer)
			{
				Cancel();
			}
			else
			{
				if (GameMain.isPaused)
				{
					return;
				}
				QueueCompletion queueCompletion = completion;
				try
				{
					queueCompletion.ProcessBatch(GameMain.gameTick);
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)ex);
				}
				if (queueCompletion == completion && !queueCompletion.Active)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Complete Queue: " + queueCompletion.CompletedCycles + " native production cycles completed."));
					if (queueCompletion.StopReason != null)
					{
						ReportStop(queueCompletion.StopReason);
					}
				}
			}
		}

		private void ReportStop(string reason)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)reason);
			UIRealtimeTip.Popup("Complete Queue: " + reason, true, 0);
		}

		internal void Cancel()
		{
			if (completion != null)
			{
				completion.Stop("Completion cancelled; remaining queue preserved.");
			}
			completion = null;
		}

		private void OnDestroy()
		{
			Cancel();
			WindowUI.Remove();
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			if (Instance == this)
			{
				Instance = null;
			}
		}

		internal void Log(Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)ex);
		}
	}
	public sealed class QueueCompletion
	{
		private readonly Dictionary<ForgeTask, int> observed = new Dictionary<ForgeTask, int>();

		private bool processing;

		public MechaForge Forge { get; private set; }

		public bool Active { get; private set; }

		public int CompletedCycles { get; private set; }

		public string StopReason { get; private set; }

		public QueueCompletion(MechaForge forge)
		{
			Forge = forge;
			if (forge == null || forge.tasks == null || forge.tasks.Count == 0)
			{
				return;
			}
			for (int i = 0; i < forge.tasks.Count; i++)
			{
				ForgeTask val = forge.tasks[i];
				if (!Valid(val) || observed.ContainsKey(val) || (val.parentTaskIndex >= 0 && (val.parentTaskIndex <= i || val.parentTaskIndex >= forge.tasks.Count)))
				{
					Stop("Invalid task state; queue left unchanged.");
					return;
				}
				observed.Add(val, val.count);
			}
			Active = true;
		}

		private static bool Valid(ForgeTask task)
		{
			if (task == null || task.count <= 0 || task.tickSpend <= 0 || task.itemIds == null || task.itemCounts == null || task.served == null || task.productIds == null || task.productCounts == null || task.produced == null || task.itemIds.Length != task.itemCounts.Length || task.served.Length != task.itemCounts.Length || task.productIds.Length != task.productCounts.Length || task.produced.Length != task.productCounts.Length)
			{
				return false;
			}
			for (int i = 0; i < task.itemCounts.Length; i++)
			{
				if (task.itemIds[i] <= 0 || task.itemCounts[i] <= 0 || task.served[i] < 0)
				{
					return false;
				}
			}
			for (int j = 0; j < task.productCounts.Length; j++)
			{
				if (task.productIds[j] <= 0 || task.productCounts[j] <= 0 || task.produced[j] != 0)
				{
					return false;
				}
			}
			return true;
		}

		public void Stop(string reason)
		{
			Active = false;
			StopReason = reason;
		}

		public int ProcessBatch(long gameTick, int maxCycles = 128, double maxMilliseconds = 4.0)
		{
			if (!Active || processing || maxCycles <= 0 || maxMilliseconds <= 0.0)
			{
				return 0;
			}
			int num = 0;
			Stopwatch stopwatch = Stopwatch.StartNew();
			processing = true;
			try
			{
				while (Active && num < maxCycles && stopwatch.Elapsed.TotalMilliseconds < maxMilliseconds)
				{
					if (Forge.tasks == null || Forge.player == null || Forge.mecha == null || !Forge.player.isAlive)
					{
						Stop("Forge or player is no longer available.");
						break;
					}
					if (Forge.tasks.Count == 0)
					{
						Stop(null);
						break;
					}
					ForgeTask val = Forge.tasks[0];
					if (val == null || !observed.TryGetValue(val, out var value) || val.count > value)
					{
						Stop("Queue changed; press Complete Queue again to include new tasks.");
						break;
					}
					if (!Valid(val) || !val.itemEnough || (val.parentTaskIndex >= 0 && (val.parentTaskIndex == 0 || val.parentTaskIndex >= Forge.tasks.Count || !observed.ContainsKey(Forge.tasks[val.parentTaskIndex]))))
					{
						Stop("Missing inputs or invalid task state; remaining queue preserved.");
						break;
					}
					int count = val.count;
					int tick = val.tick;
					val.tick = Math.Max(val.tick, val.tickSpend);
					try
					{
						Forge.GameTick(gameTick, 0f);
					}
					catch
					{
						if (val.count == count)
						{
							val.tick = tick;
						}
						Stop("Native forge raised an error; accelerated completion stopped.");
						throw;
					}
					if (val.count != count - 1)
					{
						if (val.count == count)
						{
							val.tick = tick;
						}
						Stop("Native forge made no expected progress; remaining queue preserved.");
						break;
					}
					observed[val] = val.count;
					num++;
					CompletedCycles++;
					if (Forge.tasks == null || Forge.tasks.Count == 0)
					{
						Stop(null);
					}
				}
			}
			finally
			{
				processing = false;
			}
			return num;
		}
	}
	[HarmonyPatch]
	internal static class WindowUI
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__7_0;

			internal void <Ensure>b__7_0()
			{
				InstantCraft.CompleteAllTasks(GetForge(owner));
			}
		}

		private static UIReplicatorWindow owner;

		private static Button button;

		private static Text label;

		private static bool createFailed;

		private static readonly FieldInfo ForgeField = typeof(UIReplicatorWindow).GetField("mechaForge", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static MechaForge GetForge(UIReplicatorWindow window)
		{
			if (!((Object)(object)window != (Object)null) || !(ForgeField != null))
			{
				return null;
			}
			object? value = ForgeField.GetValue(window);
			return (MechaForge)((value is MechaForge) ? value : null);
		}

		internal static void Remove()
		{
			if ((Object)(object)button != (Object)null)
			{
				((UnityEventBase)button.onClick).RemoveAllListeners();
				((Component)button).gameObject.SetActive(false);
				Object.Destroy((Object)(object)((Component)button).gameObject);
			}
			button = null;
			label = null;
			owner = null;
			createFailed = false;
		}

		private static void Ensure(UIReplicatorWindow window)
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Expected O, but got Unknown
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: 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_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: 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_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: 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_0354: Unknown result type (might be due to invalid IL or missing references)
			//IL_0359: Unknown result type (might be due to invalid IL or missing references)
			//IL_035f: Expected O, but got Unknown
			if (((Object)(object)button != (Object)null && (Object)(object)owner == (Object)(object)window) || (createFailed && (Object)(object)owner == (Object)(object)window))
			{
				return;
			}
			Remove();
			owner = window;
			GameObject val = null;
			try
			{
				Transform val2 = ((Component)window).transform.Find("panel-bg");
				if ((Object)(object)val2 == (Object)null || (Object)(object)window.minusButton == (Object)null)
				{
					return;
				}
				Image component = ((Component)window.minusButton).GetComponent<Image>();
				val = new GameObject("DSPCompleteReplicatorQueueButton", new Type[3]
				{
					typeof(RectTransform),
					typeof(Image),
					typeof(Button)
				});
				val.SetActive(false);
				val.transform.SetParent(val2, false);
				RectTransform component2 = val.GetComponent<RectTransform>();
				Transform obj = val2.Find("btn-box");
				RectTransform val3 = (RectTransform)(object)((obj is RectTransform) ? obj : null);
				component2.anchorMin = (Vector2)(((Object)(object)val3 != (Object)null) ? val3.anchorMin : new Vector2(1f, 1f));
				component2.anchorMax = (Vector2)(((Object)(object)val3 != (Object)null) ? val3.anchorMax : new Vector2(1f, 1f));
				component2.pivot = new Vector2(1f, 0.5f);
				component2.sizeDelta = new Vector2(235f, 30f);
				component2.anchoredPosition = new Vector2(-28f, -65f);
				Image component3 = val.GetComponent<Image>();
				if ((Object)(object)component != (Object)null)
				{
					component3.sprite = component.sprite;
					component3.type = component.type;
					((Graphic)component3).material = ((Graphic)component).material;
				}
				((Graphic)component3).color = Color.white;
				button = val.GetComponent<Button>();
				((Selectable)button).targetGraphic = (Graphic)(object)component3;
				ColorBlock colors = ((Selectable)button).colors;
				((ColorBlock)(ref colors)).normalColor = new Color(0.05f, 0.09f, 0.09f, 0.25f);
				((ColorBlock)(ref colors)).highlightedColor = new Color(0.16f, 0.18f, 0.18f, 0.7f);
				((ColorBlock)(ref colors)).pressedColor = new Color(0.18f, 0.27f, 0.27f, 0.7f);
				((ColorBlock)(ref colors)).disabledColor = new Color(0.05f, 0.09f, 0.09f, 0.05f);
				((Selectable)button).colors = colors;
				GameObject val4 = new GameObject("text", new Type[2]
				{
					typeof(RectTransform),
					typeof(Text)
				});
				val4.transform.SetParent(val.transform, false);
				RectTransform component4 = val4.GetComponent<RectTransform>();
				component4.anchorMin = Vector2.zero;
				component4.anchorMax = Vector2.one;
				component4.offsetMin = Vector2.zero;
				component4.offsetMax = Vector2.zero;
				label = val4.GetComponent<Text>();
				label.font = window.multiValueText.font;
				label.fontSize = 16;
				label.alignment = (TextAnchor)4;
				((Graphic)label).color = new Color(0.95f, 0.95f, 0.95f, 1f);
				((Graphic)label).raycastTarget = false;
				label.text = "Complete Replication Queue";
				ButtonClickedEvent onClick = button.onClick;
				object obj2 = <>c.<>9__7_0;
				if (obj2 == null)
				{
					UnityAction val5 = delegate
					{
						InstantCraft.CompleteAllTasks(GetForge(owner));
					};
					<>c.<>9__7_0 = val5;
					obj2 = (object)val5;
				}
				((UnityEvent)onClick).AddListener((UnityAction)obj2);
				val.SetActive(true);
			}
			catch (Exception ex)
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
				button = null;
				label = null;
				createFailed = true;
				if ((Object)(object)Main.Instance != (Object)null)
				{
					Main.Instance.Log(ex);
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(UIReplicatorWindow), "_OnCreate")]
		private static void Created(UIReplicatorWindow __instance)
		{
			Ensure(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(UIReplicatorWindow), "_OnOpen")]
		private static void Opened(UIReplicatorWindow __instance)
		{
			createFailed = false;
			Ensure(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPriority(0)]
		[HarmonyPatch(typeof(UIReplicatorWindow), "_OnUpdate")]
		private static void Updated(UIReplicatorWindow __instance)
		{
			Ensure(__instance);
			if (!((Object)(object)button == (Object)null))
			{
				bool flag = (Object)(object)Main.Instance != (Object)null && Main.Instance.Busy;
				MechaForge forge = GetForge(__instance);
				((Selectable)button).interactable = !flag && forge != null && forge.tasks != null && forge.tasks.Count > 0;
				label.text = (flag ? "Completing Queue..." : "Complete Replication Queue");
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(UIReplicatorWindow), "_OnFree")]
		private static void Freed(UIReplicatorWindow __instance)
		{
			if ((Object)(object)owner == (Object)(object)__instance && (Object)(object)Main.Instance != (Object)null)
			{
				Main.Instance.Cancel();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(UIReplicatorWindow), "_OnDestroy")]
		private static void Destroyed(UIReplicatorWindow __instance)
		{
			if (!((Object)(object)owner != (Object)(object)__instance))
			{
				if ((Object)(object)Main.Instance != (Object)null)
				{
					Main.Instance.Cancel();
				}
				Remove();
			}
		}
	}
}