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 _fillModifierName; internal static ConfigEntry DebugLogging; private static List _modifierKeys = new List { (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("General", "FillModifier", "LeftControl", "触发一键装满需要按住的修饰键。可用值:Control / Shift / Alt(任一侧),或具体 KeyCode 名(LeftControl、RightControl、LeftShift、LeftAlt 等),也可用逗号分隔多个键(任一按下即触发)。"); RebuildKeyList(); DebugLogging = ((BaseUnityPlugin)this).Config.Bind("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 ParseKeys(string raw) { //IL_00d0: Unknown result type (might be due to invalid IL or missing references) List list = new List(); 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(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()); 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); } }