Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of SmartContainersIgnore v1.3.0
SmartContainersIgnore.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: AssemblyFileVersion("1.3.0.0")] [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("1.3.0.0")] namespace SmartContainersIgnore; internal static class ChestPolicy { internal const string Key = "niclas.smartcontainers.ignore.v1"; internal static bool IsExcluded(ZNetView view) { if (!Object.op_Implicit((Object)(object)view) || !view.IsValid()) { return true; } ZDO zDO = view.GetZDO(); if (zDO != null) { return zDO.GetBool("niclas.smartcontainers.ignore.v1", false); } return true; } internal static bool CanToggle(ZNetView view, bool hasAccess) { if (!hasAccess || !Object.op_Implicit((Object)(object)view) || !view.IsValid() || !view.IsOwner()) { return false; } ZDO zDO = view.GetZDO(); if (zDO != null) { return zDO.Persistent; } return false; } internal static bool TryToggle(ZNetView view, bool hasAccess, out bool excluded) { excluded = false; if (!CanToggle(view, hasAccess)) { return false; } ZDO zDO = view.GetZDO(); excluded = !zDO.GetBool("niclas.smartcontainers.ignore.v1", false); zDO.Set("niclas.smartcontainers.ignore.v1", excluded); return true; } } internal static class DirectTransferScope { [ThreadStatic] private static int depth; internal static bool Active => depth > 0; internal static void Run(Action transfer) { if (transfer == null) { throw new ArgumentNullException("transfer"); } depth++; try { transfer(); } finally { depth--; } } } internal sealed class GroupingConfigGuard : IDisposable { private readonly ConfigEntry<bool> entry; private readonly Action<Exception> report; private bool resaveAfterReload; internal GroupingConfigGuard(ConfigEntry<bool> entry, Action<Exception> report) { if (entry == null) { throw new ArgumentNullException("entry"); } if (report == null) { throw new ArgumentNullException("report"); } this.entry = entry; this.report = report; entry.SettingChanged += OnChanged; ((ConfigEntryBase)entry).ConfigFile.ConfigReloaded += OnReloaded; ForceOff(reloaded: false); resaveAfterReload = false; } private void OnChanged(object sender, EventArgs args) { ForceOff(reloaded: false); } private void OnReloaded(object sender, EventArgs args) { ForceOff(reloaded: true); } private void ForceOff(bool reloaded) { try { bool value = entry.Value; if (value) { resaveAfterReload = true; entry.Value = false; } if ((reloaded && resaveAfterReload) || (value && !((ConfigEntryBase)entry).ConfigFile.SaveOnConfigSet)) { ((ConfigEntryBase)entry).ConfigFile.Save(); } if (reloaded) { resaveAfterReload = false; } } catch (Exception obj) { report(obj); } } public void Dispose() { entry.SettingChanged -= OnChanged; ((ConfigEntryBase)entry).ConfigFile.ConfigReloaded -= OnReloaded; } } [BepInProcess("valheim.exe")] [BepInPlugin("niclas.smartcontainers.ignore", "SmartContainers Ignore", "1.3.0")] [BepInDependency("flueno.SmartContainers", "1.8.3")] public sealed class Plugin : BaseUnityPlugin { internal const string Id = "niclas.smartcontainers.ignore"; internal const string SmartId = "flueno.SmartContainers"; private static Plugin instance; private Harmony harmony; private GroupingConfigGuard groupingGuard; private static FieldInfo currentContainer; private static FieldInfo containerView; private static FieldInfo grouping; private static FieldInfo master; private static FieldInfo buttonPosition; private static FieldInfo dragObject; private static Func<string, string, Vector2, Vector2, Transform> createButton; private static Func<Container, long, bool> checkAccess; private static Action<InventoryGui, InventoryGrid, ItemData, Vector2i, Modifier> selectItem; private static Button button; private static TMP_Text label; private static UITooltip tooltip; private static bool ready; private static bool uiFault; private static bool routingFaultLogged; private void Awake() { //IL_0475: Unknown result type (might be due to invalid IL or missing references) //IL_047f: Expected O, but got Unknown instance = this; try { if (!Chainloader.PluginInfos.TryGetValue("flueno.SmartContainers", out var value) || !Object.op_Implicit((Object)(object)value.Instance)) { throw new NotSupportedException("SmartContainers 1.8.3 or newer is required."); } Assembly assembly = ((object)value.Instance).GetType().Assembly; Type type = assembly.GetType("SmartContainers.Mod", throwOnError: true); Type type2 = assembly.GetType("SmartContainers.Inventory_Patch", throwOnError: true); Type type3 = assembly.GetType("SmartContainers.Gui_Patch", throwOnError: true); currentContainer = Field(typeof(InventoryGui), "m_currentContainer", typeof(Container)); dragObject = Field(typeof(InventoryGui), "m_dragGo", typeof(GameObject)); selectItem = (Action<InventoryGui, InventoryGrid, ItemData, Vector2i, Modifier>)Delegate.CreateDelegate(typeof(Action<InventoryGui, InventoryGrid, ItemData, Vector2i, Modifier>), Method(typeof(InventoryGui), "OnSelectedItem", typeof(void), typeof(InventoryGrid), typeof(ItemData), typeof(Vector2i), typeof(Modifier))); containerView = Field(typeof(Container), "m_nview", typeof(ZNetView)); checkAccess = (Func<Container, long, bool>)Delegate.CreateDelegate(typeof(Func<Container, long, bool>), Method(typeof(Container), "CheckAccess", typeof(bool), typeof(long))); grouping = Field(type, "groupingEnabled", typeof(ConfigEntry<bool>)); master = Field(type, "modEnabled", typeof(ConfigEntry<bool>)); buttonPosition = Field(type, "createGroupBtnPos", typeof(ConfigEntry<Vector2>)); MethodInfo method = Method(assembly.GetType("SmartContainers.GuiFactory", throwOnError: true), "AddContainerGuiButton", typeof(Transform), typeof(string), typeof(string), typeof(Vector2), typeof(Vector2)); createButton = (Func<string, string, Vector2, Vector2, Transform>)Delegate.CreateDelegate(typeof(Func<string, string, Vector2, Vector2, Transform>), method); MethodInfo methodInfo = Method(assembly.GetType("SmartContainers.ContainersTracker", throwOnError: true), "GetNearbyContainers", typeof(List<Container>), typeof(Vector3), typeof(bool)); MethodInfo methodInfo2 = Method(type2, "AddItemToContainer", typeof(bool), typeof(ItemData), typeof(Container), typeof(bool)); MethodInfo methodInfo3 = Method(type2, "TryAddToNearBy", typeof(bool), typeof(ItemData), typeof(bool), typeof(bool)); MethodInfo methodInfo4 = Method(type3, "AddCreateGroupBtn", typeof(void), typeof(InventoryGui)); MethodInfo methodInfo5 = Method(typeof(InventoryGui), "UpdateContainer", typeof(void), typeof(Player)); MethodInfo methodInfo6 = Method(typeof(InventoryGui), "OnRightClickItem", typeof(void), typeof(InventoryGrid), typeof(ItemData), typeof(Vector2i)); MethodInfo methodInfo7 = Method(type, "Start", typeof(void)); MethodInfo methodInfo8 = Method(type2, "Postfix", typeof(void), typeof(Inventory), typeof(ItemData), typeof(bool).MakeByRefType()); harmony = new Harmony("niclas.smartcontainers.ignore"); harmony.Patch((MethodBase)methodInfo8, (HarmonyMethod)null, (HarmonyMethod)null, Patch("VerifyRoutingFailure"), (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo3, Patch("BeforeRouting"), (HarmonyMethod)null, Patch("WithoutGroups"), (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, Patch("FilterCandidates"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo2, Patch("BeforeAutomaticAdd"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo4, Patch("SkipGroupButton"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, Patch("UpdateButton"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo6, Patch("BeforeRightClick"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo7, (HarmonyMethod)null, Patch("AfterSmartStarted"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); BindGroupingConfig(); ready = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Ready: shared persistent chest exclusion; same-item routing only; Auto button replaces groups."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Ctrl + right-click: native transfer to/from the open chest without SmartContainers routing."); } catch (Exception ex) { ready = false; if (groupingGuard != null) { groupingGuard.Dispose(); } if (harmony != null) { harmony.UnpatchSelf(); } ((BaseUnityPlugin)this).Logger.LogError((object)("SmartContainers Ignore disabled: " + ex)); } } private void BindGroupingConfig() { if (groupingGuard == null && grouping.GetValue(null) is ConfigEntry<bool> entry) { groupingGuard = new GroupingConfigGuard(entry, delegate(Exception error) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not save disabled grouping; group routing remains disabled: " + error)); }); ((BaseUnityPlugin)this).Logger.LogInfo((object)"SmartContainers Grouping.enabled is forced off, including config changes and reloads."); } } private static void AfterSmartStarted() { if (!ready) { return; } try { instance.BindGroupingConfig(); } catch (Exception ex) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)("Could not bind grouping config; group routing remains disabled: " + ex)); } } private static IEnumerable<CodeInstruction> VerifyRoutingFailure(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); MethodInfo method = __originalMethod.DeclaringType.GetMethod("TryAddToNearBy", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[3] { typeof(ItemData), typeof(bool), typeof(bool) }, null); if (method == null || method.ReturnType != typeof(bool)) { throw new NotSupportedException("SmartContainers routing signature changed."); } CheckRoutingFailure(list, method); return list; } private static void CheckRoutingFailure(IEnumerable<CodeInstruction> instructions, MethodInfo route) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); int num = 0; for (int i = 0; i < list.Count; i++) { if (!(list[i].opcode != OpCodes.Call) && object.Equals(list[i].operand, route)) { num++; if (i + 1 >= list.Count || (list[i + 1].opcode != OpCodes.Brfalse && list[i + 1].opcode != OpCodes.Brfalse_S)) { throw new NotSupportedException("SmartContainers failed-transfer branch changed."); } } } if (num == 0) { throw new NotSupportedException("SmartContainers routing call missing."); } } private static FieldInfo Field(Type type, string name, Type expected) { FieldInfo fieldInfo = AccessTools.Field(type, name); if (fieldInfo == null || fieldInfo.FieldType != expected) { throw new MissingFieldException(type.FullName, name); } return fieldInfo; } private static MethodInfo Method(Type type, string name, Type result, params Type[] args) { MethodInfo methodInfo = AccessTools.Method(type, name, args, (Type[])null); if (methodInfo == null || methodInfo.ReturnType != result) { throw new MissingMethodException(type.FullName, name); } return methodInfo; } private static HarmonyMethod Patch(string name) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown return new HarmonyMethod(AccessTools.Method(typeof(Plugin), name, (Type[])null, (Type[])null)); } private static IEnumerable<CodeInstruction> WithoutGroups(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); MethodInfo getMethod = typeof(ConfigEntry<bool>).GetProperty("Value").GetGetMethod(); int num = -1; for (int i = 0; i < list.Count; i++) { if (!(list[i].opcode != OpCodes.Ldsfld) && object.Equals(list[i].operand, grouping)) { if (num >= 0 || i + 1 >= list.Count || list[i + 1].opcode != OpCodes.Callvirt || !object.Equals(list[i + 1].operand, getMethod) || list[i].blocks.Count != 0 || list[i + 1].blocks.Count != 0 || list[i + 1].labels.Count != 0) { throw new NotSupportedException("SmartContainers grouping gate changed."); } num = i; } } if (num < 0) { throw new NotSupportedException("SmartContainers grouping gate missing."); } list[num].opcode = OpCodes.Ldc_I4_0; list[num].operand = null; list[num + 1].opcode = OpCodes.Nop; list[num + 1].operand = null; return list; } private static ZNetView View(Container container) { if (!Object.op_Implicit((Object)(object)container)) { return null; } object? value = containerView.GetValue(container); return (ZNetView)((value is ZNetView) ? value : null); } private static void FilterCandidates(bool __1, ref List<Container> __result) { if (__1 || __result == null) { return; } try { __result.RemoveAll((Container c) => ChestPolicy.IsExcluded(View(c))); } catch (Exception error) { __result.Clear(); RoutingFault(error); } } private static bool BeforeAutomaticAdd(Container __1, ref bool __result) { try { if (!ChestPolicy.IsExcluded(View(__1))) { return true; } } catch (Exception error) { RoutingFault(error); } __result = false; return false; } private static bool BeforeRouting(ref bool __result) { if (!DirectTransferScope.Active) { return true; } __result = false; return false; } private static bool BeforeRightClick(InventoryGui __instance, InventoryGrid __0, ItemData __1, Vector2i __2) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (!ready || !ZInput.GetMouseButton(1) || (!ZInput.GetKey((KeyCode)306, true) && !ZInput.GetKey((KeyCode)305, true))) { return true; } try { Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)__instance) || (Object)(object)__instance != (Object)(object)InventoryGui.instance || !Object.op_Implicit((Object)(object)__0)) { return true; } Container val = OpenContainer(__instance); if (!Object.op_Implicit((Object)(object)val)) { return true; } if (__1 == null || __1.m_shared == null || Object.op_Implicit((Object)/*isinst with value type is only supported in some contexts*/)) { return false; } Inventory inventory = __0.GetInventory(); Inventory inventory2 = ((Humanoid)localPlayer).GetInventory(); Inventory inventory3 = val.GetInventory(); if (inventory == null || inventory3 == null || (!object.ReferenceEquals(inventory, inventory2) && !object.ReferenceEquals(inventory, inventory3)) || !inventory.ContainsItem(__1)) { return false; } ZNetView val2 = View(val); if (!Object.op_Implicit((Object)(object)val2) || !val2.IsValid() || !val2.IsOwner() || !checkAccess(val, localPlayer.GetPlayerID())) { return false; } DirectTransferScope.Run(delegate { //IL_0018: Unknown result type (might be due to invalid IL or missing references) selectItem(__instance, __0, __1, __2, (Modifier)2); }); } catch (Exception ex) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)("Direct chest transfer stopped: " + ex)); Notice("Direkter Transfer abgebrochen. Siehe BepInEx-Log."); } return false; } private static void RoutingFault(Exception error) { if (!routingFaultLogged) { routingFaultLogged = true; ((BaseUnityPlugin)instance).Logger.LogError((object)("Automatic destination blocked because exclusion could not be checked: " + error)); } } private static bool SkipGroupButton() { return false; } private static Container OpenContainer(InventoryGui gui) { if (!Object.op_Implicit((Object)(object)gui) || !gui.IsContainerOpen()) { return null; } object? value = currentContainer.GetValue(gui); return (Container)((value is Container) ? value : null); } private static bool SmartEnabled() { if (master.GetValue(null) is ConfigEntry<bool> val) { return val.Value; } return false; } private static void UpdateButton(InventoryGui __instance) { //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) if (!ready || uiFault) { return; } try { Container val = OpenContainer(__instance); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || !SmartEnabled()) { if (Object.op_Implicit((Object)(object)button)) { ((Component)button).gameObject.SetActive(false); } return; } if (!Object.op_Implicit((Object)(object)button)) { MakeButton(__instance); } ((Component)button).gameObject.SetActive(true); ZNetView view = View(val); bool flag = ChestPolicy.IsExcluded(view); bool hasAccess = checkAccess(val, Player.m_localPlayer.GetPlayerID()); ((Selectable)button).interactable = ChestPolicy.CanToggle(view, hasAccess); string text = (flag ? "Auto\nAUS" : "Auto\nAN"); if (label.text != text) { label.text = text; } ((Graphic)label).color = (flag ? new Color(1f, 0.55f, 0.35f) : new Color(0.65f, 1f, 0.65f)); if (Object.op_Implicit((Object)(object)tooltip)) { tooltip.m_topic = "SmartContainers"; tooltip.m_text = ((!((Selectable)button).interactable) ? "Truhe noch nicht bereit oder kein Zugriff. Erneut oeffnen." : (flag ? "Diese Truhe wird ignoriert. Klicken: automatisches Einsortieren wieder zulassen." : "Klicken: diese Truhe vom automatischen Einsortieren ausschliessen. Gilt fuer alle mit diesem Zusatz.")); } } catch (Exception ex) { uiFault = true; if (Object.op_Implicit((Object)(object)button)) { ((Component)button).gameObject.SetActive(false); } ((BaseUnityPlugin)instance).Logger.LogError((object)("Exclusion button unavailable; saved exclusions still apply: " + ex)); } } private static void MakeButton(InventoryGui gui) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0015: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) Vector2 arg = (Vector2)((!(buttonPosition.GetValue(null) is ConfigEntry<Vector2> val)) ? new Vector2(1.5f, 10.7f) : val.Value); Transform val2 = createButton("SmartContainersIgnoreButton", "Auto\nAN", new Vector2(45f, 30f), arg); button = ((Component)val2).GetComponent<Button>(); if (!Object.op_Implicit((Object)(object)button)) { throw new MissingComponentException("Container button template has no Button."); } button.onClick = new ButtonClickedEvent(); ((UnityEvent)button.onClick).AddListener(new UnityAction(ToggleCurrent)); UIGamePad[] componentsInChildren = ((Component)val2).GetComponentsInChildren<UIGamePad>(true); foreach (UIGamePad val3 in componentsInChildren) { ((Behaviour)val3).enabled = false; if (Object.op_Implicit((Object)(object)val3.m_hint)) { val3.m_hint.SetActive(false); } } Transform val4 = val2.Find("gamepad_hint"); if (Object.op_Implicit((Object)(object)val4)) { ((Component)val4).gameObject.SetActive(false); } val4 = val2.Find("GamepadHint"); if (Object.op_Implicit((Object)(object)val4)) { ((Component)val4).gameObject.SetActive(false); } label = ((Component)val2).GetComponentInChildren<TMP_Text>(true); if (!Object.op_Implicit((Object)(object)label)) { throw new MissingComponentException("Container button template has no TMP text."); } label.fontSize = 11f; label.enableAutoSizing = true; label.fontSizeMin = 8f; label.fontSizeMax = 11f; label.alignment = (TextAlignmentOptions)514; tooltip = ((Component)val2).GetComponent<UITooltip>(); if (!Object.op_Implicit((Object)(object)tooltip)) { UITooltip componentInChildren = ((Component)gui).GetComponentInChildren<UITooltip>(true); if (Object.op_Implicit((Object)(object)componentInChildren) && Object.op_Implicit((Object)(object)componentInChildren.m_tooltipPrefab)) { tooltip = ((Component)val2).gameObject.AddComponent<UITooltip>(); tooltip.m_tooltipPrefab = componentInChildren.m_tooltipPrefab; } } } private static void ToggleCurrent() { try { if (!ready || !SmartEnabled()) { return; } InventoryGui val = InventoryGui.instance; Container val2 = OpenContainer(val); Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)localPlayer)) { if (!ChestPolicy.TryToggle(View(val2), checkAccess(val2, localPlayer.GetPlayerID()), out var excluded)) { Notice("Truhe noch nicht bereit oder kein Zugriff. Bitte erneut oeffnen."); return; } Notice(excluded ? "SmartContainers: Diese Truhe wird ignoriert." : "SmartContainers: Diese Truhe ist wieder zugelassen."); UpdateButton(val); } } catch (Exception ex) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)("Chest exclusion could not be changed: " + ex)); Notice("Truhen-Sperre konnte nicht geaendert werden. Siehe BepInEx-Log."); } } private static void Notice(string text) { if (Object.op_Implicit((Object)(object)MessageHud.instance)) { MessageHud.instance.ShowMessage((MessageType)2, text, 0, (Sprite)null, false, true); } } private void OnDestroy() { ready = false; if (groupingGuard != null) { groupingGuard.Dispose(); } if (harmony != null) { harmony.UnpatchSelf(); } if (Object.op_Implicit((Object)(object)button)) { Object.Destroy((Object)(object)((Component)button).gameObject); } } }