using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("InventoryLink")] [assembly: AssemblyFileVersion("0.2.5")] [assembly: AssemblyCompany("R4V9N1")] [assembly: AssemblyDescription("Created by R4V9N1")] [assembly: AssemblyProduct("InventoryLink")] [assembly: AssemblyCopyright("Created by R4V9N1")] [assembly: AssemblyMetadata("Creator", "Created by R4V9N1")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("0.2.5.0")] namespace InventoryLink; [BepInPlugin("r4v9n1.inventorylink", "InventoryLink", "0.2.5")] public sealed class InventoryLinkPlugin : BaseUnityPlugin { internal sealed class RequirementCheckContext { public readonly Player Player; public readonly Inventory PlayerInventory; public readonly bool CountAmounts; public readonly bool CountAny; public RequirementCheckContext(Player player, Inventory playerInventory, bool countAmounts, bool countAny) { Player = player; PlayerInventory = playerInventory; CountAmounts = countAmounts; CountAny = countAny; } } internal sealed class RequirementDisplayContext { public readonly Player Player; public readonly Inventory PlayerInventory; public RequirementDisplayContext(Player player, Inventory playerInventory) { Player = player; PlayerInventory = playerInventory; } } internal sealed class PullPlan { public readonly Player Player; public readonly List Items = new List(); public bool HasItems => Items.Count > 0; public PullPlan(Player player) { Player = player; } public void Add(string name, int quality, int amount) { for (int i = 0; i < Items.Count; i++) { if (Items[i].Name == name && Items[i].Quality == quality) { Items[i].Amount += amount; return; } } Items.Add(new PullItem(name, quality, amount)); } } internal sealed class PullItem { public readonly string Name; public readonly int Quality; public int Amount; public PullItem(string name, int quality, int amount) { Name = name; Quality = quality; Amount = amount; } } private sealed class ContainerCandidate { public readonly Container Container; public readonly float DistanceSqr; public ContainerCandidate(Container container, float distanceSqr) { Container = container; DistanceSqr = distanceSqr; } } public const string PluginGuid = "r4v9n1.inventorylink"; public const string PluginName = "InventoryLink"; public const string PluginVersion = "0.2.5"; public const string CreatorCredit = "Created by R4V9N1"; private const string PreviousDefaultCraftingStationNames = "$piece_workbench,$piece_stonecutter"; private const string DefaultCraftingStationNames = "$piece_workbench,$piece_stonecutter,$piece_forge,$piece_blackforge,$piece_magetable,$piece_artisanstation"; private static ConfigEntry _enabled; private static ConfigEntry _pullRadius; private static ConfigEntry _extendCraftingStationBuildRange; private static ConfigEntry _craftingStationBuildRange; private static ConfigEntry _craftingStationBuildRangeNames; private static ConfigEntry _respectWards; private static ConfigEntry _respectContainerAccess; private static ConfigEntry _skipInUseContainers; private static ConfigEntry _logPulls; private static ManualLogSource _log; private static FieldInfo _containerNViewField; private static FieldInfo _inventoryGuiCraftRecipeField; private static MethodInfo _containerLoadMethod; private static float _nextContainerFailureLogTime; private static int _suppressedContainerFailures; private static RequirementCheckContext _requirementCheck; private static RequirementDisplayContext _requirementDisplay; private static Player _lastPlacedPlayer; private static int _lastPlacedFrame = -1; private static Player _craftingPlayer; private static int _craftingFrame = -1; private static Player _cachedPlayer; private static int _cachedFrame = -1; private static List _cachedContainers; private Harmony _harmony; private void Awake() { //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Expected O, but got Unknown _log = ((BaseUnityPlugin)this).Logger; _enabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Enable InventoryLink."); _pullRadius = ((BaseUnityPlugin)this).Config.Bind("General", "PullRadius", 50f, "How far from the player to search for linked containers."); _extendCraftingStationBuildRange = ((BaseUnityPlugin)this).Config.Bind("Crafting Stations", "ExtendBuildRange", true, "Extend configured crafting station build radii."); _craftingStationBuildRange = ((BaseUnityPlugin)this).Config.Bind("Crafting Stations", "BuildRange", 50f, "Minimum build radius for configured crafting stations."); _craftingStationBuildRangeNames = ((BaseUnityPlugin)this).Config.Bind("Crafting Stations", "StationNames", "$piece_workbench,$piece_stonecutter,$piece_forge,$piece_blackforge,$piece_magetable,$piece_artisanstation", "Comma-separated CraftingStation m_name values to extend. Defaults to the workbench, stonecutter, forge, black forge, Galdr table, and artisan table."); _respectWards = ((BaseUnityPlugin)this).Config.Bind("Access", "RespectWards", true, "Skip containers blocked by ward/private-area access."); _respectContainerAccess = ((BaseUnityPlugin)this).Config.Bind("Access", "RespectContainerAccess", true, "Respect personal/private container access rules."); _skipInUseContainers = ((BaseUnityPlugin)this).Config.Bind("Access", "SkipInUseContainers", true, "Do not pull from containers that another player has open."); _logPulls = ((BaseUnityPlugin)this).Config.Bind("Debug", "LogPulls", false, "Log each successful item pull to the BepInEx log."); MigrateOldDefaults(); _containerNViewField = AccessTools.Field(typeof(Container), "m_nview"); _inventoryGuiCraftRecipeField = AccessTools.Field(typeof(InventoryGui), "m_craftRecipe"); _containerLoadMethod = AccessTools.Method(typeof(Container), "Load", (Type[])null, (Type[])null); _harmony = new Harmony("r4v9n1.inventorylink"); _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"InventoryLink 0.2.5 loaded."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Created by R4V9N1."); } private void OnDestroy() { if (_harmony != null) { _harmony.UnpatchSelf(); _harmony = null; } } internal static bool IsEnabledFor(Player player) { if (_enabled == null || !_enabled.Value || (Object)(object)player == (Object)null) { return false; } if (!((Object)(object)Player.m_localPlayer == (Object)null)) { return Player.m_localPlayer == player; } return true; } internal static void ExtendCraftingStationBuildRange(CraftingStation station, ref float range) { if (_enabled != null && _enabled.Value && _extendCraftingStationBuildRange != null && _extendCraftingStationBuildRange.Value && !((Object)(object)station == (Object)null) && IsConfiguredCraftingStation(station)) { float num = ((_craftingStationBuildRange == null) ? 50f : Math.Max(0f, _craftingStationBuildRange.Value)); if (range < num) { range = num; } } } internal static void BeginRequirementCheck(Player player, RequirementMode mode) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Invalid comparison between Unknown and I4 //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 if (IsEnabledFor(player) && ((int)mode == 0 || (int)mode == 2)) { _requirementCheck = new RequirementCheckContext(player, ((Humanoid)player).GetInventory(), (int)mode == 0, (int)mode == 2); } } internal static void EndRequirementCheck() { _requirementCheck = null; } internal static void BeginRecipeRequirementCheck(Player player, Recipe recipe, bool discover) { if (!(!IsEnabledFor(player) || discover) && SupportsRecipeAutoPull(recipe)) { _requirementCheck = new RequirementCheckContext(player, ((Humanoid)player).GetInventory(), countAmounts: true, countAny: false); } } internal static void BeginRequirementDisplay(Player player) { if (IsEnabledFor(player)) { _requirementDisplay = new RequirementDisplayContext(player, ((Humanoid)player).GetInventory()); } } internal static void EndRequirementDisplay() { _requirementDisplay = null; } internal static void BeginCrafting(InventoryGui inventoryGui, Player player) { if (IsEnabledFor(player) && SupportsRecipeAutoPull(GetCraftRecipe(inventoryGui))) { _craftingPlayer = player; _craftingFrame = Time.frameCount; } } internal static void EndCrafting() { _craftingPlayer = null; _craftingFrame = -1; } internal static void AddNearbyCountForRequirement(Inventory inventory, string itemName, int quality, bool matchWorldLevel, ref int count) { Player val = null; Inventory val2 = null; if (_requirementCheck != null && _requirementCheck.CountAmounts) { val = _requirementCheck.Player; val2 = _requirementCheck.PlayerInventory; } else { if (_requirementDisplay == null) { return; } val = _requirementDisplay.Player; val2 = _requirementDisplay.PlayerInventory; } if (inventory == val2) { count += CountNearbyItem(val, itemName, quality, matchWorldLevel, int.MaxValue); } } internal static void AddNearbyHaveItemForRequirement(Inventory inventory, string itemName, bool matchWorldLevel, ref bool haveItem) { if (!haveItem && _requirementCheck != null && _requirementCheck.CountAny && inventory == _requirementCheck.PlayerInventory) { haveItem = CountNearbyItem(_requirementCheck.Player, itemName, -1, matchWorldLevel, 1) > 0; } } internal static void MarkPlaced(Player player, bool placed) { if (placed && IsEnabledFor(player)) { _lastPlacedPlayer = player; _lastPlacedFrame = Time.frameCount; } } internal static PullPlan CreatePullPlan(Player player, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier) { bool flag = _lastPlacedPlayer == player && _lastPlacedFrame == Time.frameCount; bool flag2 = _craftingPlayer == player && _craftingFrame == Time.frameCount; if (!IsEnabledFor(player) || (!flag && !flag2)) { return null; } if (requirements == null || requirements.Length == 0) { return null; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return null; } PullPlan pullPlan = new PullPlan(player); foreach (Requirement val in requirements) { if (val == null || (Object)(object)val.m_resItem == (Object)null) { continue; } int num = val.GetAmount(qualityLevel) * multiplier; if (num > 0) { string name = val.m_resItem.m_itemData.m_shared.m_name; int num2 = inventory.CountItems(name, itemQuality, true); int num3 = num - num2; if (num3 > 0) { pullPlan.Add(name, itemQuality, num3); } } } if (!pullPlan.HasItems) { return null; } return pullPlan; } internal static void PayPullPlan(PullPlan plan) { if (plan == null || !IsEnabledFor(plan.Player)) { return; } List list = FindContainers(plan.Player); for (int i = 0; i < plan.Items.Count; i++) { PullItem pullItem = plan.Items[i]; int num = pullItem.Amount; for (int j = 0; j < list.Count; j++) { if (num <= 0) { break; } num -= PullFromContainer(list[j].Container, pullItem.Name, pullItem.Quality, num); } if (num > 0 && _log != null) { _log.LogWarning((object)("InventoryLink could not pull " + num + "x " + pullItem.Name + " after placement. The container contents may have changed.")); } } ClearContainerCache(); } private static int CountNearbyItem(Player player, string itemName, int quality, bool matchWorldLevel, int stopAt) { if (string.IsNullOrEmpty(itemName) || !IsEnabledFor(player)) { return 0; } int num = 0; List list = FindContainers(player); for (int i = 0; i < list.Count; i++) { Inventory loadedInventory = GetLoadedInventory(list[i].Container); if (loadedInventory != null) { num += loadedInventory.CountItems(itemName, quality, matchWorldLevel); if (num >= stopAt) { return num; } } } return num; } private static int PullFromContainer(Container container, string itemName, int quality, int amount) { if ((Object)(object)container == (Object)null || amount <= 0) { return 0; } ZNetView containerView = GetContainerView(container); if ((Object)(object)containerView != (Object)null && containerView.IsValid() && !containerView.IsOwner()) { containerView.ClaimOwnership(); } Inventory loadedInventory = GetLoadedInventory(container); if (loadedInventory == null) { return 0; } int num = loadedInventory.CountItems(itemName, quality, true); int num2 = Math.Min(num, amount); if (num2 <= 0) { return 0; } loadedInventory.RemoveItem(itemName, num2, quality, true); int num3 = loadedInventory.CountItems(itemName, quality, true); int num4 = num - num3; if (num4 > 0 && _log != null && _logPulls != null && _logPulls.Value) { _log.LogInfo((object)("Pulled " + num4 + "x " + itemName + " from " + container.GetHoverName() + ".")); } return Math.Max(num4, 0); } private static List FindContainers(Player player) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_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) if (_cachedContainers != null && _cachedPlayer == player && _cachedFrame == Time.frameCount) { return _cachedContainers; } List list = new List(); if (!IsEnabledFor(player)) { return list; } float num = ((_pullRadius == null) ? 50f : Math.Max(0f, _pullRadius.Value)); float num2 = num * num; Vector3 position = ((Component)player).transform.position; long playerID = player.GetPlayerID(); Container[] array = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (Container val in array) { if (!((Object)(object)val == (Object)null)) { Vector3 val2 = ((Component)val).transform.position - position; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (!(sqrMagnitude > num2) && CanUseContainer(val, playerID)) { list.Add(new ContainerCandidate(val, sqrMagnitude)); } } } list.Sort(delegate(ContainerCandidate left, ContainerCandidate right) { float distanceSqr = left.DistanceSqr; return distanceSqr.CompareTo(right.DistanceSqr); }); _cachedPlayer = player; _cachedFrame = Time.frameCount; _cachedContainers = list; return list; } private static bool CanUseContainer(Container container, long playerId) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) try { if (!TryGetReadyContainer(container, out var _)) { return false; } if (_skipInUseContainers != null && _skipInUseContainers.Value && container.IsInUse()) { return false; } if (_respectWards != null && _respectWards.Value && ContainerChecksGuardStone(container) && !PrivateArea.CheckAccess(((Component)container).transform.position, 0f, true, false)) { return false; } if (_respectContainerAccess != null && _respectContainerAccess.Value && !CheckContainerAccess(container, playerId)) { return false; } return GetLoadedInventory(container) != null; } catch (Exception exception) { LogUnexpectedContainerFailure(container, exception); return false; } } private static bool ContainerChecksGuardStone(Container container) { if ((Object)(object)container != (Object)null) { return container.m_checkGuardStone; } return false; } private static bool CheckContainerAccess(Container container, long playerId) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected I4, but got Unknown if ((Object)(object)container == (Object)null) { return false; } PrivacySetting privacy = container.m_privacy; switch ((int)privacy) { case 2: return true; case 0: { Piece component = ((Component)container).GetComponent(); if ((Object)(object)component != (Object)null) { return component.GetCreator() == playerId; } return false; } default: return false; } } private static Inventory GetLoadedInventory(Container container) { try { if (!TryGetReadyContainer(container, out var view)) { return null; } LoadContainer(container); if (!view.IsValid()) { return null; } return container.GetInventory(); } catch (Exception exception) { LogUnexpectedContainerFailure(container, exception); return null; } } private static void LoadContainer(Container container) { if (_containerLoadMethod != null) { _containerLoadMethod.Invoke(container, null); } } private static ZNetView GetContainerView(Container container) { if (_containerNViewField == null || (Object)(object)container == (Object)null) { return null; } object? value = _containerNViewField.GetValue(container); return (ZNetView)((value is ZNetView) ? value : null); } private static bool TryGetReadyContainer(Container container, out ZNetView view) { view = null; if ((Object)(object)container == (Object)null || !((Behaviour)container).isActiveAndEnabled) { return false; } view = GetContainerView(container); if ((Object)(object)view != (Object)null && view.IsValid()) { return container.GetInventory() != null; } return false; } private static void LogUnexpectedContainerFailure(Container container, Exception exception) { if (_log != null && exception != null) { while (exception is TargetInvocationException && exception.InnerException != null) { exception = exception.InnerException; } float unscaledTime = Time.unscaledTime; if (unscaledTime < _nextContainerFailureLogTime) { _suppressedContainerFailures++; return; } string text = (((Object)(object)container == (Object)null) ? "" : ((Object)((Component)container).gameObject).name); string text2 = ((_suppressedContainerFailures > 0) ? (" (" + _suppressedContainerFailures + " similar failures suppressed)") : ""); _suppressedContainerFailures = 0; _nextContainerFailureLogTime = unscaledTime + 5f; _log.LogDebug((object)("Skipped unavailable container '" + text + "': " + exception.GetType().Name + ": " + exception.Message + text2)); } } private static Recipe GetCraftRecipe(InventoryGui inventoryGui) { if (_inventoryGuiCraftRecipeField == null || (Object)(object)inventoryGui == (Object)null) { return null; } object? value = _inventoryGuiCraftRecipeField.GetValue(inventoryGui); return (Recipe)((value is Recipe) ? value : null); } private static bool SupportsRecipeAutoPull(Recipe recipe) { if ((Object)(object)recipe != (Object)null) { return !recipe.m_requireOnlyOneIngredient; } return false; } private static bool IsConfiguredCraftingStation(CraftingStation station) { if ((Object)(object)station == (Object)null) { return false; } string text = ((_craftingStationBuildRangeNames == null) ? "$piece_workbench,$piece_stonecutter,$piece_forge,$piece_blackforge,$piece_magetable,$piece_artisanstation" : _craftingStationBuildRangeNames.Value); if (string.IsNullOrEmpty(text)) { return false; } string a = station.m_name ?? ""; string[] array = text.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.Length != 0 && string.Equals(a, text2, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } private void MigrateOldDefaults() { bool flag = false; if (_pullRadius != null && Math.Abs(_pullRadius.Value - 30f) < 0.001f) { _pullRadius.Value = 50f; flag = true; } if (_craftingStationBuildRangeNames != null && string.Equals(_craftingStationBuildRangeNames.Value, "$piece_workbench,$piece_stonecutter", StringComparison.Ordinal)) { _craftingStationBuildRangeNames.Value = "$piece_workbench,$piece_stonecutter,$piece_forge,$piece_blackforge,$piece_magetable,$piece_artisanstation"; flag = true; } if (flag) { ((BaseUnityPlugin)this).Config.Save(); } } private static void ClearContainerCache() { _cachedPlayer = null; _cachedFrame = -1; _cachedContainers = null; } } [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Piece), typeof(RequirementMode) })] internal static class PlayerHaveRequirementsPatch { private static void Prefix(Player __instance, RequirementMode mode) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) InventoryLinkPlugin.BeginRequirementCheck(__instance, mode); } private static void Postfix() { InventoryLinkPlugin.EndRequirementCheck(); } } [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Recipe), typeof(bool), typeof(int), typeof(int) })] internal static class PlayerHaveRecipeRequirementsPatch { private static void Prefix(Player __instance, Recipe recipe, bool discover) { InventoryLinkPlugin.BeginRecipeRequirementCheck(__instance, recipe, discover); } private static void Postfix() { InventoryLinkPlugin.EndRequirementCheck(); } } [HarmonyPatch(typeof(InventoryGui), "SetupRequirement", new Type[] { typeof(Transform), typeof(Requirement), typeof(Player), typeof(bool), typeof(int), typeof(int) })] internal static class InventoryGuiSetupRequirementPatch { private static void Prefix(Player player) { InventoryLinkPlugin.BeginRequirementDisplay(player); } private static void Postfix() { InventoryLinkPlugin.EndRequirementDisplay(); } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting", new Type[] { typeof(Player) })] internal static class InventoryGuiDoCraftingPatch { private static void Prefix(InventoryGui __instance, Player player) { InventoryLinkPlugin.BeginCrafting(__instance, player); } private static void Postfix() { InventoryLinkPlugin.EndCrafting(); } } [HarmonyPatch(typeof(Inventory), "CountItems", new Type[] { typeof(string), typeof(int), typeof(bool) })] internal static class InventoryCountItemsPatch { private static void Postfix(Inventory __instance, string name, int quality, bool matchWorldLevel, ref int __result) { InventoryLinkPlugin.AddNearbyCountForRequirement(__instance, name, quality, matchWorldLevel, ref __result); } } [HarmonyPatch(typeof(Inventory), "HaveItem", new Type[] { typeof(string), typeof(bool) })] internal static class InventoryHaveItemPatch { private static void Postfix(Inventory __instance, string name, bool matchWorldLevel, ref bool __result) { InventoryLinkPlugin.AddNearbyHaveItemForRequirement(__instance, name, matchWorldLevel, ref __result); } } [HarmonyPatch(typeof(CraftingStation), "GetStationBuildRange")] internal static class CraftingStationGetStationBuildRangePatch { private static void Postfix(CraftingStation __instance, ref float __result) { InventoryLinkPlugin.ExtendCraftingStationBuildRange(__instance, ref __result); } } [HarmonyPatch(typeof(Player), "TryPlacePiece", new Type[] { typeof(Piece) })] internal static class PlayerTryPlacePiecePatch { private static void Postfix(Player __instance, bool __result) { InventoryLinkPlugin.MarkPlaced(__instance, __result); } } [HarmonyPatch(typeof(Player), "ConsumeResources", new Type[] { typeof(Requirement[]), typeof(int), typeof(int), typeof(int) })] internal static class PlayerConsumeResourcesPatch { private static void Prefix(Player __instance, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier, ref InventoryLinkPlugin.PullPlan __state) { __state = InventoryLinkPlugin.CreatePullPlan(__instance, requirements, qualityLevel, itemQuality, multiplier); } private static void Postfix(InventoryLinkPlugin.PullPlan __state) { InventoryLinkPlugin.PayPullPlan(__state); } } [BepInPlugin("r4v9n1.inventorylink.autosort", "InventoryLink Auto Sort", "0.1.0")] public sealed class InventorySortPlugin : BaseUnityPlugin { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static UnityAction <>9__18_0; public static UnityAction <>9__18_1; internal void b__18_0() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { SortInventory(((Humanoid)localPlayer).GetInventory()); } } internal void b__18_1() { InventoryGui instance = InventoryGui.instance; Container val = (((Object)(object)instance != (Object)null) ? GetCurrentContainer(instance) : null); if ((Object)(object)val != (Object)null) { SortInventory(val.GetInventory()); } } } public const string PluginGuid = "r4v9n1.inventorylink.autosort"; public const string PluginName = "InventoryLink Auto Sort"; public const string PluginVersion = "0.1.0"; private static readonly Dictionary CategoryOrder = new Dictionary { { (ItemType)3, 0 }, { (ItemType)14, 0 }, { (ItemType)22, 0 }, { (ItemType)4, 0 }, { (ItemType)20, 0 }, { (ItemType)5, 1 }, { (ItemType)6, 2 }, { (ItemType)7, 2 }, { (ItemType)11, 2 }, { (ItemType)17, 2 }, { (ItemType)12, 2 }, { (ItemType)19, 3 }, { (ItemType)18, 3 }, { (ItemType)15, 3 }, { (ItemType)9, 4 }, { (ItemType)23, 4 }, { (ItemType)2, 5 }, { (ItemType)21, 5 }, { (ItemType)13, 6 }, { (ItemType)10, 7 }, { (ItemType)24, 7 }, { (ItemType)1, 8 }, { (ItemType)16, 9 }, { (ItemType)0, 9 } }; private static ConfigEntry _enabled; private static ConfigEntry _addSortButtons; private static ConfigEntry _sortKey; private static ConfigEntry _playerButtonOffsetY; private static ConfigEntry _containerButtonOffsetY; private static ManualLogSource _log; private static Button _playerSortButton; private static Button _containerSortButton; private static FieldInfo _currentContainerField; private static MethodInfo _inventoryChangedMethod; private Harmony _harmony; private void Awake() { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Expected O, but got Unknown _log = ((BaseUnityPlugin)this).Logger; _currentContainerField = AccessTools.Field(typeof(InventoryGui), "m_currentContainer"); _inventoryChangedMethod = AccessTools.Method(typeof(Inventory), "Changed", (Type[])null, (Type[])null); _enabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Enable auto-sort for the player inventory and open containers."); _addSortButtons = ((BaseUnityPlugin)this).Config.Bind("General", "AddSortButtons", true, "Clone vanilla buttons into 'Sort' buttons on the inventory/container panels."); _sortKey = ((BaseUnityPlugin)this).Config.Bind("General", "SortKey", new KeyboardShortcut((KeyCode)120, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Key combo that sorts the player inventory, and the open container if any."); _playerButtonOffsetY = ((BaseUnityPlugin)this).Config.Bind("General", "PlayerButtonOffsetY", 35f, "Vertical offset (UI units) of the cloned player-inventory sort button from the Stack All button it's cloned from."); _containerButtonOffsetY = ((BaseUnityPlugin)this).Config.Bind("General", "ContainerButtonOffsetY", 35f, "Vertical offset (UI units) of the cloned container sort button from the Take All button it's cloned from."); _harmony = new Harmony("r4v9n1.inventorylink.autosort"); _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"InventoryLink Auto Sort 0.1.0 loaded."); } private void OnDestroy() { if (_harmony != null) { _harmony.UnpatchSelf(); _harmony = null; } } private void Update() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (_enabled == null || !_enabled.Value || _sortKey == null) { return; } KeyboardShortcut value = _sortKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { SortInventory(((Humanoid)localPlayer).GetInventory()); } InventoryGui instance = InventoryGui.instance; Container val = (((Object)(object)instance != (Object)null && instance.IsContainerOpen()) ? GetCurrentContainer(instance) : null); if ((Object)(object)val != (Object)null) { SortInventory(val.GetInventory()); } } } internal static void SetupButtons(InventoryGui gui) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Expected O, but got Unknown if (_addSortButtons == null || !_addSortButtons.Value || (Object)(object)gui == (Object)null) { return; } if ((Object)(object)_playerSortButton == (Object)null) { if ((Object)(object)gui.m_stackAllButton == (Object)null) { if (_log != null) { _log.LogWarning((object)"Auto Sort: InventoryGui.m_stackAllButton was null; player sort button was not created."); } } else { float offsetY = ((_playerButtonOffsetY == null) ? 35f : _playerButtonOffsetY.Value); Button stackAllButton = gui.m_stackAllButton; object obj = <>c.<>9__18_0; if (obj == null) { UnityAction val = delegate { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { SortInventory(((Humanoid)localPlayer).GetInventory()); } }; <>c.<>9__18_0 = val; obj = (object)val; } _playerSortButton = CloneButton(stackAllButton, offsetY, "Sort Inv.", "PlayerSortButton", (UnityAction)obj); } } if (!((Object)(object)_containerSortButton == (Object)null)) { return; } if ((Object)(object)gui.m_takeAllButton == (Object)null) { if (_log != null) { _log.LogWarning((object)"Auto Sort: InventoryGui.m_takeAllButton was null; container sort button was not created."); } return; } float offsetY2 = ((_containerButtonOffsetY == null) ? 35f : _containerButtonOffsetY.Value); Button takeAllButton = gui.m_takeAllButton; object obj2 = <>c.<>9__18_1; if (obj2 == null) { UnityAction val2 = delegate { InventoryGui instance = InventoryGui.instance; Container val3 = (((Object)(object)instance != (Object)null) ? GetCurrentContainer(instance) : null); if ((Object)(object)val3 != (Object)null) { SortInventory(val3.GetInventory()); } }; <>c.<>9__18_1 = val2; obj2 = (object)val2; } _containerSortButton = CloneButton(takeAllButton, offsetY2, "Sort", "ContainerSortButton", (UnityAction)obj2); ((Component)_containerSortButton).gameObject.SetActive(false); } private static Container GetCurrentContainer(InventoryGui gui) { if (_currentContainerField == null || (Object)(object)gui == (Object)null) { return null; } object? value = _currentContainerField.GetValue(gui); return (Container)((value is Container) ? value : null); } internal static void SetContainerButtonVisible(bool visible) { if ((Object)(object)_containerSortButton != (Object)null) { ((Component)_containerSortButton).gameObject.SetActive(visible); } } private unsafe static Button CloneButton(Button template, float offsetY, string label, string cloneName, UnityAction onClick) { //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) //IL_0065: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: 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_00ed: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate(((Component)template).gameObject, ((Component)template).transform.parent); ((Object)val).name = cloneName; val.SetActive(true); LayoutElement val2 = val.GetComponent(); if ((Object)(object)val2 == (Object)null) { val2 = val.AddComponent(); } val2.ignoreLayout = true; RectTransform component = val.GetComponent(); if ((Object)(object)component != (Object)null) { component.anchoredPosition += new Vector2(0f, offsetY); } TMP_Text componentInChildren = val.GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.text = label; } Button component2 = val.GetComponent