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 KMartBoysMustHaveMod v1.13.1
K-MartBoysMustHaveMod.dll
Decompiled 2 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Networking; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] namespace KMartBoysMustHaveMod; [HarmonyPatch(typeof(CraftingStation), "Interact")] internal static class CraftingStation_Interact_AutoRepair_Patch { private static readonly MethodInfo CanRepair = AccessTools.Method(typeof(InventoryGui), "CanRepair", new Type[1] { typeof(ItemData) }, (Type[])null); private static void Postfix(CraftingStation __instance, Humanoid user, bool repeat) { //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) try { if (repeat || !KMartBoysPlugin.ModEnabled.Value || !KMartBoysPlugin.AutoRepairEnabled.Value || KMartBoysPlugin.OtherRepairModLoaded) { return; } Player val = (Player)(object)((user is Player) ? user : null); if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer || (Object)(object)val.GetCurrentCraftingStation() != (Object)(object)__instance) { return; } InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance == (Object)null || CanRepair == null) { return; } List<ItemData> list = new List<ItemData>(); ((Humanoid)val).GetInventory().GetWornItems(list); int num = 0; foreach (ItemData item in list) { if (item != null && (bool)CanRepair.Invoke(instance, new object[1] { item })) { float maxDurability = item.GetMaxDurability(); if (!(item.m_durability >= maxDurability)) { item.m_durability = maxDurability; num++; } } } if (num > 0) { if (__instance.m_repairItemDoneEffects != null) { __instance.m_repairItemDoneEffects.Create(((Component)__instance).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); } if (KMartBoysPlugin.AutoRepairShowMessage.Value) { ((Character)val).Message((MessageType)2, "Repaired " + num + " item" + ((num == 1) ? "" : "s"), 0, (Sprite)null, false); } } } catch (Exception ex) { KMartBoysPlugin.LogOnce("autorepair", "Auto-repair failed: " + ex.Message); } } } public enum ClockAnchor { TopLeft, TopCenter, TopRight, BottomLeft, BottomCenter, BottomRight } internal static class ClockHud { private const string ObjectName = "KMartBoys_Clock"; private const float UpdateInterval = 0.25f; private static TextMeshProUGUI _text; private static float _nextUpdate; private static readonly Dictionary<string, string> WeatherNames = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { { "Clear", "Clear" }, { "Twilight_Clear", "Clear" }, { "Heath clear", "Clear" }, { "nofogts", "Clear" }, { "Mistlands_clear", "Clear" }, { "Misty", "Misty" }, { "Ashlands_misty", "Misty" }, { "DeepForest Mist", "Forest Mist" }, { "Darklands_dark", "Dark" }, { "Rain", "Rain" }, { "LightRain", "Light Rain" }, { "Mistlands_rain", "Rain" }, { "SwampRain", "Swamp Rain" }, { "ThunderStorm", "Thunderstorm" }, { "Mistlands_thunder", "Thunderstorm" }, { "Snow", "Snow" }, { "Twilight_Snow", "Snow" }, { "SnowStorm", "Snowstorm" }, { "Twilight_SnowStorm", "Snowstorm" }, { "Ashrain", "Ash Rain" }, { "Ashlands_ashrain", "Ash Rain" }, { "Ashlands_storm", "Ash Storm" }, { "Ashlands_CinderRain", "Cinder Rain" }, { "Eikthyr", "Boss Storm" }, { "GDKing", "Eerie" }, { "Bonemass", "Toxic" }, { "Moder", "Blizzard" }, { "GoblinKing", "Ominous" }, { "Queen", "Ominous" }, { "Fader", "Inferno" }, { "Crypt", "Crypt" }, { "SunkenCrypt", "Sunken Crypt" }, { "Caves", "Cave" }, { "InfectedMine", "Infested Mine" } }; public static void Tick() { try { if (!KMartBoysPlugin.ModEnabled.Value || !KMartBoysPlugin.ClockEnabled.Value || !((Object)(object)Hud.instance != (Object)null) || !((Object)(object)Hud.instance.m_rootObject != (Object)null) || !((Object)(object)EnvMan.instance != (Object)null) || !((Object)(object)Player.m_localPlayer != (Object)null)) { if ((Object)(object)_text != (Object)null && ((Component)_text).gameObject.activeSelf) { ((Component)_text).gameObject.SetActive(false); } return; } if ((Object)(object)_text == (Object)null) { Create(); } if (!((Object)(object)_text == (Object)null)) { if (!((Component)_text).gameObject.activeSelf) { ((Component)_text).gameObject.SetActive(true); } if (!(Time.unscaledTime < _nextUpdate)) { _nextUpdate = Time.unscaledTime + 0.25f; ApplyLayout(); ((TMP_Text)_text).text = BuildText(); } } } catch (Exception ex) { KMartBoysPlugin.LogOnce("clock", "Clock error: " + ex.Message); } } private static void Create() { //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) Transform transform = Hud.instance.m_rootObject.transform; Transform val = transform.Find("KMartBoys_Clock"); if ((Object)(object)val != (Object)null) { _text = ((Component)val).GetComponent<TextMeshProUGUI>(); } else { _text = CreateHudText("KMartBoys_Clock", transform); } if (!((Object)(object)_text == (Object)null)) { GameObject gameObject = ((Component)_text).gameObject; ((Graphic)_text).raycastTarget = false; ((TMP_Text)_text).richText = true; ((TMP_Text)_text).enableAutoSizing = false; ((TMP_Text)_text).overflowMode = (TextOverflowModes)0; ((RectTransform)gameObject.transform).sizeDelta = new Vector2(600f, 40f); ApplyLayout(); } } internal static TextMeshProUGUI CreateHudText(string name, Transform parent) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name); val.SetActive(false); val.AddComponent<RectTransform>(); val.transform.SetParent(parent, false); TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>(); TMP_Text val3 = (TMP_Text)(object)(((Object)(object)Hud.instance != (Object)null) ? Hud.instance.m_hoverName : null); if ((Object)(object)val3 != (Object)null && (Object)(object)val3.font != (Object)null) { ((TMP_Text)val2).font = val3.font; ((TMP_Text)val2).fontSharedMaterial = val3.fontSharedMaterial; } val.SetActive(true); return val2; } private static void ApplyLayout() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) RectTransform val = (RectTransform)((TMP_Text)_text).transform; Vector2 val2 = default(Vector2); TextAlignmentOptions alignment; switch (KMartBoysPlugin.ClockPosition.Value) { case ClockAnchor.TopLeft: ((Vector2)(ref val2))..ctor(0f, 1f); alignment = (TextAlignmentOptions)257; break; case ClockAnchor.TopRight: ((Vector2)(ref val2))..ctor(1f, 1f); alignment = (TextAlignmentOptions)260; break; case ClockAnchor.BottomLeft: ((Vector2)(ref val2))..ctor(0f, 0f); alignment = (TextAlignmentOptions)1025; break; case ClockAnchor.BottomCenter: ((Vector2)(ref val2))..ctor(0.5f, 0f); alignment = (TextAlignmentOptions)1026; break; case ClockAnchor.BottomRight: ((Vector2)(ref val2))..ctor(1f, 0f); alignment = (TextAlignmentOptions)1028; break; default: ((Vector2)(ref val2))..ctor(0.5f, 1f); alignment = (TextAlignmentOptions)258; break; } val.anchorMin = val2; val.anchorMax = val2; val.pivot = val2; val.anchoredPosition = new Vector2(KMartBoysPlugin.ClockOffsetX.Value, KMartBoysPlugin.ClockOffsetY.Value); ((TMP_Text)_text).alignment = alignment; ((TMP_Text)_text).fontSize = KMartBoysPlugin.ClockFontSize.Value; ((Graphic)_text).color = KMartBoysPlugin.ClockColor.Value; } private static string BuildText() { EnvMan instance = EnvMan.instance; int num = Mathf.FloorToInt(Mathf.Repeat(instance.GetDayFraction(), 1f) * 24f * 60f); int num2 = Mathf.Max(1, KMartBoysPlugin.ClockMinuteStep.Value); int num3 = num - num % num2; int num4 = num3 / 60 % 24; int num5 = num3 % 60; int num6 = ((num4 % 12 == 0) ? 12 : (num4 % 12)); string text = ((num4 < 12) ? "AM" : "PM"); string newValue = num6 + ":" + num5.ToString("00") + " " + text; EnvSetup currentEnvironment = instance.GetCurrentEnvironment(); string newValue2 = ((currentEnvironment != null) ? Friendly(currentEnvironment.m_name) : ""); string newValue3 = Conditions(currentEnvironment, EnvMan.IsNight()); return (KMartBoysPlugin.ClockFormat.Value ?? "{time}").Replace("\\n", "\n").Replace("{time}", newValue).Replace("{weather}", newValue2) .Replace("{conditions}", newValue3) .Replace("{day}", instance.GetDay().ToString()) .Replace("()", "") .Replace("[]", "") .Trim(); } private static string Conditions(EnvSetup setup, bool night) { if (setup == null) { return ""; } List<string> list = new List<string>(2); if (setup.m_isFreezing || (night && setup.m_isFreezingAtNight)) { list.Add("Freezing"); } else if (setup.m_isCold || (night && setup.m_isColdAtNight)) { list.Add("Cold"); } if (setup.m_isWet) { list.Add("Wet"); } return string.Join(", ", list.ToArray()); } private static string Friendly(string raw) { if (string.IsNullOrEmpty(raw)) { return ""; } if (WeatherNames.TryGetValue(raw, out var value)) { return value; } string text = raw; int num = text.LastIndexOf('_'); if (num >= 0 && num < text.Length - 1) { text = text.Substring(num + 1); } StringBuilder stringBuilder = new StringBuilder(text.Length + 4); for (int i = 0; i < text.Length; i++) { char c = text[i]; if (i > 0 && char.IsUpper(c) && char.IsLower(text[i - 1])) { stringBuilder.Append(' '); } stringBuilder.Append((i == 0) ? char.ToUpperInvariant(c) : c); } return stringBuilder.ToString(); } } internal sealed class ConfigurationManagerAttributes { public bool? ShowRangeAsPercent; public Action<ConfigEntryBase> CustomDrawer; public bool? Browsable; public string Category; public object DefaultValue; public bool? HideDefaultButton; public bool? HideSettingName; public string Description; public string DispName; public int? Order; public bool? ReadOnly; public bool? IsAdvanced; public Func<object, string> ObjToStr; public Func<string, object> StrToObj; } internal static class ContainerSource { private static readonly FieldRef<Container, ZNetView> ContainerNView = AccessTools.FieldRefAccess<Container, ZNetView>("m_nview"); private static readonly FieldRef<InventoryGui, Container> GuiCurrentContainer = AccessTools.FieldRefAccess<InventoryGui, Container>("m_currentContainer"); private static readonly MethodInfo ContainerCheckAccess = AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null); private const float CacheSeconds = 1f; private static readonly List<Container> Cached = new List<Container>(); private static float _cachedAt = -999f; private static readonly Dictionary<string, int> CountMemo = new Dictionary<string, int>(); private static int _memoFrame = -1; public static List<Container> GetContainers() { if (Time.unscaledTime - _cachedAt >= 1f) { Rebuild(); } for (int num = Cached.Count - 1; num >= 0; num--) { if ((Object)(object)Cached[num] == (Object)null) { Cached.RemoveAt(num); } } return Cached; } public static void Invalidate() { _cachedAt = -999f; CountMemo.Clear(); } private static void Rebuild() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) _cachedAt = Time.unscaledTime; CountMemo.Clear(); Cached.Clear(); Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { Cached.AddRange(FindAround(((Component)localPlayer).transform.position, KMartBoysPlugin.CraftRadius.Value)); } } private static bool IsUsable(Container c, long playerId, Container openContainer) { //IL_00e9: Unknown result type (might be due to invalid IL or missing references) ZNetView val = ContainerNView.Invoke(c); if ((Object)(object)val == (Object)null || !val.IsValid()) { return false; } if (c.GetInventory() == null) { return false; } if ((Object)(object)((Component)c).GetComponentInParent<TombStone>() != (Object)null) { return false; } if (c.IsInUse() && (Object)(object)c != (Object)(object)openContainer) { return false; } if (KMartBoysPlugin.CraftIgnoreMoving.Value && ((Object)(object)c.m_wagon != (Object)null || (Object)(object)((Component)c).GetComponentInParent<Vagon>() != (Object)null || (Object)(object)((Component)c).GetComponentInParent<Ship>() != (Object)null)) { return false; } if (KMartBoysPlugin.CraftOnlyPlayerBuilt.Value) { Piece componentInParent = ((Component)c).GetComponentInParent<Piece>(); if ((Object)(object)componentInParent == (Object)null || !componentInParent.IsPlacedByPlayer()) { return false; } } if (ContainerCheckAccess != null && !(bool)ContainerCheckAccess.Invoke(c, new object[1] { playerId })) { return false; } if (c.m_checkGuardStone && !PrivateArea.CheckAccess(((Component)c).transform.position, 0f, false, false)) { return false; } return true; } public static int Count(string name, int quality, bool matchWorldLevel) { if (string.IsNullOrEmpty(name)) { return 0; } if (_memoFrame != Time.frameCount) { _memoFrame = Time.frameCount; CountMemo.Clear(); } string key = name + "|" + quality + "|" + (matchWorldLevel ? "1" : "0"); if (CountMemo.TryGetValue(key, out var value)) { return value; } int num = 0; foreach (Container container in GetContainers()) { Inventory inventory = container.GetInventory(); if (inventory != null) { num += inventory.CountItems(name, quality, matchWorldLevel); } } CountMemo[key] = num; return num; } public static bool Have(string name, bool matchWorldLevel) { foreach (Container container in GetContainers()) { Inventory inventory = container.GetInventory(); if (inventory != null && inventory.HaveItem(name, matchWorldLevel)) { return true; } } return false; } public static int Remove(string name, int amount, int itemQuality, bool worldLevelBased) { return Remove(GetContainers(), name, amount, itemQuality, worldLevelBased); } public static int Remove(List<Container> containers, string name, int amount, int itemQuality, bool worldLevelBased, int keepPerContainer = 0) { int num = amount; foreach (Container container in containers) { if (num <= 0) { break; } if ((Object)(object)container == (Object)null) { continue; } Inventory inventory = container.GetInventory(); if (inventory != null) { int num2 = inventory.CountItems(name, itemQuality, worldLevelBased); int num3 = num2 - Math.Max(0, keepPerContainer); if (num3 > 0 && ClaimOwnership(container)) { int num4 = Math.Min(num3, num); inventory.RemoveItem(name, num4, itemQuality, worldLevelBased); int val = num2 - inventory.CountItems(name, itemQuality, worldLevelBased); num -= Math.Max(0, val); } } } CountMemo.Clear(); StorageStock.Invalidate(); return amount - num; } public static bool ClaimOwnership(Container c) { ZNetView val = ContainerNView.Invoke(c); if ((Object)(object)val == (Object)null || !val.IsValid()) { return false; } if (!val.IsOwner()) { val.ClaimOwnership(); } return val.IsOwner(); } public static List<Container> FindAround(Vector3 origin, float radius) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) List<Container> list = new List<Container>(); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return list; } long playerID = localPlayer.GetPlayerID(); Container openContainer = (((Object)(object)InventoryGui.instance != (Object)null) ? GuiCurrentContainer.Invoke(InventoryGui.instance) : null); List<KeyValuePair<float, Container>> list2 = new List<KeyValuePair<float, Container>>(); Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0); foreach (Container val in array) { try { if (!((Object)(object)val == (Object)null) && ((Behaviour)val).isActiveAndEnabled) { float num = Vector3.Distance(origin, ((Component)val).transform.position); if (!(num > radius) && IsUsable(val, playerID, openContainer)) { list2.Add(new KeyValuePair<float, Container>(num, val)); } } } catch (Exception ex) { KMartBoysPlugin.LogOnce("containersource2", "Skipped a container while scanning: " + ex.Message); } } list2.Sort((KeyValuePair<float, Container> a, KeyValuePair<float, Container> b) => a.Key.CompareTo(b.Key)); foreach (KeyValuePair<float, Container> item in list2) { list.Add(item.Value); } return list; } } internal static class CraftScope { public static int CountDepth; public static int ConsumeDepth; public static bool CraftingEnabled { get { if (KMartBoysPlugin.ModEnabled.Value && KMartBoysPlugin.CraftEnabled.Value) { return !KMartBoysPlugin.OtherCraftModLoaded; } return false; } } public static bool BuildingEnabled { get { if (CraftingEnabled) { return KMartBoysPlugin.CraftAllowBuilding.Value; } return false; } } public static bool IsLocalPlayer(Player p) { if ((Object)(object)p != (Object)null) { return (Object)(object)p == (Object)(object)Player.m_localPlayer; } return false; } public static bool IsLocalInventory(Inventory inv) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && inv != null) { return inv == ((Humanoid)localPlayer).GetInventory(); } return false; } } [HarmonyPatch(typeof(Player), "HaveRequirementItems")] internal static class Player_HaveRequirementItems_Patch { private static void Prefix(Player __instance, bool discover, out bool __state) { __state = !discover && CraftScope.CraftingEnabled && CraftScope.IsLocalPlayer(__instance); if (__state) { CraftScope.CountDepth++; } } private static Exception Finalizer(Exception __exception, bool __state) { if (__state) { CraftScope.CountDepth--; } return __exception; } } [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Piece), typeof(RequirementMode) })] internal static class Player_HaveRequirementsPiece_Patch { private static void Prefix(Player __instance, RequirementMode mode, out bool __state) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 __state = (int)mode != 1 && CraftScope.BuildingEnabled && CraftScope.IsLocalPlayer(__instance); if (__state) { CraftScope.CountDepth++; } } private static Exception Finalizer(Exception __exception, bool __state) { if (__state) { CraftScope.CountDepth--; } return __exception; } } [HarmonyPatch(typeof(InventoryGui), "SetupRequirement")] internal static class InventoryGui_SetupRequirement_Color_Patch { private static void Prefix(Player player, bool craft, out bool __state) { __state = KMartBoysPlugin.CraftFixColors.Value && (craft ? CraftScope.CraftingEnabled : CraftScope.BuildingEnabled) && CraftScope.IsLocalPlayer(player); if (__state) { CraftScope.CountDepth++; } } private static Exception Finalizer(Exception __exception, bool __state) { if (__state) { CraftScope.CountDepth--; } return __exception; } } [HarmonyPatch(typeof(Inventory), "CountItems")] internal static class Inventory_CountItems_Patch { private static void Postfix(Inventory __instance, string name, int quality, bool matchWorldLevel, ref int __result) { if (CraftScope.CountDepth <= 0 || CraftScope.ConsumeDepth > 0 || !CraftScope.IsLocalInventory(__instance)) { return; } try { __result += ContainerSource.Count(name, quality, matchWorldLevel); } catch (Exception ex) { KMartBoysPlugin.LogOnce("countitems", "Counting container items failed: " + ex.Message); } } } [HarmonyPatch(typeof(Inventory), "HaveItem", new Type[] { typeof(string), typeof(bool) })] internal static class Inventory_HaveItem_Patch { private static void Postfix(Inventory __instance, string name, bool matchWorldLevel, ref bool __result) { if (__result || CraftScope.CountDepth <= 0 || CraftScope.ConsumeDepth > 0 || !CraftScope.IsLocalInventory(__instance)) { return; } try { __result = ContainerSource.Have(name, matchWorldLevel); } catch (Exception ex) { KMartBoysPlugin.LogOnce("haveitem", "Checking container items failed: " + ex.Message); } } } [HarmonyPatch(typeof(Player), "ConsumeResources")] internal static class Player_ConsumeResources_Patch { private static void Prefix(Player __instance, out bool __state) { __state = CraftScope.CraftingEnabled && CraftScope.IsLocalPlayer(__instance); if (__state) { CraftScope.ConsumeDepth++; } } private static Exception Finalizer(Exception __exception, bool __state) { if (__state) { CraftScope.ConsumeDepth--; } return __exception; } } [HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[] { typeof(string), typeof(int), typeof(int), typeof(bool) })] internal static class Inventory_RemoveItemByName_Patch { private static void Prefix(Inventory __instance, string name, ref int amount, int itemQuality, bool worldLevelBased) { if (CraftScope.ConsumeDepth <= 0 || amount <= 0 || !CraftScope.IsLocalInventory(__instance)) { return; } try { int num = __instance.CountItems(name, itemQuality, worldLevelBased); if (num < amount) { int num2 = amount - num; int num3 = ContainerSource.Remove(name, num2, itemQuality, worldLevelBased); if (num3 < num2) { KMartBoysPlugin.LogOnce("consumeshort", "Containers had " + (num2 - num3) + " fewer " + name + " than expected while crafting/building."); } amount = num; } } catch (Exception ex) { KMartBoysPlugin.LogOnce("consume", "Taking materials from containers failed: " + ex.Message); } } } public enum StockDisplayMode { InSlotNumber, LineBelowSlot } internal static class StorageStock { private static readonly FieldRef<Container, ZNetView> ContainerNView = AccessTools.FieldRefAccess<Container, ZNetView>("m_nview"); private static readonly MethodInfo ContainerCheckAccess = AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null); private static readonly Dictionary<string, int> Counts = new Dictionary<string, int>(); private static float _lastScan = -999f; private static int _containersCounted; public static int ContainersCounted => _containersCounted; public static int Get(string itemName) { if (string.IsNullOrEmpty(itemName)) { return 0; } float num = Mathf.Max(0.25f, KMartBoysPlugin.StockRefreshSeconds.Value); if (Time.unscaledTime - _lastScan >= num) { Rescan(); } if (!Counts.TryGetValue(itemName, out var value)) { return 0; } return value; } public static void Invalidate() { _lastScan = -999f; } private static void Rescan() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) _lastScan = Time.unscaledTime; Counts.Clear(); _containersCounted = 0; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } Vector3 position = ((Component)localPlayer).transform.position; float value = KMartBoysPlugin.StockRadius.Value; bool value2 = KMartBoysPlugin.StockOnlyAccessible.Value; long playerID = localPlayer.GetPlayerID(); Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0); foreach (Container val in array) { try { if ((Object)(object)val == (Object)null || !((Behaviour)val).isActiveAndEnabled || (value > 0f && Vector3.Distance(position, ((Component)val).transform.position) > value)) { continue; } ZNetView val2 = ContainerNView.Invoke(val); if ((Object)(object)val2 == (Object)null || !val2.IsValid()) { continue; } Inventory inventory = val.GetInventory(); if (inventory == null || (Object)(object)((Component)val).GetComponentInParent<TombStone>() != (Object)null || (value2 && ((ContainerCheckAccess != null && !(bool)ContainerCheckAccess.Invoke(val, new object[1] { playerID })) || (val.m_checkGuardStone && !PrivateArea.CheckAccess(((Component)val).transform.position, 0f, false, false))))) { continue; } _containersCounted++; foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem != null && allItem.m_shared != null) { string name = allItem.m_shared.m_name; Counts.TryGetValue(name, out var value3); Counts[name] = value3 + allItem.m_stack; } } } catch (Exception ex) { KMartBoysPlugin.LogOnce("stockscan", "Storage scan skipped a container: " + ex.Message); } } } public static int CountInInventory(Player player, string itemName) { if ((Object)(object)player == (Object)null) { return 0; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return 0; } int num = 0; foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem != null && allItem.m_shared != null && allItem.m_shared.m_name == itemName) { num += allItem.m_stack; } } return num; } } [HarmonyPatch(typeof(InventoryGui), "SetupRequirement")] internal static class InventoryGui_SetupRequirement_Patch { private const string LabelName = "KMartBoys_Stock"; private static bool _loggedLayout; private static void Postfix(Transform elementRoot, Requirement req, Player player, bool craft, int quality, int craftMultiplier, bool __result) { //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) try { bool num = __result && KMartBoysPlugin.ModEnabled.Value && KMartBoysPlugin.StockEnabled.Value && (craft || KMartBoysPlugin.StockInBuildMenu.Value) && (Object)(object)elementRoot != (Object)null && req != null && (Object)(object)req.m_resItem != (Object)null && (Object)(object)player != (Object)null; TMP_Text val = FindLabel(elementRoot); bool flag = KMartBoysPlugin.StockDisplay.Value == StockDisplayMode.LineBelowSlot; if ((!num || !flag) && (Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(false); } if (!num) { return; } TMP_Text val2 = FindAmountText(elementRoot); string name = req.m_resItem.m_itemData.m_shared.m_name; int num2 = ReadNeed(val2, req, quality, craftMultiplier); int num3 = StorageStock.CountInInventory(player, name); int num4 = StorageStock.Get(name); int num5 = num3 + num4; if (!flag) { if ((Object)(object)val2 != (Object)null) { val2.text = Format(KMartBoysPlugin.StockAmountFormat.Value, num2, num3, num4, num5); val2.overflowMode = (TextOverflowModes)0; } return; } if ((Object)(object)val == (Object)null) { val = CreateLabel(elementRoot, val2); } if (!((Object)(object)val == (Object)null)) { LogLayoutOnce(elementRoot); val.text = Format(KMartBoysPlugin.StockFormat.Value, num2, num3, num4, num5); ((Graphic)val).color = ((num5 >= num2) ? KMartBoysPlugin.StockEnoughColor.Value : KMartBoysPlugin.StockShortColor.Value); val.fontSize = KMartBoysPlugin.StockFontSize.Value; ((RectTransform)val.transform).anchoredPosition = new Vector2(KMartBoysPlugin.StockOffsetX.Value, KMartBoysPlugin.StockOffsetY.Value); if (!((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(true); } } } catch (Exception ex) { KMartBoysPlugin.LogOnce("stockui", "Crafting stock display error: " + ex); } } internal static TMP_Text FindLabel(Transform elementRoot) { if ((Object)(object)elementRoot == (Object)null) { return null; } Transform val = elementRoot.Find("KMartBoys_Stock"); if (!((Object)(object)val != (Object)null)) { return null; } return ((Component)val).GetComponent<TMP_Text>(); } private static TMP_Text FindAmountText(Transform elementRoot) { Transform val = elementRoot.Find("res_amount"); if (!((Object)(object)val != (Object)null)) { return null; } return ((Component)val).GetComponent<TMP_Text>(); } private static TMP_Text CreateLabel(Transform elementRoot, TMP_Text template) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) GameObject val; if ((Object)(object)template != (Object)null) { val = Object.Instantiate<GameObject>(((Component)template).gameObject, elementRoot, false); for (int num = val.transform.childCount - 1; num >= 0; num--) { Object.Destroy((Object)(object)((Component)val.transform.GetChild(num)).gameObject); } } else { val = ((Component)ClockHud.CreateHudText("KMartBoys_Stock", elementRoot)).gameObject; } ((Object)val).name = "KMartBoys_Stock"; TMP_Text component = val.GetComponent<TMP_Text>(); if ((Object)(object)component == (Object)null) { return null; } RectTransform val2 = (RectTransform)val.transform; val2.anchorMin = new Vector2(0.5f, 0f); val2.anchorMax = new Vector2(0.5f, 0f); val2.pivot = new Vector2(0.5f, 1f); val2.sizeDelta = new Vector2(120f, 40f); ((Transform)val2).localScale = Vector3.one; ((Transform)val2).localRotation = Quaternion.identity; component.alignment = (TextAlignmentOptions)258; component.overflowMode = (TextOverflowModes)0; component.richText = true; ((Graphic)component).raycastTarget = false; component.enableAutoSizing = false; SetNoWrap(component); ((Transform)val2).SetAsLastSibling(); return component; } private static void SetNoWrap(TMP_Text text) { try { PropertyInfo property = typeof(TMP_Text).GetProperty("textWrappingMode"); if (property != null && property.PropertyType.IsEnum) { property.SetValue(text, Enum.ToObject(property.PropertyType, 0), null); return; } PropertyInfo property2 = typeof(TMP_Text).GetProperty("enableWordWrapping"); if (property2 != null) { property2.SetValue(text, false, null); } } catch { } } private static int ReadNeed(TMP_Text amountText, Requirement req, int quality, int craftMultiplier) { if ((Object)(object)amountText != (Object)null && amountText.text != null && amountText.text.IndexOf('/') < 0 && int.TryParse(StripTags(amountText.text), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return result; } return req.GetAmount(quality) * Math.Max(1, craftMultiplier); } private static string StripTags(string s) { if (string.IsNullOrEmpty(s)) { return s; } StringBuilder stringBuilder = new StringBuilder(s.Length); bool flag = false; foreach (char c in s) { switch (c) { case '<': flag = true; continue; case '>': flag = false; continue; } if (!flag) { stringBuilder.Append(c); } } return stringBuilder.ToString().Trim(); } private static string Format(string template, int need, int have, int stored, int total) { if (string.IsNullOrEmpty(template)) { return string.Empty; } return template.Replace("\\n", "\n").Replace("{need}", need.ToString()).Replace("{have}", have.ToString()) .Replace("{stored}", stored.ToString()) .Replace("{total}", total.ToString()) .Replace("{missing}", Math.Max(0, need - total).ToString()); } private static void LogLayoutOnce(Transform elementRoot) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) if (_loggedLayout) { return; } _loggedLayout = true; try { StringBuilder stringBuilder = new StringBuilder("Requirement slot layout: "); stringBuilder.Append(Path(elementRoot)); RectTransform val = (RectTransform)(object)((elementRoot is RectTransform) ? elementRoot : null); Rect rect; if ((Object)(object)val != (Object)null) { StringBuilder stringBuilder2 = stringBuilder.Append(" size="); rect = val.rect; stringBuilder2.Append(((Rect)(ref rect)).size); } for (int i = 0; i < elementRoot.childCount; i++) { Transform child = elementRoot.GetChild(i); RectTransform val2 = (RectTransform)(object)((child is RectTransform) ? child : null); stringBuilder.Append(" | ").Append(((Object)child).name); if ((Object)(object)val2 != (Object)null) { StringBuilder stringBuilder3 = stringBuilder.Append(" pos=").Append(val2.anchoredPosition).Append(" size="); rect = val2.rect; stringBuilder3.Append(((Rect)(ref rect)).size); } } KMartBoysPlugin.Log(stringBuilder.ToString()); } catch { } } private static string Path(Transform t) { string text = ((Object)t).name; int num = 0; while ((Object)(object)t.parent != (Object)null && num++ < 4) { t = t.parent; text = ((Object)t).name + "/" + text; } return text; } } [HarmonyPatch(typeof(InventoryGui), "HideRequirement")] internal static class InventoryGui_HideRequirement_Patch { private static void Postfix(Transform elementRoot) { TMP_Text val = InventoryGui_SetupRequirement_Patch.FindLabel(elementRoot); if ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(false); } } } public enum DeathChatChannel { Shout, Normal } [HarmonyPatch(typeof(Player), "OnDeath")] internal static class Player_OnDeath_Patch { private static float _lastSent = -999f; private static void Prefix(Player __instance) { //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) try { if (KMartBoysPlugin.ModEnabled.Value && KMartBoysPlugin.DeathMessageEnabled.Value && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !((Object)(object)Chat.instance == (Object)null) && !(Time.unscaledTime - _lastSent < 3f)) { _lastSent = Time.unscaledTime; string text = Pick(KMartBoysPlugin.DeathMessages.Value); if (!string.IsNullOrEmpty(text)) { text = text.Replace("{name}", __instance.GetPlayerName()); Type val = (Type)((KMartBoysPlugin.DeathMessageChannel.Value == DeathChatChannel.Normal) ? 1 : 2); Chat.instance.SendText(val, text); } } } catch (Exception ex) { KMartBoysPlugin.LogOnce("deathmsg", "Death message failed: " + ex.Message); } } private static string Pick(string raw) { if (string.IsNullOrEmpty(raw)) { return null; } string[] array = raw.Split('|'); int num = array.Length; while (num-- > 0) { string text = array[Random.Range(0, array.Length)].Trim(); if (text.Length > 0) { return text; } } return null; } } internal static class Depositor { private static readonly FieldRef<Container, ZNetView> ContainerNView = AccessTools.FieldRefAccess<Container, ZNetView>("m_nview"); private static readonly FieldRef<InventoryGui, Container> GuiCurrentContainer = AccessTools.FieldRefAccess<InventoryGui, Container>("m_currentContainer"); private static readonly FieldRef<InventoryGui, ItemData> GuiDragItem = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_dragItem"); private static readonly MethodInfo ContainerCheckAccess = AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null); public static void DepositNearby(Player player) { Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return; } List<Container> list = FindContainers(player); if (list.Count == 0) { Notify(player, KMartBoysPlugin.NoContainersMessage.Value, 0, 0); return; } ItemData dragItem = null; if ((Object)(object)InventoryGui.instance != (Object)null) { dragItem = GuiDragItem.Invoke(InventoryGui.instance); } HashSet<long> locks = SlotLocks.GetLocks(player); List<ItemData> list2 = new List<ItemData>(inventory.GetAllItems()); int num = 0; HashSet<Container> hashSet = new HashSet<Container>(); foreach (ItemData item in list2) { if (!ShouldDeposit(item, dragItem, locks)) { continue; } foreach (Container item2 in list) { if (!inventory.ContainsItem(item)) { break; } Inventory inventory2 = item2.GetInventory(); if (inventory2.ContainsItemByName(item.m_shared.m_name) && EnsureOwnership(item2)) { int num2 = MoveInto(inventory, inventory2, item); if (num2 > 0) { num += num2; hashSet.Add(item2); } } } } if (num > 0) { StorageStock.Invalidate(); if (KMartBoysPlugin.CenterMessageEnabled.Value) { string text = Format(PickTier(num), num, hashSet.Count); if (!string.IsNullOrEmpty(text)) { ((Character)player).Message((MessageType)2, text, 0, (Sprite)null, false); } } Notify(player, KMartBoysPlugin.SummaryMessage.Value, num, hashSet.Count); } else { Notify(player, KMartBoysPlugin.NothingToDepositMessage.Value, 0, 0); } } private static bool ShouldDeposit(ItemData item, ItemData dragItem, HashSet<long> lockedSlots) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Invalid comparison between Unknown and I4 //IL_007e: Unknown result type (might be due to invalid IL or missing references) if (item == null || item.m_shared == null) { return false; } if (item == dragItem) { return false; } if (KMartBoysPlugin.IgnoreEquipped.Value && item.m_equipped) { return false; } if (KMartBoysPlugin.IgnoreHotbar.Value && item.m_gridPos.y == 0) { return false; } if (KMartBoysPlugin.IgnoreAmmo.Value && (int)item.m_shared.m_itemType == 9) { return false; } if (ModCompat.IsSpecialSlot(item.m_gridPos)) { return false; } if (KMartBoysPlugin.SlotLockEnabled.Value && lockedSlots.Contains(SlotLocks.Key(item.m_gridPos))) { return false; } if (!KMartBoysPlugin.DepositNonStackables.Value && item.m_shared.m_maxStackSize <= 1) { return false; } return true; } private static List<Container> FindContainers(Player player) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) float value = KMartBoysPlugin.Radius.Value; Vector3 position = ((Component)player).transform.position; long playerID = player.GetPlayerID(); Container val = (((Object)(object)InventoryGui.instance != (Object)null) ? GuiCurrentContainer.Invoke(InventoryGui.instance) : null); List<KeyValuePair<float, Container>> list = new List<KeyValuePair<float, Container>>(); Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0); foreach (Container val2 in array) { if ((Object)(object)val2 == (Object)null || !((Behaviour)val2).isActiveAndEnabled) { continue; } float num = Vector3.Distance(position, ((Component)val2).transform.position); if (!(num > value)) { ZNetView val3 = ContainerNView.Invoke(val2); if (!((Object)(object)val3 == (Object)null) && val3.IsValid() && val2.GetInventory() != null && !((Object)(object)((Component)val2).GetComponentInParent<TombStone>() != (Object)null) && (!val2.IsInUse() || !((Object)(object)val2 != (Object)(object)val)) && (!(ContainerCheckAccess != null) || (bool)ContainerCheckAccess.Invoke(val2, new object[1] { playerID })) && (!val2.m_checkGuardStone || PrivateArea.CheckAccess(((Component)val2).transform.position, 0f, false, false))) { list.Add(new KeyValuePair<float, Container>(num, val2)); } } } list.Sort((KeyValuePair<float, Container> a, KeyValuePair<float, Container> b) => a.Key.CompareTo(b.Key)); List<Container> list2 = new List<Container>(list.Count); foreach (KeyValuePair<float, Container> item in list) { list2.Add(item.Value); } return list2; } private static bool EnsureOwnership(Container c) { ZNetView val = ContainerNView.Invoke(c); if ((Object)(object)val == (Object)null || !val.IsValid()) { return false; } if (!val.IsOwner()) { val.ClaimOwnership(); } return val.IsOwner(); } private static bool SameStack(ItemData a, ItemData b) { if (a.m_shared.m_name == b.m_shared.m_name && a.m_quality == b.m_quality) { return a.m_worldLevel == b.m_worldLevel; } return false; } private static int MoveInto(Inventory from, Inventory target, ItemData item) { int num = Math.Max(1, item.m_shared.m_maxStackSize); int num2 = 0; if (num > 1) { foreach (ItemData item2 in new List<ItemData>(target.GetAllItems())) { if (!from.ContainsItem(item)) { return num2; } if (SameStack(item2, item) && item2.m_stack < num) { int amount = Math.Min(item.m_stack, num - item2.m_stack); num2 += MoveSlot(from, target, item, amount, item2.m_gridPos.x, item2.m_gridPos.y); } } } int width = target.GetWidth(); int height = target.GetHeight(); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { if (!from.ContainsItem(item)) { return num2; } if (target.GetItemAt(j, i) == null) { int amount2 = Math.Min(item.m_stack, num); num2 += MoveSlot(from, target, item, amount2, j, i); } } } return num2; } private static int MoveSlot(Inventory from, Inventory target, ItemData item, int amount, int x, int y) { if (amount <= 0) { return 0; } int stack = item.m_stack; target.MoveItemToThis(from, item, amount, x, y); int num = (from.ContainsItem(item) ? item.m_stack : 0); return Math.Max(0, stack - num); } private static string PickTier(int items) { string result = null; int num = -1; for (int i = 0; i < KMartBoysPlugin.TierMinItems.Length; i++) { int value = KMartBoysPlugin.TierMinItems[i].Value; string value2 = KMartBoysPlugin.TierMessages[i].Value; if (value > 0 && !string.IsNullOrEmpty(value2) && items >= value && value > num) { num = value; result = value2; } } return result; } private static string Format(string template, int items, int containers) { if (string.IsNullOrEmpty(template)) { return template; } return template.Replace("{items}", items.ToString()).Replace("{containers}", containers.ToString()).Replace("{itemsWord}", (items == 1) ? "item" : "items") .Replace("{containersWord}", (containers == 1) ? "container" : "containers"); } private static void Notify(Player player, string template, int items, int containers) { if (KMartBoysPlugin.SummaryMessageEnabled.Value) { string text = Format(template, items, containers); if (!string.IsNullOrEmpty(text)) { ((Character)player).Message((MessageType)1, text, 0, (Sprite)null, false); } } } } public enum SortMode { Name, Type, Value, Quality, Power, Weight } internal static class InventorySorter { private static readonly MethodInfo InventoryChanged = AccessTools.Method(typeof(Inventory), "Changed", new Type[2] { typeof(bool), typeof(bool) }, (Type[])null); public static void Sort(Inventory inv, bool isPlayer) { //IL_0078: 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) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) if (inv == null) { return; } Player player = Player.m_localPlayer; Func<Vector2i, bool> func = delegate(Vector2i pos) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) if (!isPlayer) { return false; } if (KMartBoysPlugin.SortSkipHotbar.Value && pos.y == 0) { return true; } if (ModCompat.IsSpecialSlot(pos)) { return true; } return ((Object)(object)player != (Object)null && KMartBoysPlugin.SlotLockEnabled.Value && SlotLocks.IsLocked(player, pos)) ? true : false; }; ItemData val = null; if ((Object)(object)InventoryGui.instance != (Object)null) { val = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_dragItem").Invoke(InventoryGui.instance); } List<ItemData> list = new List<ItemData>(); foreach (ItemData allItem in inv.GetAllItems()) { if (allItem != null && allItem != val && !func(allItem.m_gridPos)) { list.Add(allItem); } } if (list.Count == 0) { return; } if (KMartBoysPlugin.SortMergeStacks.Value) { MergeStacks(inv, list); } list.Sort(Comparer(KMartBoysPlugin.SortModeSetting.Value)); List<Vector2i> list2 = new List<Vector2i>(); HashSet<long> hashSet = new HashSet<long>(); foreach (ItemData allItem2 in inv.GetAllItems()) { if (allItem2 != null && !list.Contains(allItem2)) { hashSet.Add(SlotLocks.Key(allItem2.m_gridPos)); } } Vector2i val2 = default(Vector2i); for (int num = 0; num < inv.GetHeight(); num++) { for (int num2 = 0; num2 < inv.GetWidth(); num2++) { ((Vector2i)(ref val2))..ctor(num2, num); if (!func(val2) && !hashSet.Contains(SlotLocks.Key(val2))) { list2.Add(val2); } } } if (list2.Count >= list.Count) { for (int num3 = 0; num3 < list.Count; num3++) { list[num3].m_gridPos = list2[num3]; } if (InventoryChanged != null) { InventoryChanged.Invoke(inv, new object[2] { false, false }); } } } private static void MergeStacks(Inventory inv, List<ItemData> items) { Dictionary<string, ItemData> dictionary = new Dictionary<string, ItemData>(); List<ItemData> list = new List<ItemData>(); foreach (ItemData item in items) { int maxStackSize = item.m_shared.m_maxStackSize; if (maxStackSize <= 1 || item.m_equipped) { continue; } string key = item.m_shared.m_name + "|" + item.m_quality + "|" + item.m_worldLevel; if (dictionary.TryGetValue(key, out var value) && value.m_stack < maxStackSize) { int num = Math.Min(maxStackSize - value.m_stack, item.m_stack); ItemData obj = value; obj.m_stack += num; item.m_stack -= num; if (item.m_stack <= 0) { list.Add(item); continue; } } if (item.m_stack < maxStackSize) { dictionary[key] = item; } else { dictionary.Remove(key); } } foreach (ItemData item2 in list) { items.Remove(item2); inv.RemoveItem(item2); } } private static string DisplayName(ItemData item) { string name = item.m_shared.m_name; if (Localization.instance == null) { return name; } return Localization.instance.Localize(name); } private static float Power(ItemData item) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) float num = 0f; try { float val = num; DamageTypes damage = item.GetDamage(); num = Math.Max(val, ((DamageTypes)(ref damage)).GetTotalDamage()); num = Math.Max(num, item.GetArmor()); num = Math.Max(num, item.GetBaseBlockPower()); } catch { } return num; } private static int TypeOrder(ItemData item) { //IL_0006: 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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected I4, but got Unknown ItemType itemType = item.m_shared.m_itemType; switch (itemType - 1) { case 2: case 3: case 13: case 19: case 21: return 0; case 8: case 22: return 1; case 4: return 2; case 5: case 6: case 10: case 11: case 16: return 3; case 17: case 23: return 4; case 14: case 18: return 5; case 1: return 6; case 20: return 7; case 0: return 8; case 12: return 9; default: return 10; } } private static Comparison<ItemData> Comparer(SortMode mode) { Comparison<ItemData> byName = delegate(ItemData a, ItemData b) { int num = string.Compare(DisplayName(a), DisplayName(b), StringComparison.CurrentCultureIgnoreCase); if (num != 0) { return num; } num = b.m_quality.CompareTo(a.m_quality); return (num == 0) ? b.m_stack.CompareTo(a.m_stack) : num; }; return mode switch { SortMode.Type => delegate(ItemData a, ItemData b) { int num = TypeOrder(a).CompareTo(TypeOrder(b)); return (num == 0) ? byName(a, b) : num; }, SortMode.Value => delegate(ItemData a, ItemData b) { int num = ((long)b.m_shared.m_value * (long)b.m_stack).CompareTo((long)a.m_shared.m_value * (long)a.m_stack); return (num == 0) ? byName(a, b) : num; }, SortMode.Quality => delegate(ItemData a, ItemData b) { int num = b.m_quality.CompareTo(a.m_quality); return (num == 0) ? byName(a, b) : num; }, SortMode.Power => delegate(ItemData a, ItemData b) { int num = Power(b).CompareTo(Power(a)); return (num == 0) ? byName(a, b) : num; }, SortMode.Weight => delegate(ItemData a, ItemData b) { int num = (b.m_shared.m_weight * (float)b.m_stack).CompareTo(a.m_shared.m_weight * (float)a.m_stack); return (num == 0) ? byName(a, b) : num; }, _ => byName, }; } } internal class SortButtonClick : MonoBehaviour, IPointerClickHandler, IEventSystemHandler { public bool ForPlayer; public void OnPointerClick(PointerEventData e) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_003e: Unknown result type (might be due to invalid IL or missing references) try { if ((int)e.button == 1) { int length = Enum.GetValues(typeof(SortMode)).Length; KMartBoysPlugin.SortModeSetting.Value = (SortMode)((int)(KMartBoysPlugin.SortModeSetting.Value + 1) % length); SortButtons.RefreshLabels(); } else { if ((int)e.button != 0) { return; } Inventory inv = null; if (ForPlayer) { if ((Object)(object)Player.m_localPlayer != (Object)null) { inv = ((Humanoid)Player.m_localPlayer).GetInventory(); } } else { Container val = SortButtons.OpenContainer(); if ((Object)(object)val != (Object)null) { ContainerSource.ClaimOwnership(val); inv = val.GetInventory(); } } InventorySorter.Sort(inv, ForPlayer); } } catch (Exception ex) { KMartBoysPlugin.LogOnce("sortclick", "Sorting failed: " + ex); } } } internal static class SortButtons { private const string PlayerButtonName = "KMartBoys_SortPlayer"; private const string ContainerButtonName = "KMartBoys_SortContainer"; private static readonly FieldRef<InventoryGui, Container> CurrentContainer = AccessTools.FieldRefAccess<InventoryGui, Container>("m_currentContainer"); private static GameObject _playerButton; private static GameObject _containerButton; public static Container OpenContainer() { if (!((Object)(object)InventoryGui.instance != (Object)null)) { return null; } return CurrentContainer.Invoke(InventoryGui.instance); } public static void Ensure(InventoryGui gui) { bool flag = KMartBoysPlugin.ModEnabled.Value && KMartBoysPlugin.SortEnabled.Value; if (!((Object)(object)gui == (Object)null) && !((Object)(object)gui.m_takeAllButton == (Object)null)) { if (flag && (Object)(object)_playerButton == (Object)null && (Object)(object)gui.m_player != (Object)null) { _playerButton = Create(gui, gui.m_player, "KMartBoys_SortPlayer", forPlayer: true); } if (flag && (Object)(object)_containerButton == (Object)null && (Object)(object)gui.m_container != (Object)null) { _containerButton = Create(gui, gui.m_container, "KMartBoys_SortContainer", forPlayer: false); } if ((Object)(object)_playerButton != (Object)null) { _playerButton.SetActive(flag); Place(_playerButton, forPlayer: true); } if ((Object)(object)_containerButton != (Object)null) { _containerButton.SetActive(flag); Place(_containerButton, forPlayer: false); } RefreshLabels(); } } private static GameObject Create(InventoryGui gui, RectTransform parent, string name, bool forPlayer) { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate<GameObject>(((Component)gui.m_takeAllButton).gameObject, (Transform)(object)parent, false); ((Object)val).name = name; MonoBehaviour[] componentsInChildren = val.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val2 in componentsInChildren) { string name2 = ((object)val2).GetType().Name; if (name2 == "Localize" || name2 == "UIGamePad") { Object.DestroyImmediate((Object)(object)val2); } } Button component = val.GetComponent<Button>(); if ((Object)(object)component != (Object)null) { component.onClick = new ButtonClickedEvent(); ((Selectable)component).interactable = true; } val.AddComponent<SortButtonClick>().ForPlayer = forPlayer; RectTransform val3 = (RectTransform)val.transform; val3.sizeDelta = new Vector2(140f, (val3.sizeDelta.y > 0f) ? val3.sizeDelta.y : 32f); return val; } private static void Place(GameObject go, bool forPlayer) { //IL_0006: 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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) RectTransform val = (RectTransform)go.transform; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(1f, 1f); val.anchorMax = val2; val.anchorMin = val2; val.pivot = new Vector2(1f, 0f); Vector2 anchoredPosition = (forPlayer ? new Vector2(KMartBoysPlugin.SortPlayerOffsetX.Value, KMartBoysPlugin.SortPlayerOffsetY.Value) : new Vector2(KMartBoysPlugin.SortChestOffsetX.Value, KMartBoysPlugin.SortChestOffsetY.Value)); val.anchoredPosition = anchoredPosition; } public static void RefreshLabels() { string text = "Sort: " + KMartBoysPlugin.SortModeSetting.Value; SetLabel(_playerButton, text); SetLabel(_containerButton, text); } private static void SetLabel(GameObject go, string text) { if (!((Object)(object)go == (Object)null)) { TMP_Text componentInChildren = go.GetComponentInChildren<TMP_Text>(true); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.text = text; } } } } [HarmonyPatch(typeof(InventoryGui), "Show")] internal static class InventoryGui_Show_SortButtons_Patch { private static void Postfix(InventoryGui __instance) { try { SortButtons.Ensure(__instance); } catch (Exception ex) { KMartBoysPlugin.LogOnce("sortbuttons", "Creating sort buttons failed: " + ex); } } } internal static class ModCompat { private static bool _resolved; private static MethodInfo _eaqsIsSlotCell; private static void Resolve() { if (_resolved) { return; } _resolved = true; try { Type type = AccessTools.TypeByName("EquipmentAndQuickSlots.API"); if (type != null) { _eaqsIsSlotCell = AccessTools.Method(type, "IsSlotCell", new Type[3] { typeof(int), typeof(int), typeof(string).MakeByRefType() }, (Type[])null); } if (_eaqsIsSlotCell != null) { KMartBoysPlugin.Log("Equipment and Quick Slots detected: its slots will be skipped."); } } catch (Exception ex) { KMartBoysPlugin.Log("EAQS compatibility lookup failed: " + ex.Message); _eaqsIsSlotCell = null; } } public static bool IsSpecialSlot(Vector2i pos) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) Resolve(); if (_eaqsIsSlotCell == null) { return false; } try { object[] parameters = new object[3] { pos.x, pos.y, null }; return (bool)_eaqsIsSlotCell.Invoke(null, parameters); } catch { return false; } } } [BepInPlugin("matt.valheim.kmartboysmusthavemod", "K-MartBoysMustHaveMod", "1.13.1")] public class KMartBoysPlugin : BaseUnityPlugin { public const string PluginGuid = "matt.valheim.kmartboysmusthavemod"; public const string PluginName = "K-MartBoysMustHaveMod"; public const string PluginVersion = "1.13.1"; internal static KMartBoysPlugin Instance; internal static ConfigEntry<bool> ModEnabled; internal static ConfigEntry<KeyCode> DepositKey; internal static ConfigEntry<KeyCode> DepositModifier; internal static ConfigEntry<float> Radius; internal static ConfigEntry<bool> AllowWhileInventoryOpen; internal static ConfigEntry<bool> IgnoreHotbar; internal static ConfigEntry<bool> IgnoreEquipped; internal static ConfigEntry<bool> DepositNonStackables; internal static ConfigEntry<bool> IgnoreAmmo; internal static ConfigEntry<bool> SlotLockEnabled; internal static ConfigEntry<LockClick> SlotLockClick; internal static ConfigEntry<KeyCode> SlotLockModifier; internal static ConfigEntry<Color> SlotLockColor; internal static ConfigEntry<bool> CenterMessageEnabled; internal static ConfigEntry<bool> SummaryMessageEnabled; internal static ConfigEntry<string> SummaryMessage; internal static ConfigEntry<string> NothingToDepositMessage; internal static ConfigEntry<string> NoContainersMessage; internal static ConfigEntry<int>[] TierMinItems; internal static ConfigEntry<string>[] TierMessages; internal static ConfigEntry<bool> StockEnabled; internal static ConfigEntry<bool> StockInBuildMenu; internal static ConfigEntry<string> StockFormat; internal static ConfigEntry<StockDisplayMode> StockDisplay; internal static ConfigEntry<string> StockAmountFormat; internal static ConfigEntry<Color> StockEnoughColor; internal static ConfigEntry<Color> StockShortColor; internal static ConfigEntry<float> StockFontSize; internal static ConfigEntry<float> StockOffsetX; internal static ConfigEntry<float> StockOffsetY; internal static ConfigEntry<float> StockRadius; internal static ConfigEntry<float> StockRefreshSeconds; internal static ConfigEntry<bool> StockOnlyAccessible; internal static ConfigEntry<bool> CraftEnabled; internal static ConfigEntry<bool> CraftAllowBuilding; internal static ConfigEntry<float> CraftRadius; internal static ConfigEntry<bool> CraftIgnoreMoving; internal static ConfigEntry<bool> CraftOnlyPlayerBuilt; internal static ConfigEntry<bool> CraftFixColors; internal static ConfigEntry<bool> RefuelEnabled; internal static ConfigEntry<float> RefuelInterval; internal static ConfigEntry<float> RefuelRadius; internal static ConfigEntry<bool> RefuelFireplaces; internal static ConfigEntry<bool> RefuelOvens; internal static ConfigEntry<bool> RefuelSmelters; internal static ConfigEntry<float> RefuelBelowPercent; internal static ConfigEntry<int> RefuelKeepReserve; internal static ConfigEntry<bool> RefuelLeaveOnePerChest; internal static ConfigEntry<bool> RefuelUseInventory; internal static ConfigEntry<string> RefuelExcluded; internal static ConfigEntry<bool> RefuelShowMessage; internal static ConfigEntry<bool> FillSmelters; internal static ConfigEntry<bool> FillEitrRefinery; internal static ConfigEntry<bool> FillKilns; internal static ConfigEntry<bool> FillWindmills; internal static ConfigEntry<bool> FillSpinningWheels; internal static ConfigEntry<bool> DeathMessageEnabled; internal static ConfigEntry<string> DeathMessages; internal static ConfigEntry<DeathChatChannel> DeathMessageChannel; internal static ConfigEntry<bool> AutoRepairEnabled; internal static ConfigEntry<bool> AutoRepairShowMessage; internal static ConfigEntry<bool> ClockEnabled; internal static ConfigEntry<string> ClockFormat; internal static ConfigEntry<int> ClockMinuteStep; internal static ConfigEntry<ClockAnchor> ClockPosition; internal static ConfigEntry<float> ClockOffsetX; internal static ConfigEntry<float> ClockOffsetY; internal static ConfigEntry<float> ClockFontSize; internal static ConfigEntry<Color> ClockColor; internal static ConfigEntry<KeyCode> ShipEditModifier; internal static ConfigEntry<CustomImageSource> ImagesFrom; internal static ConfigEntry<string> TrustedPlayers; internal static ConfigEntry<string> FavoriteSailUrl; internal static ConfigEntry<bool> ApplyFavoriteWhenSteering; internal static ConfigEntry<bool> ShipNamesEnabled; internal static ConfigEntry<bool> ShowShipNameTags; internal static ConfigEntry<float> ShipNameTagDistance; internal static ConfigEntry<float> ShipNameTagHeight; internal static ConfigEntry<float> ShipNameTagFontSize; internal static ConfigEntry<Color> ShipNameTagColor; internal static ConfigEntry<bool> SortEnabled; internal static ConfigEntry<SortMode> SortModeSetting; internal static ConfigEntry<bool> SortSkipHotbar; internal static ConfigEntry<bool> SortMergeStacks; internal static ConfigEntry<float> SortPlayerOffsetX; internal static ConfigEntry<float> SortPlayerOffsetY; internal static ConfigEntry<float> SortChestOffsetX; internal static ConfigEntry<float> SortChestOffsetY; internal static ConfigEntry<bool> BannerFitImage; internal static ConfigEntry<bool> BannerFlipImage; private const int TierCount = 6; private static readonly int[] DefaultTierMin = new int[6] { 1, 2, 10, 50, 200, 500 }; private static readonly string[] DefaultTierText = new string[6] { "One whole item. Great Job, Jackass.", "Great Job, Jackass", "{items} items stashed. Great Job, Jackass!", "Look at you go! {items} items. Great Job, Jackass!", "{items} items?! Your back thanks you. Great Job, Jackass!", "{items} ITEMS ACROSS {containers} CHESTS. Odin weeps. Great Job, Jackass!!" }; private const string PlaceholderHelp = " Placeholders: {items} = number of items, {containers} = number of containers, {itemsWord} = item/items, {containersWord} = container/containers."; private Harmony _harmony; private FileSystemWatcher _watcher; private volatile bool _configFileChanged; private float _reloadAt; private int _order; internal static bool OtherCraftModLoaded; internal static bool OtherRefuelModLoaded; internal static bool OtherRepairModLoaded; private static readonly string[] RepairMods = new string[3] { "mtsukn.AutoRepair", "Tekla.AutoRepair", "aedenthorn.AutoRepair" }; private static readonly string[] CraftFromContainerMods = new string[5] { "com.mikeg.valheim.nearbycrafting", "aedenthorn.CraftFromContainers", "Azumatt.AzuCraftyBoxes", "org.bepinex.plugins.craftfromcontainers", "com.maxsch.valheim.MultiUserChest" }; private static readonly string[] RefuelMods = new string[2] { "simplifydave.autorefillfires", "aedenthorn.AutoFuel" }; private static readonly HashSet<string> LoggedKeys = new HashSet<string>(); private ConfigEntry<T> Bind<T>(string section, string key, string dispName, T defaultValue, string description, AcceptableValueBase range = null) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown ConfigurationManagerAttributes configurationManagerAttributes = new ConfigurationManagerAttributes { DispName = dispName, Order = 1000 - _order++ }; return ((BaseUnityPlugin)this).Config.Bind<T>(section, key, defaultValue, new ConfigDescription(description, range, new object[1] { configurationManagerAttributes })); } private void Awake() { //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_045d: Unknown result type (might be due to invalid IL or missing references) //IL_0496: Unknown result type (might be due to invalid IL or missing references) //IL_0b0d: Unknown result type (might be due to invalid IL or missing references) //IL_0d14: Unknown result type (might be due to invalid IL or missing references) //IL_0e7f: Unknown result type (might be due to invalid IL or missing references) //IL_0e89: Expected O, but got Unknown Instance = this; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = true; ModEnabled = Bind("1 - General", "Enabled", "Mod enabled", defaultValue: true, "Turn the whole mod on or off."); DepositKey = Bind<KeyCode>("1 - General", "DepositKey", "Deposit key", (KeyCode)287, "Key that deposits your items into nearby matching containers."); DepositModifier = Bind<KeyCode>("1 - General", "DepositModifier", "Deposit modifier key", (KeyCode)0, "Optional key that must be held together with the deposit key (e.g. LeftShift). None = no modifier."); Radius = Bind("1 - General", "Radius", "Search radius (m)", 10f, "Radius in meters around you to search for containers.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f)); AllowWhileInventoryOpen = Bind("1 - General", "AllowWhileInventoryOpen", "Works with inventory open", defaultValue: true, "Allow the deposit key to work while the inventory screen is open."); IgnoreHotbar = Bind("2 - Filters", "IgnoreHotbar", "Skip hotbar", defaultValue: true, "Never deposit items in your hotbar (the top row of the inventory, slots 1-8)."); IgnoreEquipped = Bind("2 - Filters", "IgnoreEquipped", "Skip equipped items", defaultValue: true, "Never deposit items you have equipped (weapons, tools, armor, utility items)."); IgnoreAmmo = Bind("2 - Filters", "IgnoreAmmo", "Skip ammo", defaultValue: true, "Never deposit ammo (arrows, bolts and other ammo you can equip), even if a chest already has the same kind."); DepositNonStackables = Bind("2 - Filters", "DepositNonStackables", "Deposit non-stackables", defaultValue: true, "Also deposit non-stacking items (tools, weapons, armor) when a container already has the same item."); SlotLockEnabled = Bind("3 - Slot Locking", "Enabled", "Slot locking enabled", defaultValue: true, "Allow locking inventory slots so they are never deposited."); SlotLockClick = Bind("3 - Slot Locking", "LockClick", "Lock mouse button", LockClick.MiddleClick, "Mouse button that locks / unlocks the inventory slot under the cursor (inventory open). Disabled = off."); SlotLockModifier = Bind<KeyCode>("3 - Slot Locking", "LockModifierKey", "Lock modifier + left-click", (KeyCode)0, "Optional alternative: hold this key and left-click a slot to lock / unlock it. None = off. (LeftAlt is already used by Crop Utils, Better Archery and Equipment and Quick Slots.)"); SlotLockColor = Bind<Color>("3 - Slot Locking", "LockMarkerColor", "Lock marker color", new Color(0.6f, 0.2f, 0.95f, 0.5f), "Color of the marker drawn on locked slots (RGBA). The corner badge uses the same color at full opacity."); CenterMessageEnabled = Bind("4 - Messages", "CenterMessageEnabled", "Show center message", defaultValue: true, "Show the big center-screen message after depositing (wording set by the tiers below)."); SummaryMessageEnabled = Bind("4 - Messages", "SummaryMessageEnabled", "Show summary message", defaultValue: true, "Show the small top-left summary / status messages."); SummaryMessage = Bind("4 - Messages", "SummaryMessage", "Summary text", "Deposited {items} {itemsWord} into {containers} {containersWord}", "Top-left message after a successful deposit. Placeholders: {items} = number of items, {containers} = number of containers, {itemsWord} = item/items, {containersWord} = container/containers."); NothingToDepositMessage = Bind("4 - Messages", "NothingToDepositMessage", "Nothing-to-deposit text", "Nothing to deposit", "Top-left message when nothing matched. Leave empty for no message."); NoContainersMessage = Bind("4 - Messages", "NoContainersMessage", "No-containers text", "No containers in range", "Top-left message when no usable containers are nearby. Leave empty for no message."); TierMinItems = new ConfigEntry<int>[6]; TierMessages = new ConfigEntry<string>[6]; for (int i = 0; i < 6; i++) { int num = i + 1; TierMinItems[i] = Bind("5 - Center Message Tiers", "Tier" + num + "MinItems", "Tier " + num + " - min items", DefaultTierMin[i], "Tier " + num + " is used when at least this many items were deposited (the highest matching tier wins). 0 = tier disabled.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100000)); TierMessages[i] = Bind("5 - Center Message Tiers", "Tier" + num + "Message", "Tier " + num + " - message", DefaultTierText[i], "Center-screen text for tier " + num + ". Leave empty to disable this tier. Placeholders: {items} = number of items, {containers} = number of containers, {itemsWord} = item/items, {containersWord} = container/containers."); } StockEnabled = Bind("6 - Crafting Stock", "Enabled", "Show stock at crafting", defaultValue: true, "Under each required material at a crafting station, show how many you carry and how many are in your storage boxes."); StockInBuildMenu = Bind("6 - Crafting Stock", "ShowInBuildMenu", "Also show in build menu", defaultValue: false, "Also show the stock line under build-piece requirements (hammer, hoe, cultivator)."); StockDisplay = Bind("6 - Crafting Stock", "Display", "Where to show it", StockDisplayMode.InSlotNumber, "InSlotNumber = replace the number on each ingredient slot (always visible). LineBelowSlot = an extra line under the slot (can be cut off by the crafting panel)."); StockAmountFormat = Bind("6 - Crafting Stock", "SlotNumberFormat", "Slot number text", "{total}/{need}", "Text for the ingredient slot's number when Display = InSlotNumber. Default shows have (bag + chests) / need. Placeholders: {need}, {have}, {stored}, {total}, {missing}."); StockFormat = Bind("6 - Crafting Stock", "Format", "Line below slot text", "{total} total\n<size=80%>{have} bag | {stored} box</size>", "Text shown under each requirement. Placeholders: {need} = amount required, {have} = in your inventory, {stored} = in storage boxes, {total} = have + stored, {missing} = how many more you need (0 if enough). \\n = new line. Unity rich text tags like <size=80%> and <color=#ff0> work."); StockEnoughColor = Bind<Color>("6 - Crafting Stock", "EnoughColor", "Color when you have enough", new Color(0.55f, 0.95f, 0.55f, 1f), "Text color when inventory + storage covers the requirement."); StockShortColor = Bind<Color>("6 - Crafting Stock", "ShortColor", "Color when short", new Color(1f, 0.55f, 0.35f, 1f), "Text color when inventory + storage is not enough."); StockFontSize = Bind("6 - Crafting Stock", "FontSize", "Font size", 14f, "Font size of the stock text.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(6f, 40f)); StockOffsetX = Bind("6 - Crafting Stock", "OffsetX", "Position offset X", 0f, "Move the stock text left (-) or right (+), in UI pixels.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-300f, 300f)); StockOffsetY = Bind("6 - Crafting Stock", "OffsetY", "Position offset Y", -2f, "Move the stock text up (+) or down (-), in UI pixels. 0 = just below the requirement slot.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-300f, 300f)); StockRadius = Bind("6 - Crafting Stock", "StorageRadius", "Storage search radius (m)", 0f, "Only count containers within this many meters of you. 0 = every container currently loaded around you (roughly your whole base).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 500f)); StockRefreshSeconds = Bind("6 - Crafting Stock", "RefreshSeconds", "Storage refresh interval (s)", 1f, "How often storage boxes are re-counted while a crafting screen is open.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 10f)); StockOnlyAccessible = Bind("6 - Crafting Stock", "OnlyAccessibleContainers", "Only count chests you can open", defaultValue: true, "Skip private chests you don't own and chests in wards you can't access. Graves are never counted."); CraftEnabled = Bind("7 - Craft From Containers", "Enabled", "Craft from containers", defaultValue: true, "Crafting and upgrading can use materials from nearby containers. Your inventory is used first, then the nearest containers."); CraftAllowBuilding = Bind("7 - Craft From Containers", "AllowBuilding", "Build from containers", defaultValue: true, "Building (hammer, hoe, cultivator) can also use materials from nearby containers."); CraftRadius = Bind("7 - Craft From Containers", "ContainerRadius", "Container radius (m)", 30f, "How far from you (in meters) containers are used for crafting, building and auto-refuel fuel.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f)); CraftIgnoreMoving = Bind("7 - Craft From Containers", "IgnoreCartsAndShips", "Ignore carts and ships", defaultValue: true, "Don't use containers on carts or ships (safer in multiplayer)."); CraftOnlyPlayerBuilt = Bind("7 - Craft From Containers", "OnlyPlayerBuiltContainers", "Only player-built containers", defaultValue: true, "Only use containers built by players, so dungeon and world loot chests are never touched."); CraftFixColors = Bind("7 - Craft From Containers", "CountContainersInRequirementColors", "Requirement colors count containers", defaultValue: true, "Requirement slots only flash red when your inventory AND nearby containers together are short."); RefuelEnabled = Bind("8 - Auto Refuel", "Enabled", "Auto refuel", defaultValue: true, "Every few seconds, top up fuel in nearby fires, ovens and smelters, and fill smelters, refineries, kilns, windmills and spinning wheels with their inputs, all from nearby containers."); RefuelInterval = Bind("8 - Auto Refuel", "IntervalSeconds", "Check every (s)", 5f, "How often (in seconds) to check nearby fuel levels.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 120f)); RefuelRadius = Bind("8 - Auto Refuel", "Radius", "Refuel radius (m)", 20f, "Fires, ovens, smelters and other processors within this many meters of you get refilled.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f)); RefuelFireplaces = Bind("8 - Auto Refuel", "Fires", "Refuel fires", defaultValue: true, "Campfires, hearths, braziers, bonfires, torches, sconces, hot tubs and anything else that burns fuel."); RefuelOvens = Bind("8 - Auto Refuel", "Ovens", "Refuel ovens", defaultValue: true, "Stone ovens and other cooking stations that use fuel."); RefuelSmelters = Bind("8 - Auto Refuel", "Smelters", "Refuel smelters", defaultValue: true, "Fuel for smelters, blast furnaces (coal) and eitr refineries (sap)."); FillSmelters = Bind("8 - Auto Refuel", "FillSmelterOre", "Fill smelters & furnaces with ore", defaultValue: true, "Add ore and scrap (copper, tin, iron, silver, black metal, flametal...) to smelters and blast furnaces."); FillEitrRefinery = Bind("8 - Auto Refuel", "FillEitrRefinery", "Fill eitr refineries", defaultValue: true, "Add soft tissue to eitr refineries."); FillKilns = Bind("8 - Auto Refuel", "FillKilns", "Fill charcoal kilns", defaultValue: true, "Add wood to charcoal kilns. Careful: this turns the wood in your chests into coal. Use KeepReserve to hold some back."); FillWindmills = Bind("8 - Auto Refuel", "FillWindmills", "Fill windmills", defaultValue: true, "Add barley to windmills."); FillSpinningWheels = Bind("8 - Auto Refuel", "FillSpinningWheels", "Fill spinning wheels", defaultValue: true, "Add flax to spinning wheels."); RefuelBelowPercent = Bind("8 - Auto Refuel", "RefillBelowPercent", "Refill below (%)", 100f, "Only refuel when fuel drops below this percent of max. 100 = keep everything topped off.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f)); RefuelKeepReserve = Bind("8 - Auto Refuel", "KeepReserve", "Keep in reserve", 0, "Leave at least this many of each fuel or input item (wood, ore, coal...) in your containers.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 10000)); RefuelLeaveOnePerChest = Bind("8 - Auto Refuel", "LeaveOneInEachChest", "Leave 1 in each chest", defaultValue: true, "Never take the last fuel/input item out of a chest, so F6 auto-deposit still knows that chest is where it goes."); RefuelUseInventory = Bind("8 - Auto Refuel", "UseInventoryFuel", "Also use your inventory", defaultValue: false, "If the containers run out, also take fuel and inputs (ore, wood...) from your own inventory."); RefuelExcluded = Bind("8 - Auto Refuel", "ExcludedObjects", "Never refuel these", "", "Comma-separated prefab names to never refuel, e.g. piece_groundtorch_wood, piece_brazierceiling01."); RefuelShowMessage = Bind("8 - Auto Refuel", "ShowMessage", "Show refuel message", defaultValue: false, "Show a small top-left message when something was refueled."); DeathMessageEnabled = Bind("9 - Death Message", "Enabled", "Announce your deaths", defaultValue: true, "When you die, post a message in chat."); DeathMessages = Bind("9 - Death Message", "Messages", "Death message(s)", "I WAS AN IDIOT AND I DIED HAHAHAHAHAHA", "What you say in chat when you die. Separate several with | and one is picked at random. {name} = your character's name."); DeathMessageChannel = Bind("9 - Death Message", "Channel", "Chat channel", DeathChatChannel.Shout, "Shout = everyone in the world sees it. Normal = only players near you."); AutoRepairEnabled = Bind("10 - Auto Repair", "Enabled", "Auto repair at stations", defaultValue: true, "When you open a crafting station, repair everything in your inventory that station can repair."); AutoRepairShowMessage = Bind("10 - Auto Repair", "ShowMessage", "Show repair message", defaultValue: true, "Show \"Repaired N items\" when something was repaired."); ClockEnabled = Bind("11 - Clock", "Enabled", "Show clock", defaultValue: true, "Show an in-game 12-hour clock with the current weather."); ClockFormat = Bind("11 - Clock", "Format", "Clock text", "{time} | {weather}", "Placeholders: {time} = e.g. 7:45 PM, {weather} = current weather, {conditions} = Cold/Freezing/Wet, {day} = day number. \\n = new line. Example: Day {day} {time} {weather} ({conditions})"); ClockMinuteStep = Bind("11 - Clock", "MinuteStep", "Round minutes to", 1, "Show the time in steps of this many minutes (1 = every minute, 5 = 7:45, 7:50...).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 60)); ClockPosition = Bind("11 - Clock", "Position", "Screen position", ClockAnchor.TopCenter, "Which corner/edge of the screen the clock sits in."); ClockOffsetX = Bind("11 - Clock", "OffsetX", "Offset X", 0f, "Move the clock left (-) or right (+), in UI pixels.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-2000f, 2000f)); ClockOffsetY = Bind("11 - Clock", "OffsetY", "Offset Y", -10f, "Move the clock up (+) or down (-), in UI pixels.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-2000f, 2000f)); ClockFontSize = Bind("11 - Clock", "FontSize", "Font size", 22f, "Clock text size.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 60f)); ClockColor = Bind<Color>("11 - Clock", "Color", "Text color", new Color(1f, 0.93f, 0.75f, 1f), "Clock text color."); ShipEditModifier = Bind<KeyCode>("12 - Ships & Banners", "EditModifierKey", "Edit modifier key", (KeyCode)306, "Hold this while looking at a ship or banner: + Use sets the image, + Shift + Use names a ship. None = no key needed."); ImagesFrom = Bind("12 - Ships & Banners", "ShowImagesFrom", "Show custom images from", CustomImageSource.Everyone, "Everyone = show every custom sail/banner. TrustedPlayersOnly = only images set by you or the players listed below. Off = never download or show custom images. (Your game downloads the image from its URL, so that site sees your IP.)"); TrustedPlayers = Bind("12 - Ships & Banners", "TrustedPlayers", "Trusted players", "", "Comma-separated character names whose images you'll see when ShowImagesFrom = TrustedPlayersOnly."); FavoriteSailUrl = Bind("12 - Ships & Banners", "FavoriteSailUrl", "Favorite sail image URL", "", "If set, this image is put on the sail when you take the helm of a ship."); ApplyFavoriteWhenSteering = Bind("12 - Ships & Banners", "ApplyFavoriteWhenSteering", "Apply favorite when steering", defaultValue: true, "Put your favorite sail image on any ship you start steering."); ShipNamesEnabled = Bind("12 - Ships & Banners", "ShipNames", "Ship names", defaultValue: true, "Allow naming ships and show their names."); ShowShipNameTags = Bind("12 - Ships & Banners", "ShowNameTags", "Floating ship names", defaultValue: true, "Show ship names floating above the ships."); ShipNameTagDistance = Bind("12 - Ships & Banners", "NameTagDistance", "Name visible within (m)", 10f, "Ship names only show when you're within this many meters of the ship.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 300f)); ShipNameTagHeight = Bind("12 - Ships & Banners", "NameTagHeight", "Name height above ship (m)", 9f, "How high above the ship the name floats.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 40f)); ShipNameTagFontSize = Bind("12 - Ships & Banners", "NameTagFontSize", "Name font size", 26f, "Floating name size.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 60f)); BannerFitImage = Bind("12 - Ships & Banners", "BannerFitImage", "Fit image to banner", defaultValue: true, "Show the whole custom image once across hanging banners (fixes the cut-in-half, mirrored look of the game's banner layout)."); BannerFlipImage = Bind("12 - Ships & Banners", "BannerFlipImage", "Flip banner image", defaultValue: false, "Mirror custom banner images left-to-right. Turn on if your banner image shows up backwards."); ShipNameTagColor = Bind<Color>("12 - Ships & Banners", "NameTagColor", "Name color", new Color(1f, 0.85f, 0.4f, 1f), "Floating name color."); SortEnabled = Bind("13 - Sorting", "Enabled", "Sort buttons", defaultValue: true, "Show a Sort button on your inventory and on open chests. Left-click sorts, right-click changes the sort mode."); SortModeSetting = Bind("13 - Sorting", "Mode", "Sort by", SortMode.Name, "Name = A to Z. Type = weapons, ammo, shields, armor, utility, tools, food, fish, materials, trophies. Value = most valuable stacks first. Quality = highest upgrade level first. Power = strongest damage / armor / block first. Weight = heaviest stacks first."); SortSkipHotbar = Bind("13 - Sorting", "SkipHotbar", "Keep hotbar in place", defaultValue: true, "Don't move items in your hotbar (top row) when sorting your inventory. Locked slots never move either."); SortMergeStacks = Bind("13 - Sorting", "MergeStacks", "Merge partial stacks", defaultValue: true, "Combine partial stacks of the same item while sorting."); SortPlayerOffsetX = Bind("13 - Sorting", "InventoryButtonOffsetX", "Inventory button X", 0f, "Move your inventory's Sort button left (-) or right (+).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1500f, 1500f)); SortPlayerOffsetY = Bind("13 - Sorting", "InventoryButtonOffsetY", "Inventory button Y", 4f, "Move your inventory's Sort button up (+) or down (-).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1500f, 1500f)); SortChestOffsetX = Bind("13 - Sorting", "ChestButtonOffsetX", "Chest button X", 0f, "Move the chest Sort button left (-) or right (+).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1500f, 1500f)); SortChestOffsetY = Bind("13 - Sorting", "ChestButtonOffsetY", "Chest button Y", 4f, "Move the chest Sort button up (+) or down (-).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1500f, 1500f)); _harmony = new Harmony("matt.valheim.kmartboysmusthavemod"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); WatchConfigFile(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"K-MartBoysMustHaveMod 1.13.1 loaded."); } private void WatchConfigFile() { try { string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath; _watcher = new FileSystemWatcher(Path.GetDirectoryName(configFilePath), Path.GetFileName(configFilePath)); _watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite; _watcher.Changed += OnConfigFileEvent; _watcher.Created += OnConfigFileEvent; _watcher.Renamed += OnConfigFileEvent; _watcher.IncludeSubdirectories = false; _watcher.SynchronizingObject = null; _watcher.EnableRaisingEvents = true; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not watch config file for changes: " + ex.Message)); } } private void OnConfigFileEvent(object sender, FileSystemEventArgs e) { _configFileChanged = true; } private void ReloadConfigIfChanged() { if (_configFileChanged) { _configFileChanged = false; _reloadAt = Time.unscaledTime + 0.5f; } if (_reloadAt > 0f && Time.unscaledTime >= _reloadAt) { _reloadAt = 0f; try { ((BaseUnityPlugin)this).Config.Reload(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Config reload failed: " + ex.Message)); } } } private void Start() { string[] craftFromContainerMods = CraftFromContainerMods; foreach (string text in craftFromContainerMods) { if (Chainloader.PluginInfos.ContainsKey(text)) { OtherCraftModLoaded = true; ((BaseUnityPlugin)this).Logger.LogWarning((object)("Another craft-from-containers mod is installed (" + text + "). This mod's Craft From Containers is turned OFF to avoid counting chests twice. Remove that mod to use ours.")); } } craftFromContainerMods = RepairMods; foreach (string text2 in craftFromContainerMods) { if (Chainloader.PluginInfos.ContainsKey(text2)) { OtherRepairModLoaded = true; ((BaseUnityPlugin)this).Logger.LogWarning((object)("Another auto-repair mod is installed (" + text2 + "). This mod's Auto Repair is turned OFF. Remove that mod to use ours.")); } } craftFromContainerMods = RefuelMods; foreach (string text3 in craftFromContainerMods) { if (Chainloader.PluginInfos.ContainsKey(text3)) { OtherRefuelModLoaded = true; ((BaseUnityPlugin)this).Logger.LogWarning((object)("Another auto-refuel mod is installed (" + text3 + "). This mod's Auto Refuel is turned OFF to avoid double refueling. Remove that mod to use ours.")); } } } private void OnDestroy() { if (_watcher != null) { _watcher.Dispose(); } if (_harmony != null) { _harmony.UnpatchSelf(); } } private void Update() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) ReloadConfigIfChanged(); ClockHud.Tick(); ShipNameTags.Tick(); if (!ModEnabled.Value) { return; } Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { SlotLockInput.Poll(localPlayer); Refueler.Tick(localPlayer); if (ZInput.GetKeyDown(DepositKey.Value, false) && ((int)DepositModifier.Value == 0 || ZInput.GetKey(DepositModifier.Value, false)) && CanTakeHotkey()) { Depositor.DepositNearby(localPlayer); } } } private static bool CanTakeHotkey() { if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()) { return false; } if (Console.IsVisible()) { return false; } if (TextInput.IsVisible()) { return false; } if (Menu.IsVisible()) { return false; } if (Minimap.IsOpen()) { return false; } if (StoreGui.IsVisible()) { return false; } if (GameCamera.InFreeFly()) { return false; } if (!AllowWhileInventoryOpen.Value && InventoryGui.IsVisible()) { return false; } return true; } internal static void Log(string msg) { if ((Object)(object)Instance != (Object)null) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)msg); } } internal static void LogOnce(string key, string msg) { if (!((Object)(object)Instance == (Object)null) && LoggedKeys.Add(key)) { ((BaseUnityPlugin)Instance).Logger.LogWarning((object)msg); } } } internal static class Refueler { private enum ProcessorKind { Smelter, EitrRefinery, Kiln, Windmill, SpinningWheel } private class FuelPool { public List<Container> Containers; public Inventory PlayerInventory; } private static readonly FieldRef<Fireplace, ZNetView> FireplaceNView = AccessTools.FieldRefAccess<Fireplace, ZNetView>("m_nview"); private static readonly FieldRef<Smelter, ZNetView> SmelterNView = AccessTools.FieldRefAccess<Smelter, ZNetView>("m_nview"); private static readonly FieldRef<CookingStation, ZNetView> CookingNView = AccessTools.FieldRefAccess<CookingStation, ZNetView>("m_nview"); private static readonly MethodInfo SmelterGetQueueSize = AccessTools.Method(typeof(Smelter), "GetQueueSize", (Type[])null, (Type[])null); private static float _nextRun; private static string _excludedRaw; private static readonly HashSet<string> Excluded = new HashSet<string>(StringComparer.OrdinalIgnoreCase); public static void Tick(Player player) { if (!KMartBoysPlugin.RefuelEnabled.Value || KMartBoysPlugin.OtherRefuelModLoaded || (Object)(object)player == (Object)null || ((Character)player).IsDead() || Time.time < _nextRun) { return; } _nextRun = Time.time + Mathf.Max(1f, KMartBoysPlugin.RefuelInterval.Value); try { Run(player); } catch (Exception ex) { KMartBoysPlugin.LogOnce("refuel", "Auto-refuel error: " + ex); } } private static void Run(Player player) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_02a9: Unknown result type (might be due to invalid IL or missing references) RefreshExcluded(); Vector3 position = ((Component)player).transform.position; float value = KMartBoysPlugin.RefuelRadius.Value; float threshold = Mathf.Clamp01(KMartBoysPlugin.RefuelBelowPercent.Value / 100f); FuelPool pool = null; int num = 0; if (KMartBoysPlugin.RefuelFireplaces.Value) { Fireplace[] array = Object.FindObjectsByType<Fireplace>((FindObjectsSortMode)0); foreach (Fireplace val in array) { if ((Object)(object)val == (Object)null || val.m_infiniteFuel || (Object)(object)val.m_fuelItem == (Object)null || val.m_maxFuel <= 0f || !InRange((Behaviour)(object)val, position, value) || IsExcluded(((Component)val).gameObject)) { continue; } int num2 = MissingFuel(FireplaceNView.Invoke(val), val.m_maxFuel, threshold); if (num2 > 0) { int num3 = TakeItem(ref pool, player, FuelName(val.m_fuelItem), num2); if (num3 > 0) { val.AddFuel((float)num3); num++; } } } } Smelter[] array2 = Object.FindObjectsByType<Smelter>((FindObjectsSortMode)0); foreach (Smelter val2 in array2) { if ((Object)(object)val2 == (Object)null || !InRange((Behaviour)(object)val2, position, value) || IsExcluded(((Component)val2).gameObject)) { continue; } ZNetView val3 = SmelterNView.Invoke(val2); if ((Object)(object)val3 == (Object)null || !val3.IsValid()) { continue; } bool flag = false; if (KMartBoysPlugin.RefuelSmelters.Value && (Object)(object)val2.m_fuelItem != (Object)null && val2.m_maxFuel > 0) { int num4 = MissingFuel(val3, val2.m_maxFuel, threshold); if (num4 > 0) { int num5 = TakeItem(ref pool, player, FuelName(val2.m_fuelItem), num4); for (int j = 0; j < num5; j++) { val3.InvokeRPC("RPC_AddFuel", Array.Empty<object>()); } flag = flag || num5 > 0; } } if (FillInputsFor(Classify(val2)) && val2.m_maxOre > 0 && val2.m_conversion != null) { flag |= FillInputs(ref pool, player, val2, val3) > 0; } if (flag) { num++; } } if (KMartBoysPlugin.RefuelOvens.Value) { CookingStation[] array3 = Object.FindObjectsByType<CookingStation>((FindObjectsSortMode)0); foreach (CookingStation val4 in array3) { if ((Object)(object)val4 == (Object)null || !val4.m_useFuel || (Object)(object)val4.m_fuelItem == (Object)null || val4.m_maxFuel <= 0 || !InRange((Behaviour)(object)val4, position, value) || IsExcluded(((Component)val4).gameObject)) { continue; } ZNetView val5 = CookingNView.Invoke(val4); int num6 = MissingFuel(val5, val4.m_maxFuel, threshold); if (num6 <= 0) { continue; } int num7 = TakeItem(ref pool, player, FuelName(val4.m_fuelItem), num6); if (num7 > 0) { for (int k = 0; k < num7; k++) { val5.InvokeRPC("RPC_AddFuel", Array.Empty<object>()); } num++; } } } if (num > 0 && KMartBoysPlugin.RefuelShowMessage.Value) { ((Character)player).Message((MessageType)1, "Refilled " + num + " station" + ((num == 1) ? "" : "s"), 0, (Sprite)null, false); } } private static ProcessorKind Classify(Smelter s) { string text = Utils.GetPrefabName(((Component)s).gameObject).ToLowerInvariant(); if (text.Contains("eitrrefinery")) { return ProcessorKind.EitrRefinery; } if (text.Contains("kiln")) { return ProcessorKind.Kiln; } if (text.Contains("windmill")) { return ProcessorKind.Windmill; } if (text.Contains("spinningwheel")) { return ProcessorKind.SpinningWheel; } return ProcessorKind.Smelter; } private static bool FillInputsFor(ProcessorKind kind) { return kind switch { ProcessorKind.EitrRefinery => KMartBoysPlugin.FillEitrRefinery.Value, ProcessorKind.Kiln => KMartBoysPlugin.FillKilns.Value, ProcessorKind.Windmill => KMartBoysPlugin.FillWindmills.Value, ProcessorKind.SpinningWheel => KMartBoysPlugin.FillSpinningWheels.Value, _ => KMartBoysPlugin.FillSmelters.Value, }; } private static int FillInputs(ref FuelPool pool, Player player, Smelter s, ZNetView nview) { int num = ((SmelterGetQueueSize != null) ? ((int)SmelterGetQueueSize.Invoke(s, null)) : 0); int num2 = s.m_maxOre - num; if (num2 <= 0) { return 0; } int num3 = 0; foreach (ItemConversion item in s.m_conversion) { if (num2 <= 0) { break; } if (item == null || (Object)(object)item.m_from == (Object)null) { continue; } string text = FuelName(item.m_from); string name = ((Object)((Component)item.m_from).gameObject).name; if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(name)) { int num4 = TakeItem(ref pool, player, text, num2); for (int i = 0; i < num4; i++) { nview.InvokeRPC("RPC_AddOre", new object[2] { name, false }); } num2 -= num4; num3 += num4; } } return num3; } private static bool InRange(Behaviour c, Vector3 origin, float radius) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (c.isActiveAndEnabled) { return Vector3.Distance(origin, ((Component)c).transform.position) <= radius; } return false; } private static int MissingFuel(ZNetView nview, float maxFuel, float threshold) { if ((Object)(object)nview == (Object)null || !nview.IsValid()) { return 0; } ZDO zDO = nview.GetZDO(); if (zDO == null) { return 0; } float num = zDO.GetFloat(ZDOVars.s_fuel, 0f); if (num >= maxFuel * threshold && threshold < 1f) { return 0; } return Mathf.FloorToInt(maxFuel - num); } private static string FuelName(ItemDrop drop) { if (!((Object)(object)drop != (Object)null) || drop.m_itemData == null || drop.m_itemData.m_shared == null) { return null; } return drop.m_itemData.m_shared.m_name; } private static int TakeItem(ref FuelPool pool, Player player, string fuelName, int amount) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(fuelName) || amount <= 0) { return 0; } if (pool == null) { pool = new FuelPool { Containers = ContainerSource.FindAround(((Component)player).transform.position, KMartBoysPlugin.CraftRadius.Value), PlayerInventory = (KMartBoysPlugin.RefuelUseInventory.