Decompiled source of BulkSellMod v1.2.1

BepInEx/plugins/BulkSellMod/BulkSellMod.dll

Decompiled 2 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FishNet.Object;
using HarmonyLib;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("BulkSellMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("BulkSellMod")]
[assembly: AssemblyTitle("BulkSellMod")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace BulkSellMod;

[BepInPlugin("com.bulksell.htf", "BulkSellMod", "1.2.1")]
[BepInProcess("How to Fish")]
public class BulkSellMod : BaseUnityPlugin
{
	private struct BulkSellJob
	{
		public NPC Npc;

		public NPCQuest Quest;

		public byte QuestIndex;

		public byte Slot;

		public PlayerInventory Inv;

		public int Remaining;

		public int ItemId;
	}

	[HarmonyPatch(typeof(NPC), "EatItem")]
	private static class EatPatch
	{
		[HarmonyPostfix]
		private static void Postfix(NPC __instance, NPCQuest quest, byte questIndex, Item item)
		{
			try
			{
				if (_isBulkFeeding || !SellWholeStack.Value || !_bulkArmed)
				{
					return;
				}
				_bulkArmed = false;
				if (!Object.op_Implicit((Object)(object)Server.Instance) || !((NetworkBehaviour)Server.Instance).IsServerInitialized || !Object.op_Implicit((Object)(object)item))
				{
					return;
				}
				Player lastHolder = item.LastHolder;
				if (!Object.op_Implicit((Object)(object)lastHolder))
				{
					return;
				}
				PlayerInventory inventory = lastHolder.Inventory;
				if (!Object.op_Implicit((Object)(object)inventory))
				{
					return;
				}
				int num = 0;
				foreach (KeyValuePair<byte, Item> item2 in inventory._items)
				{
					Item value = item2.Value;
					if (Object.op_Implicit((Object)(object)value) && value.ID == item.ID)
					{
						int num2 = StackCount(inventory, item2.Key) + 1;
						_bulkQueue.Enqueue(new BulkSellJob
						{
							Npc = __instance,
							Quest = quest,
							QuestIndex = questIndex,
							Slot = item2.Key,
							Inv = inventory,
							Remaining = num2,
							ItemId = item.ID
						});
						num += num2;
					}
				}
				if (num > 0)
				{
					_logger.LogInfo((object)string.Format("{0}: Sold {1} of item {2} in one go.", "BulkSellMod", num, item.ID));
				}
			}
			catch (Exception arg)
			{
				_logger.LogWarning((object)string.Format("{0}: bulk sell error: {1}", "BulkSellMod", arg));
			}
		}
	}

	public const string PluginGuid = "com.bulksell.htf";

	public const string PluginName = "BulkSellMod";

	public const string PluginVersion = "1.2.1";

	public static ConfigEntry<bool> SellWholeStack;

	private static bool _bulkArmed;

	private const int MaxFeedsPerFrame = 6;

	private static readonly Queue<BulkSellJob> _bulkQueue = new Queue<BulkSellJob>();

	private static bool _isBulkFeeding;

	private static MethodInfo _popServerStack;

	private static MethodInfo _getStackCount;

	private static MethodInfo _eatItem;

	private static ManualLogSource _logger;

	private void Awake()
	{
		_logger = ((BaseUnityPlugin)this).Logger;
		SellWholeStack = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SellWholeStack", true, "Master switch for bulk sell. Hold LeftShift and press Q to arm ONE whole-stack sale, then feed a fish to the NPC.");
		Type type = AccessTools.TypeByName("StackableItems.StackManager");
		if (type != null)
		{
			_popServerStack = type.GetMethod("PopServerStack", BindingFlags.Static | BindingFlags.Public);
			_getStackCount = type.GetMethod("GetStackCount", BindingFlags.Static | BindingFlags.Public);
			if (_popServerStack != null && _getStackCount != null)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"BulkSellMod: StackableItems found and hooked.");
			}
		}
		Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "com.bulksell.htf");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"BulkSellMod v1.2.1 loaded.");
	}

	private void Update()
	{
		Keyboard current = Keyboard.current;
		if (current != null && ((ButtonControl)current.leftShiftKey).isPressed && ((ButtonControl)current.qKey).wasPressedThisFrame && !_bulkArmed)
		{
			_bulkArmed = true;
			_logger.LogInfo((object)"BulkSellMod: Bulk armed for next fish feed. Throw a fish!");
		}
		if (_bulkQueue.Count == 0)
		{
			return;
		}
		int num = 0;
		while (num < 6 && _bulkQueue.Count > 0)
		{
			BulkSellJob item = _bulkQueue.Dequeue();
			num++;
			if (!Object.op_Implicit((Object)(object)item.Npc) || !Object.op_Implicit((Object)(object)item.Inv))
			{
				continue;
			}
			Item val = PopStack(item.Inv, item.Slot);
			if ((Object)(object)val == (Object)null)
			{
				val = SlotItem(item.Inv, item.Slot);
			}
			if (Object.op_Implicit((Object)(object)val) && val.ID == item.ItemId && !val.IsDestroying && !((NetworkBehaviour)val).IsDeinitializing)
			{
				_isBulkFeeding = true;
				try
				{
					EatItemDirect(item.Npc, item.Quest, item.QuestIndex, val);
				}
				finally
				{
					_isBulkFeeding = false;
				}
			}
			if (item.Remaining > 1)
			{
				item.Remaining--;
				_bulkQueue.Enqueue(item);
			}
		}
	}

	private static Item PopStack(PlayerInventory inv, byte slot)
	{
		if (_popServerStack == null)
		{
			return null;
		}
		try
		{
			object? obj = _popServerStack.Invoke(null, new object[2] { inv, slot });
			return (Item)((obj is Item) ? obj : null);
		}
		catch
		{
			return null;
		}
	}

	private static Item SlotItem(PlayerInventory inv, byte slot)
	{
		try
		{
			if (inv._items == null)
			{
				return null;
			}
			return inv._items[slot];
		}
		catch
		{
			return null;
		}
	}

	private static int StackCount(PlayerInventory inv, byte slot)
	{
		if (_getStackCount == null)
		{
			return 0;
		}
		try
		{
			return (int)_getStackCount.Invoke(null, new object[2] { inv, slot });
		}
		catch
		{
			return 0;
		}
	}

	private static void EatItemDirect(NPC npc, NPCQuest quest, byte questIndex, Item item)
	{
		if (_eatItem == null)
		{
			_eatItem = AccessTools.Method(typeof(NPC), "EatItem", (Type[])null, (Type[])null);
		}
		_eatItem.Invoke(npc, new object[3] { quest, questIndex, item });
	}
}