Decompiled source of ValheimQuickFill v1.1.1

plugins/ValheimQuickFill.dll

Decompiled a day 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 HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ValheimQuickFill")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.1.0")]
[assembly: AssemblyInformationalVersion("1.1.1+44a5fd52608f95e7cc247f911745d8bf9b9898a2")]
[assembly: AssemblyProduct("ValheimQuickFill")]
[assembly: AssemblyTitle("ValheimQuickFill")]
[assembly: AssemblyVersion("1.1.1.0")]
namespace ValheimQuickFill;

[BepInPlugin("local.valheim.quickfill", "ValheimQuickFill", "1.1.1")]
public class QuickFillPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "local.valheim.quickfill";

	public const string PluginName = "ValheimQuickFill";

	public const string PluginVersion = "1.1.1";

	internal static ManualLogSource Log;

	private static ConfigEntry<string> _fillModifierName;

	internal static ConfigEntry<bool> DebugLogging;

	private static List<KeyCode> _modifierKeys = new List<KeyCode> { (KeyCode)306 };

	private Harmony _harmony;

	private void Awake()
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		_fillModifierName = ((BaseUnityPlugin)this).Config.Bind<string>("General", "FillModifier", "LeftControl", "触发一键装满需要按住的修饰键。可用值:Control / Shift / Alt(任一侧),或具体 KeyCode 名(LeftControl、RightControl、LeftShift、LeftAlt 等),也可用逗号分隔多个键(任一按下即触发)。");
		RebuildKeyList();
		DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "DebugLogging", false, "开启后会在日志中输出补丁命中细节,用于排查问题。正常游玩建议关闭。");
		_harmony = new Harmony("local.valheim.quickfill");
		_harmony.PatchAll(typeof(Patches));
		LogPatchStatus();
		Log.LogInfo((object)"ValheimQuickFill loaded (v1.1.1)");
	}

	private static void LogPatchStatus()
	{
		string[] array = new string[2] { "OnAddOre", "OnAddFuel" };
		foreach (string text in array)
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(Smelter), text, (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				Log.LogError((object)("[QuickFill][diag] Smelter." + text + " not found!"));
				continue;
			}
			int valueOrDefault = (Harmony.GetPatchInfo((MethodBase)methodInfo)?.Prefixes?.Count).GetValueOrDefault();
			Log.LogInfo((object)$"[QuickFill][diag] Smelter.{text}: prefixes={valueOrDefault}");
		}
	}

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

	internal unsafe static void RebuildKeyList()
	{
		_modifierKeys = ParseKeys(_fillModifierName?.Value);
		Log.LogInfo((object)("[QuickFill] modifier keys = " + string.Join(", ", _modifierKeys.ConvertAll((KeyCode k) => ((object)(*(KeyCode*)(&k))/*cast due to .constrained prefix*/).ToString()).ToArray())));
	}

	private static List<KeyCode> ParseKeys(string raw)
	{
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		List<KeyCode> list = new List<KeyCode>();
		if (string.IsNullOrEmpty(raw))
		{
			raw = "LeftControl";
		}
		string[] array = raw.Split(',');
		for (int i = 0; i < array.Length; i++)
		{
			string text = array[i].Trim();
			if (text.Length == 0)
			{
				continue;
			}
			switch (text.ToLowerInvariant())
			{
			case "control":
			case "ctrl":
				list.Add((KeyCode)306);
				list.Add((KeyCode)305);
				continue;
			case "shift":
				list.Add((KeyCode)304);
				list.Add((KeyCode)303);
				continue;
			case "alt":
				list.Add((KeyCode)308);
				list.Add((KeyCode)307);
				continue;
			}
			if (Enum.TryParse<KeyCode>(text, ignoreCase: true, out KeyCode result))
			{
				list.Add(result);
			}
		}
		if (list.Count == 0)
		{
			list.Add((KeyCode)306);
		}
		return list;
	}

	internal static bool ModifierHeld()
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		foreach (KeyCode modifierKey in _modifierKeys)
		{
			if (ZInput.GetKey(modifierKey, false))
			{
				return true;
			}
		}
		return false;
	}
}
internal static class Patches
{
	private static readonly FieldInfo FZNview = AccessTools.Field(typeof(Smelter), "m_nview");

	private static readonly MethodInfo MFindCookable = AccessTools.Method(typeof(Smelter), "FindCookableItem", (Type[])null, (Type[])null);

	private static readonly MethodInfo MGetQueueSize = AccessTools.Method(typeof(Smelter), "GetQueueSize", (Type[])null, (Type[])null);

	private static readonly MethodInfo MIsItemAllowedName = AccessTools.Method(typeof(Smelter), "IsItemAllowed", new Type[1] { typeof(string) }, (Type[])null);

	private const float TakeoverCooldown = 0.25f;

	private static float _lastOreTakeover = -100f;

	private static float _lastFuelTakeover = -100f;

	private static int _oreDiag;

	private static int _fuelDiag;

	private static ZNetView NView(Smelter s)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Expected O, but got Unknown
		return (ZNetView)FZNview.GetValue(s);
	}

	private static int QueueSize(Smelter s)
	{
		return (int)MGetQueueSize.Invoke(s, null);
	}

	[HarmonyPatch(typeof(Smelter), "OnAddOre")]
	[HarmonyPrefix]
	private static bool OnAddOrePrefix(Smelter __instance, Switch sw, Humanoid user, ItemData item, ref bool __result)
	{
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Expected O, but got Unknown
		bool flag = QuickFillPlugin.ModifierHeld();
		if (QuickFillPlugin.DebugLogging.Value && _oreDiag < 5)
		{
			_oreDiag++;
			QuickFillPlugin.Log.LogInfo((object)$"[QuickFill] OnAddOre hit, player={user is Player}, modifier={flag}");
		}
		if (!(user is Player) || !flag)
		{
			return true;
		}
		if (Time.time - _lastOreTakeover < 0.25f)
		{
			__result = true;
			return false;
		}
		_lastOreTakeover = Time.time;
		Inventory inventory = user.GetInventory();
		if (inventory == null || __instance.m_conversion == null || __instance.m_conversion.Count == 0)
		{
			__result = false;
			return false;
		}
		int num = __instance.m_maxOre - QueueSize(__instance);
		if (num <= 0)
		{
			((Character)user).Message((MessageType)2, "$msg_itsfull", 0, (Sprite)null, false);
			__result = false;
			return false;
		}
		int i;
		for (i = 0; i < num; i++)
		{
			ItemData val = (ItemData)MFindCookable.Invoke(__instance, new object[1] { inventory });
			if (val == null || !(bool)MIsItemAllowedName.Invoke(__instance, new object[1] { ((Object)val.m_dropPrefab).name }))
			{
				break;
			}
			inventory.RemoveItem(val, 1);
			NView(__instance).InvokeRPC("RPC_AddOre", new object[2]
			{
				((Object)val.m_dropPrefab).name,
				val.m_cheated
			});
		}
		if (i > 0)
		{
			((Character)user).Message((MessageType)2, Localization.instance.Localize("$msg_added") + " x" + i, 0, (Sprite)null, false);
		}
		else
		{
			((Character)user).Message((MessageType)2, "$msg_noprocessableitems", 0, (Sprite)null, false);
		}
		__result = i > 0;
		return false;
	}

	[HarmonyPatch(typeof(Smelter), "OnAddFuel")]
	[HarmonyPrefix]
	private static bool OnAddFuelPrefix(Smelter __instance, Switch sw, Humanoid user, ItemData item, ref bool __result)
	{
		bool flag = QuickFillPlugin.ModifierHeld();
		if (QuickFillPlugin.DebugLogging.Value && _fuelDiag < 5)
		{
			_fuelDiag++;
			QuickFillPlugin.Log.LogInfo((object)$"[QuickFill] OnAddFuel hit, player={user is Player}, modifier={flag}");
		}
		if (!(user is Player) || !flag)
		{
			return true;
		}
		if (Time.time - _lastFuelTakeover < 0.25f)
		{
			__result = true;
			return false;
		}
		_lastFuelTakeover = Time.time;
		if ((Object)(object)__instance.m_fuelItem == (Object)null)
		{
			__result = false;
			return false;
		}
		string name = __instance.m_fuelItem.m_itemData.m_shared.m_name;
		Inventory inventory = user.GetInventory();
		if (inventory == null)
		{
			__result = false;
			return false;
		}
		float fuel = GetFuel(__instance);
		int maxFuel = __instance.m_maxFuel;
		if (maxFuel > 0 && fuel >= (float)maxFuel - 0.0001f)
		{
			((Character)user).Message((MessageType)2, "$msg_itsfull", 0, (Sprite)null, false);
			__result = false;
			return false;
		}
		int num = 0;
		while ((maxFuel == 0 || fuel + (float)num < (float)maxFuel - 0.0001f) && inventory.HaveItem(name, true))
		{
			inventory.RemoveItem(name, 1, -1, true);
			NView(__instance).InvokeRPC("RPC_AddFuel", Array.Empty<object>());
			num++;
			if (maxFuel == 0)
			{
				break;
			}
		}
		if (num > 0)
		{
			((Character)user).Message((MessageType)2, Localization.instance.Localize("$msg_added") + " " + Localization.instance.Localize(name) + " x" + num, 0, (Sprite)null, false);
			__result = true;
		}
		else
		{
			((Character)user).Message((MessageType)2, Localization.instance.Localize("$msg_donthaveany") + " " + Localization.instance.Localize(name), 0, (Sprite)null, false);
			__result = false;
		}
		return false;
	}

	private static float GetFuel(Smelter s)
	{
		ZNetView val = NView(s);
		if ((Object)(object)val == (Object)null || !val.IsValid())
		{
			return 0f;
		}
		return val.GetZDO().GetFloat(ZDOVars.s_fuel, 0f);
	}
}