Please disclose if your mod was created primarily 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 SlimesHeim v1.0.9
BepInEx/plugins/SmartContainers.dll
Decompiled 2 years agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; 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("SmartContainers")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("SmartContainers")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("6b695573-f20c-49d7-99c3-26f3bd0c12c1")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace SmartContainers; internal sealed class ConfigurationManagerAttributes { public bool? ShowRangeAsPercent; public Action<ConfigEntryBase> CustomDrawer; public bool? Browsable; public string Category; public object DefaultValue; public bool? HideDefaultButton; public bool? HideSettingName; public string Description; public string DispName; public int? Order; public bool? ReadOnly; public bool? IsAdvanced; public Func<object, string> ObjToStr; public Func<string, object> StrToObj; } public static class ContainersTracker { public static ICollection<Container> containerList = new List<Container>(); public static bool isRearrangingItem = false; public static bool teleportingInProgress = false; public static List<Container> GetNearbyContainers(Vector3 center, bool all = false) { //IL_0066: 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) List<Container> list = new List<Container>(); foreach (Container container in containerList) { int num = (all ? (Mod.range.Value * 2) : Mod.range.Value); if ((Object)(object)container != (Object)null && (Object)(object)((Component)container).transform != (Object)null && container.GetInventory() != null && (Object)(object)((Component)container).GetComponentInParent<Piece>() != (Object)null) { float num2 = Vector3.Distance(center, ((Component)container).transform.position); if ((num <= 0 || num2 < (float)num) && container.CheckAccess(Player.m_localPlayer.GetPlayerID())) { list.Add(container); } } } return list; } public static void Init() { Container[] array = Object.FindObjectsOfType<Container>(); Mod.log.LogDebug((object)$"tracking {array.Length} discovered containers."); Container[] array2 = array; foreach (Container val in array2) { if (!((Object)val).name.StartsWith("Treasure") && val.GetInventory() != null && val.m_nview.IsValid() && val.m_nview.GetZDO().GetLong(StringExtensionMethods.GetStableHashCode("creator"), 0L) != 0L) { containerList.Add(val); } } } public static void CleanupContainersList() { Mod.log.LogDebug((object)$"cleanup containerList. size before: {containerList.Count}"); foreach (Container item in containerList.ToList()) { if (!((Object)(object)item != (Object)null) || !((Object)(object)((Component)item).transform != (Object)null) || item.GetInventory() == null) { containerList.Remove(item); } } Mod.log.LogDebug((object)$"cleanup containerList. size after: {containerList.Count}"); } } [HarmonyPatch(typeof(Container), "Awake")] internal static class Container_Awake_Patch { private static void Postfix(Container __instance) { if (Mod.modEnabled.Value && !((Object)__instance).name.StartsWith("Treasure") && __instance.GetInventory() != null && __instance.m_nview.IsValid() && (__instance.m_nview.GetZDO().GetLong(StringExtensionMethods.GetStableHashCode("creator"), 0L) != 0L || __instance.m_nview.GetZDO().GetOwner() != 0L)) { ContainersTracker.containerList.Add(__instance); } } } [HarmonyPatch(typeof(Container), "OnDestroyed")] internal static class Container_OnDestroyed_Patch { private static void Prefix(Container __instance) { if (Mod.modEnabled.Value) { ContainersTracker.containerList.Remove(__instance); } } } [HarmonyPatch(typeof(Inventory), "StackAll")] internal static class Container_OnStackAll_Patch { private static void Postfix(Inventory __instance, Inventory fromInventory, bool message) { if (Mod.unloadAllEnabled.Value && Mod.unloadAllInsteadStackBtn.Value) { InventoryGui instance = InventoryGui.instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.m_playerGrid == (Object)null) && !((Object)(object)instance.m_containerGrid == (Object)null) && !((Character)Player.m_localPlayer).IsTeleporting()) { UnloadItems.UnloadAllItems(((Humanoid)Player.m_localPlayer).GetInventory()); } } } } [HarmonyPatch(typeof(Player), "UpdateTeleport")] public static class PlayerUpdateTeleport_Patch_Cleanup_Containers { public static void Prefix(float dt) { if (Mod.modEnabled.Value) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && localPlayer.m_teleporting && !ContainersTracker.teleportingInProgress) { ContainersTracker.teleportingInProgress = true; } } } } [HarmonyPatch(typeof(Player), "UpdateTeleport")] public static class PlayerUpdateTeleport_Postfix { public static void Postfix(float dt) { if (Mod.modEnabled.Value) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && ContainersTracker.teleportingInProgress && !localPlayer.m_teleporting) { ContainersTracker.CleanupContainersList(); ContainersTracker.teleportingInProgress = false; } } } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })] public static class Inventory_Patch { public static void Postfix(Inventory __instance, ItemData item, ref bool __result) { //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: 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_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) if (!Mod.modEnabled.Value || __instance == null || (Object)(object)Player.m_localPlayer == (Object)null || ((Character)Player.m_localPlayer).IsTeleporting() || ((object)__instance).Equals((object?)((Humanoid)Player.m_localPlayer).GetInventory()) || !((Humanoid)Player.m_localPlayer).GetInventory().ContainsItem(item) || (Mod.onlyStackableItems.Value && item.m_shared.m_maxStackSize == 1) || ContainersTracker.isRearrangingItem) { return; } if (Input.GetKey((KeyCode)108)) { Console.instance.Print("SmartContainers tracked item [" + item.m_shared.m_name + "]"); } KeyboardShortcut value = Mod.keyModifier.Value; if (!((KeyboardShortcut)(ref value)).IsPressed()) { value = Mod.groupingKeyModifier.Value; if (!((KeyboardShortcut)(ref value)).IsPressed() && (!Mod.gamepadKey2.Value.MainPressed() || !ZInput.GetButton(Mod.gamepadKey1.Value))) { return; } } if ((Object)(object)InventoryGui.instance == (Object)null || !InventoryGui.instance.IsContainerOpen()) { return; } ContainersTracker.isRearrangingItem = true; if (!__result) { if (TryAddToNearBy(item)) { __result = true; Mod.PlayEffect(Mod.audioFeedbackEnabled.Value, "sfx_lootspawn", ((Character)Player.m_localPlayer).GetCenterPoint()); } } else if (__instance.CountItems(item.m_shared.m_name, -1, true) == item.m_stack && TryAddToNearBy(item)) { __instance.RemoveItem(item); Mod.PlayEffect(Mod.audioFeedbackEnabled.Value, "sfx_lootspawn", ((Character)Player.m_localPlayer).GetCenterPoint()); } ContainersTracker.isRearrangingItem = false; } public static bool TryAddToNearBy(ItemData item, bool allowCurrent = false, bool forceGrouping = false) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0403: Unknown result type (might be due to invalid IL or missing references) //IL_0408: Unknown result type (might be due to invalid IL or missing references) try { Container openedContainer = InventoryGui.instance.m_currentContainer; if (Mod.concurrencyWorkaround.Value.BlockIfAnyOtherOpened() && ContainersTracker.GetNearbyContainers(((Component)Player.m_localPlayer).transform.position, all: true).Any((Container c) => ((object)openedContainer).GetHashCode() != ((object)c).GetHashCode() && c.m_nview.GetZDO().GetInt("InUse", 0) == 1)) { ((Character)Player.m_localPlayer).Message((MessageType)2, "Cant distribute items: other Player is using containers nearby.", 0, (Sprite)null); return false; } List<Container> list = (from c in ContainersTracker.GetNearbyContainers(((Component)Player.m_localPlayer).transform.position) where ((object)openedContainer).GetHashCode() == ((object)c).GetHashCode() || (Mod.concurrencyWorkaround.Value.Ignore() && ((object)openedContainer).GetHashCode() != ((object)c).GetHashCode()) || ((Mod.concurrencyWorkaround.Value.SkipOpenedOthers() || Mod.concurrencyWorkaround.Value.BlockIfAnyOtherOpened()) && c.m_nview.GetZDO().GetInt("InUse", 0) == 0) select c).ToList(); foreach (Container item2 in list) { if (item2.GetInventory().CanAddItem(item, -1) && (allowCurrent || ((object)openedContainer).GetHashCode() != ((object)item2).GetHashCode()) && item2.GetInventory().HaveItem(item.m_shared.m_name, true)) { Console.instance.Print(Localization.instance.Localize(item.m_shared.m_name) + " routed because target container has same item stack"); return AddItemToContainer(item, item2, allowCurrent); } } KeyboardShortcut value; if (Mod.groupingEnabled.Value) { if (!forceGrouping) { value = Mod.groupingKeyModifier.Value; if (!((KeyboardShortcut)(ref value)).IsPressed() && !ZInput.IsGamepadActive()) { goto IL_03ef; } } List<Tuple<string, Container>> list2 = new List<Tuple<string, Container>>(); foreach (Container item3 in list) { if (item3.GetInventory().CanAddItem(item, -1)) { string text = ItemGroups.FindMatchingUserGroup(item3, item); if (text != null) { list2.Add(Tuple.Create<string, Container>(text, item3)); } } } if (list2.Any()) { Tuple<string, Container> tuple = list2.OrderByDescending((Tuple<string, Container> t) => t.Item1).First(); if (list2.Count > 1) { Mod.log.LogWarning((object)("Ambiguous item-groups [" + string.Join(",", list2) + "] found for " + ((Object)item.m_dropPrefab).name + " item. Using " + tuple.Item1)); } Console.instance.Print(Localization.instance.Localize(item.m_shared.m_name) + " routed because target container has item from group " + tuple.Item1 + " : [" + string.Join(",", ItemGroups.Groups[tuple.Item1]) + "]"); return AddItemToContainer(item, tuple.Item2, allowCurrent); } foreach (Container item4 in list) { if (item4.GetInventory().CanAddItem(item, -1) && ItemGroups.ContainerHasSame_SystemGroupItems(item4, item)) { return AddItemToContainer(item, item4, allowCurrent); } } foreach (Container item5 in list) { if (item5.GetInventory().CanAddItem(item, -1) && ItemGroups.ContainerHasSame_NamePatternItems(item5, item)) { return AddItemToContainer(item, item5, allowCurrent); } } if (Mod.itemTypeGroupsEnabled.Value) { foreach (Container item6 in list) { if (item6.GetInventory().CanAddItem(item, -1) && ItemGroups.ContainerHasSameItemType(item6, item)) { return AddItemToContainer(item, item6, allowCurrent); } } } goto IL_03ef; } goto IL_046b; IL_03ef: if (Mod.fuzzyGroupingEnabled.Value) { if (!forceGrouping) { value = Mod.groupingKeyModifier.Value; if (!((KeyboardShortcut)(ref value)).IsPressed() && !ZInput.IsGamepadActive()) { goto IL_046b; } } foreach (Container item7 in list) { if (item7.GetInventory().CanAddItem(item, -1) && ItemGroups.ContainerHasSimilarGroupItems(item7, item)) { return AddItemToContainer(item, item7, allowCurrent); } } } goto IL_046b; IL_046b: return false; } catch (Exception ex) { Mod.log.LogError((object)("Failed to rearrange container items: " + ex)); } return false; } private static bool AddItemToContainer(ItemData item, Container targetContainer, bool allowCurrent = false) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) Container currentContainer = InventoryGui.instance.m_currentContainer; if (allowCurrent || ((object)currentContainer).GetHashCode() != ((object)targetContainer).GetHashCode()) { bool num = targetContainer.GetInventory().AddItem(item); if (num) { targetContainer.Save(); targetContainer.GetInventory().Changed(); if (Mod.hudMessageEnabled.Value && !((object)InventoryGui.instance.m_currentContainer).Equals((object?)targetContainer)) { MessageHud.instance.QueueUnlockMsg(item.GetIcon(), item.m_shared.m_name, Mod.hudMessageText.Value); } Mod.PlayEffect(Mod.effectFeedbackEnabled.Value, "vfx_Potion_health_medium", ((Component)targetContainer).transform.position); } return num; } return false; } } public static class GuiFactory { public static void CreateMrgDialog(out GameObject dialogObj, string dlgUid, string label1, string label2, string label3, UnityAction onFirst, UnityAction onSecond, UnityAction onThird) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: 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) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: 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_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Expected O, but got Unknown //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Expected O, but got Unknown //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Expected O, but got Unknown //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_035d: Unknown result type (might be due to invalid IL or missing references) //IL_0367: Unknown result type (might be due to invalid IL or missing references) //IL_0373: Unknown result type (might be due to invalid IL or missing references) //IL_0389: Unknown result type (might be due to invalid IL or missing references) //IL_039e: Unknown result type (might be due to invalid IL or missing references) //IL_03b9: Unknown result type (might be due to invalid IL or missing references) //IL_040c: Unknown result type (might be due to invalid IL or missing references) //IL_0435: Unknown result type (might be due to invalid IL or missing references) //IL_0463: Unknown result type (might be due to invalid IL or missing references) //IL_0472: Unknown result type (might be due to invalid IL or missing references) //IL_04a8: Unknown result type (might be due to invalid IL or missing references) //IL_04b7: Unknown result type (might be due to invalid IL or missing references) //IL_0504: Unknown result type (might be due to invalid IL or missing references) //IL_0527: Unknown result type (might be due to invalid IL or missing references) //IL_0531: Expected O, but got Unknown //IL_0533: Unknown result type (might be due to invalid IL or missing references) //IL_0547: Expected O, but got Unknown //IL_0576: Unknown result type (might be due to invalid IL or missing references) //IL_0585: Unknown result type (might be due to invalid IL or missing references) //IL_0590: Unknown result type (might be due to invalid IL or missing references) //IL_05a1: Unknown result type (might be due to invalid IL or missing references) //IL_05cb: Unknown result type (might be due to invalid IL or missing references) //IL_05da: Unknown result type (might be due to invalid IL or missing references) Transform val = ((Component)InventoryGui.instance).gameObject.transform.Find("root/SplitDialog"); Transform val2 = Object.Instantiate<Transform>(val, val.parent); ((Object)val2).name = dlgUid; Transform winWrap = val2.Find("win_bkg"); ((RectTransform)winWrap).SetSizeWithCurrentAnchors((Axis)0, 500f); dialogObj = ((Component)val2).gameObject; Object.Destroy((Object)(object)((Component)winWrap.Find("Icon_bkg")).gameObject); Object.Destroy((Object)(object)((Component)winWrap.Find("Slider")).gameObject); Object.Destroy((Object)(object)((Component)winWrap.Find("Text")).gameObject); Object.Destroy((Object)(object)((Component)winWrap.Find("amount")).gameObject); ((Component)winWrap.Find("Button_cancel")).gameObject.AddComponent(typeof(UIGamePad)); ((Component)winWrap.Find("Button_ok")).gameObject.AddComponent(typeof(UIGamePad)); Transform val3 = winWrap.Find("Button_cancel"); Transform val4 = winWrap.Find("Button_ok"); Transform val5 = Object.Instantiate<Transform>(val4, ((Component)winWrap).transform); ((Object)val5).name = "Button_3"; ((TMP_Text)((Component)val3.Find("Text")).GetComponent<TextMeshProUGUI>()).text = label1; ((TMP_Text)((Component)val4.Find("Text")).GetComponent<TextMeshProUGUI>()).text = label2; ((TMP_Text)((Component)val5.Find("Text")).GetComponent<TextMeshProUGUI>()).text = label3; RectTransform val6 = (RectTransform)((Component)val3).transform; val6.pivot += new Vector2(0.5f, 0.7f); RectTransform val7 = (RectTransform)((Component)val4).transform; val7.pivot += new Vector2(0.57f, 0.7f); RectTransform val8 = (RectTransform)((Component)val5).transform; val8.pivot += new Vector2(-0.48f, 0.7f); ((RectTransform)((Component)val3).transform).SetSizeWithCurrentAnchors((Axis)1, 40f); ((RectTransform)((Component)val4).transform).SetSizeWithCurrentAnchors((Axis)1, 40f); ((RectTransform)((Component)val5).transform).SetSizeWithCurrentAnchors((Axis)1, 40f); InitJoyKey((Transform)(RectTransform)val3, "JoyTabLeft", "(LB)"); InitJoyKey((Transform)(RectTransform)val4, "JoyTabRight", "(RB)"); InitJoyKey((Transform)(RectTransform)val5, "", ""); Transform obj = Object.Instantiate<Transform>(((Component)InventoryGui.instance).gameObject.transform.Find("root/Texts/Texts_frame/TextArea"), winWrap); ((Object)obj).name = "TextArea"; ((Component)obj).gameObject.SetActive(true); ((Graphic)((Component)obj).GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.4f); RectTransform val9 = (RectTransform)obj; ((Transform)val9).position = ((Transform)(RectTransform)((Component)val.Find("win_bkg/bkg")).transform).position; ((Transform)val9).localScale = ((Transform)(RectTransform)((Component)val.Find("win_bkg/bkg")).transform).localScale; val9.sizeDelta = ((RectTransform)((Component)val.Find("win_bkg/bkg")).transform).sizeDelta; val9.SetSizeWithCurrentAnchors((Axis)1, 190f); val9.SetSizeWithCurrentAnchors((Axis)0, 515f); val9.pivot = new Vector2(0.51f, 0.33f); ((RectTransform)obj.Find("ScrollArea/Content/Name")).SetSizeWithCurrentAnchors((Axis)0, 515f); ((RectTransform)obj.Find("ScrollArea/Content/Description")).SetSizeWithCurrentAnchors((Axis)0, 515f); TextMeshProUGUI component = ((Component)obj.Find("ScrollArea/Content/Name")).GetComponent<TextMeshProUGUI>(); TextMeshProUGUI component2 = ((Component)obj.Find("ScrollArea/Content/Description")).GetComponent<TextMeshProUGUI>(); ((TMP_Text)component).fontSize = 18f; ((Graphic)component).color = new Color(0.79f, 0.75f, 0.28f, 1f); ((TMP_Text)component2).fontSize = 18f; ((Graphic)component2).color = new Color(0.8f, 0.8f, 0.8f, 1f); Transform val10 = CreateButton("Selector", "--select--", winWrap.Find("TextArea"), new Vector2(380f, 24f), new Vector2(-0.23f, 11.4f)); GameObject val11 = Object.Instantiate<GameObject>(Find("RecipeList"), winWrap); ((Object)val11).name = "SelectorDlg"; ((RectTransform)val11.transform).pivot = new Vector2(-0.55f, 1.7f); Transform val12 = val11.transform.Find("Recipes/ListRoot"); for (int i = 0; i < val12.childCount; i++) { Object.Destroy((Object)(object)((Component)val12.GetChild(i)).gameObject); } ((RectTransform)val11.transform).SetSizeWithCurrentAnchors((Axis)1, 150f); ((UnityEvent)((Component)val10).GetComponent<Button>().onClick).AddListener((UnityAction)delegate { GameObject gameObject = ((Component)winWrap.Find("SelectorDlg")).gameObject; gameObject.SetActive(!gameObject.activeSelf); }); InitJoyKey((Transform)(RectTransform)val10, "", ""); Transform obj2 = Object.Instantiate<Transform>(((Component)InventoryGui.instance.m_takeAllButton).transform.Find("Text"), winWrap.Find("TextArea")); ((RectTransform)obj2).pivot = new Vector2(-0.05f, -0.13f); ((RectTransform)obj2).SetSizeWithCurrentAnchors((Axis)1, 24f); ((RectTransform)obj2).SetSizeWithCurrentAnchors((Axis)0, 150f); ((TMP_Text)((Component)obj2).GetComponent<TextMeshProUGUI>()).text = "Target group:"; ((RectTransform)((Component)winWrap).transform).pivot = new Vector2(-0.7f, 1f); ((UnityEvent)((Component)val3).GetComponent<Button>().onClick).AddListener(onFirst); ((UnityEvent)((Component)val4).GetComponent<Button>().onClick).AddListener(onSecond); ((UnityEvent)((Component)val5).GetComponent<Button>().onClick).AddListener(onThird); } public static Transform AddContainerGuiButton(string btnObjName, string text, Vector2 size, Vector2 pos) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) return CreateButton(btnObjName, text, ((Component)InventoryGui.instance.m_takeAllButton).transform.parent, size, pos); } public static Transform CreateButton(string btnObjName, string text, Transform parent, Vector2 size, Vector2 pos) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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_0040: 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_004d: 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_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0064: 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_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown _ = (RectTransform)parent.Find(btnObjName); Transform obj = Object.Instantiate<Transform>(((Component)InventoryGui.instance.m_takeAllButton).transform, parent); ((Object)obj).name = btnObjName; RectTransform val = (RectTransform)((Component)obj).transform; val.SetSizeWithCurrentAnchors((Axis)0, size.x); val.SetSizeWithCurrentAnchors((Axis)1, size.y); RectTransform val2 = (RectTransform)((Component)val).transform.Find("Text"); val2.SetSizeWithCurrentAnchors((Axis)0, size.x); val2.SetSizeWithCurrentAnchors((Axis)1, size.y); ((TMP_Text)((Component)val2).GetComponent<TextMeshProUGUI>()).text = text; val.pivot = pos; return (Transform)val; } public static void InitJoyKey(Transform btnComponent, string joyKeyCode, string tooltip) { //IL_0049: 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_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) UIGamePad component = ((Component)btnComponent).GetComponent<UIGamePad>(); Transform val = Object.Instantiate<Transform>(((Component)btnComponent).transform.Find("Text"), ((Component)component).transform); ((TMP_Text)((Component)val).GetComponent<TextMeshProUGUI>()).text = tooltip; ((Graphic)((Component)val).GetComponent<TextMeshProUGUI>()).color = new Color(0.8f, 0.8f, 0.8f, 1f); Transform transform = ((Component)val).transform; transform.position += new Vector3(0f, 13f, 0f); if ((Object)(object)component.m_hint != (Object)null) { Object.Destroy((Object)(object)component.m_hint); } component.m_hint = ((Component)val).gameObject; component.m_zinputKey = joyKeyCode; ((Behaviour)((Component)val).GetComponent<TextMeshProUGUI>()).enabled = ZInput.IsGamepadActive(); } public static void FillResList(RectTransform parent, ICollection<string> names, ICollection<Object> m_resObjects, Action<string> cb) { //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Expected O, but got Unknown //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) foreach (Object m_resObject in m_resObjects) { Object.Destroy(m_resObject); } m_resObjects.Clear(); float num = 0f; GameObject val = Find("RecipeList/Recipes/RecipeElement"); foreach (string groupName in names) { GameObject val2 = Object.Instantiate<GameObject>(val, ((Component)parent).transform); Object.Destroy((Object)(object)((Component)val2.transform.Find("icon")).gameObject); Object.Destroy((Object)(object)((Component)val2.transform.Find("Durability")).gameObject); Object.Destroy((Object)(object)((Component)val2.transform.Find("QualityLevel")).gameObject); val2.SetActive(true); ((UnityEvent)val2.GetComponentInChildren<Button>().onClick).AddListener((UnityAction)delegate { cb(groupName); }); Transform transform = val2.transform; ((RectTransform)((transform is RectTransform) ? transform : null)).anchoredPosition = new Vector2(0f, num * -20f); ((TMP_Text)val2.GetComponentInChildren<TextMeshProUGUI>()).text = groupName; m_resObjects.Add((Object)(object)val2); num += 1f; } Rect rect = parent.rect; parent.SetSizeWithCurrentAnchors((Axis)1, Mathf.Max(((Rect)(ref rect)).height, num * 20f)); } private static GameObject Find(string name) { GameObject val = GameObject.Find("_GameMain/LoadingGUI/PixelFix/IngameGui/Inventory_screen/root/Crafting/" + name); if ((Object)(object)val == (Object)null) { Mod.log.LogWarning((object)("Failed to locate '" + name + "' GameObject - fallback to IngameGui(Clone) lookup..")); val = ((Component)GameObject.Find("IngameGui").transform.Find("Inventory_screen/root/Crafting/" + name)).gameObject; } return val; } } [HarmonyPatch(typeof(InventoryGui), "Show")] public static class Gui_Patch { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static Func<Tuple<string, List<string>>, string> <>9__8_3; public static UnityAction <>9__8_0; public static Func<Tuple<string, List<string>>, string> <>9__8_4; public static UnityAction <>9__8_1; public static Func<Tuple<string, List<string>>, string> <>9__8_5; public static UnityAction <>9__8_2; public static Func<Tuple<string, List<string>>, string> <>9__10_0; public static Func<Tuple<string, List<string>>, IEnumerable<string>> <>9__10_1; public static Func<ItemData, bool> <>9__10_5; public static Func<ItemData, string> <>9__10_6; public static Func<Tuple<string, List<string>>, string> <>9__10_8; public static Func<Tuple<string, List<string>>, string> <>9__10_3; internal void <InitButtons>b__8_0() { if (containersUniqueItems != null && intersectedGroups != null) { ItemGroupUtils.ExtendGroup(SelectedTargetGroupId(), intersectedGroups.Map((Tuple<string, List<string>> _) => _.Item1).ToList(), containersUniqueItems); } groupsDialogObj.gameObject.SetActive(false); } internal string <InitButtons>b__8_3(Tuple<string, List<string>> _) { return _.Item1; } internal void <InitButtons>b__8_1() { if (containersUniqueItems != null) { ItemGroupUtils.ExtendAndMerge(SelectedTargetGroupId(), intersectedGroups.Map((Tuple<string, List<string>> _) => _.Item1).ToList(), containersUniqueItems); } groupsDialogObj.gameObject.SetActive(false); } internal string <InitButtons>b__8_4(Tuple<string, List<string>> _) { return _.Item1; } internal void <InitButtons>b__8_2() { if (containersUniqueItems != null && intersectedGroups != null) { ItemGroupUtils.MergeAllToSingleGroup(SelectedTargetGroupId(), intersectedGroups.Map((Tuple<string, List<string>> _) => _.Item1).ToList(), containersUniqueItems); } groupsDialogObj.gameObject.SetActive(false); } internal string <InitButtons>b__8_5(Tuple<string, List<string>> _) { return _.Item1; } internal string <InitMergePromptDlg>b__10_0(Tuple<string, List<string>> _) { return _.Item1; } internal IEnumerable<string> <InitMergePromptDlg>b__10_1(Tuple<string, List<string>> _) { return _.Item2; } internal bool <InitMergePromptDlg>b__10_5(ItemData i) { return intersectedGroups[0].Item2.Contains(i.SCName()); } internal string <InitMergePromptDlg>b__10_6(ItemData _) { return Localization.instance.Localize(_.m_shared.m_name); } internal string <InitMergePromptDlg>b__10_8(Tuple<string, List<string>> _) { return _.Item1; } internal string <InitMergePromptDlg>b__10_3(Tuple<string, List<string>> _) { return _.Item1; } } public static bool initialized = false; private static Transform createGroupButton; private static Transform storeAllButton; public static GameObject groupsDialogObj; private static readonly ICollection<Object> groupSelectorItems = new List<Object>(); private static List<Tuple<string, List<string>>> intersectedGroups; private static List<string> containersUniqueItems; private static void Postfix(InventoryGui __instance) { if (Mod.modEnabled.Value && Mod.groupingEnabled.Value && !((Object)(object)__instance == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null) && !initialized && __instance.IsContainerOpen()) { InitButtons(__instance); } } private static void InitButtons(InventoryGui __instance) { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Expected O, but got Unknown if (!Mod.modEnabled.Value) { return; } try { if ((Mod.groupingEnabled.Value || Mod.unloadAllEnabled.Value) && Mod.createGroupBtnEnabled.Value) { AddCreateGroupBtn(__instance); if (Mod.groupingEnabled.Value && Mod.mergePromptEnabled.Value) { object obj = <>c.<>9__8_0; if (obj == null) { UnityAction val = delegate { if (containersUniqueItems != null && intersectedGroups != null) { ItemGroupUtils.ExtendGroup(SelectedTargetGroupId(), intersectedGroups.Map((Tuple<string, List<string>> _) => _.Item1).ToList(), containersUniqueItems); } groupsDialogObj.gameObject.SetActive(false); }; <>c.<>9__8_0 = val; obj = (object)val; } object obj2 = <>c.<>9__8_1; if (obj2 == null) { UnityAction val2 = delegate { if (containersUniqueItems != null) { ItemGroupUtils.ExtendAndMerge(SelectedTargetGroupId(), intersectedGroups.Map((Tuple<string, List<string>> _) => _.Item1).ToList(), containersUniqueItems); } groupsDialogObj.gameObject.SetActive(false); }; <>c.<>9__8_1 = val2; obj2 = (object)val2; } object obj3 = <>c.<>9__8_2; if (obj3 == null) { UnityAction val3 = delegate { if (containersUniqueItems != null && intersectedGroups != null) { ItemGroupUtils.MergeAllToSingleGroup(SelectedTargetGroupId(), intersectedGroups.Map((Tuple<string, List<string>> _) => _.Item1).ToList(), containersUniqueItems); } groupsDialogObj.gameObject.SetActive(false); }; <>c.<>9__8_2 = val3; obj3 = (object)val3; } GuiFactory.CreateMrgDialog(out groupsDialogObj, "mrgToGroupDialog", "Extend", "Extend&Merge", "Merge All", (UnityAction)obj, (UnityAction)obj2, (UnityAction)obj3); } } if (Mod.unloadAllEnabled.Value && !Mod.unloadAllInsteadStackBtn.Value) { AddStoreAllBtn(__instance); } initialized = true; } catch (Exception ex) { Mod.log.LogError((object)("Failed to properly patch GUI with additional buttons: " + ex)); Clean(); } finally { Mod.log.LogInfo((object)"Initialized UI extensions."); } } private static void AddCreateGroupBtn(InventoryGui __instance) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown createGroupButton = GuiFactory.AddContainerGuiButton("createGroupBtn", "+æ+", new Vector2(45f, 30f), Mod.createGroupBtnPos.Value); GuiFactory.InitJoyKey(createGroupButton, "JoyMap", "(Гг)"); ((UnityEvent)((Component)createGroupButton).GetComponent<Button>().onClick).AddListener((UnityAction)delegate { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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) if (!((Object)(object)__instance.m_playerGrid == (Object)null) && !((Object)(object)__instance.m_containerGrid == (Object)null) && !((Character)Player.m_localPlayer).IsTeleporting()) { Inventory inventory = __instance.m_containerGrid.GetInventory(); KeyboardShortcut value; if (Mod.unloadAllEnabled.Value) { value = Mod.unloadAllItemsGroupKeyModifier.Value; if (((KeyboardShortcut)(ref value)).IsPressed() || ZInput.GetButton("JoyRTrigger")) { UnloadItems.AddToUnloadAllItemsFilter(inventory); return; } } if (Mod.unloadAllEnabled.Value) { value = Mod.unloadAllSkipItemsGroupKeyModifier.Value; if (((KeyboardShortcut)(ref value)).IsPressed() || ZInput.GetButton("JoyLTrigger")) { UnloadItems.AddToUnloadAllItemsSkipList(inventory); return; } } if (Mod.groupingEnabled.Value) { containersUniqueItems = ItemGroupUtils.ExtractUniqueItemNames(inventory); if (containersUniqueItems.Count >= 2) { if (Mod.mergePromptEnabled.Value) { InitMergePromptDlg(inventory); } else { ItemGroupUtils.RegisterNewGroup(inventory); } } } } }); } private static void InitMergePromptDlg(Inventory inventory) { //IL_0378: Unknown result type (might be due to invalid IL or missing references) //IL_0382: Expected O, but got Unknown //IL_0396: Unknown result type (might be due to invalid IL or missing references) //IL_03ed: Expected O, but got Unknown intersectedGroups = ItemGroupUtils.FindIntersections(containersUniqueItems); if (!intersectedGroups.Any()) { ItemGroupUtils.RegisterNewGroup(inventory); return; } List<string> second = intersectedGroups.Map((Tuple<string, List<string>> _) => _.Item1).ToList(); HashSet<string> intersectedItemNames = intersectedGroups.FlatMap((Tuple<string, List<string>> _) => _.Item2).ToHashSet(); List<string> nonGroupedItems = containersUniqueItems.Filter((string _) => !intersectedItemNames.Contains(_)).ToList(); TextMeshProUGUI component = ((Component)groupsDialogObj.transform.Find("win_bkg/TextArea/ScrollArea/Content/Name")).GetComponent<TextMeshProUGUI>(); TextMeshProUGUI component2 = ((Component)groupsDialogObj.transform.Find("win_bkg/TextArea/ScrollArea/Content/Description")).GetComponent<TextMeshProUGUI>(); if (intersectedGroups.Count == 1) { if (!nonGroupedItems.Any()) { ((Character)Player.m_localPlayer).Message((MessageType)2, "Group " + intersectedGroups[0].Item1 + " already contains these items", 0, (Sprite)null); return; } List<string> list = inventory.m_inventory.Filter((ItemData i) => intersectedGroups[0].Item2.Contains(i.SCName())).Map((ItemData _) => Localization.instance.Localize(_.m_shared.m_name)).Distinct() .ToList(); ((TMP_Text)component).text = string.Join(",", list.Take(3)) + " " + ((list.Count > 3) ? "and others " : "") + ((list.Count > 1) ? "are already members" : "is already a member") + $" of an existing group of {ItemGroups.Groups[intersectedGroups[0].Item1].Count} items. "; } else { ((TMP_Text)component).text = $"Items from {intersectedGroups.Count} different groups are already presented in this container."; } ((TMP_Text)component2).text = " Please review info bellow, select target-group & action.\n You can: \n • <color=#FFA13CB7>'Extend'</color>: add previously non-grouped items \n(colored in <color=green>green</color>) to a selected target-group.\n"; ((TMP_Text)component2).text = ((TMP_Text)component2).text + " • <color=#FFA13CB7>'Extend & merge'</color>: add all items from this container to a selected target-group. All conflicting items (colored in <color=red>red</color>) would be removed from their current groups.\n"; ((TMP_Text)component2).text = ((TMP_Text)component2).text + " • <color=#FFA13CB7>'Merge all'</color>: (Not recommended) move all items (from this container) & all conflicting group items to a target group.All members of all listed bellow groups will be moved to a target group. \n<color=grey>(target-group could be a new or an existing group)</color>\n"; List<string> list2 = UnloadItems.unloadAllGroupsList.Intersect(second).ToList(); if (Mod.unloadAllEnabled.Value && list2.Any()) { ((TMP_Text)component2).text = ((TMP_Text)component2).text + " \n<color=orange> ! Please note that groups [" + string.Join(",", list2) + "] are used for 'Unloading' filtering. Changing them will affect it's behaviour.</color>\n"; } ((TMP_Text)component2).text = ((TMP_Text)component2).text + "\n Items in the container: " + GeneralExtensions.Join<string>(containersUniqueItems.Map((string itemName) => "<color=" + (nonGroupedItems.Contains(itemName) ? "green" : "red") + ">" + itemName + "</color>"), (Func<string, string>)null, ",") + ".\n"; ((TMP_Text)component2).text = ((TMP_Text)component2).text + "\n Detected groups: \n"; ((TMP_Text)component2).text = ((TMP_Text)component2).text + GeneralExtensions.Join<string>(intersectedGroups.Map((Tuple<string, List<string>> _) => _.Item1).Map(delegate(string gKey) { IEnumerable<string> values = ItemGroups.Groups[gKey].Map((string _) => (!intersectedItemNames.Contains(_)) ? _ : ("<color=red>" + _ + "</color>")); return "<color=yellow>" + gKey + "</color>: [" + string.Join(", ", values) + "] \n"; }), (Func<string, string>)null, ""); RectTransform selectorBtn = (RectTransform)groupsDialogObj.transform.Find("win_bkg/TextArea/Selector"); RectTransform val = (RectTransform)groupsDialogObj.transform.Find("win_bkg/SelectorDlg/Recipes/ListRoot"); List<string> names = intersectedGroups.Map((Tuple<string, List<string>> _) => _.Item1).Prepend("--new Group--").ToList(); GuiFactory.FillResList(val, names, groupSelectorItems, delegate(string selection) { ((TMP_Text)((Component)selectorBtn).GetComponentInChildren<TextMeshProUGUI>()).text = selection; ((Component)groupsDialogObj.transform.Find("win_bkg/SelectorDlg")).gameObject.SetActive(false); }); ((TMP_Text)((Component)selectorBtn).GetComponentInChildren<TextMeshProUGUI>()).text = ((intersectedGroups.Count == 1) ? intersectedGroups[0].Item1 : "--new Group--"); ((Component)groupsDialogObj.transform.Find("win_bkg/SelectorDlg/RecipeScroll")).GetComponent<Scrollbar>().value = 1f; ((Component)groupsDialogObj.transform.Find("win_bkg/SelectorDlg")).gameObject.SetActive(false); groupsDialogObj.SetActive(true); } private static string SelectedTargetGroupId() { return ((TMP_Text)((Component)groupsDialogObj.transform.Find("win_bkg/TextArea/Selector")).GetComponentInChildren<TextMeshProUGUI>()).text; } private static void AddStoreAllBtn(InventoryGui __instance) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown storeAllButton = GuiFactory.AddContainerGuiButton("storeAllButton", "\\||/", new Vector2(45f, 36f), Mod.unloadAllBtnPos.Value); GuiFactory.InitJoyKey(storeAllButton, "JoyMenu", "(≡)"); ((UnityEvent)((Component)storeAllButton).GetComponent<Button>().onClick).AddListener((UnityAction)delegate { if (!((Object)(object)__instance.m_playerGrid == (Object)null) && !((Object)(object)__instance.m_containerGrid == (Object)null) && !((Character)Player.m_localPlayer).IsTeleporting()) { UnloadItems.UnloadAllItems(((Humanoid)Player.m_localPlayer).GetInventory()); } }); } public static void Init() { if ((Object)(object)InventoryGui.instance != (Object)null) { InitButtons(InventoryGui.instance); } } public static void Clean() { if ((Object)(object)createGroupButton != (Object)null) { Object.Destroy((Object)(object)((Component)createGroupButton).gameObject); } if ((Object)(object)storeAllButton != (Object)null) { Object.Destroy((Object)(object)((Component)storeAllButton).gameObject); } if ((Object)(object)groupsDialogObj != (Object)null) { Object.Destroy((Object)(object)groupsDialogObj); } initialized = false; Mod.log.LogInfo((object)"Cleaned up UI extensions."); } } [HarmonyPatch(typeof(Game), "Start")] public static class Game_Start_Patch { private static void Postfix(Game __instance) { Gui_Patch.Clean(); } } [HarmonyPatch(typeof(InventoryGui), "Hide")] public static class Gui_Hide_Patch { private static void Postfix(InventoryGui __instance) { if (Gui_Patch.initialized) { GameObject groupsDialogObj = Gui_Patch.groupsDialogObj; if (groupsDialogObj != null) { groupsDialogObj.SetActive(false); } } } } public static class ItemGroups { private static ICollection<string> prefixItemGroups = new HashSet<string>(); private static ICollection<string> postfixItemGroups = new HashSet<string>(); public static readonly IDictionary<string, ISet<string>> Groups = new Dictionary<string, ISet<string>>(); public static void ParseConfig() { foreach (KeyValuePair<ConfigDefinition, string> item in Mod.ConfigOrphanedEntries().ToList()) { if (item.Key.Section.Equals("ItemGroup")) { Mod.config.Bind<string>(item.Key.Section, item.Key.Key, item.Value.ToLower().Replace("_", ""), Mod.groupDescr("user-added items-group based on item-names list")); } } ConfigEntry<string> val = default(ConfigEntry<string>); if (Mod.config.TryGetEntry<string>("PrefixedItemGroups", "prefixes", ref val) && val.Value.Length > 0) { prefixItemGroups = ItemGroupUtils.ParseGroupConfigEntry(val); Mod.log.LogInfo((object)string.Format("parsed PrefixedItemGroups : [{0}] ({1})", string.Join(",", prefixItemGroups), prefixItemGroups.Count)); } ConfigEntry<string> val2 = default(ConfigEntry<string>); if (Mod.config.TryGetEntry<string>("PostfixedItemGroups", "posfixes", ref val2) && val2.Value.Length > 0) { postfixItemGroups = ItemGroupUtils.ParseGroupConfigEntry(val2); Mod.log.LogInfo((object)string.Format("parsed PostfixedItemGroups: [{0}] ({1})", string.Join(",", postfixItemGroups), postfixItemGroups.Count)); } ConfigEntry<string> val3 = default(ConfigEntry<string>); foreach (ConfigDefinition item2 in from itemKey in Mod.config.Keys where itemKey.Section.Equals("ItemGroup") select itemKey into _ orderby _.Key select _) { if (Mod.config.TryGetEntry<string>(item2.Section, item2.Key, ref val3) && val3.Value.Length > 0) { ISet<string> set = ItemGroupUtils.ParseGroupConfigEntry(val3); Groups.Add(item2.Key, set); Mod.log.LogInfo((object)string.Format("parsed items group '{0}': [{1}] ({2})", item2.Key, string.Join(",", set), set.Count)); } } } public static string FindMatchingUserGroup(Container container, ItemData item) { if (item.m_shared.m_name.Length < 7) { Mod.log.LogWarning((object)("Cant process Unexpected Item " + item.m_shared.m_name)); return null; } ICollection<string> collection = FindMatchingGroups(container, item.SCName(), item, Groups.Keys.Except(Mod.systemGroupKeys).ToList()); if (collection.Count > 1) { Mod.log.LogWarning((object)("Ambiguous item-groups [" + string.Join(",", collection) + "] found for " + ((Object)item.m_dropPrefab).name + " item in single container.")); } if (!collection.Any()) { return null; } return collection.Max((string _) => _); } public static bool ContainerHasSame_SystemGroupItems(Container container, ItemData item) { if (item.m_shared.m_name.Length < 7) { Mod.log.LogWarning((object)("Cant process Unexpected Item " + item.m_shared.m_name)); return false; } return TestConfiguredGroups(container, item.SCName(), item, Mod.systemGroupKeys); } public static bool ContainerHasSame_NamePatternItems(Container container, ItemData item) { if (item.m_shared.m_name.Length < 7) { Mod.log.LogWarning((object)("Cant process Unexpected Item " + item.m_shared.m_name)); return false; } string shortItemName = item.SCName(); if (!TestItemNamePrefix(container, shortItemName, item)) { return TestItemNamePostfix(container, shortItemName, item); } return true; } public static bool ContainerHasSameItemType(Container container, ItemData item) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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) if (item.m_shared.m_name.Length < 7) { return false; } ItemType itemType = item.m_shared.m_itemType; string shortItemName = item.SCName(); int num; if ((!IsTrophie(itemType) || !HaveMatchingItem(container, (ItemData _) => IsTrophie(_.m_shared.m_itemType) && !_.SCName().Equals(shortItemName))) && (!IsTool(itemType) || !HaveMatchingItem(container, (ItemData _) => IsTool(_.m_shared.m_itemType) && !_.SCName().Equals(shortItemName))) && (!IsAmmo(itemType) || !HaveMatchingItem(container, (ItemData _) => IsAmmo(_.m_shared.m_itemType) && !_.SCName().Equals(shortItemName))) && (!IsArmor(itemType) || !HaveMatchingItem(container, (ItemData _) => IsArmor(_.m_shared.m_itemType) && !_.SCName().Equals(shortItemName)))) { if (IsWeapon(itemType)) { num = (HaveMatchingItem(container, (ItemData _) => IsWeapon(_.m_shared.m_itemType) && !_.SCName().Equals(shortItemName)) ? 1 : 0); if (num != 0) { goto IL_00c6; } } else { num = 0; } goto IL_00ff; } num = 1; goto IL_00c6; IL_00ff: return (byte)num != 0; IL_00c6: Console.instance.Print($"{Localization.instance.Localize(item.m_shared.m_name)} routed because target container has same item type {item.m_shared.m_itemType}"); goto IL_00ff; } public static bool ContainerHasSimilarGroupItems(Container container, ItemData item) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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_0087: Unknown result type (might be due to invalid IL or missing references) if (item.m_shared.m_name.Length < 7) { return false; } string shortItemName = item.m_shared.m_name.SCName(); ItemType itemType = item.m_shared.m_itemType; int num; if ((int)itemType != 0) { num = (HaveMatchingItem(container, (ItemData _) => _.m_shared.m_itemType == itemType && !_.SCName().Equals(shortItemName)) ? 1 : 0); if (num != 0) { Console.instance.Print($"{Localization.instance.Localize(item.m_shared.m_name)} routed because target container has same item type (fuzzy) {item.m_shared.m_itemType}"); } } else { num = 0; } return (byte)num != 0; } private static bool TestItemNamePrefix(Container container, string shortItemName, ItemData item) { foreach (string prefix in prefixItemGroups) { if (shortItemName.StartsWith(prefix) && HaveMatchingItem(container, (ItemData _) => _.m_shared.m_name.StartsWith("$item_" + prefix) && !_.SCName().Equals(shortItemName))) { Console.instance.Print(Localization.instance.Localize(item.m_shared.m_name) + " routed because target container has item with Prefix " + prefix); return true; } } return false; } private static bool TestItemNamePostfix(Container container, string shortItemName, ItemData item) { foreach (string postfix in postfixItemGroups) { if (shortItemName.EndsWith(postfix) && HaveMatchingItem(container, (ItemData _) => _.m_shared.m_name.EndsWith(postfix) && !_.SCName().Equals(shortItemName))) { Console.instance.Print(Localization.instance.Localize(item.m_shared.m_name) + " routed because target container has item with Postfix " + postfix); return true; } } return false; } private static bool TestConfiguredGroups(Container container, string shortItemName, ItemData item, ICollection<string> grKeys = null) { foreach (string item2 in grKeys ?? Groups.Keys) { if (Groups.ContainsKey(item2)) { ISet<string> set = Groups[item2]; if (TestGroup(shortItemName, container, set)) { Console.instance.Print(Localization.instance.Localize(item.m_shared.m_name) + " routed because target container has item from group " + item2 + " : [" + string.Join(",", set) + "]"); return true; } } } return false; } private static ICollection<string> FindMatchingGroups(Container container, string shortItemName, ItemData item, ICollection<string> grKeys = null) { ICollection<string> obj = grKeys ?? Groups.Keys; List<string> list = new List<string>(); foreach (string item2 in obj) { if (Groups.ContainsKey(item2)) { ISet<string> group = Groups[item2]; if (TestGroup(shortItemName, container, group)) { list.Add(item2); } } } return list; } private static bool TestGroup(string shortItemName, Container container, ICollection<string> group) { if (group.Contains(shortItemName)) { foreach (string iname in group) { if (!iname.Equals(shortItemName) && HaveMatchingItem(container, (ItemData _) => _.SCName().Equals(iname))) { return true; } } } return false; } private static bool HaveMatchingItem(Container container, Func<ItemData, bool> predicate) { foreach (ItemData item in container.GetInventory().m_inventory) { if (predicate(item)) { return true; } } return false; } private static bool IsArmor(ItemType _) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Invalid comparison between Unknown and I4 if ((int)_ != 6 && (int)_ != 7 && (int)_ != 11 && (int)_ != 17) { return (int)_ == 18; } return true; } private static bool IsWeapon(ItemType _) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 if ((int)_ != 3 && (int)_ != 4 && (int)_ != 14) { return (int)_ == 5; } return true; } private static bool IsTrophie(ItemType _) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 return (int)_ == 13; } private static bool IsTool(ItemType _) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 return (int)_ == 19; } private static bool IsAmmo(ItemType _) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 return (int)_ == 9; } public static void Clear() { prefixItemGroups.Clear(); postfixItemGroups.Clear(); Groups.Clear(); } } public static class ItemGroupUtils { private static readonly Predicate<string> IsItemSupported = (string itemName) => itemName.StartsWith("$item_") || itemName.StartsWith("$mod_"); public static void RegisterNewGroup(Inventory inventory) { List<string> list = ExtractUniqueItemNames(inventory); if (list.Count > 1) { RegisterNewGroup((ICollection<string>)list); } } public static void RegisterNewGroup(ICollection<string> names) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown if (!names.Any()) { ((Character)Player.m_localPlayer).Message((MessageType)2, "No new items to create a group from.", 0, (Sprite)null); return; } Mod.ignoreUpdate = true; ConfigDefinition val = new ConfigDefinition("ItemGroup", "userGroup" + DateTimeOffset.UtcNow.ToUnixTimeSeconds()); Mod.config.Bind<string>(val, string.Join(",", names), Mod.groupDescr("user-added items-group based on item-names list")); ConfigEntry<string> val2 = default(ConfigEntry<string>); if (Mod.config.TryGetEntry<string>(val, ref val2) && val2.Value.Length > 0) { ISet<string> set = ParseGroupConfigEntry(val2); ItemGroups.Groups.Add(val.Key, set); ManualLogSource log = Mod.log; if (log != null) { log.LogInfo((object)string.Format("parsed items group '{0}': [{1}] ({2})", val.Key, string.Join(",", set), set.Count)); } NotifyPlayer(set.Count, "Registered new group of {0} items."); } } public static void MergeAllToSingleGroup(string targetGroupId, List<string> groupIds, List<string> newItems) { HashSet<string> hashSet = groupIds.Filter((string _) => !_.Equals(targetGroupId)).FlatMap((string _) => ItemGroups.Groups[_]).ToList() .Concat(newItems) .ToHashSet(); if (!ItemGroups.Groups.ContainsKey(targetGroupId)) { RegisterNewGroup((ICollection<string>)hashSet); } else { hashSet = hashSet.Except(ItemGroups.Groups[targetGroupId]).ToHashSet(); if (!hashSet.Any()) { ((Character)Player.m_localPlayer).Message((MessageType)2, "Existing group already contained all items", 0, (Sprite)null); } else { AddToItemsGroup(targetGroupId, hashSet); NotifyPlayer(hashSet.Count, "Added {0} new items to existing group."); } } foreach (string item in groupIds.Filter((string _) => !_.Equals(targetGroupId))) { Mod.log.LogInfo((object)("flattened group : " + item)); ClearItemsGroup(item); } } public static void ExtendGroup(string targetGroupId, List<string> groupIds, List<string> newItems) { List<string> second = groupIds.FlatMap((string _) => ItemGroups.Groups[_]).Intersect(newItems).ToList(); HashSet<string> hashSet = newItems.Except(second).ToHashSet(); if (!ItemGroups.Groups.ContainsKey(targetGroupId)) { RegisterNewGroup((ICollection<string>)hashSet); return; } if (!hashSet.Any()) { ((Character)Player.m_localPlayer).Message((MessageType)2, "Existing group already contained all items", 0, (Sprite)null); return; } AddToItemsGroup(targetGroupId, hashSet); NotifyPlayer(hashSet.Count, "Added {0} new items to existing group."); } public static void ExtendAndMerge(string targetGroupId, List<string> groupIds, List<string> newItems) { foreach (string item in groupIds.Filter((string _) => !_.Equals(targetGroupId))) { List<string> items = newItems.Intersect(ItemGroups.Groups[item]).ToList(); RemoveFromItemsGroup(item, items); } if (!ItemGroups.Groups.ContainsKey(targetGroupId)) { RegisterNewGroup((ICollection<string>)newItems); return; } HashSet<string> hashSet = newItems.Except(ItemGroups.Groups[targetGroupId]).ToHashSet(); if (!hashSet.Any()) { ((Character)Player.m_localPlayer).Message((MessageType)2, "Existing group already contained all items", 0, (Sprite)null); return; } AddToItemsGroup(targetGroupId, hashSet); NotifyPlayer(hashSet.Count, "Added {0} new items to existing group."); } public static ConfigEntry<string> AddToItemListConfig(ICollection<string> names, ISet<string> targetSet, ConfigEntry<string> configEntry, string uiMessage) { foreach (string name in names) { targetSet.Add(name); } Mod.ignoreUpdate = true; configEntry.Value = string.Join(",", targetSet); NotifyPlayer(names.Count, uiMessage); return configEntry; } private static void NotifyPlayer(int count, string uiMessage) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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_004a: Unknown result type (might be due to invalid IL or missing references) ((Character)Player.m_localPlayer).Message((MessageType)2, string.Format(uiMessage, count), 0, (Sprite)null); if (Mod.effectFeedbackEnabled.Value) { Vector3 position = ((Component)InventoryGui.instance.m_currentContainer).gameObject.transform.position; Player.m_localPlayer.m_skillLevelupEffects.Create(position, Quaternion.identity, (Transform)null, 1f, -1); } } public static List<Tuple<string, List<string>>> FindIntersections(List<string> names) { List<Tuple<string, List<string>>> list = new List<Tuple<string, List<string>>>(); foreach (string item in ItemGroups.Groups.Keys.ToList()) { List<string> list2 = ItemGroups.Groups[item].Intersect(names).ToList(); if (list2.Any()) { list.Add(new Tuple<string, List<string>>(item, list2)); } } return list.OrderByDescending((Tuple<string, List<string>> tt) => tt.Item2.Count).ToList(); } public static List<string> ExtractUniqueItemNames(Inventory inventory) { foreach (string item in inventory.m_inventory.Map((ItemData invi) => invi.m_shared.m_name).Filter((string _) => !IsItemSupported(_)).ToList()) { Mod.log.LogWarning((object)("Unsupported item name " + item)); } return inventory.m_inventory.Map((ItemData invi) => invi.m_shared.m_name).Filter((string _) => IsItemSupported(_)).Distinct() .Map((string _) => _.SCName()) .ToList(); } public static ISet<string> ParseGroupConfigEntry(ConfigEntry<string> configEntry) { return new HashSet<string>(configEntry.Value.Split(new char[1] { ',' }).Map((string _) => _.SCName().Replace(" ", ""))); } private static void AddToItemsGroup(string groupId, ICollection<string> items) { foreach (string item in items) { ItemGroups.Groups[groupId].Add(item); } SaveItemsGroup(groupId, ItemGroups.Groups[groupId]); } private static void RemoveFromItemsGroup(string groupId, ICollection<string> items) { foreach (string item in items) { ItemGroups.Groups[groupId].Remove(item); } SaveItemsGroup(groupId, ItemGroups.Groups[groupId]); } private static void ClearItemsGroup(string flattenedGroupId) { ItemGroups.Groups[flattenedGroupId].Clear(); SaveItemsGroup(flattenedGroupId, ItemGroups.Groups[flattenedGroupId]); } private static void SaveItemsGroup(string groupId, ICollection<string> groupItems) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown ConfigEntry<string> val = default(ConfigEntry<string>); if (Mod.config.TryGetEntry<string>(new ConfigDefinition("ItemGroup", groupId), ref val)) { Mod.ignoreUpdate = true; val.Value = string.Join(",", groupItems); } } } [BepInPlugin("flueno.SmartContainers", "Smart Containers Mod", "1.7.0")] public class Mod : BaseUnityPlugin { internal readonly Harmony harmony; internal readonly Assembly assembly; public static ManualLogSource log; public static ConfigFile config; public static ConfigEntry<bool> modEnabled; public static ConfigEntry<bool> groupingEnabled; public static ConfigEntry<bool> itemTypeGroupsEnabled; public static ConfigEntry<bool> fuzzyGroupingEnabled; public static ConfigEntry<bool> onlyStackableItems; public static ConfigEntry<ConcurrentChestModificationWorkaround> concurrencyWorkaround; public static ConfigEntry<bool> hudMessageEnabled; public static ConfigEntry<bool> audioFeedbackEnabled; public static ConfigEntry<bool> effectFeedbackEnabled; public static ConfigEntry<string> hudMessageText; public static ConfigEntry<int> range; public static ConfigEntry<KeyboardShortcut> keyModifier; public static ConfigEntry<string> gamepadKey1; public static ConfigEntry<KeyboardShortcut> gamepadKey2; public static ConfigEntry<KeyboardShortcut> groupingKeyModifier; public static ConfigEntry<bool> createGroupBtnEnabled; public static ConfigEntry<bool> mergePromptEnabled; public static ConfigEntry<Vector2> createGroupBtnPos; public static ConfigEntry<bool> unloadAllEnabled; public static ConfigEntry<bool> unloadAllInsteadStackBtn; public static ConfigEntry<Vector2> unloadAllBtnPos; public static ConfigEntry<KeyboardShortcut> unloadAllItemsGroupKeyModifier; public static ConfigEntry<KeyboardShortcut> unloadAllSkipItemsGroupKeyModifier; public static ConfigEntry<bool> unloadForceGrouping; public static ConfigEntry<string> unloadAllItemsList; public static ConfigEntry<string> unloadAllSkipList; public static ConfigEntry<string> unloadAllGroupsList; public static ConfigEntry<string> unloadAllPrefixItemGroups; public static ConfigEntry<string> unloadAllPostfixItemGroups; public static ConfigEntry<bool> unloadAllMaterialsFiltering; public static ConfigEntry<bool> unloadAllTrophiesFiltering; public static ConfigEntry<bool> unloadAllConsumableFiltering; public static bool ignoreUpdate = false; public static readonly ICollection<string> systemGroupKeys = new HashSet<string> { "valuables", "ore", "rock", "ingots", "wood", "mushrooms", "berries", "vegetables", "cookedMeat", "food" }; public Mod() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown harmony = new Harmony("flueno.SmartContainers"); assembly = Assembly.GetExecutingAssembly(); config = ((BaseUnityPlugin)this).Config; log = ((BaseUnityPlugin)this).Logger; } public void Start() { //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_02a9: Unknown result type (might be due to invalid IL or missing references) //IL_04d3: Unknown result type (might be due to invalid IL or missing references) //IL_04fd: Unknown result type (might be due to invalid IL or missing references) //IL_054b: Unknown result type (might be due to invalid IL or missing references) ((BaseUnityPlugin)this).Config.Bind<int>("General", "NexusID", 332, "Nexus mod ID"); modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "enabled", true, "Enables this mod"); MigrateConfig(ConfigOrphanedEntries()); onlyStackableItems = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "onlyStackableItems", true, "Rearranges only stackable items"); hudMessageEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "hudMessageEnabled", true, "Enables hud message indicating that item was routed & placed to some other chest"); hudMessageText = ((BaseUnityPlugin)this).Config.Bind<string>("General", "hudMessageText", "Routed to another Chest", "HUD message consists of Icon, item-name plus this text."); range = ((BaseUnityPlugin)this).Config.Bind<int>("General", "range", 14, new ConfigDescription("Range within which containers will participate in resources arrangement.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(5, 99), Array.Empty<object>())); keyModifier = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "hkeyModifier", new KeyboardShortcut((KeyCode)306, Array.Empty<KeyCode>()), "Change only if you wish to have even longer than ctrl+click combination (holding ctrl is mandatory since it's a 'move-stack' ingame key)"); gamepadKey1 = ((BaseUnityPlugin)this).Config.Bind<string>("General", "gamepadKey1", "JoyLTrigger", "first part of gamepads transfer-item key-combo"); gamepadKey2 = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "gamepadKey2", new KeyboardShortcut((KeyCode)332, Array.Empty<KeyCode>()), "second part of gamepads transfer-item key-combo"); audioFeedbackEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "audioFeedbackEnabled", true, "Enables playing of sound on successful items transfer"); effectFeedbackEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "effectFeedbackEnabled", true, "Enables highlighting of end-target chests where items have been transferred."); concurrencyWorkaround = ((BaseUnityPlugin)this).Config.Bind<ConcurrentChestModificationWorkaround>("General", "concurrentChestModificationWorkaround", ConcurrentChestModificationWorkaround.ExcludeContainersOpenedByOthers, "There are rare possibility of items loss if two players simultaneously (within a ~second) modify same containers inventory. Options are: ignore possible issue; ignore 'opened' chests; block mod if any other nearby player opened a chest"); groupingEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Grouping", "enabled", true, "Enables distributing items to containers with 'same-kinded' items (used if no nearby containers contain 'same item')"); itemTypeGroupsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Grouping", "itemTypeGroupsEnabled", true, "Enable grouping by item-types (Trophie, Tool, Ammo, Armor, Weapon)."); fuzzyGroupingEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Grouping", "fuzzyGroupingEnabled", false, "Enable grouping by more broad criteria."); groupingKeyModifier = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Grouping", "groupingKeyModifier", new KeyboardShortcut((KeyCode)306, Array.Empty<KeyCode>()), " Change to 'LeftControl + LeftShift' if you want to trigger grouping with a separate hotkey (ctrl+shift+click)(holding ctrl is mandatory since it's a 'move-stack' ingame key)"); createGroupBtnEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Grouping", "createGroupBtnEnabled", true, "Adds to the chest UI button [☼] which creates items-group based on the current items set in the chest."); mergePromptEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Grouping", "mergePromptEnabled", true, "In case when createGroupBtn clicked and chest already contains some members of one ore more groups - dialog showed with option to merge items & groups into a single group."); createGroupBtnPos = ((BaseUnityPlugin)this).Config.Bind<Vector2>("Grouping", "createGroupBtnPos", new Vector2(1.5f, 10.7f), "Adjusts btn position on inventory ui. →x:1.5..-10 ↓y:0.4..10.7 bottom-left: (1.5f, 10.7f) top-right:(-10f, 0.4f) bottom-right:(-10f, 10.7f)"); ((BaseUnityPlugin)this).Config.Bind<string>("PrefixedItemGroups", "prefixes", "trophy,mead,arrow,armor,cape,helmet,atgeir,bow,battleaxe,knife,mace,shield,sledge,spear,sword,tankard,club,mushroom,arrow", groupDescr("If both item names start with same 'prefix' - they are considered to have same group. I.e. arrowFire & arrowFlint")); ((BaseUnityPlugin)this).Config.Bind<string>("PostfixedItemGroups", "posfixes", "cone,seeds,pelt,hide,berries", groupDescr("If both item names end with same 'postfix' - they are considered to have same group. I.e. carrotSeeds & turnipSeeds")); ((BaseUnityPlugin)this).Config.Bind<string>("ItemGroup", "valuables", "ruby,coins,amber,amberpearl", groupDescr()); ((BaseUnityPlugin)this).Config.Bind<string>("ItemGroup", "ore", "copperore,flametalore,ironore,silverore,tinore,ironscrap,blackmetalscrap", groupDescr()); ((BaseUnityPlugin)this).Config.Bind<string>("ItemGroup", "rock", "stone,flint,obsidian", groupDescr()); ((BaseUnityPlugin)this).Config.Bind<string>("ItemGroup", "ingots", "copper,bronze,flametal,iron,silver,tin,blackmetal", groupDescr()); ((BaseUnityPlugin)this).Config.Bind<string>("ItemGroup", "wood", "wood,finewood,corewood,elderbark,roundlog", groupDescr()); ((BaseUnityPlugin)this).Config.Bind<string>("ItemGroup", "mushrooms", "Mushroom,MushroomBlue,MushroomYellow,mushroomcommon", groupDescr()); ((BaseUnityPlugin)this).Config.Bind<string>("ItemGroup", "berries", "Blueberries,raspberries,cloudberries,honey", groupDescr()); ((BaseUnityPlugin)this).Config.Bind<string>("ItemGroup", "vegetables", "Carrot,Turnip", groupDescr()); ((BaseUnityPlugin)this).Config.Bind<string>("ItemGroup", "cookedMeat", "CookedLoxMeat,NeckTailGrilled,MeatCooked,FishCooked,SerpentMeatCooked", groupDescr()); ((BaseUnityPlugin)this).Config.Bind<string>("ItemGroup", "food", "CarrotSoup,Sausages,QueensJam,SerpentStew,TurnipStew,BloodPudding", groupDescr()); unloadAllEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Unload", "enabled", false, "Enables Unload-all option & UI button [\\||/]. Allows to batch-unload all eligible items from players inventory to their corresponding stacks & groups in nearby chests."); unloadAllInsteadStackBtn = ((BaseUnityPlugin)this).Config.Bind<bool>("Unload", "nativeButton", false, "Use existing 'place-stacks' UI button for unloading. If disabled - new UI button [\\||/] will be created."); unloadAllBtnPos = ((BaseUnityPlugin)this).Config.Bind<Vector2>("Unload", "btnPos", new Vector2(1.5f, 8.15f), (ConfigDescription)null); unloadAllItemsGroupKeyModifier = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Unload", "addToItemsFilterKeyModifier", new KeyboardShortcut((KeyCode)304, Array.Empty<KeyCode>()), "If pressed - overrides createGroupBtn behaviour by passing item-names to unload 'itemsList' instead of creating new items group"); unloadForceGrouping = ((BaseUnityPlugin)this).Config.Bind<bool>("Unload", "alwaysGrouping", true, "If enabled - check for groupingKeyModifier pressed is ignored for 'unload' button"); unloadAllSkipItemsGroupKeyModifier = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Unload", "addToSkipItemsFilterKeyModifier", new KeyboardShortcut((KeyCode)306, Array.Empty<KeyCode>()), "If pressed - overrides createGroupBtn behaviour by passing item-names to unload 'itemsSkipList' instead of creating new items group"); unloadAllItemsList = ((BaseUnityPlugin)this).Config.Bind<string>("Unload", "itemsList", "", groupDescr("List of item-names allowed to be 'unloaded'")); unloadAllSkipList = ((BaseUnityPlugin)this).Config.Bind<string>("Unload", "itemsSkipList", "", groupDescr("List of item-names to exclude from being 'unloaded'")); unloadAllGroupsList = ((BaseUnityPlugin)this).Config.Bind<string>("Unload", "groupsList", "valuables,ore,wood,mushrooms", "List of items group-ids from [ItemGroup] config section allowed to be 'unloaded'"); unloadAllPrefixItemGroups = ((BaseUnityPlugin)this).Config.Bind<string>("Unload", "prefixItemGroups", "trophy", (ConfigDescription)null); unloadAllPostfixItemGroups = ((BaseUnityPlugin)this).Config.Bind<string>("Unload", "postfixItemGroups", "seeds", (ConfigDescription)null); unloadAllMaterialsFiltering = ((BaseUnityPlugin)this).Config.Bind<bool>("Unload", "materialsFiltering", true, "allow all Materials to be 'unloaded'"); unloadAllTrophiesFiltering = ((BaseUnityPlugin)this).Config.Bind<bool>("Unload", "trophiesFiltering", true, "allow all Trophies to be 'unloaded'"); unloadAllConsumableFiltering = ((BaseUnityPlugin)this).Config.Bind<bool>("Unload", "consumableFiltering", false, "allow all Consumables to be 'unloaded'"); if (modEnabled.Value) { ItemGroups.ParseConfig(); UnloadItems.ParseConfig(); ContainersTracker.Init(); Gui_Patch.Init(); ((BaseUnityPlugin)this).Config.SettingChanged += HandleConfigUpdate; harmony.PatchAll(assembly); } } public static ConfigDescription groupDescr(string descr = "Items-group based on item-names list") { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown return new ConfigDescription(descr, (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { CustomDrawer = TextAreaDrawer } }); } private static void TextAreaDrawer(ConfigEntryBase entry) { GUILayout.ExpandHeight(true); GUILayout.ExpandWidth(true); entry.BoxedValue = GUILayout.TextArea((string)entry.BoxedValue, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true) }); } private void HandleConfigUpdate(object sender, SettingChangedEventArgs e) { if (ignoreUpdate) { ignoreUpdate = false; log.LogInfo((object)$"SettingChangedEventArgs (ignored) {e.ChangedSetting.Definition}"); return; } Gui_Patch.Clean(); Gui_Patch.Init(); ItemGroups.Clear(); ItemGroups.ParseConfig(); UnloadItems.Clear(); UnloadItems.ParseConfig(); } private void OnDestroy() { harmony.UnpatchSelf(); ((BaseUnityPlugin)this).Config.Reload(); Gui_Patch.Clean(); ItemGroups.Clear(); UnloadItems.Clear(); ContainersTracker.containerList.Clear(); } public static bool isSystemGroup(string groupId) { return systemGroupKeys.Contains(groupId); } public static void PlayEffect(bool allowed, string prefabName, Vector3 pos) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (allowed) { GameObject prefab = ZNetScene.instance.GetPrefab(prefabName); if ((Object)(object)prefab != (Object)null) { Object.Instantiate<GameObject>(prefab, pos, Quaternion.identity); } else { log.LogWarning((object)("Failed to locate FeedbackEffect " + prefabName + " prefab")); } } } public static Dictionary<ConfigDefinition, string> ConfigOrphanedEntries() { return Traverse.Create((object)config).Property("OrphanedEntries", (object[])null).GetValue<Dictionary<ConfigDefinition, string>>(); } private static void MigrateConfig(Dictionary<ConfigDefinition, string> orphans) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown //IL_0038: 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_0051: Expected O, but got Unknown //IL_0051: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_0075: Expected O, but got Unknown //IL_0080: 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: Expected O, but got Unknown //IL_0099: Expected O, but got Unknown //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown //IL_00bd: Expected O, but got Unknown //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Expected O, but got Unknown //IL_00e1: Expected O, but got Unknown //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown if (orphans.ContainsKey(new ConfigDefinition("ItemGroup", "coockedMeat"))) { orphans.Remove(new ConfigDefinition("ItemGroup", "coockedMeat")); } ChangeKey<bool>(orphans, new ConfigDefinition("General", "groupingEnabled"), new ConfigDefinition("Grouping", "enabled")); ChangeKey<bool>(orphans, new ConfigDefinition("General", "itemTypeGroupsEnabled"), new ConfigDefinition("Grouping", "itemTypeGroupsEnabled")); ChangeKey<bool>(orphans, new ConfigDefinition("General", "fuzzyGroupingEnabled"), new ConfigDefinition("Grouping", "fuzzyGroupingEnabled")); ChangeKey<bool>(orphans, new ConfigDefinition("General", "createGroupBtnEnabled"), new ConfigDefinition("Grouping", "createGroupBtnEnabled")); ChangeKey<Vector2>(orphans, new ConfigDefinition("General", "createGroupBtnPos"), new ConfigDefinition("Grouping", "createGroupBtnPos")); } private static void ChangeKey<T>(Dictionary<ConfigDefinition, string> orphans, ConfigDefinition dkey, ConfigDefinition dkeyNew) { if (orphans.ContainsKey(dkey)) { orphans.Add(dkeyNew, orphans[dkey]); orphans.Remove(dkey); } } } public enum ConcurrentChestModificationWorkaround { None, ExcludeContainersOpenedByOthers, BlockIfOtherContainersAreOpened } internal static class ConcurrentChestModificationWorkaroundMethods { public static bool SkipOpenedOthers(this ConcurrentChestModificationWorkaround option) { return option == ConcurrentChestModificationWorkaround.ExcludeContainersOpenedByOthers; } public static bool Ignore(this ConcurrentChestModificationWorkaround option) { return option == ConcurrentChestModificationWorkaround.None; } public static bool BlockIfAnyOtherOpened(this ConcurrentChestModificationWorkaround option) { return option == ConcurrentChestModificationWorkaround.BlockIfOtherContainersAreOpened; } } internal static class KeyboardShortcutMethods { public static bool IsPressedOrNone(this KeyboardShortcut shortcut) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 if (!((KeyboardShortcut)(ref shortcut)).IsPressed()) { return (int)((KeyboardShortcut)(ref shortcut)).MainKey == 0; } return true; } public static bool MainPressed(this KeyboardShortcut shortcut) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return Input.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey); } } internal static class ItemDataMethods { public static string SCName(this string itemName) { return itemName.ToLower().Replace("$item_", "").Replace("_", ""); } public static string SCName(this ItemData itemDrop) { return itemDrop.m_shared.m_name.SCName(); } } internal static class EnumerableMethods { public static IEnumerable<R> Map<T, R>(this IEnumerable<T> self, Func<T, R> selector) { return self.Select(selector); } public static T Reduce<T>(this IEnumerable<T> self, Func<T, T, T> func) { return self.Aggregate(func); } public static T Reduce<T>(this IEnumerable<T> self, T seed, Func<T, T, T> func) { return self.Aggregate(seed, func); } public static IEnumerable<R> FlatMap<T, R>(this IEnumerable<T> self, Func<T, IEnumerable<R>> func) { return self.SelectMany(func); } public static IEnumerable<T> Filter<T>(this IEnumerable<T> self, Func<T, bool> predicate) { return self.Where(predicate); } } public static class UnloadItems { private static ISet<string> unloadAllItemsList = new HashSet<string>(); private static ISet<string> unloadAllItemsSkipList = new HashSet<string>(); public static ICollection<string> unloadAllGroupsList = new HashSet<string>(); private static ICollection<string> unloadAllPrefixItemGroups = new HashSet<string>(); private static ICollection<string> unloadAllPostfixItemGroups = new HashSet<string>(); public static void ParseConfig() { if (Mod.unloadAllPrefixItemGroups.Value.Length > 0) { unloadAllPrefixItemGroups = ItemGroupUtils.ParseGroupConfigEntry(Mod.unloadAllPrefixItemGroups); } if (Mod.unloadAllPostfixItemGroups.Value.Length > 0) { unloadAllPostfixItemGroups = ItemGroupUtils.ParseGroupConfigEntry(Mod.unloadAllPostfixItemGroups); } if (Mod.unloadAllItemsList.Value.Length > 0) { unloadAllItemsList = ItemGroupUtils.ParseGroupConfigEntry(Mod.unloadAllItemsList); } if (Mod.unloadAllSkipList.Value.Length > 0) { unloadAllItemsSkipList = ItemGroupUtils.ParseGroupConfigEntry(Mod.unloadAllSkipList); } if (Mod.unloadAllGroupsList.Value.Length > 0) { unloadAllGroupsList = ItemGroupUtils.ParseGroupConfigEntry(Mod.unloadAllGroupsList); } } public static void UnloadAllItems(Inventory playerInv) { //IL_0127: Unknown result type (might be due to invalid IL or missing references) List<ItemData> list = playerInv.m_inventory.Filter((ItemData i) => !i.m_equipped).Map((ItemData i) => (i, i.m_shared.m_name.SCName())).Filter<(ItemData, string)>(((ItemData i, string) tuple) => !Mod.onlyStackableItems.Value || tuple.i.m_shared.m_maxStackSize > 1) .Filter<(ItemData, string)>(((ItemData i, string) tuple) => !unloadAllItemsSkipList.Contains(tuple.Item2)) .Filter<(ItemData, string)>(((ItemData i, string) tuple) => (Mod.unloadAllMaterialsFiltering.Value && (int)tuple.i.m_shared.m_itemType == 1) || (Mod.unloadAllTrophiesFiltering.Value && (int)tuple.i.m_shared.m_itemType == 13) || (Mod.unloadAllConsumableFiltering.Value && (int)tuple.i.m_shared.m_itemType == 2) || (unloadAllItemsList.Any() && unloadAllItemsList.Contains(tuple.Item2)) || (unloadAllPrefixItemGroups.Any() && TestList((string _) => tuple.Item2.StartsWith(_), unloadAllPrefixItemGroups)) || (unloadAllPostfixItemGroups.Any() && TestList((string _) => tuple.Item2.EndsWith(_), unloadAllPostfixItemGroups)) || (unloadAllGroupsList.Any() && unloadAllGroupsList.Any((string groupId) => TestList((string _) => tuple.Item2.Equals(_), ItemGroups.Groups[groupId])))) .Map<(ItemData, string), ItemData>(((ItemData i, string) tuple) => tuple.i) .ToList(); bool flag = false; foreach (ItemData item in list) { if (Inventory_Patch.TryAddToNearBy(item, allowCurrent: true, Mod.unloadForceGrouping.Value)) { playerInv.RemoveItem(item); if (!flag) { Mod.PlayEffect(Mod.audioFeedbackEnabled.Value, "sfx_lootspawn", ((Character)Player.m_localPlayer).GetCenterPoint()); flag = true; } } } } public static void AddToUnloadAllItemsFilter(Inventory inventory) { Mod.unloadAllItemsList = AddToItemListConfig(inventory, unloadAllItemsList, Mod.unloadAllItemsList, "Added {0} items to unload-items filter"); } public static void AddToUnloadAllItemsSkipList(Inventory inventory) { Mod.unloadAllSkipList = AddToItemListConfig(inventory, unloadAllItemsSkipList, Mod.unloadAllSkipList, "Added {0} items to unload-skip-items list"); } private static ConfigEntry<string> AddToItemListConfig(Inventory inventory, ISet<string> targetSet, ConfigEntry<string> configEntry, string uiMessage) { List<string> list = ItemGroupUtils.ExtractUniqueItemNames(inventory); if (list.Count < 1) { return configEntry; } return ItemGroupUtils.AddToItemListConfig(list, targetSet, configEntry, uiMessage); } private static bool TestList(Func<string, bool> predicate, ICollection<string> group) { foreach (string item in group) { if (predicate(item)) { return true; } } return false; } public static void Clear() { unloadAllItemsList.Clear(); unloadAllItemsSkipList.Clear(); unloadAllGroupsList.Clear(); unloadAllPrefixItemGroups.Clear(); unloadAllPostfixItemGroups.Clear(); } }