Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ShiftFillFromStorage v1.0.0
ShiftFillFromStorage.dll
Decompiled 11 hours agousing System; using System.Collections; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("ShiftFillFromStorage")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ShiftFillFromStorage")] [assembly: AssemblyTitle("ShiftFillFromStorage")] [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 ShiftFillFromStorage { [BepInPlugin("pieter.valheim.shiftfillfromstorage", "Shift Fill From Storage", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string Guid = "pieter.valheim.shiftfillfromstorage"; public const string Name = "Shift Fill From Storage"; public const string Version = "1.0.0"; private const string LcfspGuid = "LuminairPrime.valheim.localcraftfromstorageprime"; private const string BetterSmelterGuid = "com.alan.bettersmelter"; private const int MaxItemsPerFill = 200; private static Plugin _instance; private static bool _filling; private static FieldInfo _inSwitch; private static PropertyInfo _busy; private static PropertyInfo _settings; private static PropertyInfo _dispatchReturned; private static PropertyInfo _enabled; private static PropertyInfo _fuelFromStorage; private static PropertyInfo _oreFromStorage; private static PropertyInfo _refuelDistance; private static MethodInfo _start; private static MethodInfo _fuelName; private static MethodInfo _fuelRoom; private static MethodInfo _oreRoom; private static MethodInfo _carriesOre; private static MethodInfo _suppliesAny; private static ConstructorInfo _operation; private static ConstructorInfo _fuelSupply; private static ConstructorInfo _oreSupply; private static MethodInfo _betterFuelPrefix; private static MethodInfo _betterOrePrefix; private static ConfigEntry<bool> _fermenterFromStorage; private static readonly ConditionalWeakTable<object, Fermenter> FermenterTargets = new ConditionalWeakTable<object, Fermenter>(); private static MethodInfo _spare; private static MethodInfo _updateCover; private static FieldInfo _hasRoof; private static FieldInfo _exposed; private static bool Busy => (bool)_busy.GetValue(null); private static object Settings => _settings.GetValue(null); private void Awake() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown _instance = this; try { Resolve(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Disabled, Local Craft From Storage Prime internals not found: " + ex.Message)); return; } Harmony val = new Harmony("pieter.valheim.shiftfillfromstorage"); MethodInfo methodInfo = AccessTools.Method(typeof(Smelter), "OnAddFuel", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(Smelter), "OnAddOre", (Type[])null, (Type[])null); _betterFuelPrefix = AccessTools.Method(AccessTools.TypeByName("Smelter_OnAddFuel_BulkPatch"), "Prefix", (Type[])null, (Type[])null); _betterOrePrefix = AccessTools.Method(AccessTools.TypeByName("Smelter_OnAddOre_BulkPatch"), "Prefix", (Type[])null, (Type[])null); if (_betterFuelPrefix != null) { val.Unpatch((MethodBase)methodInfo, _betterFuelPrefix); val.Patch((MethodBase)methodInfo, Hook("BetterFuelWrapper"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } if (_betterOrePrefix != null) { val.Unpatch((MethodBase)methodInfo2, _betterOrePrefix); val.Patch((MethodBase)methodInfo2, Hook("BetterOreWrapper"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, Hook("AddFuelPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, Hook("AddOrePostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _fermenterFromStorage = ((BaseUnityPlugin)this).Config.Bind<bool>("Fermenter", "Fill from storage", true, "Interacting with an empty fermenter while carrying no mead base takes one from a nearby chest."); try { PatchFermenter(val); } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogError((object)("Fermenter from storage disabled: " + ex2.Message)); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Shift-filling smelters now also pulls from nearby chests; fermenters fill from chests."); } private static HarmonyMethod Hook(string name) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown return new HarmonyMethod(typeof(Plugin).GetMethod(name, BindingFlags.Static | BindingFlags.NonPublic)); } private static void Resolve() { Type type = L("SupplyAction"); _inSwitch = Need<FieldInfo>(AccessTools.Field(type, "InSwitch"), "InSwitch"); _fuelName = Need<MethodInfo>(AccessTools.Method(type, "FuelName", (Type[])null, (Type[])null), "FuelName"); _fuelRoom = Need<MethodInfo>(AccessTools.Method(type, "SmelterFuelRoom", (Type[])null, (Type[])null), "SmelterFuelRoom"); _oreRoom = Need<MethodInfo>(AccessTools.Method(type, "SmelterOreRoom", (Type[])null, (Type[])null), "SmelterOreRoom"); _carriesOre = Need<MethodInfo>(AccessTools.Method(type, "CarriesOre", (Type[])null, (Type[])null), "CarriesOre"); _suppliesAny = Need<MethodInfo>(AccessTools.Method(type, "SuppliesAny", (Type[])null, (Type[])null), "SuppliesAny"); Type type2 = L("ContainerAccessService"); _busy = Need<PropertyInfo>(AccessTools.Property(type2, "Busy"), "Busy"); _start = Need<MethodInfo>(AccessTools.Method(type2, "Start", (Type[])null, (Type[])null), "Start"); Type type3 = L("SupplyPaymentOperation"); _operation = Need<ConstructorInfo>(AccessTools.Constructor(type3, new Type[4] { typeof(Player), L("SupplyTarget"), typeof(Vector3), typeof(float) }, false), "SupplyPaymentOperation()"); _dispatchReturned = Need<PropertyInfo>(AccessTools.Property(type3, "DispatchReturned"), "DispatchReturned"); _fuelSupply = Need<ConstructorInfo>(AccessTools.Constructor(L("SmelterFuelSupply"), new Type[2] { typeof(Smelter), typeof(string) }, false), "SmelterFuelSupply()"); _oreSupply = Need<ConstructorInfo>(AccessTools.Constructor(L("SmelterOreSupply"), new Type[1] { typeof(Smelter) }, false), "SmelterOreSupply()"); _settings = Need<PropertyInfo>(AccessTools.Property(L("Plugin"), "Settings"), "Settings"); Type type4 = L("RuntimeSettings"); _enabled = Need<PropertyInfo>(AccessTools.Property(type4, "Enabled"), "Enabled"); _fuelFromStorage = Need<PropertyInfo>(AccessTools.Property(type4, "SmelterFuelFromStorage"), "SmelterFuelFromStorage"); _oreFromStorage = Need<PropertyInfo>(AccessTools.Property(type4, "SmelterOreFromStorage"), "SmelterOreFromStorage"); _refuelDistance = Need<PropertyInfo>(AccessTools.Property(type4, "RefuelDistance"), "RefuelDistance"); static Type L(string name) { return Need<Type>(AccessTools.TypeByName("LocalCraftFromStoragePrime." + name), name); } static T Need<T>(T member, string what) where T : class { return member ?? throw new MissingMemberException(what); } } private static bool ShiftHeld() { if (!ZInput.GetKey((KeyCode)304, true)) { return ZInput.GetKey((KeyCode)303, true); } return true; } private static bool Setting(PropertyInfo p) { object settings = Settings; if (settings != null) { return (bool)p.GetValue(settings); } return false; } private static string FuelName(Smelter s) { return _fuelName.Invoke(null, new object[1] { s.m_fuelItem }) as string; } private static bool FuelRoom(Smelter s) { return (bool)_fuelRoom.Invoke(null, new object[1] { s }); } private static bool OreRoom(Smelter s) { return (bool)_oreRoom.Invoke(null, new object[1] { s }); } private static bool CarriesFuel(Player p, Smelter s) { string text = FuelName(s); if (text != null) { return ((Humanoid)p).GetInventory().HaveItem(text, true); } return false; } private static bool CarriesOre(Player p, Smelter s) { return (bool)_carriesOre.Invoke(null, new object[2] { s, ((Humanoid)p).GetInventory() }); } private static int FuelSpace(Smelter s) { ZNetView component = ((Component)s).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return 0; } return Mathf.Max(0, s.m_maxFuel - Mathf.CeilToInt(component.GetZDO().GetFloat(ZDOVars.s_fuel, 0f))); } private static int OreSpace(Smelter s) { ZNetView component = ((Component)s).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return 0; } return Mathf.Max(0, s.m_maxOre - component.GetZDO().GetInt(ZDOVars.s_queued, 0)); } private static bool BetterFuelWrapper(Switch sw, Humanoid user, ItemData item, Smelter __instance, ref bool __result) { Player val = (Player)(object)((user is Player) ? user : null); if (val != null && item == null && !CarriesFuel(val, __instance)) { return true; } return CallBetter(_betterFuelPrefix, sw, user, item, __instance, ref __result); } private static bool BetterOreWrapper(Switch sw, Humanoid user, ItemData item, Smelter __instance, ref bool __result) { Player val = (Player)(object)((user is Player) ? user : null); if (val != null && item == null && !CarriesOre(val, __instance)) { return true; } return CallBetter(_betterOrePrefix, sw, user, item, __instance, ref __result); } private static bool CallBetter(MethodInfo prefix, Switch sw, Humanoid user, ItemData item, Smelter smelter, ref bool result) { object[] array = new object[5] { sw, user, item, smelter, result }; bool result2 = (bool)prefix.Invoke(null, array); result = (bool)array[4]; return result2; } private static void AddFuelPostfix(Humanoid user, ItemData item, Smelter __instance) { TryFill(user, item, __instance, fuel: true); } private static void AddOrePostfix(Humanoid user, ItemData item, Smelter __instance) { TryFill(user, item, __instance, fuel: false); } private static void TryFill(Humanoid user, ItemData item, Smelter smelter, bool fuel) { if (_filling || item != null || !ShiftHeld() || !(bool)_inSwitch.GetValue(null)) { return; } Player val = (Player)(object)((user is Player) ? user : null); if (val == null || (Object)(object)val != (Object)(object)Player.m_localPlayer || !Setting(_enabled)) { return; } if (fuel) { if (!Setting(_fuelFromStorage) || FuelName(smelter) == null || CarriesFuel(val, smelter)) { return; } } else if (!Setting(_oreFromStorage) || CarriesOre(val, smelter) || !(bool)_suppliesAny.Invoke(null, new object[2] { smelter, Settings })) { return; } int num = (fuel ? FuelSpace(smelter) : OreSpace(smelter)); if (num > 1) { ((MonoBehaviour)_instance).StartCoroutine(Fill(val, smelter, fuel, Mathf.Min(num - 1, 200))); } } private static void PatchFermenter(Harmony harmony) { Type type = AccessTools.TypeByName("LocalCraftFromStoragePrime.SmelterOreSupply"); _spare = AccessTools.Method(AccessTools.TypeByName("LocalCraftFromStoragePrime.SupplyTarget"), "Spare", (Type[])null, (Type[])null) ?? throw new MissingMemberException("SupplyTarget.Spare"); _updateCover = AccessTools.Method(typeof(Fermenter), "UpdateCover", new Type[2] { typeof(float), typeof(bool) }, (Type[])null) ?? throw new MissingMemberException("Fermenter.UpdateCover"); _hasRoof = AccessTools.Field(typeof(Fermenter), "m_hasRoof") ?? throw new MissingMemberException("Fermenter.m_hasRoof"); _exposed = AccessTools.Field(typeof(Fermenter), "m_exposed") ?? throw new MissingMemberException("Fermenter.m_exposed"); Redirect(AccessTools.PropertyGetter(type, "Station"), "StationPrefix"); Redirect(AccessTools.PropertyGetter(type, "MissingMessage"), "MissingPrefix"); Redirect(AccessTools.Method(type, "CanReceive", (Type[])null, (Type[])null), "CanReceivePrefix"); Redirect(AccessTools.Method(type, "Carried", (Type[])null, (Type[])null), "CarriedPrefix"); Redirect(AccessTools.Method(type, "Pick", (Type[])null, (Type[])null), "PickPrefix"); Redirect(AccessTools.Method(type, "Send", (Type[])null, (Type[])null), "SendPrefix"); Redirect(AccessTools.Method(type, "ShowFeedback", (Type[])null, (Type[])null), "FeedbackPrefix"); harmony.Patch((MethodBase)AccessTools.Method(typeof(Fermenter), "Interact", (Type[])null, (Type[])null), Hook("FermenterInteractPrefix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); void Redirect(MethodInfo method, string hook) { if (method == null) { throw new MissingMemberException("SmelterOreSupply member for " + hook); } harmony.Patch((MethodBase)method, Hook(hook), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } private static bool FermenterEmpty(Fermenter f) { ZNetView val = (((Object)(object)f == (Object)null) ? null : ((Component)f).GetComponent<ZNetView>()); if ((Object)(object)val != (Object)null && val.IsValid()) { return val.GetZDO().GetInt(ZDOVars.s_content, 0) == 0; } return false; } private static ItemData CarriedMeadBase(Fermenter f, Inventory inventory) { foreach (ItemConversion item2 in f.m_conversion) { ItemData item = inventory.GetItem(item2.m_from.m_itemData.m_shared.m_name, -1, false); if (item != null) { return item; } } return null; } private static bool FermenterInteractPrefix(Fermenter __instance, Humanoid user, bool hold, ref bool __result) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) if (!hold && _fermenterFromStorage.Value) { Player val = (Player)(object)((user is Player) ? user : null); if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer)) { if (!Setting(_enabled) || Busy || !FermenterEmpty(__instance)) { return true; } if (!PrivateArea.CheckAccess(((Component)__instance).transform.position, 0f, false, false)) { return true; } _updateCover.Invoke(__instance, new object[2] { 0f, true }); if (!(bool)_hasRoof.GetValue(__instance) || (bool)_exposed.GetValue(__instance)) { return true; } if (CarriedMeadBase(__instance, ((Humanoid)val).GetInventory()) != null) { return true; } object obj = _oreSupply.Invoke(new object[1]); FermenterTargets.Add(obj, __instance); float num = (float)_refuelDistance.GetValue(Settings); _start.Invoke(null, new object[1] { _operation.Invoke(new object[4] { val, obj, ((Component)__instance).transform.position, num }) }); __result = true; return false; } } return true; } private static bool StationPrefix(object __instance, ref Component __result) { if (!FermenterTargets.TryGetValue(__instance, out var value)) { return true; } __result = (Component)(object)value; return false; } private static bool MissingPrefix(object __instance, ref string __result) { if (!FermenterTargets.TryGetValue(__instance, out var _)) { return true; } __result = "$msg_noprocessableitems"; return false; } private static bool CanReceivePrefix(object __instance, ref bool __result) { if (!FermenterTargets.TryGetValue(__instance, out var value)) { return true; } __result = FermenterEmpty(value); return false; } private static bool CarriedPrefix(object __instance, Inventory inventory, ref bool __result) { if (!FermenterTargets.TryGetValue(__instance, out var value)) { return true; } __result = CarriedMeadBase(value, inventory) != null; return false; } private static bool PickPrefix(object __instance, object[] __args, ref ItemData __result) { if (!FermenterTargets.TryGetValue(__instance, out var value)) { return true; } __result = null; foreach (ItemConversion item in value.m_conversion) { object? obj = _spare.Invoke(null, new object[3] { __args[0], item.m_from.m_itemData.m_shared.m_name, __args[1] }); ItemData val = (ItemData)((obj is ItemData) ? obj : null); if ((Object)(object)val?.m_dropPrefab != (Object)null) { __result = val; break; } } return false; } private static bool SendPrefix(object __instance, ZNetView view, string prefab, bool cheated) { if (!FermenterTargets.TryGetValue(__instance, out var _)) { return true; } view.InvokeRPC("RPC_AddItem", new object[2] { StringExtensionMethods.GetStableHashCode(prefab), cheated }); return false; } private static bool FeedbackPrefix(object __instance, Player player, string name) { if (!FermenterTargets.TryGetValue(__instance, out var _)) { return true; } ((Character)player).Message((MessageType)2, "$msg_added " + name, 0, (Sprite)null, false); return false; } private static IEnumerator Fill(Player player, Smelter smelter, bool fuel, int remaining) { _filling = true; try { while (Busy) { yield return null; } Vector3 origin = ((Component)smelter).transform.position; float radius = (float)_refuelDistance.GetValue(Settings); while (remaining > 0 && (Object)(object)smelter != (Object)null && (Object)(object)player == (Object)(object)Player.m_localPlayer && !((Character)player).IsDead() && (fuel ? FuelRoom(smelter) : OreRoom(smelter)) && !(fuel ? CarriesFuel(player, smelter) : CarriesOre(player, smelter))) { object obj = (fuel ? _fuelSupply.Invoke(new object[2] { smelter, FuelName(smelter) }) : _oreSupply.Invoke(new object[1] { smelter })); object operation = _operation.Invoke(new object[4] { player, obj, origin, radius }); _start.Invoke(null, new object[1] { operation }); yield return null; while (Busy) { yield return null; } if ((bool)_dispatchReturned.GetValue(operation)) { remaining--; continue; } break; } } finally { _filling = false; } } } }