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.5.0
SmartContainersIgnore.dll
Decompiled a month agousing System; using System.Collections.Generic; using System.Globalization; 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.5.0.0")] [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("1.5.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 ContentsCache { private sealed class Entry { internal bool Dirty = true; internal readonly SingleItemHint Hint = new SingleItemHint(); } private static readonly ConditionalWeakTable<Inventory, Entry> entries = new ConditionalWeakTable<Inventory, Entry>(); internal static void Changed(Inventory inventory) { if (inventory != null) { entries.GetOrCreateValue(inventory).Dirty = true; } } internal static void Fresh(Inventory inventory) { if (inventory != null) { entries.GetOrCreateValue(inventory).Dirty = false; } } internal static bool IsDirty(Inventory inventory) { if (inventory != null && entries.TryGetValue(inventory, out var value)) { return value.Dirty; } return false; } internal static bool Rejects(Inventory inventory, ZDO data, ItemData item) { if (inventory != null && entries.TryGetValue(inventory, out var value)) { return value.Hint.Rejects(data, value.Dirty, item.m_shared.m_name, Game.m_worldLevel); } return false; } internal static string Describe(Inventory inventory) { string text = null; int num = int.MinValue; List<ItemData> allItems = inventory.GetAllItems(); foreach (ItemData item in allItems) { if (item == null || item.m_shared == null || string.IsNullOrEmpty(item.m_shared.m_name)) { return ""; } if (text != null && text != item.m_shared.m_name) { return ""; } text = item.m_shared.m_name; num = Math.Max(num, item.m_worldLevel); } return SingleItemHint.Encode(text, num); } } 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.5.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 FieldInfo lastRevision; private static FieldInfo rearranging; private static FieldInfo trackedContainers; private static FieldInfo onlyStackable; private static FieldInfo keyModifier; private static FieldInfo groupingModifier; private static FieldInfo gamepadKey1; private static FieldInfo gamepadKey2; private static Func<KeyboardShortcut, bool> gamepadPressed; private static Func<ItemData, bool, bool, bool> routeItems; private static Func<Inventory, ItemData, bool> nativeAdd; 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 Button priorityButton; private static TMP_Text priorityLabel; private static UITooltip priorityTooltip; private static bool ready; private static bool uiFault; private static bool routingFaultLogged; private static bool cacheFault; private void Awake() { //IL_06eb: Unknown result type (might be due to invalid IL or missing references) //IL_06f5: 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)); lastRevision = Field(typeof(Container), "m_lastRevision", typeof(uint)); 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>)); onlyStackable = Field(type, "onlyStackableItems", typeof(ConfigEntry<bool>)); keyModifier = Field(type, "keyModifier", typeof(ConfigEntry<KeyboardShortcut>)); groupingModifier = Field(type, "groupingKeyModifier", typeof(ConfigEntry<KeyboardShortcut>)); gamepadKey1 = Field(type, "gamepadKey1", typeof(ConfigEntry<string>)); gamepadKey2 = Field(type, "gamepadKey2", typeof(ConfigEntry<KeyboardShortcut>)); gamepadPressed = (Func<KeyboardShortcut, bool>)Delegate.CreateDelegate(typeof(Func<KeyboardShortcut, bool>), Method(assembly.GetType("SmartContainers.KeyboardShortcutMethods", throwOnError: true), "MainPressed", typeof(bool), typeof(KeyboardShortcut))); 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); Type type4 = assembly.GetType("SmartContainers.ContainersTracker", throwOnError: true); rearranging = Field(type4, "isRearrangingItem", typeof(bool)); trackedContainers = Field(type4, "containerList", typeof(ICollection<Container>)); MethodInfo methodInfo = Method(type4, "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)); routeItems = (Func<ItemData, bool, bool, bool>)Delegate.CreateDelegate(typeof(Func<ItemData, bool, bool, bool>), methodInfo3); MethodInfo methodInfo4 = Method(typeof(Inventory), "AddItem", typeof(bool), typeof(ItemData)); nativeAdd = (Func<Inventory, ItemData, bool>)Delegate.CreateDelegate(typeof(Func<Inventory, ItemData, bool>), methodInfo4); MethodInfo methodInfo5 = Method(typeof(Inventory), "MoveItemToThis", typeof(void), typeof(Inventory), typeof(ItemData)); MethodInfo methodInfo6 = Method(typeof(Inventory), "Changed", typeof(void), typeof(bool), typeof(bool)); MethodInfo methodInfo7 = Method(typeof(Container), "Save", typeof(void)); MethodInfo methodInfo8 = Method(typeof(Container), "Load", typeof(bool)); MethodInfo methodInfo9 = Method(type3, "AddCreateGroupBtn", typeof(void), typeof(InventoryGui)); MethodInfo methodInfo10 = Method(typeof(InventoryGui), "UpdateContainer", typeof(void), typeof(Player)); MethodInfo methodInfo11 = Method(typeof(InventoryGui), "OnRightClickItem", typeof(void), typeof(InventoryGrid), typeof(ItemData), typeof(Vector2i)); MethodInfo methodInfo12 = Method(type, "Start", typeof(void)); MethodInfo methodInfo13 = Method(type2, "Postfix", typeof(void), typeof(Inventory), typeof(ItemData), typeof(bool).MakeByRefType()); harmony = new Harmony("niclas.smartcontainers.ignore"); harmony.Patch((MethodBase)methodInfo13, (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)methodInfo9, Patch("SkipGroupButton"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo10, (HarmonyMethod)null, Patch("UpdateButton"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo11, Patch("BeforeRightClick"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo12, (HarmonyMethod)null, Patch("AfterSmartStarted"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, (HarmonyMethod)null, Patch("RouteBeforeOpenChest"), (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, Patch("ObservePriorityAdd"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo6, Patch("BeforeInventoryChanged"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo7, (HarmonyMethod)null, Patch("AfterContainerSaved"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo8, (HarmonyMethod)null, Patch("AfterContainerLoaded"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); BindGroupingConfig(); ready = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Ready: shared Auto and Prio buttons; client-only, same-item priority routing and revision-validated contents hints."); ((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 IEnumerable<CodeInstruction> RouteBeforeOpenChest(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); MethodInfo method = typeof(Inventory).GetMethod("AddItem", new Type[1] { typeof(ItemData) }); MethodInfo method2 = typeof(Plugin).GetMethod("AddToPriorityOrCurrent", BindingFlags.Static | BindingFlags.NonPublic); int num = -1; for (int i = 0; i < list.Count; i++) { if ((!(list[i].opcode != OpCodes.Call) || !(list[i].opcode != OpCodes.Callvirt)) && object.Equals(list[i].operand, method)) { if (num >= 0 || i + 1 >= list.Count || (list[i + 1].opcode != OpCodes.Brfalse && list[i + 1].opcode != OpCodes.Brfalse_S)) { throw new NotSupportedException("Native stack-transfer success branch changed."); } num = i; } } if (num < 0) { throw new NotSupportedException("Native stack-transfer AddItem call missing."); } list[num].opcode = OpCodes.Call; list[num].operand = method2; return list; } private static bool RoutingShortcutPressed() { //IL_0048: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) ConfigEntry<KeyboardShortcut> val = keyModifier.GetValue(null) as ConfigEntry<KeyboardShortcut>; ConfigEntry<KeyboardShortcut> val2 = groupingModifier.GetValue(null) as ConfigEntry<KeyboardShortcut>; ConfigEntry<KeyboardShortcut> val3 = gamepadKey2.GetValue(null) as ConfigEntry<KeyboardShortcut>; ConfigEntry<string> val4 = gamepadKey1.GetValue(null) as ConfigEntry<string>; if (val != null) { KeyboardShortcut value = val.Value; if (((KeyboardShortcut)(ref value)).IsPressed()) { goto IL_0092; } } if (val2 != null) { KeyboardShortcut value2 = val2.Value; if (((KeyboardShortcut)(ref value2)).IsPressed()) { goto IL_0092; } } if (val4 != null && val3 != null && gamepadPressed(val3.Value)) { return ZInput.GetButton(val4.Value); } return false; IL_0092: return true; } private static bool AnyPriorityTracked() { if (!(trackedContainers.GetValue(null) is ICollection<Container> collection)) { return false; } foreach (Container item in collection) { if (PriorityPolicy.IsPriority(View(item))) { return true; } } return false; } private static bool AddToPriorityOrCurrent(Inventory target, ItemData item) { if (!ready || DirectTransferScope.Active || PriorityTransferScope.Current != null) { return nativeAdd(target, item); } bool flag = false; try { Player localPlayer = Player.m_localPlayer; Container val = OpenContainer(InventoryGui.instance); ConfigEntry<bool> val2 = onlyStackable.GetValue(null) as ConfigEntry<bool>; flag = SmartEnabled() && Object.op_Implicit((Object)(object)localPlayer) && !((Character)localPlayer).IsTeleporting() && Object.op_Implicit((Object)(object)val) && item != null && item.m_shared != null && !item.m_shared.m_questItem && object.ReferenceEquals(target, val.GetInventory()) && ((Humanoid)localPlayer).GetInventory().ContainsItem(item) && !(bool)rearranging.GetValue(null) && (val2 == null || !val2.Value || item.m_shared.m_maxStackSize != 1) && RoutingShortcutPressed() && AnyPriorityTracked(); } catch (Exception error) { RoutingFault(error); } if (!flag) { return nativeAdd(target, item); } if (TryPriorityTransfer(item)) { return true; } return nativeAdd(target, item); } private static bool TryPriorityTransfer(ItemData item) { bool flag = (bool)rearranging.GetValue(null); using (PriorityTransferScope priorityTransferScope = new PriorityTransferScope(item)) { try { rearranging.SetValue(null, true); if (routeItems(item, arg2: true, arg3: false) || priorityTransferScope.Committed) { return true; } } catch (Exception error) { RoutingFault(error); if (priorityTransferScope.Committed) { return true; } } finally { rearranging.SetValue(null, flag); } } return false; } private static void ObservePriorityAdd(Inventory __instance, ItemData __0, bool __result) { PriorityTransferScope current = PriorityTransferScope.Current; if (__result && current != null && object.ReferenceEquals(current.Item, __0) && Object.op_Implicit((Object)(object)Player.m_localPlayer) && !object.ReferenceEquals(__instance, ((Humanoid)Player.m_localPlayer).GetInventory())) { current.Committed = true; } } private static void BeforeInventoryChanged(Inventory __instance) { if (!ready || cacheFault) { return; } try { ContentsCache.Changed(__instance); } catch (Exception error) { DisableContentsHints(error); } } private static void AfterContainerSaved(Container __instance) { RefreshContentsHint(__instance, saved: true); } private static void AfterContainerLoaded(Container __instance, bool __result) { if (__result) { RefreshContentsHint(__instance, saved: false); } } private static void RefreshContentsHint(Container container, bool saved) { if (!ready || cacheFault) { return; } try { ZNetView val = View(container); if (!Object.op_Implicit((Object)(object)val) || !val.IsValid()) { return; } ZDO zDO = val.GetZDO(); if (zDO == null || (!saved && zDO.GetByteArray(ZDOVars.s_items, (byte[])null) == null)) { return; } Inventory inventory = container.GetInventory(); ContentsCache.Fresh(inventory); if (val.IsOwner() && zDO.Persistent) { if (PriorityPolicy.IsPriority(val)) { SingleItemHint.Publish(zDO, ContentsCache.Describe(inventory)); } lastRevision.SetValue(container, zDO.DataRevision); } } catch (Exception error) { DisableContentsHints(error); } } private static void DisableContentsHints(Exception error) { cacheFault = true; ((BaseUnityPlugin)instance).Logger.LogWarning((object)("Contents hints disabled; normal item checks remain active: " + error)); } private static bool CachedRejects(Container container, ZNetView view, ItemData item) { if (cacheFault) { return false; } try { return ContentsCache.Rejects(container.GetInventory(), view.GetZDO(), item); } catch (Exception error) { DisableContentsHints(error); return false; } } private static void FilterCandidates(bool __1, ref List<Container> __result) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown if (__1 || __result == null) { return; } try { __result.RemoveAll((Container c) => ChestPolicy.IsExcluded(View(c))); PriorityTransferScope current = PriorityTransferScope.Current; List<Container> list = null; List<Container> list2 = null; foreach (Container item in __result) { ZNetView view = View(item); if (PriorityPolicy.IsPriority(view)) { if (current == null || !CachedRejects(item, view, (ItemData)current.Item)) { if (list == null) { list = new List<Container>(); } list.Add(item); } } else if (current == null) { if (list2 == null) { list2 = new List<Container>(); } list2.Add(item); } } if (current != null || list != null) { __result.Clear(); if (list != null) { __result.AddRange(list); } if (list2 != null) { __result.AddRange(list2); } } } catch (Exception error) { __result.Clear(); RoutingFault(error); } } private static bool BeforeAutomaticAdd(Container __1, ref bool __result) { try { if (!ChestPolicy.IsExcluded(View(__1)) && (PriorityTransferScope.Current == null || PriorityPolicy.IsPriority(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 routing compatibility check failed: " + 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_0134: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: 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); } if (Object.op_Implicit((Object)(object)priorityButton)) { ((Component)priorityButton).gameObject.SetActive(false); } return; } if (!Object.op_Implicit((Object)(object)button)) { MakeButton(__instance); } if (!Object.op_Implicit((Object)(object)priorityButton)) { MakePriorityButton(__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.")); } ((Component)priorityButton).gameObject.SetActive(!flag); ((Selectable)priorityButton).interactable = ((Selectable)button).interactable && !flag; bool flag2 = PriorityPolicy.IsPriority(view); string text2 = (flag2 ? "Prio\nAN" : "Prio\nAUS"); if (priorityLabel.text != text2) { priorityLabel.text = text2; } ((Graphic)priorityLabel).color = (Color)(flag2 ? new Color(1f, 0.85f, 0.35f) : Color.white); if (Object.op_Implicit((Object)(object)priorityTooltip)) { priorityTooltip.m_topic = "SmartContainers Prioritaet"; priorityTooltip.m_text = ((!((Selectable)priorityButton).interactable) ? "Truhe noch nicht bereit oder kein Zugriff. Erneut oeffnen." : "Passende Stapel zuerst hier einraeumen, sofern Platz ist. Gilt fuer alle mit diesem Zusatz. Klicken: Prioritaet umschalten."); } } catch (Exception ex) { uiFault = true; if (Object.op_Implicit((Object)(object)button)) { ((Component)button).gameObject.SetActive(false); } if (Object.op_Implicit((Object)(object)priorityButton)) { ((Component)priorityButton).gameObject.SetActive(false); } ((BaseUnityPlugin)instance).Logger.LogError((object)("Exclusion button unavailable; saved exclusions still apply: " + ex)); } } private static void MakeButton(InventoryGui gui) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown button = CreateContainerButton(gui, "SmartContainersIgnoreButton", "Auto\nAN", 0f, new UnityAction(ToggleCurrent), out label, out tooltip); } private static void MakePriorityButton(InventoryGui gui) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown priorityButton = CreateContainerButton(gui, "SmartContainersPriorityButton", "Prio\nAUS", 50f, new UnityAction(TogglePriority), out priorityLabel, out priorityTooltip); } private static Button CreateContainerButton(InventoryGui gui, string name, string text, float offset, UnityAction click, out TMP_Text textLabel, out UITooltip tip) { //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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: 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(name, text, new Vector2(45f, 30f), arg); RectTransform component = ((Component)val2).GetComponent<RectTransform>(); if (Object.op_Implicit((Object)(object)component)) { component.anchoredPosition += new Vector2(offset, 0f); } Button component2 = ((Component)val2).GetComponent<Button>(); if (!Object.op_Implicit((Object)(object)component2)) { throw new MissingComponentException("Container button template has no Button."); } component2.onClick = new ButtonClickedEvent(); ((UnityEvent)component2.onClick).AddListener(click); 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); } textLabel = ((Component)val2).GetComponentInChildren<TMP_Text>(true); if (!Object.op_Implicit((Object)(object)textLabel)) { throw new MissingComponentException("Container button template has no TMP text."); } textLabel.fontSize = 11f; textLabel.enableAutoSizing = true; textLabel.fontSizeMin = 8f; textLabel.fontSizeMax = 11f; textLabel.alignment = (TextAlignmentOptions)514; tip = ((Component)val2).GetComponent<UITooltip>(); if (!Object.op_Implicit((Object)(object)tip)) { UITooltip componentInChildren = ((Component)gui).GetComponentInChildren<UITooltip>(true); if (Object.op_Implicit((Object)(object)componentInChildren) && Object.op_Implicit((Object)(object)componentInChildren.m_tooltipPrefab)) { tip = ((Component)val2).gameObject.AddComponent<UITooltip>(); tip.m_tooltipPrefab = componentInChildren.m_tooltipPrefab; } } return component2; } 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)) { return; } ZNetView val3 = View(val2); bool flag = Object.op_Implicit((Object)(object)val3) && val3.IsValid() && val3.GetZDO() != null && (uint)lastRevision.GetValue(val2) == val3.GetZDO().DataRevision && !ContentsCache.IsDirty(val2.GetInventory()); 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."); if (flag) { RefreshContentsHint(val2, saved: true); } 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 TogglePriority() { 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)) { return; } ZNetView val3 = View(val2); bool flag = Object.op_Implicit((Object)(object)val3) && val3.IsValid() && val3.GetZDO() != null && (uint)lastRevision.GetValue(val2) == val3.GetZDO().DataRevision && !ContentsCache.IsDirty(val2.GetInventory()); if (!PriorityPolicy.TryToggle(val3, checkAccess(val2, localPlayer.GetPlayerID()), out var priority)) { Notice("Truhe noch nicht bereit, Auto AUS oder kein Zugriff. Bitte erneut oeffnen."); return; } if (flag) { RefreshContentsHint(val2, saved: true); } Notice(priority ? "SmartContainers: Diese Truhe hat Prioritaet." : "SmartContainers: Prioritaet ausgeschaltet."); UpdateButton(val); } catch (Exception ex) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)("Chest priority could not be changed: " + ex)); Notice("Prioritaet 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); } if (Object.op_Implicit((Object)(object)priorityButton)) { Object.Destroy((Object)(object)((Component)priorityButton).gameObject); } } } internal static class PriorityPolicy { internal const string Key = "niclas.smartcontainers.priority.v1"; internal static bool IsPriority(ZNetView view) { if (!ChestPolicy.IsExcluded(view)) { return view.GetZDO().GetBool("niclas.smartcontainers.priority.v1", false); } return false; } internal static bool TryToggle(ZNetView view, bool access, out bool priority) { priority = false; if (!ChestPolicy.CanToggle(view, access) || ChestPolicy.IsExcluded(view)) { return false; } ZDO zDO = view.GetZDO(); priority = !zDO.GetBool("niclas.smartcontainers.priority.v1", false); zDO.Set("niclas.smartcontainers.priority.v1", priority); return true; } } internal sealed class PriorityTransferScope : IDisposable { [ThreadStatic] private static PriorityTransferScope current; private readonly PriorityTransferScope previous; internal bool Committed; internal readonly object Item; internal static PriorityTransferScope Current => current; internal PriorityTransferScope(object item) { Item = item; previous = current; current = this; } public void Dispose() { current = previous; } } internal sealed class SingleItemHint { internal const string HintKey = "niclas.smartcontainers.single.v1"; internal const string RevisionKey = "niclas.smartcontainers.single.revision.v1"; private string encoded; private string name; private int maxWorldLevel; internal static string Encode(string name, int maxWorldLevel) { if (!string.IsNullOrEmpty(name)) { return maxWorldLevel.ToString(CultureInfo.InvariantCulture) + "|" + name; } return string.Empty; } internal static void Publish(ZDO data, string hint) { if (!(data.GetString("niclas.smartcontainers.single.v1", "") == hint) || data.GetLong("niclas.smartcontainers.single.revision.v1", -1L) != data.DataRevision) { data.Set("niclas.smartcontainers.single.v1", hint); data.Set("niclas.smartcontainers.single.revision.v1", (long)(data.DataRevision + 1)); } } internal bool Rejects(ZDO data, bool dirty, string incomingName, int worldLevel) { if (dirty || data == null || data.GetLong("niclas.smartcontainers.single.revision.v1", -1L) != data.DataRevision) { return false; } string text = data.GetString("niclas.smartcontainers.single.v1", "") ?? ""; if (!string.Equals(encoded, text, StringComparison.Ordinal)) { encoded = text; name = null; int num = text.IndexOf('|'); if (num > 0 && num + 1 < text.Length && int.TryParse(text.Substring(0, num), NumberStyles.Integer, CultureInfo.InvariantCulture, out maxWorldLevel)) { name = text.Substring(num + 1); } } if (name != null) { if (!(name != incomingName)) { return maxWorldLevel < worldLevel; } return true; } return false; } }