Decompiled source of MachineMaxInput v1.1.1

plugins/MachineMaxInput.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("Reynum")]
[assembly: AssemblyTitle("MachineMaxInput")]
[assembly: AssemblyVersion("1.1.1.0")]
namespace MachineMaxInput;

[BepInPlugin("Reynum.MachineMaxInput", "Machine Max Input", "1.1.1")]
public class MachineMaxInputPlugin : BaseUnityPlugin
{
	public const string ModGuid = "Reynum.MachineMaxInput";

	public const string ModName = "Machine Max Input";

	public const string ModVersion = "1.1.1";

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<KeyCode> ModifierKey;

	internal static ConfigEntry<bool> ShowHoverHint;

	internal static ConfigEntry<bool> UseContainers;

	internal static ConfigEntry<float> ContainerRange;

	private Harmony _harmony;

	private void Awake()
	{
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Expected O, but got Unknown
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: Expected O, but got Unknown
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Enabled", true, "Turn the mod on or off.");
		ModifierKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("1 - General", "Modifier Key", (KeyCode)304, "Hold this key while pressing Use (E) on a smelter, furnace, kiln, blast furnace, windmill, spinning wheel or eitr refinery to add as much ore/fuel as fits.");
		ShowHoverHint = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Show Hover Hint", true, "Add a hint line to the machine's hover text.");
		UseContainers = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Nearby Containers", "Pull From Nearby Containers", true, "Also take ore/fuel from nearby chests when your inventory runs out. Skips chests someone has open, private chests you can't open, warded areas you lack access to, and tombstones.");
		ContainerRange = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Nearby Containers", "Container Range", 10f, new ConfigDescription("How far (metres) from the machine to look for chests.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>()));
		_harmony = new Harmony("Reynum.MachineMaxInput");
		_harmony.PatchAll(typeof(SmelterPatches));
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Machine Max Input 1.1.1 loaded.");
	}

	private void OnDestroy()
	{
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
	}

	internal static bool ModifierHeld()
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		if (!Enabled.Value)
		{
			return false;
		}
		try
		{
			return UnityInput.Current.GetKey(ModifierKey.Value);
		}
		catch
		{
			return false;
		}
	}

	internal static string KeyLabel()
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: 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_002f: Expected I4, but got Unknown
		//IL_004e: 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)
		KeyCode value = ModifierKey.Value;
		return (value - 303) switch
		{
			1 => "L.Shift", 
			0 => "R.Shift", 
			3 => "L.Ctrl", 
			5 => "L.Alt", 
			_ => ((object)ModifierKey.Value/*cast due to .constrained prefix*/).ToString(), 
		};
	}
}
internal static class SmelterAccess
{
	internal static readonly FieldRef<Smelter, ZNetView> NView = AccessTools.FieldRefAccess<Smelter, ZNetView>("m_nview");

	internal static readonly FieldRef<Smelter, float> AddedOreTime = AccessTools.FieldRefAccess<Smelter, float>("m_addedOreTime");

	internal static readonly Func<Smelter, Inventory, ItemData> FindCookableItem = AccessTools.MethodDelegate<Func<Smelter, Inventory, ItemData>>(AccessTools.Method(typeof(Smelter), "FindCookableItem", new Type[1] { typeof(Inventory) }, (Type[])null), (object)null, true);

	internal static readonly Func<Smelter, string, bool> IsItemAllowed = AccessTools.MethodDelegate<Func<Smelter, string, bool>>(AccessTools.Method(typeof(Smelter), "IsItemAllowed", new Type[1] { typeof(string) }, (Type[])null), (object)null, true);

	internal static readonly Func<Smelter, int> GetQueueSize = AccessTools.MethodDelegate<Func<Smelter, int>>(AccessTools.Method(typeof(Smelter), "GetQueueSize", (Type[])null, (Type[])null), (object)null, true);

	internal static readonly Func<Smelter, float> GetFuel = AccessTools.MethodDelegate<Func<Smelter, float>>(AccessTools.Method(typeof(Smelter), "GetFuel", (Type[])null, (Type[])null), (object)null, true);

	internal static readonly Action<Smelter, bool> SetAnimation = AccessTools.MethodDelegate<Action<Smelter, bool>>(AccessTools.Method(typeof(Smelter), "SetAnimation", new Type[1] { typeof(bool) }, (Type[])null), (object)null, true);
}
internal static class ContainerAccess
{
	internal static readonly FieldRef<Container, ZNetView> NView = AccessTools.FieldRefAccess<Container, ZNetView>("m_nview");

	internal static readonly Func<Container, long, bool> CheckAccess = AccessTools.MethodDelegate<Func<Container, long, bool>>(AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null), (object)null, true);
}
[HarmonyPatch]
internal static class SmelterPatches
{
	private static bool IsLocalPlayer(Humanoid user)
	{
		if ((Object)(object)user != (Object)null)
		{
			return (Object)(object)user == (Object)(object)Player.m_localPlayer;
		}
		return false;
	}

	private static void Msg(Humanoid user, string text)
	{
		((Character)user).Message((MessageType)2, text, 0, (Sprite)null, false);
	}

	private static List<Inventory> GetSources(Humanoid user, Vector3 machinePos)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: 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_010e: Unknown result type (might be due to invalid IL or missing references)
		List<Inventory> list = new List<Inventory> { user.GetInventory() };
		if (!MachineMaxInputPlugin.UseContainers.Value)
		{
			return list;
		}
		float value = MachineMaxInputPlugin.ContainerRange.Value;
		long arg = (((Object)(object)Game.instance != (Object)null && Game.instance.GetPlayerProfile() != null) ? Game.instance.GetPlayerProfile().GetPlayerID() : 0);
		HashSet<Container> hashSet = new HashSet<Container>();
		List<Container> list2 = new List<Container>();
		Collider[] array = Physics.OverlapSphere(machinePos, value);
		foreach (Collider val in array)
		{
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			Container componentInParent = ((Component)val).GetComponentInParent<Container>();
			if (!((Object)(object)componentInParent == (Object)null) && hashSet.Add(componentInParent) && !((Object)(object)((Component)componentInParent).GetComponent<TombStone>() != (Object)null))
			{
				ZNetView val2 = ContainerAccess.NView.Invoke(componentInParent);
				if (!((Object)(object)val2 == (Object)null) && val2.IsValid() && !componentInParent.IsInUse() && ContainerAccess.CheckAccess(componentInParent, arg) && PrivateArea.CheckAccess(((Component)componentInParent).transform.position, 0f, false, false) && componentInParent.GetInventory() != null)
				{
					list2.Add(componentInParent);
				}
			}
		}
		list2.Sort((Container a, Container b) => Vector3.Distance(machinePos, ((Component)a).transform.position).CompareTo(Vector3.Distance(machinePos, ((Component)b).transform.position)));
		foreach (Container item in list2)
		{
			ZNetView val3 = ContainerAccess.NView.Invoke(item);
			if (!val3.IsOwner())
			{
				val3.ClaimOwnership();
			}
			list.Add(item.GetInventory());
		}
		return list;
	}

	private static int TakeItems(List<Inventory> sources, Func<ItemData, bool> match, int max, Action<ItemData, int> onTake, out int fromChests)
	{
		int num = 0;
		fromChests = 0;
		for (int i = 0; i < sources.Count; i++)
		{
			if (num >= max)
			{
				break;
			}
			Inventory val = sources[i];
			List<ItemData> list = new List<ItemData>();
			foreach (ItemData allItem in val.GetAllItems())
			{
				if (allItem != null && match(allItem))
				{
					list.Add(allItem);
				}
			}
			list.Sort((ItemData a, ItemData b) => a.m_stack.CompareTo(b.m_stack));
			foreach (ItemData item in list)
			{
				if (num >= max)
				{
					break;
				}
				int num2 = Math.Min(item.m_stack, max - num);
				if (num2 > 0)
				{
					onTake(item, num2);
					val.RemoveItem(item, num2);
					num += num2;
					if (i > 0)
					{
						fromChests += num2;
					}
				}
			}
		}
		return num;
	}

	private static string ChestNote(int fromChests)
	{
		if (fromChests <= 0)
		{
			return "";
		}
		return " (" + fromChests + " from chests)";
	}

	[HarmonyPatch(typeof(Smelter), "OnAddOre")]
	[HarmonyPrefix]
	[HarmonyPriority(200)]
	private static bool OnAddOre_Prefix(Smelter __instance, Switch sw, Humanoid user, ItemData item, ref bool __result, bool __runOriginal)
	{
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		if (!__runOriginal)
		{
			return false;
		}
		if (!MachineMaxInputPlugin.ModifierHeld() || !IsLocalPlayer(user))
		{
			return true;
		}
		try
		{
			ZNetView nview = SmelterAccess.NView.Invoke(__instance);
			if ((Object)(object)nview == (Object)null || !nview.IsValid())
			{
				return true;
			}
			int num = __instance.m_maxOre - SmelterAccess.GetQueueSize(__instance);
			if (num <= 0)
			{
				return true;
			}
			List<Inventory> sources = GetSources(user, ((Component)__instance).transform.position);
			if (item == null)
			{
				foreach (Inventory item2 in sources)
				{
					item = SmelterAccess.FindCookableItem(__instance, item2);
					if (item != null)
					{
						break;
					}
				}
			}
			if (item == null || (Object)(object)item.m_dropPrefab == (Object)null)
			{
				return true;
			}
			string prefab = ((Object)item.m_dropPrefab).name;
			if (!SmelterAccess.IsItemAllowed(__instance, prefab))
			{
				return true;
			}
			string name = item.m_shared.m_name;
			int fromChests;
			int num2 = TakeItems(sources, (ItemData it) => (Object)(object)it.m_dropPrefab != (Object)null && ((Object)it.m_dropPrefab).name == prefab, num, delegate(ItemData stack, int n)
			{
				bool cheated = stack.m_cheated;
				for (int i = 0; i < n; i++)
				{
					nview.InvokeRPC("RPC_AddOre", new object[2] { prefab, cheated });
				}
			}, out fromChests);
			if (num2 <= 0)
			{
				return true;
			}
			Msg(user, "$msg_added " + num2 + "x " + name + ChestNote(fromChests));
			SmelterAccess.AddedOreTime.Invoke(__instance) = Time.time;
			if (__instance.m_addOreAnimationDuration > 0f)
			{
				SmelterAccess.SetAnimation(__instance, arg2: true);
			}
			__result = true;
			return false;
		}
		catch (Exception ex)
		{
			Debug.LogWarning((object)("[MachineMaxInput] ore fill failed, using vanilla: " + ex));
			return true;
		}
	}

	[HarmonyPatch(typeof(Smelter), "OnAddFuel")]
	[HarmonyPrefix]
	[HarmonyPriority(200)]
	private static bool OnAddFuel_Prefix(Smelter __instance, Switch sw, Humanoid user, ItemData item, ref bool __result, bool __runOriginal)
	{
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		if (!__runOriginal)
		{
			return false;
		}
		if (!MachineMaxInputPlugin.ModifierHeld() || !IsLocalPlayer(user))
		{
			return true;
		}
		try
		{
			ZNetView nview = SmelterAccess.NView.Invoke(__instance);
			if ((Object)(object)nview == (Object)null || !nview.IsValid() || (Object)(object)__instance.m_fuelItem == (Object)null)
			{
				return true;
			}
			string fuelName = __instance.m_fuelItem.m_itemData.m_shared.m_name;
			if (item != null && item.m_shared.m_name != fuelName)
			{
				return true;
			}
			int num = Mathf.FloorToInt((float)__instance.m_maxFuel - SmelterAccess.GetFuel(__instance));
			if (num <= 0)
			{
				return true;
			}
			int fromChests;
			int num2 = TakeItems(GetSources(user, ((Component)__instance).transform.position), (ItemData it) => it.m_shared.m_name == fuelName, num, delegate(ItemData stack, int n)
			{
				for (int i = 0; i < n; i++)
				{
					nview.InvokeRPC("RPC_AddFuel", Array.Empty<object>());
				}
			}, out fromChests);
			if (num2 <= 0)
			{
				return true;
			}
			Msg(user, "$msg_added " + num2 + "x " + fuelName + ChestNote(fromChests));
			__result = true;
			return false;
		}
		catch (Exception ex)
		{
			Debug.LogWarning((object)("[MachineMaxInput] fuel fill failed, using vanilla: " + ex));
			return true;
		}
	}

	[HarmonyPatch(typeof(Smelter), "OnHoverAddOre")]
	[HarmonyPostfix]
	[HarmonyPriority(0)]
	private static void OnHoverAddOre_Postfix(ref string __result)
	{
		__result = AddHint(__result);
	}

	[HarmonyPatch(typeof(Smelter), "OnHoverAddFuel")]
	[HarmonyPostfix]
	[HarmonyPriority(0)]
	private static void OnHoverAddFuel_Postfix(ref string __result)
	{
		__result = AddHint(__result);
	}

	private static string AddHint(string text)
	{
		if (!MachineMaxInputPlugin.Enabled.Value || !MachineMaxInputPlugin.ShowHoverHint.Value || string.IsNullOrEmpty(text))
		{
			return text;
		}
		if (text.Contains("] Add max"))
		{
			return text;
		}
		string text2 = "\n[<color=yellow><b>" + MachineMaxInputPlugin.KeyLabel() + " + $KEY_Use</b></color>] Add max";
		return text + ((Localization.instance != null) ? Localization.instance.Localize(text2) : text2);
	}
}