Decompiled source of ReplicatorQuantity v1.0.0

plugins/ReplicatorQuantity.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("ReplicatorQuantity.InGameTests")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("ReplicatorQuantity")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+a98b6e74d9370058d4aed382d50a7f90cc20eb66")]
[assembly: AssemblyProduct("ReplicatorQuantity")]
[assembly: AssemblyTitle("ReplicatorQuantity")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ReplicatorQuantity
{
	[BepInPlugin("com.github.jiesiluo.replicatorquantity", "Replicator Quantity", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.github.jiesiluo.replicatorquantity";

		public const string Name = "Replicator Quantity";

		public const string Version = "1.0.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<int> CtrlStep;

		internal static ConfigEntry<int> ShiftStep;

		internal static ConfigEntry<int> MaxQuantity;

		internal static ConfigEntry<bool> AltForMax;

		internal static Func<(bool ctrl, bool shift, bool alt)> Modifiers = () => (ctrl: Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305), shift: Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303), alt: Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307));

		internal static Func<int> KeyDirection = () => (Input.GetKeyDown((KeyCode)61) || Input.GetKeyDown((KeyCode)270)) ? 1 : ((Input.GetKeyDown((KeyCode)45) || Input.GetKeyDown((KeyCode)269)) ? (-1) : 0);

		private int lastRecipe;

		private int lastAmount;

		private void Awake()
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			CtrlStep = ((BaseUnityPlugin)this).Config.Bind<int>("Steps", "CtrlStep", 10, "Ctrl + click on +/- changes the amount by this much.");
			ShiftStep = ((BaseUnityPlugin)this).Config.Bind<int>("Steps", "ShiftStep", 100, "Shift + click on +/- changes the amount by this much.");
			AltForMax = ((BaseUnityPlugin)this).Config.Bind<bool>("Steps", "AltForMax", true, "Alt + click on + sets the amount to as many as you can craft; Alt + click on - resets it to 1.");
			MaxQuantity = ((BaseUnityPlugin)this).Config.Bind<int>("Limits", "MaxQuantity", 999, new ConfigDescription("Largest amount one click on the produce button can queue (the game's own limit is 10).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 9999), Array.Empty<object>()));
			new Harmony("com.github.jiesiluo.replicatorquantity").PatchAll(typeof(ReplicatorPatches));
		}

		private void LateUpdate()
		{
			UIReplicatorWindow val = UIRoot.instance?.uiGame?.replicator;
			RecipeProto val2 = (((Object)(object)val != (Object)null && ((ManualBehaviour)val).active) ? ReplicatorPatches.SelectedRecipe.Invoke(val) : null);
			if (val2 == null || val.multipliers == null)
			{
				lastRecipe = 0;
				return;
			}
			int num = KeyDirection();
			if (num != 0 && ((Proto)val2).ID == lastRecipe)
			{
				val.multipliers[((Proto)val2).ID] = ReplicatorPatches.Next(val, val2, lastAmount, num);
			}
			lastRecipe = ((Proto)val2).ID;
			lastAmount = ReplicatorPatches.Amount(val, val2);
		}
	}
	[HarmonyPatch(typeof(UIReplicatorWindow))]
	internal static class ReplicatorPatches
	{
		internal static readonly FieldRef<UIReplicatorWindow, RecipeProto> SelectedRecipe = AccessTools.FieldRefAccess<UIReplicatorWindow, RecipeProto>("selectedRecipe");

		private static readonly FieldRef<UIReplicatorWindow, MechaForge> Forge = AccessTools.FieldRefAccess<UIReplicatorWindow, MechaForge>("mechaForge");

		private static Action<int> plusHandler;

		private static Action<int> minusHandler;

		public static int Cap()
		{
			return Math.Max(10, Plugin.MaxQuantity.Value);
		}

		[HarmonyPostfix]
		[HarmonyPatch("_OnRegEvent")]
		private static void RegisterButtons(UIReplicatorWindow __instance)
		{
			UIReplicatorWindow window = __instance;
			__instance.plusButton.onClick -= GameHandler(__instance, "OnPlusButtonClick");
			__instance.minusButton.onClick -= GameHandler(__instance, "OnMinusButtonClick");
			plusHandler = delegate
			{
				Change(window, 1);
			};
			minusHandler = delegate
			{
				Change(window, -1);
			};
			__instance.plusButton.onClick += plusHandler;
			__instance.minusButton.onClick += minusHandler;
		}

		[HarmonyPostfix]
		[HarmonyPatch("_OnUnregEvent")]
		private static void UnregisterButtons(UIReplicatorWindow __instance)
		{
			if (plusHandler != null)
			{
				__instance.plusButton.onClick -= plusHandler;
			}
			if (minusHandler != null)
			{
				__instance.minusButton.onClick -= minusHandler;
			}
			plusHandler = (minusHandler = null);
		}

		private static Action<int> GameHandler(UIReplicatorWindow window, string method)
		{
			return (Action<int>)Delegate.CreateDelegate(typeof(Action<int>), window, AccessTools.Method(typeof(UIReplicatorWindow), method, (Type[])null, (Type[])null));
		}

		internal static int Amount(UIReplicatorWindow window, RecipeProto recipe)
		{
			if (window.multipliers == null || !window.multipliers.TryGetValue(((Proto)recipe).ID, out var value))
			{
				return 1;
			}
			return value;
		}

		internal static void Change(UIReplicatorWindow window, int direction)
		{
			RecipeProto val = SelectedRecipe.Invoke(window);
			if (val != null && window.multipliers != null)
			{
				window.multipliers[((Proto)val).ID] = Next(window, val, Amount(window, val), direction);
			}
		}

		internal static int Next(UIReplicatorWindow window, RecipeProto recipe, int current, int direction)
		{
			(bool, bool, bool) tuple = Plugin.Modifiers();
			bool item = tuple.Item1;
			bool item2 = tuple.Item2;
			bool item3 = tuple.Item3;
			int num = Cap();
			int val;
			if (item3 && Plugin.AltForMax.Value)
			{
				if (direction < 0)
				{
					val = 1;
				}
				else if (window.isInstantItem)
				{
					val = num;
				}
				else
				{
					MechaForge obj = Forge.Invoke(window);
					val = ((obj != null) ? obj.PredictTaskCount(((Proto)recipe).ID, num, false) : current);
				}
			}
			else
			{
				int num2 = Math.Max(1, item2 ? Plugin.ShiftStep.Value : ((!item) ? 1 : Plugin.CtrlStep.Value));
				val = ((direction > 0 && current == 1 && num2 > 1) ? num2 : (current + direction * num2));
			}
			return Math.Max(1, Math.Min(num, val));
		}

		[HarmonyTranspiler]
		[HarmonyPatch("OnOkButtonClick")]
		private static IEnumerable<CodeInstruction> ProduceTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			MethodInfo predict = AccessTools.Method(typeof(MechaForge), "PredictTaskCount", (Type[])null, (Type[])null);
			MethodInfo operand = AccessTools.Method(typeof(ReplicatorPatches), "Cap", (Type[])null, (Type[])null);
			List<CodeInstruction> list2 = list.Where((CodeInstruction ci) => CodeInstructionExtensions.LoadsConstant(ci, 10L)).ToList();
			int num = list.FindIndex((CodeInstruction ci) => CodeInstructionExtensions.Calls(ci, predict));
			bool flag = num >= 2 && CodeInstructionExtensions.LoadsConstant(list[num - 2], 99L);
			if (list2.Count != 2 || !flag)
			{
				Plugin.Log.LogError((object)($"The replicator's produce button has changed (found {list2.Count} limits of 10, " + "material check " + (flag ? "found" : "not found") + "); keeping the game's limit of 10 per click."));
				return list;
			}
			foreach (CodeInstruction item in list2.Append(list[num - 2]))
			{
				item.opcode = OpCodes.Call;
				item.operand = operand;
			}
			Plugin.Log.LogInfo((object)"Replicator produce button: limit raised from 10 to the MaxQuantity setting.");
			return list;
		}
	}
}