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 ChestButler v2.1.3
ChestButler.dll
Decompiled a month 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.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ChestButler.Core; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using MultiUserChest; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = "")] [assembly: AssemblyCompany("ChestButler")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("2.1.3.0")] [assembly: AssemblyInformationalVersion("2.1.3")] [assembly: AssemblyProduct("ChestButler")] [assembly: AssemblyTitle("ChestButler")] [assembly: AssemblyVersion("2.1.3.0")] namespace ChestButler { [BepInPlugin("eksolutions.chestbutler", "ChestButler", "2.1.3")] [BepInProcess("valheim.exe")] [BepInProcess("valheim_server.exe")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string ModGuid = "eksolutions.chestbutler"; public const string ModName = "ChestButler"; public const string ModVersion = "2.1.3"; internal static Plugin Instance; internal static ManualLogSource Log; internal static ConfigEntry<float> SorterRadius; internal static ConfigEntry<float> TransferInterval; internal static ConfigEntry<int> StacksPerTick; internal static ConfigEntry<bool> ContainsFallback; internal static ConfigEntry<bool> FreeChestFallback; internal static ConfigEntry<bool> VehiclesAreStorage; private Harmony _harmony; internal static ConfigEntry<float> StationRange => OrganizeConfig.StationRange; private void Awake() { //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_004f: Expected O, but got Unknown //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Expected O, but got Unknown //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Expected O, but got Unknown //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Expected O, but got Unknown //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_0133: Expected O, but got Unknown //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Expected O, but got Unknown //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Expected O, but got Unknown //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Expected O, but got Unknown //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; SorterRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Sorting", "Radius", 128f, new ConfigDescription("Radius (m) around a sorter chest in which target chests are searched.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 128f), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); TransferInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Sorting", "TransferInterval", 1f, new ConfigDescription("Seconds between transfer ticks per sorter. Client-side: raise it if the mod costs you frames.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>())); StacksPerTick = ((BaseUnityPlugin)this).Config.Bind<int>("Sorting", "StacksPerTick", 2, new ConfigDescription("How many item stacks a sorter moves per tick. Client-side.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 8), Array.Empty<object>())); ContainsFallback = ((BaseUnityPlugin)this).Config.Bind<bool>("Sorting", "ContainsFallback", true, new ConfigDescription("Route items to chests that already contain them when no explicit filter matches.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); FreeChestFallback = ((BaseUnityPlugin)this).Config.Bind<bool>("Sorting", "FreeChestFallback", true, new ConfigDescription("When no chest holds an item yet, put it in the nearest empty chest, or the chest with the most free slots if none is empty. Chests with a pin, a sign label or a station next to them are never used for this, and empty Organize homes are kept for their category.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); VehiclesAreStorage = ((BaseUnityPlugin)this).Config.Bind<bool>("Sorting", "VehiclesAreStorage", false, new ConfigDescription("Treat cart and ship inventories as storage. Off (default): the sorter, Organize, Pull and Gather all ignore vehicles entirely - they are transport, and their own Pin/Pull buttons still work for manual loading.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); Groups.Init(((BaseUnityPlugin)this).Config); Stations.Init(((BaseUnityPlugin)this).Config); OrganizeConfig.Init(((BaseUnityPlugin)this).Config); Gather.Init(((BaseUnityPlugin)this).Config); PullerConfig.Init(((BaseUnityPlugin)this).Config); SorterChestPiece.Register(); PullerChestPiece.Register(); _harmony = new Harmony("eksolutions.chestbutler"); _harmony.PatchAll(); Log.LogInfo((object)"ChestButler 2.1.3 loaded"); } } } namespace ChestButler.Patches { [HarmonyPatch(typeof(Hud))] internal static class BuildGatherPatch { internal static bool InBuildInfo { get; private set; } [HarmonyPrefix] [HarmonyPatch("SetupPieceInfo")] private static void SetupPieceInfoPrefix() { InBuildInfo = true; } [HarmonyPostfix] [HarmonyPatch("SetupPieceInfo")] private static void SetupPieceInfoPostfix() { InBuildInfo = false; } } [HarmonyPatch(typeof(Container), "Awake")] internal static class Container_Awake_Patch { private static void Postfix(Container __instance) { ContainerTracker.Register(__instance); if ((Object)(object)((Component)__instance).GetComponent<SorterBehaviour>() == (Object)null && (Object)(object)((Component)__instance).GetComponentInParent<Piece>() != (Object)null) { ((Component)__instance).gameObject.AddComponent<SorterBehaviour>(); } if ((Object)(object)((Component)__instance).GetComponent<PullerBehaviour>() == (Object)null && (Object)(object)((Component)__instance).GetComponentInParent<Piece>() != (Object)null) { ((Component)__instance).gameObject.AddComponent<PullerBehaviour>(); } } } [HarmonyPatch(typeof(Container), "OnDestroyed")] internal static class Container_OnDestroyed_Patch { private static void Prefix(Container __instance) { ContainerTracker.Unregister(__instance); } } [HarmonyPatch(typeof(InventoryGui))] internal static class GatherPatch { private static Button _gatherBtn; private static TMP_Text _gatherLabel; private static readonly List<GatherNeed> Needs = new List<GatherNeed>(); private static readonly HashSet<string> Seen = new HashSet<string>(); private static bool _onlyOneIngredient; private static List<Container> _sources; private const int MaxNeeds = 16; private static readonly FieldInfo SelectedRecipeField = AccessTools.Field(typeof(InventoryGui), "m_selectedRecipe"); private static readonly MethodInfo RecipeGetter = ((SelectedRecipeField != null) ? AccessTools.PropertyGetter(SelectedRecipeField.FieldType, "Recipe") : null); private static bool _reflectionWarned; private static Recipe SelectedRecipe(InventoryGui gui) { if ((Object)(object)gui == (Object)null || SelectedRecipeField == null || RecipeGetter == null) { if (!_reflectionWarned) { _reflectionWarned = true; Plugin.Log.LogWarning((object)"[gather] could not reach InventoryGui.m_selectedRecipe; require-only-one-ingredient recipes will be treated as normal ones"); } return null; } try { object value = SelectedRecipeField.GetValue(gui); return (Recipe)((value == null) ? null : /*isinst with value type is only supported in some contexts*/); } catch (Exception ex) { if (!_reflectionWarned) { _reflectionWarned = true; Plugin.Log.LogWarning((object)("[gather] reading m_selectedRecipe failed: " + ex.Message)); } return null; } } [HarmonyPrefix] [HarmonyPatch("SetupRequirementList")] private static void SetupRequirementListPrefix(InventoryGui __instance) { Needs.Clear(); Seen.Clear(); _sources = null; Recipe val = SelectedRecipe(__instance); _onlyOneIngredient = (Object)(object)val != (Object)null && val.m_requireOnlyOneIngredient; } [HarmonyPostfix] [HarmonyPatch("SetupRequirement")] private static void SetupRequirementPostfix(Transform elementRoot, Requirement req, Player player, bool craft, int quality, int craftMultiplier, bool __result) { if (!__result || req?.m_resItem?.m_itemData?.m_shared == null || (Object)(object)player == (Object)null) { return; } string name = req.m_resItem.m_itemData.m_shared.m_name; if (string.IsNullOrEmpty(name)) { return; } int amount = req.GetAmount(quality); if (amount <= 0) { return; } int needed = amount * Mathf.Max(1, craftMultiplier); Inventory inventory = ((Humanoid)player).GetInventory(); int inPlayer = ((inventory != null) ? inventory.CountItems(name, -1, true) : 0); bool inBuildInfo = BuildGatherPatch.InBuildInfo; List<Container> sources; if (inBuildInfo) { sources = BuildGather.SourcesCached(); } else { if (_sources == null) { _sources = Gatherer.Sources(); } sources = _sources; } int num = Gatherer.CountInStorage(sources, name); if (!inBuildInfo && Seen.Add(name) && Needs.Count < 16) { Needs.Add(new GatherNeed { SharedName = name, Display = Names.Normalize(name), Needed = needed, InPlayer = inPlayer, InStorage = num }); } if (Gather.CountsShown && num > 0) { Annotate(elementRoot, num); } } private static void Annotate(Transform elementRoot, int inStorage) { if ((Object)(object)elementRoot == (Object)null) { return; } TMP_Text val = null; Transform val2 = elementRoot.Find("res_amount"); if ((Object)(object)val2 != (Object)null) { val = ((Component)val2).GetComponent<TMP_Text>(); } if ((Object)(object)val == (Object)null) { TMP_Text[] componentsInChildren = ((Component)elementRoot).GetComponentsInChildren<TMP_Text>(true); if (componentsInChildren != null && componentsInChildren.Length != 0) { val = componentsInChildren[^1]; } } if (!((Object)(object)val == (Object)null) && (val.text == null || !val.text.Contains(" <color=#9BE07A>"))) { val.textWrappingMode = (TextWrappingModes)0; val.overflowMode = (TextOverflowModes)0; TMP_Text obj = val; obj.text = obj.text + " <color=#9BE07A><size=85%>(" + inStorage + ")</size></color>"; } } [HarmonyPostfix] [HarmonyPatch("Show")] private static void ShowPostfix(InventoryGui __instance) { EnsureButton(__instance); } [HarmonyPostfix] [HarmonyPatch("UpdateRecipe")] private static void UpdateRecipePostfix(InventoryGui __instance) { EnsureButton(__instance); RefreshButton(); } [HarmonyPostfix] [HarmonyPatch("Hide")] private static void HidePostfix() { if ((Object)(object)_gatherBtn != (Object)null) { ((Component)_gatherBtn).gameObject.SetActive(false); } } private static void EnsureButton(InventoryGui gui) { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected O, but got Unknown //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: 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_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_gatherBtn != (Object)null || (Object)(object)gui == (Object)null) { return; } Button craftButton = gui.m_craftButton; if ((Object)(object)craftButton == (Object)null) { return; } RectTransform component = ((Component)craftButton).GetComponent<RectTransform>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)((Transform)component).parent == (Object)null)) { Button val = Object.Instantiate<Button>(craftButton, ((Transform)component).parent); ((Object)val).name = "psort_gather"; Localize componentInChildren = ((Component)val).GetComponentInChildren<Localize>(true); if ((Object)(object)componentInChildren != (Object)null) { Object.DestroyImmediate((Object)(object)componentInChildren); } UIGamePad[] componentsInChildren = ((Component)val).GetComponentsInChildren<UIGamePad>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } val.onClick = new ButtonClickedEvent(); ((UnityEvent)val.onClick).AddListener(new UnityAction(OnGatherClick)); RectTransform component2 = ((Component)val).GetComponent<RectTransform>(); component2.anchorMin = component.anchorMin; component2.anchorMax = component.anchorMax; component2.pivot = component.pivot; component2.sizeDelta = component.sizeDelta; Vector2 anchoredPosition = component.anchoredPosition; Rect rect = component.rect; component2.anchoredPosition = anchoredPosition - new Vector2(0f, ((Rect)(ref rect)).height + 6f); _gatherLabel = ((Component)val).GetComponentInChildren<TMP_Text>(); if ((Object)(object)_gatherLabel != (Object)null) { float fontSize = _gatherLabel.fontSize; _gatherLabel.enableAutoSizing = true; _gatherLabel.fontSizeMax = fontSize; _gatherLabel.fontSizeMin = fontSize - 4f; _gatherLabel.text = "Gather"; } _gatherBtn = val; } } private static void RefreshButton() { if ((Object)(object)_gatherBtn == (Object)null) { return; } if (!Gather.IsEnabled) { ((Component)_gatherBtn).gameObject.SetActive(false); return; } List<GatherNeed> list = GatherMath.Resolve(Needs, _onlyOneIngredient); int num = 0; foreach (GatherNeed item in list) { num += item.Gatherable; } bool flag = num > 0; ((Component)_gatherBtn).gameObject.SetActive(Needs.Count > 0); ((Selectable)_gatherBtn).interactable = flag; if ((Object)(object)_gatherLabel != (Object)null) { _gatherLabel.text = (flag ? ("Gather (" + num + ")") : "Gather"); } InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance != (Object)null && (Object)(object)instance.m_craftButton != (Object)null && ((Component)_gatherBtn).gameObject.activeInHierarchy) { GamepadNav.LinkVertical((Selectable)(object)instance.m_craftButton, (Selectable)(object)_gatherBtn, onlyIfVanillaEmpty: false); } } private static void OnGatherClick() { if (Gather.IsEnabled && !((Object)(object)Player.m_localPlayer == (Object)null)) { List<GatherNeed> list = GatherMath.Resolve(Needs, _onlyOneIngredient); if (list.Count == 0) { Msg((Needs.Count == 0) ? "Select a recipe first" : "Nothing to gather - nearby chests have none of what this needs"); return; } Gatherer.Pull(list, out var movedTotal, out var typesMoved); Msg((movedTotal > 0) ? ("Gathered " + movedTotal + " item" + ((movedTotal == 1) ? "" : "s") + " (" + typesMoved + " type" + ((typesMoved == 1) ? "" : "s") + ")") : "Nothing could be gathered - your inventory may be full"); } } private static void Msg(string text) { if ((Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false); } } } [HarmonyPatch(typeof(InventoryGui))] internal static class GuiPatch { private static RectTransform _bar; private static Button _sorterBtn; private static Button _pinBtn; private static Button _clearBtn; private static Button _pullBtn; private static Button _organizeBtn; private static TMP_Text _sorterLabel; private static TMP_Text _pinLabel; private static TMP_Text _clearLabel; private static TMP_Text _pullLabel; private static TMP_Text _organizeLabel; private static Container _current; private static readonly FieldRef<InventoryGui, InventoryGrid> ContainerGridRef = AccessTools.FieldRefAccess<InventoryGui, InventoryGrid>("m_containerGrid"); private static readonly FieldRef<InventoryGrid, RectTransform> GridRootRef = AccessTools.FieldRefAccess<InventoryGrid, RectTransform>("m_gridRoot"); private static float _lastBarY = float.NaN; private static readonly Vector3[] Corners = (Vector3[])(object)new Vector3[4]; private const float ConfirmWindow = 5f; private const float MinConfirmDelay = 0.3f; private static OrganizePlan _pendingPlan; private static Container _pendingChest; private static float _pendingAt; [HarmonyPostfix] [HarmonyPatch("Show")] private static void ShowPostfix(InventoryGui __instance, Container container) { if ((Object)(object)container != (Object)(object)_pendingChest) { ClearPending(); } _current = container; _lastBarY = float.NaN; EnsureBar(__instance); PositionBar(__instance); Refresh(); } [HarmonyPostfix] [HarmonyPatch("UpdateContainer")] private static void UpdateContainerPostfix(InventoryGui __instance) { if (!((Object)(object)_current == (Object)null) && !((Object)(object)_bar == (Object)null) && ((Component)_bar).gameObject.activeSelf) { PositionBar(__instance); } } [HarmonyPostfix] [HarmonyPatch("Hide")] private static void HidePostfix() { _current = null; ClearPending(); if ((Object)(object)_bar != (Object)null) { ((Component)_bar).gameObject.SetActive(false); } } [HarmonyPostfix] [HarmonyPatch("Update")] private static void UpdatePostfix() { if (_pendingPlan != null && Time.time - _pendingAt > 5f) { ClearPending(); } } private static void EnsureBar(InventoryGui gui) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: 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) //IL_0067: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Expected O, but got Unknown //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Expected O, but got Unknown //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Expected O, but got Unknown //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Expected O, but got Unknown //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Expected O, but got Unknown if ((Object)(object)_bar != (Object)null) { return; } Button takeAllButton = gui.m_takeAllButton; if (!((Object)(object)takeAllButton == (Object)null)) { RectTransform component = ((Component)takeAllButton).GetComponent<RectTransform>(); Transform parent = ((Transform)component).parent; if (!((Object)(object)((parent is RectTransform) ? parent : null) == (Object)null)) { GameObject val = new GameObject("psort_bar", new Type[1] { typeof(RectTransform) }); _bar = (RectTransform)val.transform; ((Transform)_bar).SetParent(((Transform)component).parent, false); _bar.anchorMin = new Vector2(0f, 0f); _bar.anchorMax = new Vector2(0f, 0f); _bar.pivot = new Vector2(0f, 1f); HorizontalLayoutGroup obj = val.AddComponent<HorizontalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)obj).spacing = 8f; ((LayoutGroup)obj).childAlignment = (TextAnchor)6; ((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = false; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false; ContentSizeFitter obj2 = val.AddComponent<ContentSizeFitter>(); obj2.horizontalFit = (FitMode)2; obj2.verticalFit = (FitMode)2; _sorterBtn = MakeButton(takeAllButton, "psort_toggle", new UnityAction(OnSorterClick), out _sorterLabel); _pinBtn = MakeButton(takeAllButton, "psort_pin", new UnityAction(OnPinClick), out _pinLabel); _clearBtn = MakeButton(takeAllButton, "psort_clear", new UnityAction(OnClearClick), out _clearLabel); _pullBtn = MakeButton(takeAllButton, "psort_pull", new UnityAction(OnPullClick), out _pullLabel); _organizeBtn = MakeButton(takeAllButton, "psort_organize", new UnityAction(OnOrganizeClick), out _organizeLabel); } } } private unsafe static void PositionBar(InventoryGui gui) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_bar == (Object)null) { return; } Button takeAllButton = gui.m_takeAllButton; if ((Object)(object)takeAllButton == (Object)null) { return; } RectTransform component = ((Component)takeAllButton).GetComponent<RectTransform>(); Transform parent = ((Transform)component).parent; RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null); if ((Object)(object)val == (Object)null) { return; } Rect rect = val.rect; Rect val2 = component.rect; float width = ((Rect)(ref val2)).width; val2 = component.rect; float height = ((Rect)(ref val2)).height; float num = ((Rect)(ref rect)).x + ((Rect)(ref rect)).width * component.anchorMin.x; float num2 = ((Rect)(ref rect)).y + ((Rect)(ref rect)).height * component.anchorMin.y; float num3 = num + component.anchoredPosition.x + (0.5f - component.pivot.x) * width; float num4 = num2 + component.anchoredPosition.y + (0.5f - component.pivot.y) * height; float num5 = num3 - width * 0.5f - ((Rect)(ref rect)).xMin; float num6 = ((Rect)(ref rect)).yMax - (num4 + height * 0.5f) + height; if (TryGetUsedGridBottom(gui, val, out var bottomLocalY) && ((Rect)(ref rect)).yMin + num6 > bottomLocalY - 6f) { num6 = bottomLocalY - 6f - ((Rect)(ref rect)).yMin; float num7 = 0f - height; if (num6 < num7) { num6 = num7; } } if (float.IsNaN(_lastBarY) || Mathf.Abs(num6 - _lastBarY) > 0.5f) { _bar.anchoredPosition = new Vector2(num5, num6); _lastBarY = num6; ManualLogSource log = Plugin.Log; string[] obj = new string[8] { "[ui] panel=", null, null, null, null, null, null, null }; val2 = rect; obj[1] = ((object)(*(Rect*)(&val2))/*cast due to .constrained prefix*/).ToString(); obj[2] = " usedGridBottom="; obj[3] = bottomLocalY.ToString(); obj[4] = " barY="; obj[5] = num6.ToString(); obj[6] = " leftMargin="; obj[7] = num5.ToString(); log.LogDebug((object)string.Concat(obj)); } } private static bool TryGetUsedGridBottom(InventoryGui gui, RectTransform space, out float bottomLocalY) { //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) bottomLocalY = 0f; InventoryGrid val = ContainerGridRef.Invoke(gui); if ((Object)(object)val == (Object)null) { return false; } RectTransform val2 = GridRootRef.Invoke(val); if ((Object)(object)val2 == (Object)null || ((Transform)val2).childCount == 0) { return false; } float num = float.MaxValue; bool flag = false; for (int i = 0; i < ((Transform)val2).childCount; i++) { Transform child = ((Transform)val2).GetChild(i); if ((Object)(object)child == (Object)null || !((Component)child).gameObject.activeSelf) { continue; } RectTransform val3 = (RectTransform)(object)((child is RectTransform) ? child : null); if (!((Object)(object)val3 == (Object)null)) { val3.GetWorldCorners(Corners); float y = ((Transform)space).InverseTransformPoint(Corners[0]).y; if (y < num) { num = y; flag = true; } } } if (!flag) { return false; } bottomLocalY = num; return true; } private static Button MakeButton(Button template, string name, UnityAction onClick, out TMP_Text label) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) Button val = Object.Instantiate<Button>(template, (Transform)(object)_bar); ((Object)val).name = name; Localize componentInChildren = ((Component)val).GetComponentInChildren<Localize>(true); if ((Object)(object)componentInChildren != (Object)null) { Object.DestroyImmediate((Object)(object)componentInChildren); } UIGamePad[] componentsInChildren = ((Component)val).GetComponentsInChildren<UIGamePad>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } val.onClick = new ButtonClickedEvent(); ((UnityEvent)val.onClick).AddListener(onClick); RectTransform component = ((Component)template).GetComponent<RectTransform>(); LayoutElement obj = ((Component)val).gameObject.AddComponent<LayoutElement>(); Rect rect = component.rect; obj.preferredWidth = ((Rect)(ref rect)).width; rect = component.rect; obj.preferredHeight = ((Rect)(ref rect)).height; label = ((Component)val).GetComponentInChildren<TMP_Text>(); if ((Object)(object)label != (Object)null) { float fontSize = label.fontSize; label.enableAutoSizing = true; label.fontSizeMax = fontSize; label.fontSizeMin = fontSize - 4f; } return val; } private static void OnSorterClick() { if (!((Object)(object)_current == (Object)null)) { bool flag = !SorterZdo.IsSorter(_current); SorterZdo.SetSorter(_current, flag); ClearPending(); Msg(flag ? "Sorter enabled. Contents distribute when the chest is closed" : "Sorter disabled"); Refresh(); } } private static void OnPinClick() { if ((Object)(object)_current == (Object)null) { return; } if (Filters.GetPinned(_current).Count <= 0) { if (Filters.PinContents(_current) > 0) { Filters.SetManual(_current, manual: false); List<string> pinned = Filters.GetPinned(_current); Msg("Pinned: " + string.Join(", ", pinned) + " (auto-fill on)"); Plugin.Log.LogInfo((object)("[pin] " + string.Join(", ", pinned))); } else { bool flag = !Filters.GetManual(_current); Filters.SetManual(_current, flag); Msg(flag ? "Chest is empty - marked Manual. Organize will not claim or fill it" : "Manual off. Organize may claim this empty chest as a home"); } } else { bool flag2 = !Filters.GetManual(_current); Filters.SetManual(_current, flag2); Msg(flag2 ? "Auto-fill off. This chest only fills when you click Pull" : "Auto-fill on. The sorter routes matching items here"); } Refresh(); } private static void OnClearClick() { if (!((Object)(object)_current == (Object)null)) { Filters.ClearPinned(_current); Filters.SetManual(_current, manual: false); Filters.ClearHome(_current); Msg("Filters cleared"); Refresh(); } } private static void OnPullClick() { if (!((Object)(object)_current == (Object)null)) { Puller.PullInto(_current, out var movedTotal, out var typesMoved); Msg((movedTotal > 0) ? ("Pulled " + movedTotal + " item" + ((movedTotal == 1) ? "" : "s") + " (" + typesMoved + " type" + ((typesMoved == 1) ? "" : "s") + ")") : "Nothing to pull from nearby chests"); } } private static void OnOrganizeClick() { if ((Object)(object)_current == (Object)null) { return; } if (_pendingPlan != null && (Object)(object)_pendingChest == (Object)(object)_current && Time.time - _pendingAt <= 5f) { if (!(Time.time - _pendingAt < 0.3f)) { Container current = _current; ClearPending(); OrganizePlan organizePlan = Organizer.BuildPlan(current, Plugin.SorterRadius.Value); if (organizePlan.IsEmpty) { Msg("Nothing left to organize"); } else { Organizer.Execute(organizePlan); } } return; } OrganizePlan organizePlan2 = Organizer.BuildPlan(_current, Plugin.SorterRadius.Value); if (organizePlan2.IsEmpty) { ClearPending(); Msg("Nothing to organize"); return; } _pendingPlan = organizePlan2; _pendingChest = _current; _pendingAt = Time.time; OrganizeSummary summary = organizePlan2.Summary; if ((Object)(object)_organizeLabel != (Object)null) { _organizeLabel.text = "Confirm?"; } Plugin.Log.LogInfo((object)("[organize] plan ready: " + summary.TotalItems + " items -> " + summary.TargetChests + " chest(s) from " + summary.SourceChests + " source(s); awaiting confirm")); string text = "Organize: move " + summary.TotalItems + " item" + ((summary.TotalItems == 1) ? "" : "s") + " across " + summary.TargetChests + " chest" + ((summary.TargetChests == 1) ? "" : "s"); if (summary.HomelessItems > 0) { text = text + " (" + summary.HomelessItems + " won't fit - add more chests)"; } Msg(text + " - press again to confirm"); } private static void ClearPending() { _pendingPlan = null; _pendingChest = null; _pendingAt = 0f; if ((Object)(object)_organizeLabel != (Object)null) { _organizeLabel.text = "Organize"; } } private static void Refresh() { if ((Object)(object)_bar == (Object)null) { return; } bool flag = (Object)(object)_current != (Object)null && SorterZdo.HasValidNView(_current) && !PullerChestPiece.IsPullerChest(_current); ((Component)_bar).gameObject.SetActive(flag); if (!flag) { return; } bool flag2 = SorterZdo.IsSorter(_current); _sorterLabel.text = (flag2 ? "Sorter: ON" : "Sorter: OFF"); bool flag3 = !flag2; bool flag4 = false; bool flag5 = false; if (flag3) { int count = Filters.GetPinned(_current).Count; bool manual = Filters.GetManual(_current); FilterSpec spec = Filters.GetSpec(_current); _pinLabel.text = ((count != 0) ? (manual ? ("Manual (" + count + ")") : ("Auto (" + count + ")")) : (manual ? "Manual" : "Pin")); flag4 = count > 0 || manual || !string.IsNullOrEmpty(spec.Home); if (flag4) { _clearLabel.text = "Clear"; } flag5 = spec.HasExplicit; if (flag5) { _pullLabel.text = "Pull"; } } if (flag2) { _organizeLabel.text = ((_pendingPlan != null && (Object)(object)_pendingChest == (Object)(object)_current) ? "Confirm?" : "Organize"); } ((Component)_pinBtn).gameObject.SetActive(flag3); ((Component)_clearBtn).gameObject.SetActive(flag4); ((Component)_pullBtn).gameObject.SetActive(flag5); ((Component)_organizeBtn).gameObject.SetActive(flag2); LinkGamepadNav(); } private static void LinkGamepadNav() { if (!((Object)(object)_bar == (Object)null)) { List<Selectable> row = new List<Selectable> { (Selectable)(object)_sorterBtn, (Selectable)(object)_pinBtn, (Selectable)(object)_clearBtn, (Selectable)(object)_pullBtn, (Selectable)(object)_organizeBtn }; GamepadNav.LinkRow(row); InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance != (Object)null && (Object)(object)instance.m_takeAllButton != (Object)null) { GamepadNav.AttachRowToAnchor((Selectable)(object)instance.m_takeAllButton, row); } } } private static void Msg(string text) { if ((Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false); } } } [HarmonyPatch(typeof(InventoryHandler), "RPC_RequestItemRemoveResponse", new Type[] { typeof(Inventory), typeof(RequestChestRemoveResponse) })] internal static class InventoryHandler_RemoveResponse_Patch { private static void Postfix(RequestChestRemoveResponse response) { if (response != null) { MucResults.RecordRemove(response.SourceID, response.Success, response.Amount); } } } [HarmonyPatch] internal static class PlaceGatherPatch { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(Player), "UpdatePlacement", new Type[2] { typeof(bool), typeof(float) }, (Type[])null); } [HarmonyPrefix] private static void Prefix(Player __instance, bool takeInput) { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) if (!Gather.IsEnabled || !Gather.IsBuildEnabled || (Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || !takeInput || !((Character)__instance).InPlaceMode() || Hud.IsPieceSelectionVisible() || __instance.PlacementCostDisabled || (!ZInput.GetButtonDown("Attack") && !ZInput.GetButtonDown("JoyPlace")) || ZInput.GetButton("AltPlace") || ZInput.GetButton("JoyAltKeys")) { return; } Piece selectedPiece = __instance.GetSelectedPiece(); if ((Object)(object)selectedPiece == (Object)null || selectedPiece.m_resources == null || selectedPiece.m_resources.Length == 0 || __instance.HaveRequirements(selectedPiece, (RequirementMode)0) || (int)__instance.GetPlacementStatus() != 0) { return; } BuildGather.Invalidate(); List<GatherNeed> list = GatherMath.Resolve(BuildGather.NeedsFor(selectedPiece), onlyOneIngredient: false); if (list.Count != 0) { Gatherer.Pull(list, out var movedTotal, out var typesMoved); BuildGather.Invalidate(); if (movedTotal > 0) { Plugin.Log.LogInfo((object)("[gather] place-triggered pull: " + movedTotal + " item(s), " + typesMoved + " type(s) for " + ((Object)selectedPiece).name)); } } } } [HarmonyPatch(typeof(Smelter), "Awake")] internal static class Smelter_Awake_Patch { private static void Postfix(Smelter __instance) { Stations.RegisterProcessor((Component)(object)__instance, __instance.m_name); } } [HarmonyPatch(typeof(Smelter), "OnDestroyed")] internal static class Smelter_OnDestroyed_Patch { private static void Prefix(Smelter __instance) { Stations.UnregisterProcessor((Component)(object)__instance); } } [HarmonyPatch(typeof(Fermenter), "Awake")] internal static class Fermenter_Awake_Patch { private static void Postfix(Fermenter __instance) { Stations.RegisterProcessor((Component)(object)__instance, __instance.m_name); } } [HarmonyPatch(typeof(Fermenter), "OnDestroyed")] internal static class Fermenter_OnDestroyed_Patch { private static void Prefix(Fermenter __instance) { Stations.UnregisterProcessor((Component)(object)__instance); } } [HarmonyPatch(typeof(CookingStation), "Awake")] internal static class CookingStation_Awake_Patch { private static void Postfix(CookingStation __instance) { Stations.RegisterProcessor((Component)(object)__instance, __instance.m_name); } } [HarmonyPatch(typeof(CookingStation), "OnDestroyed")] internal static class CookingStation_OnDestroyed_Patch { private static void Prefix(CookingStation __instance) { Stations.UnregisterProcessor((Component)(object)__instance); } } [HarmonyPatch(typeof(InventoryGui))] internal static class PullerPanelPatch { private const float CensusInterval = 1f; private const float Pad = 12f; private const float TitleHeight = 32f; private const float SearchHeight = 34f; private const float StatusHeight = 26f; private const float ButtonHeight = 34f; private static readonly FieldRef<InventoryGui, Container> CurrentContainerRef = AccessTools.FieldRefAccess<InventoryGui, Container>("m_currentContainer"); private static readonly FieldInfo BuildSearchField = AccessTools.Field(typeof(BuildUi), "m_searchField"); private static RectTransform _panel; private static TMP_Text _title; private static TMP_InputField _search; private static ScrollRect _scroll; private static RectTransform _content; private static TMP_Text _status; private static Button _sendBack; private static float _rowHeight = 30f; private static readonly List<GameObject> Rows = new List<GameObject>(); private static readonly List<string> RowNames = new List<string>(); private static Container _chest; private static bool _hidCrafting; private static List<PullerStorage.Entry> _census = new List<PullerStorage.Entry>(); private static string _censusKey = ""; private static float _censusAt = float.NegativeInfinity; private const int RowsPerNotch = 3; internal static bool SearchFocused { get { if ((Object)(object)_chest != (Object)null && (Object)(object)_search != (Object)null && _search.isFocused && (Object)(object)_panel != (Object)null) { return ((Component)_panel).gameObject.activeInHierarchy; } return false; } } [HarmonyPostfix] [HarmonyPatch("Show")] private static void ShowPostfix(InventoryGui __instance, Container container) { if ((Object)(object)container != (Object)null && PullerChestPiece.IsPullerChest(container)) { Open(__instance, container); } else { Close(__instance); } } [HarmonyPostfix] [HarmonyPatch("Hide")] private static void HidePostfix(InventoryGui __instance) { Close(__instance); } [HarmonyPostfix] [HarmonyPatch("UpdateContainer")] private static void UpdateContainerPostfix(InventoryGui __instance) { if ((Object)(object)_chest == (Object)null) { if (_hidCrafting || ((Object)(object)_panel != (Object)null && ((Component)_panel).gameObject.activeSelf)) { Close(__instance); } return; } if ((Object)(object)CurrentContainerRef.Invoke(__instance) != (Object)(object)_chest) { Close(__instance); return; } if ((Object)(object)__instance.m_crafting != (Object)null && ((Component)__instance.m_crafting).gameObject.activeSelf) { ((Component)__instance.m_crafting).gameObject.SetActive(false); _hidCrafting = true; } ScrollWithWheel(); if (Time.unscaledTime - _censusAt >= 1f) { RefreshCensus(force: false); } } private static bool PointerOverList() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_scroll == (Object)null || (Object)(object)_scroll.viewport == (Object)null) { return false; } RectTransform viewport = _scroll.viewport; Canvas componentInParent = ((Component)viewport).GetComponentInParent<Canvas>(); Camera val = (((Object)(object)componentInParent != (Object)null && (int)componentInParent.renderMode != 0) ? componentInParent.worldCamera : null); return RectTransformUtility.RectangleContainsScreenPoint(viewport, Vector2.op_Implicit(ZInput.pointerPosition), val); } private static void ScrollWithWheel() { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_scroll == (Object)null || (Object)(object)_content == (Object)null || (Object)(object)_scroll.viewport == (Object)null) { return; } float mouseScrollWheel = ZInput.GetMouseScrollWheel(); if (!Mathf.Approximately(mouseScrollWheel, 0f) && PointerOverList()) { RectTransform viewport = _scroll.viewport; Rect rect = _content.rect; float height = ((Rect)(ref rect)).height; rect = viewport.rect; float num = height - ((Rect)(ref rect)).height; if (!(num <= 0f)) { float num2 = 3f * _rowHeight / num; _scroll.verticalNormalizedPosition = Mathf.Clamp01(_scroll.verticalNormalizedPosition + Mathf.Sign(mouseScrollWheel) * num2); } } } [HarmonyPrefix] [HarmonyPatch("Update")] private static void UpdatePrefix() { if (SearchFocused) { ZInput.ResetButtonStatus("Use"); ZInput.ResetButtonStatus("Inventory"); } } private static void Open(InventoryGui gui, Container chest) { if (EnsurePanel(gui)) { _chest = chest; if ((Object)(object)gui.m_crafting != (Object)null && ((Component)gui.m_crafting).gameObject.activeSelf) { ((Component)gui.m_crafting).gameObject.SetActive(false); _hidCrafting = true; } ((Component)_panel).gameObject.SetActive(true); ((Transform)_panel).SetAsLastSibling(); if ((Object)(object)_search != (Object)null) { _search.text = ""; } RefreshCensus(force: true); if ((Object)(object)_scroll != (Object)null) { _scroll.verticalNormalizedPosition = 1f; } } } private static void Close(InventoryGui gui) { _chest = null; if ((Object)(object)_search != (Object)null && _search.isFocused) { _search.DeactivateInputField(false); } if ((Object)(object)_panel != (Object)null && ((Component)_panel).gameObject.activeSelf) { ((Component)_panel).gameObject.SetActive(false); } if (_hidCrafting) { _hidCrafting = false; if ((Object)(object)gui != (Object)null && (Object)(object)gui.m_crafting != (Object)null) { ((Component)gui.m_crafting).gameObject.SetActive(true); } } } private static void RefreshCensus(bool force) { _censusAt = Time.unscaledTime; if ((Object)(object)_chest == (Object)null || (!force && PointerOverList())) { return; } List<PullerStorage.Entry> list = PullerStorage.Census(_chest); StringBuilder stringBuilder = new StringBuilder(); foreach (PullerStorage.Entry item in list) { stringBuilder.Append(item.SharedName).Append('=').Append(item.Count) .Append(';'); } string text = stringBuilder.ToString(); if (force || !(text == _censusKey)) { _census = list; _censusKey = text; Rebuild(); } } private static void Rebuild() { //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_content == (Object)null) { return; } string text = (((Object)(object)_search != (Object)null) ? (_search.text ?? "").Trim() : ""); int num = 0; foreach (PullerStorage.Entry censu in _census) { if (text.Length <= 0 || censu.Display.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0 || censu.SharedName.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0) { GameObject val = RowAt(num); if ((Object)(object)val == (Object)null) { break; } FillRow(val, censu); RowNames[num] = censu.SharedName; num++; } } for (int i = num; i < Rows.Count; i++) { if ((Object)(object)Rows[i] != (Object)null && Rows[i].activeSelf) { Rows[i].SetActive(false); } } _content.sizeDelta = new Vector2(_content.sizeDelta.x, (float)num * _rowHeight); if ((Object)(object)_status != (Object)null) { _status.text = ((num > 0) ? "Click pulls a stack, Shift-click pulls all" : ((_census.Count == 0) ? "Nothing in storage nearby" : "No matches")); } } private static void OnRowClick(int index) { if (!((Object)(object)_chest == (Object)null) && index >= 0 && index < RowNames.Count) { string text = RowNames[index]; if (!string.IsNullOrEmpty(text)) { bool all = ZInput.GetKey((KeyCode)304, false) || ZInput.GetKey((KeyCode)303, false); int num = PullerStorage.Pull(_chest, text, all); string text2 = ((Localization.instance != null) ? Localization.instance.Localize(text) : text); Msg((num > 0) ? ("Pulling " + num + " " + text2) : ("Couldn't pull " + text2 + ", the chest may be full")); _censusAt = Time.unscaledTime - 1f + 0.3f; } } } private static bool EnsurePanel(InventoryGui gui) { //IL_0097: 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_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown //IL_00be: 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_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: 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_0183: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_panel != (Object)null) { return true; } if ((Object)(object)gui == (Object)null || (Object)(object)gui.m_crafting == (Object)null) { return false; } Rows.Clear(); RowNames.Clear(); _title = null; _search = null; _scroll = null; _content = null; _status = null; _sendBack = null; RectTransform crafting = gui.m_crafting; Transform parent = ((Transform)crafting).parent; RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null); if ((Object)(object)val == (Object)null) { return false; } try { GameObject val2 = new GameObject("psort_puller_panel", new Type[1] { typeof(RectTransform) }); _panel = (RectTransform)val2.transform; ((Transform)_panel).SetParent((Transform)(object)val, false); _panel.anchorMin = crafting.anchorMin; _panel.anchorMax = crafting.anchorMax; _panel.pivot = crafting.pivot; _panel.anchoredPosition = crafting.anchoredPosition; _panel.sizeDelta = crafting.sizeDelta; ((Transform)_panel).localScale = ((Transform)crafting).localScale; Image val3 = val2.AddComponent<Image>(); Image component = ((Component)crafting).GetComponent<Image>(); if ((Object)(object)component != (Object)null && (Object)(object)component.sprite != (Object)null) { val3.sprite = component.sprite; val3.type = component.type; ((Graphic)val3).color = ((Graphic)component).color; val3.pixelsPerUnitMultiplier = component.pixelsPerUnitMultiplier; } else { ((Graphic)val3).color = new Color(0f, 0f, 0f, 0.8f); } ((Graphic)val3).raycastTarget = true; BuildTitle(gui); BuildSearch(); BuildStatus(gui); BuildSendBack(gui); BuildList(gui); ((Component)_panel).gameObject.SetActive(false); ManualLogSource log = Plugin.Log; string[] obj = new string[7] { "[puller] panel built over the crafting panel (", null, null, null, null, null, null }; Rect rect = crafting.rect; obj[1] = ((Rect)(ref rect)).width.ToString("0"); obj[2] = "x"; rect = crafting.rect; obj[3] = ((Rect)(ref rect)).height.ToString("0"); obj[4] = ", search "; obj[5] = (((Object)(object)_search != (Object)null) ? "on" : "unavailable"); obj[6] = ")"; log.LogInfo((object)string.Concat(obj)); return true; } catch (Exception ex) { Plugin.Log.LogError((object)("[puller] could not build the panel: " + ex)); if ((Object)(object)_panel != (Object)null) { Object.Destroy((Object)(object)((Component)_panel).gameObject); } _panel = null; _search = null; _scroll = null; _content = null; Rows.Clear(); RowNames.Clear(); return false; } } private static void BuildTitle(InventoryGui gui) { if (!((Object)(object)gui.m_containerName == (Object)null)) { _title = Object.Instantiate<TMP_Text>(gui.m_containerName, (Transform)(object)_panel, false); ((Object)_title).name = "psort_puller_title"; StripLocalize(((Component)_title).gameObject); _title.text = "Pull from storage"; _title.alignment = (TextAlignmentOptions)514; Stretch(_title.rectTransform, 12f, -44f, -12f, -12f, top: true); } } private static void BuildSearch() { //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Expected O, but got Unknown //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Expected O, but got Unknown //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Expected O, but got Unknown //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Expected O, but got Unknown //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Expected O, but got Unknown Hud instance = Hud.instance; TMP_InputField val = (TMP_InputField)(((Object)(object)instance != (Object)null && (Object)(object)instance.m_buildUi != (Object)null && BuildSearchField != null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"[puller] build menu search field not found; the Puller list will have no search box"); return; } GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, (Transform)(object)_panel, false); ((Object)val2).name = "psort_puller_search"; val2.SetActive(true); MonoBehaviour[] componentsInChildren = val2.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val3 in componentsInChildren) { string name = ((object)val3).GetType().Name; if (name == "UIInputHint" || name == "UIGamePad") { Object.DestroyImmediate((Object)(object)val3); } } _search = val2.GetComponent<TMP_InputField>(); if ((Object)(object)_search == (Object)null) { Object.Destroy((Object)(object)val2); return; } _search.onValueChanged = new OnChangeEvent(); _search.onEndEdit = new SubmitEvent(); _search.onSubmit = new SubmitEvent(); _search.onSelect = new SelectionEvent(); _search.onDeselect = new SelectionEvent(); _search.text = ""; ((UnityEvent<string>)(object)_search.onValueChanged).AddListener((UnityAction<string>)delegate { Rebuild(); }); LayoutElement component = val2.GetComponent<LayoutElement>(); if ((Object)(object)component != (Object)null) { component.ignoreLayout = true; } float num = -48f; Stretch((RectTransform)val2.transform, 12f, num - 34f, -12f, num, top: true); } private static void BuildList(InventoryGui gui) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Expected O, but got Unknown //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) if (gui.m_recipeListSpace > 1f) { _rowHeight = gui.m_recipeListSpace; } GameObject val = new GameObject("psort_puller_list", new Type[1] { typeof(RectTransform) }); RectTransform val2 = (RectTransform)val.transform; ((Transform)val2).SetParent((Transform)(object)_panel, false); val2.anchorMin = Vector2.zero; val2.anchorMax = Vector2.one; val2.pivot = new Vector2(0.5f, 0.5f); float num = 48f + (((Object)(object)_search != (Object)null) ? 42f : 0f); float num2 = 38f + (((Object)(object)_sendBack != (Object)null) ? 44f : 0f); val2.offsetMin = new Vector2(12f, num2); val2.offsetMax = new Vector2(-12f, 0f - num); ((Graphic)val.AddComponent<Image>()).color = new Color(0f, 0f, 0f, 0.25f); val.AddComponent<RectMask2D>(); _content = (RectTransform)new GameObject("psort_puller_content", new Type[1] { typeof(RectTransform) }).transform; ((Transform)_content).SetParent((Transform)(object)val2, false); _content.anchorMin = new Vector2(0f, 1f); _content.anchorMax = new Vector2(1f, 1f); _content.pivot = new Vector2(0.5f, 1f); _content.anchoredPosition = Vector2.zero; _content.sizeDelta = new Vector2(0f, 0f); _scroll = val.AddComponent<ScrollRect>(); _scroll.horizontal = false; _scroll.vertical = true; _scroll.movementType = (MovementType)2; _scroll.scrollSensitivity = 0f; _scroll.viewport = val2; _scroll.content = _content; } private static void BuildStatus(InventoryGui gui) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: 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) if (!((Object)(object)gui.m_containerName == (Object)null)) { _status = Object.Instantiate<TMP_Text>(gui.m_containerName, (Transform)(object)_panel, false); ((Object)_status).name = "psort_puller_status"; StripLocalize(((Component)_status).gameObject); _status.alignment = (TextAlignmentOptions)514; _status.enableAutoSizing = true; _status.fontSizeMax = _status.fontSize * 0.8f; _status.fontSizeMin = _status.fontSize * 0.5f; _status.text = ""; RectTransform rectTransform = _status.rectTransform; rectTransform.anchorMin = new Vector2(0f, 0f); rectTransform.anchorMax = new Vector2(1f, 0f); rectTransform.pivot = new Vector2(0.5f, 0f); rectTransform.offsetMin = new Vector2(12f, 6f); rectTransform.offsetMax = new Vector2(-12f, 32f); } } private static void BuildSendBack(InventoryGui gui) { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected O, but got Unknown //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: 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_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)gui.m_takeAllButton == (Object)null) { return; } Button val = Object.Instantiate<Button>(gui.m_takeAllButton, (Transform)(object)_panel, false); ((Object)val).name = "psort_puller_sendback"; StripLocalize(((Component)val).gameObject); UIGamePad[] componentsInChildren = ((Component)val).GetComponentsInChildren<UIGamePad>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } MonoBehaviour[] componentsInChildren2 = ((Component)val).GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val2 in componentsInChildren2) { if (((object)val2).GetType().Name == "UITooltip") { Object.DestroyImmediate((Object)(object)val2); } } val.onClick = new ButtonClickedEvent(); ((UnityEvent)val.onClick).AddListener(new UnityAction(OnSendBackClick)); TMP_Text componentInChildren = ((Component)val).GetComponentInChildren<TMP_Text>(); if ((Object)(object)componentInChildren != (Object)null) { float fontSize = componentInChildren.fontSize; componentInChildren.enableAutoSizing = true; componentInChildren.fontSizeMax = fontSize; componentInChildren.fontSizeMin = fontSize - 4f; componentInChildren.text = "Send back"; } RectTransform component = ((Component)val).GetComponent<RectTransform>(); component.anchorMin = new Vector2(0f, 0f); component.anchorMax = new Vector2(1f, 0f); component.pivot = new Vector2(0.5f, 0f); component.offsetMin = new Vector2(36f, 38f); component.offsetMax = new Vector2(-36f, 72f); ((Transform)component).localScale = Vector3.one; _sendBack = val; List<Selectable> list = new List<Selectable>(); if ((Object)(object)_search != (Object)null) { list.Add((Selectable)(object)_search); } list.Add((Selectable)(object)val); GamepadNav.LinkRow(list); if ((Object)(object)gui.m_takeAllButton != (Object)null) { GamepadNav.AttachRowToAnchor((Selectable)(object)gui.m_takeAllButton, list); } } private static void OnSendBackClick() { if (!((Object)(object)_chest == (Object)null)) { int types; int num = PullerStorage.ReturnAll(_chest, out types); Msg((num > 0) ? ("Sent back " + num + " item" + ((num == 1) ? "" : "s") + " (" + types + " type" + ((types == 1) ? "" : "s") + ")") : "Nothing to send back, or no chest in range has room"); _censusAt = Time.unscaledTime - 1f + 0.3f; } } private static GameObject RowAt(int index) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: 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_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Expected O, but got Unknown //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Expected O, but got Unknown while (Rows.Count <= index) { InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.m_recipeElementPrefab == (Object)null || (Object)(object)_content == (Object)null) { return null; } GameObject val = Object.Instantiate<GameObject>(instance.m_recipeElementPrefab, (Transform)(object)_content, false); ((Object)val).name = "psort_puller_row"; int i = Rows.Count; RectTransform val2 = (RectTransform)val.transform; val2.anchorMin = new Vector2(0f, 1f); val2.anchorMax = new Vector2(1f, 1f); val2.pivot = new Vector2(0.5f, 1f); val2.sizeDelta = new Vector2(0f, _rowHeight); val2.anchoredPosition = new Vector2(0f, (float)(-i) * _rowHeight); Transform val3 = val.transform.Find("Durability"); if ((Object)(object)val3 != (Object)null) { ((Component)val3).gameObject.SetActive(false); } Transform val4 = val.transform.Find("QualityLevel"); if ((Object)(object)val4 != (Object)null) { ((Component)val4).gameObject.SetActive(false); } Transform val5 = val.transform.Find("selected"); if ((Object)(object)val5 != (Object)null) { ((Component)val5).gameObject.SetActive(false); } Button component = val.GetComponent<Button>(); if ((Object)(object)component != (Object)null) { component.onClick = new ButtonClickedEvent(); ((UnityEvent)component.onClick).AddListener((UnityAction)delegate { OnRowClick(i); }); } Rows.Add(val); RowNames.Add(null); } GameObject val6 = Rows[index]; if ((Object)(object)val6 != (Object)null && !val6.activeSelf) { val6.SetActive(true); } return val6; } private static void FillRow(GameObject row, PullerStorage.Entry e) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) Transform val = row.transform.Find("icon"); if ((Object)(object)val != (Object)null) { Image component = ((Component)val).GetComponent<Image>(); if ((Object)(object)component != (Object)null) { component.sprite = e.Icon; ((Graphic)component).color = Color.white; } } Transform val2 = row.transform.Find("name"); if ((Object)(object)val2 != (Object)null) { TMP_Text component2 = ((Component)val2).GetComponent<TMP_Text>(); if ((Object)(object)component2 != (Object)null) { component2.text = e.Display + " <color=#9BE07A>" + e.Count + "</color>"; ((Graphic)component2).color = Color.white; } } } private static void Stretch(RectTransform rt, float left, float bottomY, float right, float topY, bool top) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) float num = (top ? 1f : 0f); rt.anchorMin = new Vector2(0f, num); rt.anchorMax = new Vector2(1f, num); rt.pivot = new Vector2(0.5f, num); rt.offsetMin = new Vector2(left, bottomY); rt.offsetMax = new Vector2(right, topY); ((Transform)rt).localScale = Vector3.one; } private static void StripLocalize(GameObject go) { Localize[] componentsInChildren = go.GetComponentsInChildren<Localize>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } } private static void Msg(string text) { if ((Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false); } } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] internal static class PullerSearchFocusPatch { private static void Postfix(ref bool __result) { if (!__result && PullerPanelPatch.SearchFocused) { __result = true; } } } [HarmonyPatch(typeof(Sign), "Awake")] internal static class Sign_Awake_Patch { private static void Postfix(Sign __instance) { Filters.RegisterSign(__instance); } } [HarmonyPatch(typeof(Sign), "SetText")] internal static class Sign_SetText_Patch { private static void Postfix() { Filters.InvalidateAll(); } } } namespace ChestButler.Core { internal static class BucketKeys { internal const string GearPrefix = "gear:"; internal const string Weapons = "gear:weapons"; internal const string Armor = "gear:armor"; internal const string Tools = "gear:tools"; internal const string GearMisc = "gear:misc"; internal const string TypePrefix = "item:"; internal const string Misc = "misc"; internal static string ForType(string norm) { return "item:" + norm; } internal static bool IsGear(string key) { return key?.StartsWith("gear:", StringComparison.Ordinal) ?? false; } internal static bool IsPerType(string key) { return key?.StartsWith("item:", StringComparison.Ordinal) ?? false; } internal static string TypeOf(string key) { if (!IsPerType(key)) { return null; } return key.Substring("item:".Length); } internal static string Label(string key) { if (string.IsNullOrEmpty(key)) { return "?"; } if (IsGear(key)) { return key.Substring("gear:".Length); } if (IsPerType(key)) { return key.Substring("item:".Length); } return key; } } internal static class BuildGather { private const float SourceMaxAge = 1f; private static List<Container> _sources; private static float _sourcesAt = float.NegativeInfinity; internal static List<Container> SourcesCached() { float unscaledTime = Time.unscaledTime; if (_sources == null || unscaledTime - _sourcesAt > 1f) { _sources = Gatherer.Sources(); _sourcesAt = unscaledTime; } return _sources; } internal static void Invalidate() { _sources = null; } internal static List<GatherNeed> NeedsFor(Piece piece) { List<GatherNeed> list = new List<GatherNeed>(); Player localPlayer = Player.m_localPlayer; if ((Object)(object)piece == (Object)null || (Object)(object)localPlayer == (Object)null || piece.m_resources == null) { return list; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); List<Container> sources = SourcesCached(); Requirement[] resources = piece.m_resources; foreach (Requirement val in resources) { SharedData val2 = val?.m_resItem?.m_itemData?.m_shared; if (val2 != null && !string.IsNullOrEmpty(val2.m_name) && val.m_amount > 0) { list.Add(new GatherNeed { SharedName = val2.m_name, Display = Names.Normalize(val2.m_name), Needed = val.m_amount, InPlayer = ((inventory != null) ? inventory.CountItems(val2.m_name, -1, true) : 0), InStorage = Gatherer.CountInStorage(sources, val2.m_name) }); } } return list; } } internal static class ContainerTracker { internal struct Candidate { internal Container Chest; internal float Distance; } private static readonly HashSet<Container> All = new HashSet<Container>(); private static readonly HashSet<Container> Vehicles = new HashSet<Container>(); internal static void Register(Container c) { if (!((Object)(object)c == (Object)null) && !((Object)(object)((Component)c).GetComponentInParent<Incinerator>() != (Object)null)) { All.Add(c); if ((Object)(object)((Component)c).GetComponentInParent<Vagon>() != (Object)null || (Object)(object)((Component)c).GetComponentInParent<Ship>() != (Object)null) { Vehicles.Add(c); } } } internal static void Unregister(Container c) { if (!((Object)(object)c == (Object)null)) { All.Remove(c); Vehicles.Remove(c); Filters.Invalidate(c); } } internal static List<Container> Candidates(Container sorter, float radius, bool excludeSorters = true) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Accessible(((Component)sorter).transform.position, radius, sorter, excludeSorters); } internal static List<Container> AccessibleNear(Vector3 point, float radius, bool excludeSorters = false) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return Accessible(point, radius, null, excludeSorters); } private static List<Container> Accessible(Vector3 pos, float radius, Container exclude, bool excludeSorters) { //IL_00b7: 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_00ec: Unknown result type (might be due to invalid IL or missing references) All.RemoveWhere((Container c) => (Object)(object)c == (Object)null); List<float> dists = new List<float>(); List<Container> found = new List<Container>(); bool flag = Plugin.VehiclesAreStorage != null && Plugin.VehiclesAreStorage.Value; foreach (Container item in All) { if (!((Object)(object)item == (Object)(object)exclude) && (flag || !Vehicles.Contains(item)) && SorterZdo.HasValidNView(item) && item.GetInventory() != null && !((Object)(object)((Component)item).GetComponentInParent<Piece>() == (Object)null)) { float num = Vector3.Distance(pos, ((Component)item).transform.position); if (!(num > radius) && (!excludeSorters || !SorterZdo.IsSorter(item)) && SorterZdo.PlayerCanAccess(item) && PrivateArea.CheckAccess(((Component)item).transform.position, 0f, false, true)) { dists.Add(num); found.Add(item); } } } List<int> list = new List<int>(found.Count); for (int num2 = 0; num2 < found.Count; num2++) { list.Add(num2); } list.Sort(delegate(int a, int b) { int num3 = dists[a].CompareTo(dists[b]); return (num3 != 0) ? num3 : CompareUid(found[a], found[b]); }); List<Container> list2 = new List<Container>(list.Count); foreach (int item2 in list) { list2.Add(found[item2]); } return list2; } internal static List<Candidate> CandidatesWithDistance(Container sorter, float radius, bool excludeSorters = true) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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) List<Container> list = Candidates(sorter, radius, excludeSorters); List<Candidate> list2 = new List<Candidate>(list.Count); Vector3 position = ((Component)sorter).transform.position; foreach (Container item in list) { list2.Add(new Candidate { Chest = item, Distance = Vector3.Distance(position, ((Component)item).transform.position) }); } return list2; } internal static int CompareUid(Container a, Container b) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) ZNetView val = SorterZdo.NView(a); ZNetView val2 = SorterZdo.NView(b); if ((Object)(object)val == (Object)null || !val.IsValid()) { if (!((Object)(object)val2 == (Object)null) && val2.IsValid()) { return 1; } return 0; } if ((Object)(object)val2 == (Object)null || !val2.IsValid()) { return -1; } return ((ZDOID)(ref val.GetZDO().m_uid)).CompareTo(val2.GetZDO().m_uid); } internal static Container NearestTo(Vector3 point, float maxRange) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) Container result = null; float num = maxRange; foreach (Container item in All) { if (!((Object)(object)item == (Object)null)) { float num2 = Vector3.Distance(point, ((Component)item).transform.position); if (num2 < num) { num = num2; result = item; } } } return result; } } internal sealed class FilterSpec { internal readonly HashSet<string> Items = new HashSet<string>(); internal readonly HashSet<string> GroupNames = new HashSet<string>(); internal int Priority; internal bool Ignore; internal bool ManualOnly; internal string Home; internal bool HasExplicit { get { if (Items.Count <= 0) { return GroupNames.Count > 0; } return true; } } internal bool MatchesItem(string normName) { foreach (string item in Items) { if (Names.Matches(item, normName)) { return true; } } return false; } internal bool MatchesGroup(string normName) { foreach (string groupName in GroupNames) { if (Groups.GroupContains(groupName, normName)) { return true; } } return false; } } internal static class Filters { private const float SignRange = 2.5f; private const float CacheTtl = 30f; private static readonly int ItemsHash = StringExtensionMethods.GetStableHashCode("psort_items"); private static readonly int ManualHash = StringExtensionMethods.GetStableHashCode("psort_manual"); private static readonly int HomeHash = StringExtensionMethods.GetStableHashCode("psort_home"); private static readonly HashSet<Sign> Signs = new HashSet<Sign>(); private static readonly Dictionary<Container, KeyValuePair<float, FilterSpec>> Cache = new Dictionary<Container, KeyValuePair<float, FilterSpec>>(); internal static void RegisterSign(Sign s) { if ((Object)(object)s != (Object)null) { Signs.Add(s); InvalidateAll(); } } internal static void Invalidate(Container c) { if ((Object)(object)c != (Object)null) { Cache.Remove(c); } } internal static void InvalidateAll() { Cache.Clear(); } internal static List<string> GetPinned(Container c) { List<string> list = new List<string>(); ZNetView val = SorterZdo.NView(c); if ((Object)(object)val == (Object)null || !val.IsValid()) { return list; } string[] array = val.GetZDO().GetString(ItemsHash, "").Split(','); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0) { list.Add(text); } } return list; } internal static void SetPinned(Container c, IEnumerable<string> tokens) { ZNetView val = SorterZdo.NView(c); if (!((Object)(object)val == (Object)null) && val.IsValid()) { if (!val.IsOwner()) { val.ClaimOwnership(); } val.GetZDO().Set(ItemsHash, string.Join(",", tokens)); Cache.Remove(c); } } internal static int PinContents(Container c) { Inventory inventory = c.GetInventory(); if (inventory == null) { return 0; } HashSet<string> hashSet = new HashSet<string>(); foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem?.m_shared != null) { string text = Names.Normalize(allItem.m_shared.m_name); if (text.Length > 0) { hashSet.Add(text); } } } if (hashSet.Count > 0) { SetPinned(c, hashSet); } return hashSet.Count; } internal static void ClearPinned(Container c) { SetPinned(c, new string[0]); } internal static bool GetManual(Container c) { ZNetView val = SorterZdo.NView(c); if ((Object)(object)val != (Object)null && val.IsValid()) { return val.GetZDO().GetBool(ManualHash, false); } return false; } internal static void SetManual(Container c, bool manual) { ZNetView val = SorterZdo.NView(c); if (!((Object)(object)val == (Object)null) && val.IsValid()) { if (!val.IsOwner()) { val.ClaimOwnership(); } val.GetZDO().Set(ManualHash, manual); Cache.Remove(c); } } internal static string GetHome(Container c) { ZNetView val = SorterZdo.NView(c); if ((Object)(object)val == (Object)null || !val.IsValid()) { return null; } string text = val.GetZDO().GetString(HomeHash, ""); if (!string.IsNullOrEmpty(text)) { return text; } return null; } internal static void SetHome(Container c, string bucketKey) { ZNetView val = SorterZdo.NView(c); if (!((Object)(object)val == (Object)null) && val.IsValid()) { if (!val.IsOwner()) { val.ClaimOwnership(); } val.GetZDO().Set(HomeHash, bucketKey ?? ""); Cache.Remove(c); } } internal static void ClearHome(Container c) { SetHome(c, null); } internal static FilterSpec GetSpec(Container c) { if (Cache.TryGetValue(c, out var value) && Time.time - value.Key < 30f) { return value.Value; } FilterSpec filterSpec = new FilterSpec(); foreach (string item in GetPinned(c)) { filterSpec.Items.Add(item); } filterSpec.ManualOnly = GetManual(c); filterSpec.Home = GetHome(c); ParseNearestSign(c, filterSpec); if (PullerChestPiece.IsPullerChest(c)) { filterSpec.Ignore = true; } Cache[c] = new KeyValuePair<float, FilterSpec>(Time.time, filterSpec); return filterSpec; } private static void ParseNearestSign(Container c, FilterSpec spec) { //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_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: 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) Signs.RemoveWhere((Sign s) => (Object)(object)s == (Object)null); Vector3 position = ((Component)c).transform.position; foreach (Sign sign in Signs) { string text = sign.GetText(); if (string.IsNullOrEmpty(text)) { continue; } SignSpec signSpec = SignGrammar.Parse(text); float num = Vector3.Distance(((Component)sign).transform.position, position); if (signSpec.HasOff && signSpec.AreaOffRadius > 0f && num <= signSpec.AreaOffRadius) { spec.Ignore = true; } if (num > 2.5f || !IsNearestContainerTo(((Component)sign).transform.position, c)) { continue; } if (signSpec.HasOff) { spec.Ignore = true; } foreach (string token in signSpec.Tokens) { if (token.Length >= 2 && token[0] == 'p' && int.TryParse(token.Substring(1), out var result)) { spec.Priority = result; } else if (Groups.IsGroup(token)) { spec.GroupNames.Add(token); } else { spec.Items.Add(token); } } } } private static bool IsNearestContainerTo(Vector3 signPos, Container candidate) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) Container val = ContainerTracker.NearestTo(signPos, 2.5f); if (!((Object)(object)val == (Object)null)) { return (Object)(object)val == (Object)(object)candidate; } return true; } } internal static class GamepadNav { private static ConfigEntry<bool> _enabled; private static bool _bound; internal static bool Enabled { get { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown if (!_bound) { _bound = true; Plugin instance = Plugin.Instance; if ((Object)(object)instance != (Object)null) { _enabled = ((BaseUnityPlugin)instance).Config.Bind<bool>("Gamepad", "Enabled", true, new ConfigDescription("Let a controller reach ChestButler's buttons by linking them into the panel's D-pad navigation. Client-side.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = false } })); } } if (_enabled != null) { return _enabled.Value; } return true; } } internal static void LinkRow(IList<Selectable> row) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) if (!Enabled || row == null) { return; } List<Selectable> list = new List<Selectable>(); for (int i = 0; i < row.Count; i++) { Selectable val = row[i]; if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeInHierarchy) { list.Add(val); } } if (list.Count != 0) { for (int j = 0; j < list.Count; j++) { Navigation navigation = list[j].navigation; ((Navigation)(ref navigation)).mode = (Mode)4; ((Navigation)(ref navigation)).selectOnLeft = ((j > 0) ? list[j - 1] : null); ((Navigation)(ref navigation)).selectOnRight = ((j < list.Count - 1) ? list[j + 1] : null); list[j].navigation = navigation; } } } internal static void LinkVertical(Selectable above, Selectable below, bool onlyIfVanillaEmpty) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) if (Enabled && !((Object)(object)above == (Object)null) && !((Object)(object)below == (Object)null)) { Navigation navigation = above.navigation; Navigation navigation2 = below.navigation; bool flag = false; if (!onlyIfVanillaEmpty || (Object)(object)((Navigation)(ref navigation)).selectOnDown == (Object)null) { ((Navigation)(ref navigation)).mode = (Mode)4; ((Navigation)(ref navigation)).selectOnDown = below; above.navigation = navigation; flag = true; } ((Navigation)(ref navigation2)).mode = (Mode)4; ((Navigation)(ref navigation2)).selectOnUp = above; below.navigation = navigation2; if (!flag) { Plugin.Log.LogDebug((object)("[gamepad] '" + ((Object)above).name + "' already navigates down to '" + (((Object)(object)((Navigation)(ref navigation)).selectOnDown != (Object)null) ? ((Object)((Navigation)(ref navigation)).selectOnDown).name : "?") + "'; left it alone. Our button is reachable upward from '" + ((Object)below).name + "' only.")); } } } internal static void AttachRowToAnchor(Selectable anchor, IList<Selectable> row) { if (!Enabled || (Object)(object)anchor == (Object)null || row == null) { return; } for (int i = 0; i < row.Count; i++) { Selectable val = row[i]; if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.activeInHierarchy) { LinkVertical(anchor, val, onlyIfVanillaEmpty: true); break; } } } } internal static class Gather { internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> BuildEnabled; internal static ConfigEntry<bool> ShowStorageCounts; internal static bool IsEnabled { get { if (Enabled != null) { return Enabled.Value; } return true; } } internal static bool IsBuildEnabled { get { if (BuildEnabled != null) { return BuildEnabled.Value; } return true; } } internal static bool CountsShown { get { if (ShowStorageCounts != null) { return ShowStorageCounts.Value; } return true; } } internal static void Init(ConfigFile config) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown Enabled = config.Bind<bool>("Gather", "Enabled", true, new ConfigDescription("Show the Gather button in the crafting panel. Client-side.", (AcceptableValueBase)null, Array.Empty<object>())); BuildEnabled = config.Bind<bool>("Gather", "BuildEnabled", true, new ConfigDescription("When you place a piece you can't afford, fetch the missing materials from nearby chests. Client-side.", (AcceptableValueBase)null, Array.Empty<object>())); ShowStorageCounts = config.Bind<bool>("Gather", "ShowStorageCounts", true, new ConfigDescription("Show \"(N in storage)\" beside each ingredient in the crafting panel. Client-side.", (AcceptableValueBase)null, Array.Empty<object>())); } } internal static class Gatherer { internal static List<Container> Sources() { //IL_001d: 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; } foreach (Container item in ContainerTracker.AccessibleNear(((Component)localPlayer).transform.position, Plugin.SorterRadius.Value)) { if (!Filters.GetSpec(item).Ignore) { list.Add(item); } } return list; } internal static int CountInStorage(List<Container> sources, string sharedName) { if (sources == null || string.IsNullOrEmpty(sharedName)) { return 0; } int num = 0; for (int i = 0; i < sources.Count; i++) { Inventory inventory = sources[i].GetInventory(); if (inventory != null) { num += inventory.CountItems(sharedName, -1, true); } } return num; } internal static void Pull(List<GatherNeed> needs, out int movedTotal, out int typesMoved) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) movedTotal = 0; typesMoved = 0; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || needs == null || needs.Count == 0) { return; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); if (inventory == null) { return; } ZDOID zDOID = ((Character)localPlayer).GetZDOID(); List<Container> list = Sources(); int num = 0; foreach (GatherNeed need in needs) { int num2 = need.Gatherable; if (num2 <= 0) { continue; } bool flag = false; List<KeyValuePair<int, Container>> list2 = new List<KeyValuePair<int, Container>>(); for (int i = 0; i < list.Count; i++) { Inventory inventory2 = list[i].GetInventory(); if (inventory2 != null) { int num3 = inventory2.CountItems(need.SharedName, -1, true); if (num3 > 0) { list2.Add(new KeyValuePair<int, Container>(num3, list[i])); } } } list2.Sort(delegate(KeyValuePair<int, Container> a, KeyValuePair<int, Container> b) { int num6 = b.Key.CompareTo(a.Key); return (num6 == 0) ? ContainerTracker.CompareUid(a.Value, b.Value) : num6; }); foreach (KeyValuePair<int, Container> item in list2) { if (num2 <= 0) { break; } Container value = item.Value; Inventory inventory3 = value.GetInventory(); if (inventory3 == null) { continue; } ZNetView val = SorterZdo.NView(value); if ((Object)(object)val == (Object)null || !val.IsValid() || !SorterZdo.PlayerCanAccess(value) || !PrivateArea.CheckAccess(((Component)value).transform.position, 0f, false, true)) { continue; } InventoryBlock val2 = InventoryBlock.Get(inventory3); foreach (ItemData item2 in new List<ItemData>(inventory3.GetAllItems())) { if (num2 <= 0) { break; } if (item2?.m_shared != null && !(item2.m_shared.m_name != need.SharedName) && (val2 == null || !val2.IsSlotBlocked(item2.m_gridPos))) { int num4 = Router.Room(inventory, item2) - num; if (num4 <= 0) { num2 = 0; break; } int num5 = Math.Min(Math.Min(num2, item2.m_stack), num4); if (num5 > 0) { ContainerHandler.RemoveItemFromChest(value, item2, inventory, new Vector2i(-1, -1), zDOID, num5, (ItemData)null); num += num5; movedTotal += num5; num2 -= num5; flag = true; } } } } if (flag) { typesMoved++; } } if (movedTotal > 0) { Plugin.Log.LogInfo((object)("[gather] pulled " + movedTotal + " item(s) across " + typesMoved + " type(s)")); } } } internal struct GatherNeed { public string SharedName; public string Display; public int Needed; public int InPlayer; public int InStorage; public int Shortfall => Math.Max(0, Needed - InPlayer); public int Gatherable => Math.Min(Shortfall, InStorage); } internal static class GatherMath { internal static List<GatherNeed> Resolve(IList<GatherNeed> raw, bool onlyOneIngredient) { List<GatherNeed> list = new List<GatherNeed>(); if (raw == null || raw.Count == 0) { return list; } if (!onlyOneIngredient) { for (int i = 0; i < raw.Count; i++) { if (raw[i].Gatherable > 0) { list.Add(raw[i]); } } return list; } int num = PickSingleIngredient(raw); if (num >= 0 && raw[num].Gatherable > 0) { list.Add(raw[num]); } return list; } internal static int PickSingleIngredient(IList<GatherNeed> raw) { for (int i = 0; i < raw.Count; i++) { if (raw[i].Shortfall == 0) { return -1; } } int num = -1; for (int j = 0; j < raw.Count; j++) { if (raw[j].Gatherable <= 0) { continue; } if (num < 0) { num = j; continue; } int num2 = raw[j].Shortfall - raw[j].Gatherable; int num3 = raw[num].Shortfall - raw[num].Gatherable; if (num2 < num3) { num = j; } else if (num2 <= num3) { if (raw[j].Shortfall < raw[num].Shortfall) { num = j; } else if (raw[j].Shortfall <= raw[num].Shortfall && string.CompareOrdinal(raw[j].SharedName ?? "", raw[num].SharedName ?? "") < 0) { num = j; } } } return num; } } internal static class Gear { private static readonly Dictionary<ItemType, string> ByType = new Dictionary<ItemType, string> { { (ItemType)3, "gear:weapons" }, { (ItemType)14, "gear:weapons" }, { (ItemType)22, "gear:weapons" }, { (ItemType)4, "gear:weapons" }, { (ItemType)5, "gear:weapons" }, { (ItemType)15, "gear:weapons" }, { (ItemType)20, "gear:weapons" }, { (ItemType)6, "gear:armor" }, { (ItemType)7, "gear:armor" }, { (ItemType)11, "gear:armor" }, { (ItemType)17, "gear:armor" }, { (ItemType)12, "gear:armor" }, { (ItemType)18, "gear:armor" }, { (ItemType)24, "gear:armor" }, { (ItemType)19, "gear:tools" } }; private static ConfigEntry<string> _weaponTokens; private static ConfigEntry<string> _armorTokens; private static ConfigEntry<string> _toolTokens; private static readonly List<string> Weapon = new List<string>(); private static readonly List<string> Armour = new List<string>(); private static readonly List<string> Tool = new List<string>(); private static readonly HashSet<string> Reported = new HashSet<string>(); internal static void Init(ConfigFile config) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown //IL_0058: 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) //IL_0065: Expected O, but got Unknown //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Expected O, but got Unknown _toolTokens = config.Bind<string>("Organize", "ToolTokens", "pickaxe*", new ConfigDescription("Item name tokens ('*' wildcards) forced into the TOOLS gear bucket, overriding the item's own type. Default: pickaxes, which the game classifies as weapons. Comma-separated.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); _weaponTokens = config.Bind<string>("Organize", "WeaponTokens", "", new ConfigDescription("Item name tokens forced into the WEAPONS gear bucket. Comma-separated.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); _armorTokens = config.Bind<string>("Organize", "ArmorTokens", "", new ConfigDescription("Item name tokens forced into the ARMOR gear bucket. Comma-separated.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); config.SettingChanged += delegate { Rebuild(); }; Rebuild(); } private static void Rebuild() { Fill(Weapon, _weaponTokens); Fill(Armour, _armorTokens); Fill(Tool, _toolTokens); Reported.Clear(); } private static void Fill(List<string> into, ConfigEntry<string> entry) { into.Clear(); if (entry == null || string.IsNullOrEmpty(entry.Value)) { return; } string[] array = entry.Value.Split(','); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim().ToLowerInvariant(); if (text.Length > 0) { into.Add(text); } } } internal static string BucketFor(ItemData item, string norm) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) if (item?.m_shared == null) { return "gear:misc"; } if (MatchesAny(Tool, norm)) { return "gear:tools"; } if (MatchesAny(Weapon, norm)) { return "gear:weapons"; } if (MatchesAny(Armour, norm)) { return "gear:armor"; } if (ByType.TryGetValue(item.m_shared.m_itemType, out var value)) { return value; } if (Reported.Add(norm)) { Plugin.Log.LogInfo((object)("[organize] '" + norm + "' (item type " + ((object)Unsafe.As<ItemType, ItemType>(ref item.m_shared.m_itemType)/*cast due to .constrained prefix*/).ToString() + ") has no gear bucket - filed under " + BucketKeys.Label("gear:misc") + ". Add it to [Organize] WeaponTokens/ArmorTokens/ToolTokens to place it.")); } return "gear:misc"; } private static bool MatchesAny(List<string> tokens, string norm) { for (int i = 0; i < tokens.Count; i++) { if (Names.Matches(tokens[i], norm)) { return true; } } return false; } } internal static class Groups { private static readonly Dictionary<string, ConfigEntry<string>> Entries = new Dictionary<string, ConfigEntry<string>>(); private static readonly Dictionary<string, List<string>> Parsed = new Dictionary<string, List<string>>(); private static readonly List<string> Ordered = new List<string>(); private static Dictionary<string, string> Defaults => GroupTables.Defaults; private static string[] GroupOrder => GroupTables.GroupOrder; internal static void Init(ConfigFile config) { //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Expected O, but got Unknown //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown string[] groupOrder = GroupOrder; foreach (string text in groupOrder) { if (!Defaults.ContainsKey(text)) { Plugin.Log.LogError((object)("[groups] GroupOrder lists '" + text + "', which is not a defined group")); } } foreach (KeyValuePair<string, string> @default in Defaults) { if (Array.IndexOf(GroupOrder, @default.Key) < 0) { Plugin.Log.LogError((object)("[groups] group '" + @default.Key + "' is missing from GroupOrder; overlap resolution would be non-deterministic for its items")); } } foreach (KeyValuePair<string, string> default2 in Defaults) { Entries[default2.Key] = config.Bind<string>("ItemGroups", default2.Key, default2.Value, new ConfigDescription("Comma-separated item name tokens ('*' wildcards allowed).", (AcceptableValueBase)null, new object[1] { (object)new Configuration