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 ItemStacksItemWeights v1.1.1
ItemStacksItemWeights.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; 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 System.Text; using BepInEx; using BepInEx.Configuration; using ConditionalConfigSync; using HarmonyLib; using UnityEngine; using YamlDotNet.Serialization; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("Item Stacks Item Weights")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Item Stacks Item Weights")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("52ea9c32-6004-4ec0-855e-6464cf26d40f")] [assembly: AssemblyFileVersion("1.1.1")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.1.0")] [module: UnverifiableCode] namespace ItemStacksItemWeights; public static class DocGen { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__2_0; public static Func<KeyValuePair<string, string>, bool> <>9__5_0; public static Action<KeyValuePair<string, string>> <>9__5_1; public static Func<(string prefab, string token, string english, string localized, string stack, string weight, string type), int> <>9__5_2; public static Func<(string prefab, string token, string english, string localized, string stack, string weight, string type), int> <>9__5_3; public static Func<(string prefab, string token, string english, string localized, string stack, string weight, string type), int> <>9__5_4; public static Func<(string prefab, string token, string english, string localized, string stack, string weight, string type), int> <>9__5_5; public static Func<(string prefab, string token, string english, string localized, string stack, string weight, string type), int> <>9__5_6; public static Func<(string prefab, string token, string english, string localized, string stack, string weight, string type), int> <>9__5_7; public static Func<(string prefab, string token, string english, string localized, string stack, string weight, string type), int> <>9__5_8; internal void <InitCommand>b__2_0(ConsoleEventArgs args) { GenerateDocumentationFile(args.Context); } internal bool <GetFileText>b__5_0(KeyValuePair<string, string> kvp) { return !Localization.instance.m_translations.ContainsKey(kvp.Key); } internal void <GetFileText>b__5_1(KeyValuePair<string, string> kvp) { Localization.instance.AddWord(kvp.Key, kvp.Value); } internal int <GetFileText>b__5_2((string prefab, string token, string english, string localized, string stack, string weight, string type) r) { return r.prefab.Length; } internal int <GetFileText>b__5_3((string prefab, string token, string english, string localized, string stack, string weight, string type) r) { return r.token.Length; } internal int <GetFileText>b__5_4((string prefab, string token, string english, string localized, string stack, string weight, string type) r) { return r.english.Length; } internal int <GetFileText>b__5_5((string prefab, string token, string english, string localized, string stack, string weight, string type) r) { return r.localized.Length; } internal int <GetFileText>b__5_6((string prefab, string token, string english, string localized, string stack, string weight, string type) r) { return r.stack.Length; } internal int <GetFileText>b__5_7((string prefab, string token, string english, string localized, string stack, string weight, string type) r) { return r.weight.Length; } internal int <GetFileText>b__5_8((string prefab, string token, string english, string localized, string stack, string weight, string type) r) { return r.type.Length; } } private static readonly StringBuilder sb = new StringBuilder(); internal const string docname = "Items stacks and weights.txt"; public static void InitCommand() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown object obj = <>c.<>9__2_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { GenerateDocumentationFile(args.Context); }; <>c.<>9__2_0 = val; obj = (object)val; } new ConsoleCommand("iwisdocs", "Save documentation file Items stacks and weights.txt to config directory", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } public static void GenerateDocumentationFile(Terminal terminal = null) { string text = Path.Combine(ItemStacksItemWeights.filepath, "Items stacks and weights.txt"); try { Directory.CreateDirectory(ItemStacksItemWeights.filepath); File.WriteAllText(text, GetFileText(out var itemCount)); string text2 = string.Format("Saved {0} items to \"\\BepinEx\\config\\{1}\\{2}\"", itemCount, "shudnal.ItemStacksItemWeights", "Items stacks and weights.txt"); ItemStacksItemWeights.LogInfo(text2); if (terminal != null) { terminal.AddString(text2); } } catch (Exception ex) { ItemStacksItemWeights.LogWarning("Error when writing file (" + text + ")! Error: " + ex.Message); } } private static string Pad(string text, int width) { if (text.Length >= width) { return text; } return text + new string(' ', width - text.Length); } private static string GetFileText(out int itemCount) { sb.Clear(); sb.AppendLine("This documentation is generated automatically. It contains every available item with identifiers used to configure stacks and weights."); sb.AppendLine("List does not include items without icons (incorrectly configured items or hidden items used by enemies, player model customization and such."); sb.AppendLine(); itemCount = 0; if (!Object.op_Implicit((Object)(object)ObjectDB.instance)) { return sb.ToString(); } List<(string, string, string, string, string, string, string)> list = new List<(string, string, string, string, string, string, string)>(); string selectedLanguage = Localization.instance.GetSelectedLanguage(); Dictionary<string, string> dictionary = new Dictionary<string, string>(); DictionaryExt.Copy<string, string>(dictionary, Localization.instance.m_translations); Localization.instance.SetLanguage("English"); foreach (GameObject item5 in ObjectDB.instance.m_items) { if ((Object)(object)item5 == (Object)null) { continue; } ItemDrop component = item5.GetComponent<ItemDrop>(); if (component == null) { continue; } ItemData itemData = component.m_itemData; if (itemData != null) { SharedData shared = itemData.m_shared; if (shared != null && shared.m_icons.Length != 0) { string name = ((Object)item5).name; string name2 = shared.m_name; string item = Localization.instance.Localize(name2); string item2 = shared.m_maxStackSize.ToString(); string item3 = shared.m_weight.ToString(); string item4 = ((object)Unsafe.As<ItemType, ItemType>(ref shared.m_itemType)/*cast due to .constrained prefix*/).ToString(); list.Add((name, name2, item, "", item2, item3, item4)); } } } Localization.instance.SetLanguage(selectedLanguage); CollectionExtensions.DoIf<KeyValuePair<string, string>>((IEnumerable<KeyValuePair<string, string>>)dictionary, (Func<KeyValuePair<string, string>, bool>)((KeyValuePair<string, string> kvp) => !Localization.instance.m_translations.ContainsKey(kvp.Key)), (Action<KeyValuePair<string, string>>)delegate(KeyValuePair<string, string> kvp) { Localization.instance.AddWord(kvp.Key, kvp.Value); }); for (int num = 0; num < list.Count; num++) { (string, string, string, string, string, string, string) value = list[num]; value.Item4 = Localization.instance.Localize(value.Item2); list[num] = value; } int num2 = Math.Max("Prefab name".Length, list.Max<(string, string, string, string, string, string, string)>(((string prefab, string token, string english, string localized, string stack, string weight, string type) r) => r.prefab.Length)); int num3 = Math.Max("Token".Length, list.Max<(string, string, string, string, string, string, string)>(((string prefab, string token, string english, string localized, string stack, string weight, string type) r) => r.token.Length)); int num4 = Math.Max("English".Length, list.Max<(string, string, string, string, string, string, string)>(((string prefab, string token, string english, string localized, string stack, string weight, string type) r) => r.english.Length)); int num5 = Math.Max("Localized name".Length, list.Max<(string, string, string, string, string, string, string)>(((string prefab, string token, string english, string localized, string stack, string weight, string type) r) => r.localized.Length)); int num6 = Math.Max("Stack".Length, list.Max<(string, string, string, string, string, string, string)>(((string prefab, string token, string english, string localized, string stack, string weight, string type) r) => r.stack.Length)); int num7 = Math.Max("Weight".Length, list.Max<(string, string, string, string, string, string, string)>(((string prefab, string token, string english, string localized, string stack, string weight, string type) r) => r.weight.Length)); int num8 = Math.Max("Type".Length, list.Max<(string, string, string, string, string, string, string)>(((string prefab, string token, string english, string localized, string stack, string weight, string type) r) => r.type.Length)); sb.AppendLine(Pad("Prefab name", num2) + " " + Pad("Token", num3) + " " + Pad("English", num4) + " " + Pad("Localized name", num5) + " " + Pad("Stack", num6) + " " + Pad("Weight", num7) + " " + Pad("Type", num8)); int count = num2 + num3 + num4 + num5 + num6 + num7 + num8 + 18; sb.AppendLine(new string('-', count)); foreach (var (text, text2, text3, text4, text5, text6, text7) in list) { sb.AppendLine(Pad(text, num2) + " " + Pad(text2, num3) + " " + Pad(text3, num4) + " " + Pad(text4, num5) + " " + Pad(text5, num6) + " " + Pad(text6, num7) + " " + Pad(text7, num8)); } itemCount = list.Count; return sb.ToString(); } } public class ItemConfigurations : ISerializableParameter { public const string global = "Global"; [YamlMember(Alias = "WeightMultiplier")] public Dictionary<string, float> weightMultiplier = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase); [YamlMember(Alias = "WeightAmount")] public Dictionary<string, float> weightAmount = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase); [YamlMember(Alias = "StackMultiplier")] public Dictionary<string, float> stackMultiplier = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase); [YamlMember(Alias = "StackSize")] public Dictionary<string, int> stackSize = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); public static ItemConfigurations CreateDefaultTemplate() { return new ItemConfigurations { weightMultiplier = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase) { { "Global", 1f } }, weightAmount = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase) { { "Wood", 2f } }, stackMultiplier = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase) { { "Global", 1f } }, stackSize = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase) { { "Wood", 50 } } }; } public void EnsureInitialized() { weightMultiplier = NormalizeDictionary(weightMultiplier); weightAmount = NormalizeDictionary(weightAmount); stackMultiplier = NormalizeDictionary(stackMultiplier); stackSize = NormalizeDictionary(stackSize); } private static Dictionary<string, T> NormalizeDictionary<T>(Dictionary<string, T> source) { if (source != null && source.Comparer.Equals(StringComparer.OrdinalIgnoreCase)) { return source; } Dictionary<string, T> dictionary = new Dictionary<string, T>(StringComparer.OrdinalIgnoreCase); if (source != null) { foreach (KeyValuePair<string, T> item in source) { dictionary[item.Key] = item.Value; } } return dictionary; } public void Validate() { EnsureInitialized(); foreach (KeyValuePair<string, int> item in stackSize) { if (item.Value < 1) { throw new FormatException("StackSize for '" + item.Key + "' must be positive."); } } ValidateNumbers(stackMultiplier, "StackMultiplier", allowZero: false); ValidateNumbers(weightMultiplier, "WeightMultiplier", allowZero: true); ValidateNumbers(weightAmount, "WeightAmount", allowZero: true); } private static void ValidateNumbers(Dictionary<string, float> values, string section, bool allowZero) { foreach (KeyValuePair<string, float> value in values) { if (float.IsNaN(value.Value) || float.IsInfinity(value.Value) || value.Value < 0f || (!allowZero && value.Value == 0f)) { throw new FormatException(section + " for '" + value.Key + "' must be finite and " + (allowZero ? "non-negative" : "positive") + "."); } } } public void Serialize(ref ZPackage pkg) { EnsureInitialized(); WriteDict(pkg, weightMultiplier); WriteDict(pkg, weightAmount); WriteDict(pkg, stackMultiplier); WriteDict(pkg, stackSize); } public void Deserialize(ref ZPackage pkg) { EnsureInitialized(); ReadDict(pkg, weightMultiplier); ReadDict(pkg, weightAmount); ReadDict(pkg, stackMultiplier); ReadDict(pkg, stackSize); } public void Load(ItemConfigurations itemConfigurations) { EnsureInitialized(); if (this != itemConfigurations) { if (itemConfigurations == null) { itemConfigurations = new ItemConfigurations(); } itemConfigurations.EnsureInitialized(); weightMultiplier.Clear(); weightAmount.Clear(); stackMultiplier.Clear(); stackSize.Clear(); DictionaryExt.Copy<string, float>(weightMultiplier, itemConfigurations.weightMultiplier); DictionaryExt.Copy<string, float>(weightAmount, itemConfigurations.weightAmount); DictionaryExt.Copy<string, float>(stackMultiplier, itemConfigurations.stackMultiplier); DictionaryExt.Copy<string, int>(stackSize, itemConfigurations.stackSize); } } public void FillItemNames() { CollectionExtensions.Do<string>((IEnumerable<string>)weightMultiplier.Keys.ToList(), (Action<string>)delegate(string key) { weightMultiplier[key.GetItemName()] = weightMultiplier[key]; }); CollectionExtensions.Do<string>((IEnumerable<string>)weightAmount.Keys.ToList(), (Action<string>)delegate(string key) { weightAmount[key.GetItemName()] = weightAmount[key]; }); CollectionExtensions.Do<string>((IEnumerable<string>)stackMultiplier.Keys.ToList(), (Action<string>)delegate(string key) { stackMultiplier[key.GetItemName()] = stackMultiplier[key]; }); CollectionExtensions.Do<string>((IEnumerable<string>)stackSize.Keys.ToList(), (Action<string>)delegate(string key) { stackSize[key.GetItemName()] = stackSize[key]; }); } private void ReadDict(ZPackage pkg, Dictionary<string, float> dictionary) { dictionary.Clear(); int num = pkg.ReadInt(); for (int i = 0; i < num; i++) { dictionary[pkg.ReadString()] = pkg.ReadSingle(); } } private void ReadDict(ZPackage pkg, Dictionary<string, int> dictionary) { dictionary.Clear(); int num = pkg.ReadInt(); for (int i = 0; i < num; i++) { dictionary[pkg.ReadString()] = pkg.ReadInt(); } } private void WriteDict(ZPackage pkg, Dictionary<string, float> dictionary) { pkg.Write(dictionary.Count); foreach (KeyValuePair<string, float> item in dictionary) { pkg.Write(item.Key); pkg.Write(item.Value); } } private void WriteDict(ZPackage pkg, Dictionary<string, int> dictionary) { pkg.Write(dictionary.Count); foreach (KeyValuePair<string, int> item in dictionary) { pkg.Write(item.Key); pkg.Write(item.Value); } } } public static class ItemDefaults { [HarmonyPatch(typeof(ZoneSystem), "Start")] private static class ZoneSystem_Start_UpdateRegisters { private static void Postfix() { UpdateRegisters(); } } public static readonly Dictionary<string, string> itemNames = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); public static readonly Dictionary<string, float> itemWeight = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase); public static readonly Dictionary<string, int> itemStack = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); public static void UpdateRegisters() { if (!Object.op_Implicit((Object)(object)ObjectDB.instance)) { return; } foreach (GameObject item in ObjectDB.instance.m_items) { if ((Object)(object)item == (Object)null) { continue; } ItemDrop component = item.GetComponent<ItemDrop>(); if (component == null) { continue; } ItemData itemData = component.m_itemData; if (itemData == null) { continue; } SharedData shared = itemData.m_shared; if (shared != null) { if (shared.m_name.StartsWith("$")) { itemNames[((Object)item).name] = shared.m_name; itemNames[shared.m_name] = shared.m_name; } if (!itemWeight.ContainsKey(((Object)item).name)) { itemWeight[((Object)item).name] = shared.m_weight; } if (!itemWeight.ContainsKey(shared.m_name)) { itemWeight[shared.m_name] = shared.m_weight; } if (!itemStack.ContainsKey(((Object)item).name)) { itemStack[((Object)item).name] = shared.m_maxStackSize; } if (!itemStack.ContainsKey(shared.m_name)) { itemStack[shared.m_name] = shared.m_maxStackSize; } } } ItemStacksItemWeights.LogInfo("Items defaults updated"); DocGen.GenerateDocumentationFile(); ItemProcessing.PatchObjectDB(); } public static string GetItemName(this string input) { return itemNames.GetValueOrDefault(input.Trim(), input); } public static int GetDefaultItemStack(this SharedData shared) { return itemStack.GetValueOrDefault(shared.m_name, -1); } public static float GetDefaultItemWeight(this SharedData shared) { return itemWeight.GetValueOrDefault(shared.m_name, -1f); } public static TValue GetValueOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue) { if (dictionary == null) { throw new ArgumentNullException("dictionary"); } if (!dictionary.TryGetValue(key, out var value)) { return defaultValue; } return value; } } public static class ItemProcessing { [HarmonyPatch(typeof(ItemDrop), "Awake")] public static class ItemDrop_Awake_PatchItems { [HarmonyPriority(0)] private static void Postfix(ItemDrop __instance) { if (!((Object)(object)FejdStartup.instance != (Object)null)) { PatchItem(__instance.m_itemData); } } } [HarmonyPatch(typeof(ItemDrop), "OnCreateNew", new Type[] { typeof(ItemDrop), typeof(bool) })] public static class ItemDrop_OnCreateNew_PatchItems { [HarmonyPriority(0)] private static void Postfix(ItemDrop item) { if (!((Object)(object)FejdStartup.instance != (Object)null)) { PatchItem(item.m_itemData); } } } [HarmonyPatch(typeof(Player), "Load")] public static class Player_Load_PatchItems { [HarmonyPriority(0)] private static void Postfix(Player __instance) { if (!((Object)(object)FejdStartup.instance != (Object)null)) { if (PatchPlayerInventory(__instance)) { ItemStacksItemWeights.LogInfo("Patched player inventory"); } containerInventoryUpdated.Clear(); containerUpdateRequired = false; } } } [HarmonyPatch(typeof(InventoryGui), "Show")] public static class InventoryGui_Show_PatchItems { private static void Postfix() { PatchPlayerInventory(Player.m_localPlayer); } } [HarmonyPatch(typeof(InventoryGrid), "UpdateInventory")] public static class InventoryGrid_UpdateInventory_PatchContainerItems { private static void Postfix(InventoryGrid __instance) { if ((Object)(object)InventoryGui.instance != (Object)null && (Object)(object)__instance == (Object)(object)InventoryGui.instance.ContainerGrid && containerUpdateRequired && !containerInventoryUpdated.Contains(__instance.m_inventory)) { if (PatchInventory(__instance.m_inventory)) { ItemStacksItemWeights.LogInfo($"Inventory {__instance.m_inventory} patched"); } containerInventoryUpdated.Add(__instance.m_inventory); } } } public static ItemConfigurations itemConfig = new ItemConfigurations(); public static bool containerUpdateRequired = false; public static readonly List<Inventory> containerInventoryUpdated = new List<Inventory>(); public static void OnConfigFileChange() { ItemStacksItemWeights.LogInfo("Item config updated"); itemConfig.Load(ItemStacksItemWeights.configurationFile.Value); PatchObjectDB(); if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { if (PatchPlayerInventory(Player.m_localPlayer)) { ItemStacksItemWeights.LogInfo("Patched local player inventory"); } containerUpdateRequired = true; containerInventoryUpdated.Clear(); } } public static void PatchObjectDB() { itemConfig.FillItemNames(); if (!Object.op_Implicit((Object)(object)ObjectDB.instance)) { return; } foreach (GameObject item in ObjectDB.instance.m_items) { if ((Object)(object)item == (Object)null) { continue; } ItemDrop component = item.GetComponent<ItemDrop>(); if (component == null) { continue; } ItemData itemData = component.m_itemData; if (itemData != null) { SharedData shared = itemData.m_shared; if (shared != null) { PatchShared(shared); } } } ItemStacksItemWeights.LogInfo("Patched ObjectDB items"); } public static bool PatchShared(SharedData shared) { if (shared == null) { return false; } int maxStackSize = shared.m_maxStackSize; float weight = shared.m_weight; int defaultItemStack = shared.GetDefaultItemStack(); if (defaultItemStack > 1) { shared.m_maxStackSize = defaultItemStack; int value2; float value3; float value4; if (itemConfig.stackSize.TryGetValue(shared.m_name, out var value)) { shared.m_maxStackSize = value; } else if (itemConfig.stackSize.TryGetValue("Global", out value2)) { shared.m_maxStackSize = value2; } else if (itemConfig.stackMultiplier.TryGetValue(shared.m_name, out value3)) { shared.m_maxStackSize = ScaleStackSize(shared.m_maxStackSize, value3); } else if (itemConfig.stackMultiplier.TryGetValue("Global", out value4)) { shared.m_maxStackSize = ScaleStackSize(shared.m_maxStackSize, value4); } } float defaultItemWeight = shared.GetDefaultItemWeight(); if (defaultItemWeight >= 0f) { shared.m_weight = defaultItemWeight; float value6; float value7; float value8; if (itemConfig.weightAmount.TryGetValue(shared.m_name, out var value5)) { shared.m_weight = value5; } else if (itemConfig.weightAmount.TryGetValue("Global", out value6)) { shared.m_weight = value6; } else if (itemConfig.weightMultiplier.TryGetValue(shared.m_name, out value7)) { shared.m_weight *= value7; } else if (itemConfig.weightMultiplier.TryGetValue("Global", out value8)) { shared.m_weight *= value8; } } return maxStackSize != shared.m_maxStackSize || weight != shared.m_weight; } private static int ScaleStackSize(int stackSize, float multiplier) { return (int)Math.Max(1.0, Math.Min(2147483647.0, Math.Ceiling((double)stackSize * (double)multiplier))); } public static int PatchItem(ItemData item) { return PatchShared(item?.m_shared) ? 1 : 0; } public static bool PatchInventory(Inventory inventory) { if (inventory == null) { return false; } List<ItemData> inventory2 = inventory.m_inventory; if (inventory2 != null && ((IEnumerable<ItemData>)inventory2).Sum((Func<ItemData, int>)PatchItem) > 0) { inventory.Changed(false, false); return true; } return false; } public static bool PatchPlayerInventory(Player player) { return PatchInventory((player != null) ? ((Humanoid)player).GetInventory() : null); } } internal static class LargeStackSerialization { [HarmonyPatch(typeof(ItemData), "Save", new Type[] { typeof(ZPackage) })] private static class ItemData_Save_PreserveFullStack { private struct SaveState { internal bool Changed; internal int Stack; internal Dictionary<string, string> CustomData; } [HarmonyPriority(800)] private static void Prefix(ItemData __instance, out SaveState __state) { __state = default(SaveState); Dictionary<string, string> customData = __instance.m_customData; bool flag = __instance.m_stack > 65535; if (flag || customData == null || customData.ContainsKey("shudnal.ItemStacksItemWeights.FullStack")) { Dictionary<string, string> dictionary = ((customData == null) ? new Dictionary<string, string>() : new Dictionary<string, string>(customData)); dictionary.Remove("shudnal.ItemStacksItemWeights.FullStack"); if (flag) { dictionary["shudnal.ItemStacksItemWeights.FullStack"] = __instance.m_stack.ToString(CultureInfo.InvariantCulture); } __state = new SaveState { Changed = true, Stack = __instance.m_stack, CustomData = customData }; __instance.m_customData = dictionary; if (flag) { __instance.m_stack = 65535; } } } [HarmonyPriority(0)] private static void Finalizer(ItemData __instance, SaveState __state) { if (__state.Changed) { __instance.m_stack = __state.Stack; __instance.m_customData = __state.CustomData; } } } [HarmonyPatch(typeof(ItemData), "Load", new Type[] { typeof(ZPackage), typeof(ItemData), typeof(Item) })] private static class ItemData_Load_RestoreFullStack { [HarmonyPriority(0)] private static void Postfix(ItemData itemData) { Dictionary<string, string> customData = itemData.m_customData; if (customData != null) { string value; bool flag = customData.TryGetValue("shudnal.ItemStacksItemWeights.FullStack", out value); customData.Remove("shudnal.ItemStacksItemWeights.FullStack"); if (flag && itemData.m_stack == 65535 && TryReadCount(value, out var stack)) { itemData.m_stack = stack; } } } } private const string StackKey = "shudnal.ItemStacksItemWeights.FullStack"; private static bool TryReadCount(string value, out int stack) { return int.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out stack) && stack > 65535; } } [BepInPlugin("shudnal.ItemStacksItemWeights", "Item Stacks Item Weights", "1.1.1")] [BepInDependency("_shudnal.ConditionalConfigSync", "1.0.5")] public class ItemStacksItemWeights : BaseUnityPlugin { public const string pluginID = "shudnal.ItemStacksItemWeights"; public const string pluginName = "Item Stacks Item Weights"; public const string pluginVersion = "1.1.1"; public readonly Harmony harmony = new Harmony("shudnal.ItemStacksItemWeights"); public static ItemStacksItemWeights instance; public static readonly ConfigSync configSync = new ConfigSync("shudnal.ItemStacksItemWeights") { DisplayName = "Item Stacks Item Weights", CurrentVersion = "1.1.1", MinimumRequiredVersion = "1.1.1", ModRequired = true }; public static ConfigEntry<bool> configLocked; public static ConfigEntry<bool> loggingEnabled; public static ConfigEntry<bool> hideStackSize; public static ConfigEntry<bool> compactStackSize; public static ConfigEntry<bool> compactAmountSize; public static ConfigEntry<KeyboardShortcut> showFullStackSize; public static readonly CustomSyncedValue<ItemConfigurations> configurationFile = new CustomSyncedValue<ItemConfigurations>((ConditionalConfigSync)(object)configSync, "shudnal.ItemStacksItemWeights.ConfigurationFile", new ItemConfigurations(), 0, (IEqualityComparer<ItemConfigurations>)null); public static readonly string filename = "shudnal.ItemStacksItemWeights.yml"; public static readonly string filepath = Path.Combine(Paths.ConfigPath, "shudnal.ItemStacksItemWeights"); public static readonly string fullpath = Path.Combine(filepath, filename); public FileSystemWatcher fileWatcher; private bool reloadPending; private float reloadAt; private int reloadAttempts; private void Awake() { instance = this; ConfigInit(); ((ConditionalConfigSync)configSync).AddLockingConfigEntry<bool>(configLocked); Game.isModded = true; harmony.PatchAll(); } private void Start() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!Directory.Exists(filepath)) { Directory.CreateDirectory(filepath); } if (!File.Exists(fullpath)) { File.WriteAllText(fullpath, new Serializer().Serialize((object)ItemConfigurations.CreateDefaultTemplate())); } fileWatcher = new FileSystemWatcher(filepath, filename); fileWatcher.Changed += ScheduleConfigReload; fileWatcher.Created += ScheduleConfigReload; fileWatcher.Renamed += ScheduleConfigReload; fileWatcher.Deleted += ScheduleConfigReload; fileWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; fileWatcher.EnableRaisingEvents = true; ((CustomSyncedValueBase)configurationFile).ValueChanged += ItemProcessing.OnConfigFileChange; LoadConfigs(); ItemProcessing.OnConfigFileChange(); DocGen.InitCommand(); } private void OnDestroy() { reloadPending = false; fileWatcher?.Dispose(); fileWatcher = null; ((CustomSyncedValueBase)configurationFile).ValueChanged -= ItemProcessing.OnConfigFileChange; ((BaseUnityPlugin)this).Config.Save(); instance = null; Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } public static void LogInfo(object data) { if (loggingEnabled.Value) { ((BaseUnityPlugin)instance).Logger.LogInfo(data); } } public static void LogWarning(object data) { ((BaseUnityPlugin)instance).Logger.LogWarning(data); } public void ConfigInit() { //IL_00a2: Unknown result type (might be due to invalid IL or missing references) configLocked = config("General", "Lock Configuration", defaultValue: true, "Configuration is locked and can be changed by server admins only."); loggingEnabled = config("General", "Logging enabled", defaultValue: false, "Enable logging. [Not Synced with Server]", synchronizedSetting: false); hideStackSize = config("General", "Hide stack size", defaultValue: false, "Hide stack size of items"); compactStackSize = config("General", "Compact stack size", defaultValue: false, "Display large stack sizes in a compact format (e.g. 1k instead of 1000, 1M instead of 1000000)."); compactAmountSize = config("General", "Compact amount size", defaultValue: false, "Display large amount of items in a compact format (e.g. 1k instead of 1000, 1M instead of 1000000). The number is rounded down."); showFullStackSize = config<KeyboardShortcut>("General", "Show full stack size", new KeyboardShortcut((KeyCode)308, Array.Empty<KeyCode>()), "Hold to display stack sizes without changes. [Not Synced with Server]", synchronizedSetting: false); hideStackSize.SettingChanged += delegate { ItemStackText.ClearCache(); }; compactStackSize.SettingChanged += delegate { ItemStackText.ClearCache(); }; compactAmountSize.SettingChanged += delegate { ItemStackText.ClearCache(); }; } private ConfigEntry<T> config<T>(string group, string name, T defaultValue, ConfigDescription description, bool synchronizedSetting = true) { ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, defaultValue, description); ((ConditionalConfigSync)configSync).AddConfigEntry<T>(val, (ConfigSyncMode)1, synchronizedSetting); return val; } private ConfigEntry<T> config<T>(string group, string name, T defaultValue, string description, bool synchronizedSetting = true) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown return config(group, name, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting); } public void ClearConfigs() { configurationFile.AssignLocalValueIfChanged(new ItemConfigurations()); LogInfo("Config file cleared: " + filename); } private void ScheduleConfigReload(object sender, FileSystemEventArgs args) { reloadPending = true; reloadAt = Time.unscaledTime + 0.25f; reloadAttempts = 3; } private void Update() { if (reloadPending && !(Time.unscaledTime < reloadAt)) { reloadAttempts--; if (TryLoadConfigs(out var error)) { reloadPending = false; return; } if (reloadAttempts > 0) { reloadAt = Time.unscaledTime + 0.25f; return; } reloadPending = false; LogWarning($"Could not reload {filename}; keeping the last valid configuration. {error}"); } } public void LoadConfigs() { if (!TryLoadConfigs(out var error)) { LogWarning($"Could not load {filename}; keeping the last valid configuration. {error}"); ScheduleConfigReload(null, null); } } private bool TryLoadConfigs(out Exception error) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) error = null; if (!File.Exists(fullpath)) { ClearConfigs(); return true; } try { ItemConfigurations itemConfigurations = new Deserializer().Deserialize<ItemConfigurations>(File.ReadAllText(fullpath)) ?? new ItemConfigurations(); itemConfigurations.EnsureInitialized(); itemConfigurations.Validate(); configurationFile.AssignLocalValueIfChanged(itemConfigurations); LogInfo("Config file changed: " + filename); return true; } catch (Exception ex) { error = ex; return false; } } } internal static class ItemStackText { [HarmonyPatch(typeof(HotkeyBar), "UpdateIcons")] public static class HotkeyBar_UpdateIcons_StackSizeFormatting { [HarmonyPriority(200)] public static void Postfix(HotkeyBar __instance) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut value = ItemStacksItemWeights.showFullStackSize.Value; if (((KeyboardShortcut)(ref value)).IsPressed() || (!ItemStacksItemWeights.hideStackSize.Value && !ItemStacksItemWeights.compactStackSize.Value && !ItemStacksItemWeights.compactAmountSize.Value)) { return; } foreach (ElementData element in __instance.m_elements) { if (((Component)element.m_amount).gameObject.activeInHierarchy) { string text = element.m_amount.text; if (!string.IsNullOrEmpty(text)) { element.m_amount.SetText(GetCompactText(text)); } } } } } [HarmonyPatch(typeof(InventoryGrid), "UpdateGui")] public static class InventoryGrid_UpdateGui_StackSizeFormatting { [HarmonyPriority(200)] public static void Postfix(InventoryGrid __instance) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut value = ItemStacksItemWeights.showFullStackSize.Value; if (((KeyboardShortcut)(ref value)).IsPressed() || (!ItemStacksItemWeights.hideStackSize.Value && !ItemStacksItemWeights.compactStackSize.Value && !ItemStacksItemWeights.compactAmountSize.Value)) { return; } foreach (InventoryElement element in __instance.m_elements) { if (((Component)element.m_amount).gameObject.activeInHierarchy) { string text = element.m_amount.text; if (!string.IsNullOrEmpty(text)) { element.m_amount.SetText(GetCompactText(text)); } } } } } private static readonly Dictionary<string, string> compactTextCache = new Dictionary<string, string>(256); private const int CompactCacheLimit = 1024; internal static void ClearCache() { compactTextCache.Clear(); } private static bool TryFindNextNumber(string text, int start, out int value, out int numStart, out int numLength) { value = 0; numStart = (numLength = 0); bool flag = false; for (int i = start; i < text.Length; i++) { char c = text[i]; switch (c) { case '<': flag = true; continue; case '>': flag = false; continue; } if (flag || !char.IsDigit(c)) { continue; } numStart = i; int num = 0; int j; for (j = i; j < text.Length && char.IsDigit(text[j]); j++) { int num2 = text[j] - 48; if (num2 < 0 || num2 > 9 || num > (int.MaxValue - num2) / 10) { return false; } num = num * 10 + num2; } value = num; numLength = j - i; return true; } return false; } private static string GetCompactText(string original) { if (compactTextCache.TryGetValue(original, out var value)) { return value; } string text = BuildCompactText(original); if (compactTextCache.Count > 1024) { compactTextCache.Clear(); } compactTextCache[original] = text; return text; } private static string TrimAfterIndexPreserveTags(string text, int cutIndex) { StringBuilder stringBuilder = new StringBuilder(text.Substring(0, cutIndex)); int num = cutIndex; while (num < text.Length) { int num2 = text.IndexOf('<', num); if (num2 < 0) { break; } int num3 = text.IndexOf('>', num2 + 1); if (num3 < 0) { break; } stringBuilder.Append(text, num2, num3 - num2 + 1); num = num3 + 1; } return stringBuilder.ToString(); } private static string BuildCompactText(string text) { if (!TryFindNextNumber(text, 0, out var value, out var numStart, out var numLength)) { return text; } string text2 = (ItemStacksItemWeights.compactAmountSize.Value ? FormatCompact(value) : text.Substring(numStart, numLength)); text = text.Substring(0, numStart) + text2 + text.Substring(numStart + numLength); int num = numStart + text2.Length; if (ItemStacksItemWeights.hideStackSize.Value) { return TrimAfterIndexPreserveTags(text, num); } if (ItemStacksItemWeights.compactStackSize.Value && TryFindNextNumber(text, num, out var value2, out var numStart2, out var numLength2)) { string text3 = FormatCompact(value2); text = text.Substring(0, numStart2) + text3 + text.Substring(numStart2 + numLength2); } return text; } private static string FormatCompact(int value) { if (value < 1000) { return StringExtensionMethods.ToFastString(value); } if (value < 1000000) { return (Mathf.Floor((float)value / 100f) / 10f).ToString("0.#") + "k"; } return (Mathf.Floor((float)value / 100000f) / 10f).ToString("0.#") + "M"; } }