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 SortContainers v1.0.0
SortContainers.dll
Decompiled 13 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Utils; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SortContainers { internal static class InventorySorter { private static readonly FieldRef<Inventory, List<ItemData>> ItemsRef = AccessTools.FieldRefAccess<Inventory, List<ItemData>>("m_inventory"); private static readonly Action<Inventory, bool, bool> Changed = AccessTools.MethodDelegate<Action<Inventory, bool, bool>>(AccessTools.Method(typeof(Inventory), "Changed", new Type[2] { typeof(bool), typeof(bool) }, (Type[])null), (object)null, true); public static void Sort(Inventory inventory, bool mergeStacks) { //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) if (inventory == null) { return; } List<ItemData> list = ItemsRef.Invoke(inventory); if (list != null && list.Count != 0) { if (mergeStacks) { MergeStacks(list); } List<ItemData> list2 = list.OrderBy<ItemData, string>(DisplayName, StringComparer.CurrentCultureIgnoreCase).ThenBy<ItemData, string>((ItemData i) => i.m_shared.m_name, StringComparer.Ordinal).ThenByDescending((ItemData i) => i.m_quality) .ThenBy((ItemData i) => i.m_variant) .ThenByDescending((ItemData i) => i.m_stack) .ToList(); int num = Math.Max(1, inventory.GetWidth()); int num2 = Math.Max(1, inventory.GetHeight()); int num3 = num * num2; for (int num4 = 0; num4 < list2.Count && num4 < num3; num4++) { list2[num4].m_gridPos = new Vector2i(num4 % num, num4 / num); } NotifyChanged(inventory); } } private static void MergeStacks(List<ItemData> items) { IEnumerable<IGrouping<string, ItemData>> enumerable = items.Where((ItemData i) => i.m_shared.m_maxStackSize > 1 && i.m_customData.Count == 0).GroupBy(StackKey); List<ItemData> list = new List<ItemData>(); foreach (IGrouping<string, ItemData> item in enumerable) { List<ItemData> list2 = item.OrderByDescending((ItemData i) => i.m_stack).ToList(); int maxStackSize = list2[0].m_shared.m_maxStackSize; int num = 0; for (int num2 = list2.Count - 1; num2 > num; num2--) { ItemData val = list2[num2]; while (val.m_stack > 0 && num < num2) { ItemData val2 = list2[num]; int num3 = maxStackSize - val2.m_stack; if (num3 <= 0) { num++; continue; } int num4 = Math.Min(num3, val.m_stack); val2.m_stack += num4; val.m_stack -= num4; } if (val.m_stack <= 0) { list.Add(val); } } } foreach (ItemData item2 in list) { items.Remove(item2); } } private static string StackKey(ItemData item) { return item.m_shared.m_name + "|" + item.m_quality + "|" + item.m_variant + "|" + item.m_worldLevel; } private static string DisplayName(ItemData item) { string name = item.m_shared.m_name; Localization instance = Localization.instance; if (instance == null || string.IsNullOrEmpty(name)) { return name ?? string.Empty; } string text = instance.Localize(name); if (!string.IsNullOrEmpty(text)) { return text; } return name; } private static void NotifyChanged(Inventory inventory) { if (Changed != null) { Changed(inventory, arg2: false, arg3: false); } else { inventory.m_onChanged?.Invoke(); } } } [BepInPlugin("dsoltyka.SortContainers", "SortContainers", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "dsoltyka.SortContainers"; private Harmony _harmony; internal static ManualLogSource Log { get; private set; } internal static Settings Settings { get; private set; } private void Awake() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Settings = new Settings(((BaseUnityPlugin)this).Config); _harmony = new Harmony("dsoltyka.SortContainers"); _harmony.PatchAll(typeof(SortButton)); Log.LogInfo((object)"SortContainers 1.0.0 loaded"); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } internal sealed class Settings { public ConfigEntry<bool> MergeStacks { get; } public ConfigEntry<float> ButtonGap { get; } public ConfigEntry<float> ButtonSize { get; } public ConfigEntry<float> IconPadding { get; } public Settings(ConfigFile config) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Expected O, but got Unknown MergeStacks = config.Bind<bool>("1 - General", "MergeStacks", true, "Also combine partial stacks of the same item while sorting."); ButtonGap = config.Bind<float>("2 - Layout", "ButtonGap", 4f, new ConfigDescription("Gap between the vanilla 'Place stacks' button and the sort button, in pixels.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); ButtonSize = config.Bind<float>("2 - Layout", "ButtonSize", 0f, new ConfigDescription("Sort button size in pixels. 0 matches the height of the 'Place stacks' button.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 128f), Array.Empty<object>())); IconPadding = config.Bind<float>("2 - Layout", "IconPadding", 6f, new ConfigDescription("Inset of the icon inside the button, in pixels.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 32f), Array.Empty<object>())); } } [HarmonyPatch] internal static class SortButton { [CompilerGenerated] private static class <>O { public static UnityAction <0>__OnClicked; } private const string ButtonName = "SortContainers.SortButton"; private static readonly FieldRef<InventoryGui, Container> CurrentContainerRef = AccessTools.FieldRefAccess<InventoryGui, Container>("m_currentContainer"); private static readonly Action<InventoryGui, ItemData, Inventory, int> SetupDragItem = AccessTools.MethodDelegate<Action<InventoryGui, ItemData, Inventory, int>>(AccessTools.Method(typeof(InventoryGui), "SetupDragItem", (Type[])null, (Type[])null), (object)null, true); private static Button s_button; private static Sprite s_icon; private static bool s_iconLoadAttempted; private static Settings S => Plugin.Settings; [HarmonyPatch(typeof(InventoryGui), "Show")] [HarmonyPostfix] private static void Show_Postfix(InventoryGui __instance) { try { Ensure(__instance); } catch (Exception arg) { Plugin.Log.LogError((object)$"Failed to create the sort button: {arg}"); } } private static void Ensure(InventoryGui gui) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Expected O, but got Unknown //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: 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) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)s_button != (Object)null) { return; } Button stackAllButton = gui.m_stackAllButton; if ((Object)(object)stackAllButton == (Object)null) { Plugin.Log.LogWarning((object)"InventoryGui has no 'Place stacks' button to attach to; sort button not created."); return; } GameObject obj = Object.Instantiate<GameObject>(((Component)stackAllButton).gameObject, ((Component)stackAllButton).transform.parent); ((Object)obj).name = "SortContainers.SortButton"; Button component = obj.GetComponent<Button>(); component.onClick = new ButtonClickedEvent(); ButtonClickedEvent onClick = component.onClick; object obj2 = <>O.<0>__OnClicked; if (obj2 == null) { UnityAction val = OnClicked; <>O.<0>__OnClicked = val; obj2 = (object)val; } ((UnityEvent)onClick).AddListener((UnityAction)obj2); ((Selectable)component).interactable = true; UITooltip component2 = obj.GetComponent<UITooltip>(); if ((Object)(object)component2 != (Object)null) { component2.m_text = "Sort"; } RectTransform val2 = (RectTransform)((Component)stackAllButton).transform; RectTransform val3 = (RectTransform)obj.transform; Rect rect; float num; if (!(S.ButtonSize.Value > 0f)) { rect = val2.rect; num = ((Rect)(ref rect)).height; } else { num = S.ButtonSize.Value; } float num2 = num; val3.sizeDelta = new Vector2(num2, num2); float x = val2.anchoredPosition.x; float num3 = 1f - val2.pivot.x; rect = val2.rect; float num4 = x + num3 * ((Rect)(ref rect)).width; val3.anchoredPosition = new Vector2(num4 + S.ButtonGap.Value + val3.pivot.x * num2, val2.anchoredPosition.y); TMP_Text componentInChildren = obj.GetComponentInChildren<TMP_Text>(true); Sprite val4 = LoadIcon(); if ((Object)(object)val4 != (Object)null) { if ((Object)(object)componentInChildren != (Object)null) { ((Component)componentInChildren).gameObject.SetActive(false); } CreateIcon(val3, val4, componentInChildren); } else if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.text = "Sort"; } s_button = component; } private static void CreateIcon(RectTransform parent, Sprite sprite, TMP_Text styleSource) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Icon", new Type[2] { typeof(RectTransform), typeof(Image) }); val.transform.SetParent((Transform)(object)parent, false); float value = S.IconPadding.Value; RectTransform val2 = (RectTransform)val.transform; val2.anchorMin = Vector2.zero; val2.anchorMax = Vector2.one; val2.offsetMin = new Vector2(value, value); val2.offsetMax = new Vector2(0f - value, 0f - value); Image component = val.GetComponent<Image>(); component.sprite = sprite; component.preserveAspect = true; ((Graphic)component).raycastTarget = false; ((Graphic)component).color = (((Object)(object)styleSource != (Object)null) ? ((Graphic)styleSource).color : Color.white); } private static void OnClicked() { InventoryGui instance = InventoryGui.instance; Player localPlayer = Player.m_localPlayer; if ((Object)(object)instance == (Object)null || (Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsTeleporting()) { return; } Container val = CurrentContainerRef.Invoke(instance); if ((Object)(object)val == (Object)null) { return; } if (!val.IsOwner()) { Plugin.Log.LogInfo((object)"Container is not owned by this client yet; ignoring sort."); return; } try { SetupDragItem?.Invoke(instance, null, null, 1); InventorySorter.Sort(val.GetInventory(), S.MergeStacks.Value); } catch (Exception arg) { Plugin.Log.LogError((object)$"Sort failed: {arg}"); } } private static Sprite LoadIcon() { //IL_0094: 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) if (s_iconLoadAttempted) { return s_icon; } s_iconLoadAttempted = true; try { using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("sort.png"); if (stream == null) { Plugin.Log.LogWarning((object)"Embedded sort.png not found; using a text label instead."); return null; } using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); Texture2D val = AssetUtils.LoadImage(memoryStream.ToArray()); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"Embedded sort.png could not be decoded; using a text label instead."); return null; } ((Texture)val).filterMode = (FilterMode)1; s_icon = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); ((Object)s_icon).name = "SortContainers.Icon"; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not load the sort icon: " + ex.Message)); } return s_icon; } } internal static class BuildInfo { public const string Name = "SortContainers"; public const string Version = "1.0.0"; } }