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 WeightsRebalanced v2.0.1
plugins\WeightsRebalanced.dll
Decompiled 3 months agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using LethalConfig; using LethalConfig.ConfigItems; using LethalConfig.ConfigItems.Options; using Microsoft.CodeAnalysis; using TMPro; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.UI; using WeightsRebalanced.HotReload; using WeightsRebalanced.ItemDetection; using WeightsRebalanced.Networking; using WeightsRebalanced.Presets; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("WeightsRebalanced")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("WeightsRebalanced")] [assembly: AssemblyTitle("WeightsRebalanced")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 WeightsRebalanced { public static class ConfigValidator { public const float MinWeight = 0.1f; public const float MaxWeight = 500f; public static float ClampWeight(float value, string itemName = null) { float num = Mathf.Clamp(value, 0.1f, 500f); if (num != value && itemName != null) { LogHelper.LogWarning($"Weight for '{itemName}' clamped from {value:F1} to {num:F1} kg (valid range: {0.1f}-{500f} kg)"); } return num; } public static bool IsValidWeight(float value) { if (value >= 0.1f) { return value <= 500f; } return false; } } public enum ItemCategory { Scrap, Equipment, Store, Modded } public static class LethalConfigIntegration { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static GenericButtonHandler <>9__6_0; public static GenericButtonHandler <>9__6_1; public static GenericButtonHandler <>9__6_2; public static GenericButtonHandler <>9__6_3; public static GenericButtonHandler <>9__6_4; internal void <InitializeInternal>b__6_0() { Plugin.ResetAllWeights(); } internal void <InitializeInternal>b__6_1() { DiagnosticCommands.PrintAllItemsWithOrigin(); } internal void <InitializeInternal>b__6_2() { string text = $"Custom_{DateTime.Now:yyyy-MM-dd_HH-mm}"; if (PresetManager.SavePreset(text, "User-created preset")) { LogHelper.LogInfo("Preset saved as '" + text + "'"); } } internal void <InitializeInternal>b__6_3() { Plugin.ResetAllWeights(); LogHelper.LogInfo("Loaded vanilla weight preset"); } internal void <InitializeInternal>b__6_4() { if (WeightSyncManager.IsClient()) { LogHelper.LogInfo("Using HOST'S weight configuration (synced from server)"); return; } NetworkManager singleton = NetworkManager.Singleton; if (singleton != null && singleton.IsHost) { LogHelper.LogInfo("You are the HOST - your weights are synced to all clients"); } else { LogHelper.LogInfo("Not in multiplayer - using your LOCAL weight configuration"); } } } private static bool? _isAvailable; private static bool _initialized; public static bool IsAvailable { get { if (!_isAvailable.HasValue) { _isAvailable = CheckLethalConfigAvailable(); } return _isAvailable.Value; } } private static bool CheckLethalConfigAvailable() { try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { if (assemblies[i].GetName().Name == "LethalConfig") { LogHelper.LogInfo("LethalConfig detected - GUI integration enabled."); return true; } } } catch (Exception ex) { LogHelper.LogWarning("Error checking for LethalConfig: " + ex.Message); } LogHelper.LogInfo("LethalConfig not found - mod will work without GUI."); return false; } public static void Initialize() { if (_initialized || !IsAvailable) { return; } _initialized = true; try { InitializeInternal(); } catch (Exception ex) { LogHelper.LogWarning("Failed to initialize LethalConfig integration: " + ex.Message); } } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] private static void InitializeInternal() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Expected O, but got Unknown //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Expected O, but got Unknown //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Expected O, but got Unknown //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Expected O, but got Unknown //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Expected O, but got Unknown //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Expected O, but got Unknown LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(Plugin.EnableWeightModifications, new BoolCheckBoxOptions { RequiresRestart = false })); object obj = <>c.<>9__6_0; if (obj == null) { GenericButtonHandler val = delegate { Plugin.ResetAllWeights(); }; <>c.<>9__6_0 = val; obj = (object)val; } LethalConfigManager.AddConfigItem((BaseConfigItem)new GenericButtonConfigItem("General", "Reset All Weights", "Resets all item weights to their default vanilla values.", "Reset All", (GenericButtonHandler)obj)); object obj2 = <>c.<>9__6_1; if (obj2 == null) { GenericButtonHandler val2 = delegate { DiagnosticCommands.PrintAllItemsWithOrigin(); }; <>c.<>9__6_1 = val2; obj2 = (object)val2; } LethalConfigManager.AddConfigItem((BaseConfigItem)new GenericButtonConfigItem("General", "Diagnostic: Print Item Detection", "Prints all items with detected origin (vanilla/modded) and category to log.", "Print Diagnostics", (GenericButtonHandler)obj2)); object obj3 = <>c.<>9__6_2; if (obj3 == null) { GenericButtonHandler val3 = delegate { string text = $"Custom_{DateTime.Now:yyyy-MM-dd_HH-mm}"; if (PresetManager.SavePreset(text, "User-created preset")) { LogHelper.LogInfo("Preset saved as '" + text + "'"); } }; <>c.<>9__6_2 = val3; obj3 = (object)val3; } LethalConfigManager.AddConfigItem((BaseConfigItem)new GenericButtonConfigItem("Presets", "Save Current as Preset", "Save your current weight configuration as a preset. The preset will be named with current timestamp.", "Save Preset", (GenericButtonHandler)obj3)); object obj4 = <>c.<>9__6_3; if (obj4 == null) { GenericButtonHandler val4 = delegate { Plugin.ResetAllWeights(); LogHelper.LogInfo("Loaded vanilla weight preset"); }; <>c.<>9__6_3 = val4; obj4 = (object)val4; } LethalConfigManager.AddConfigItem((BaseConfigItem)new GenericButtonConfigItem("Presets", "Load Vanilla Weights", "Reset all items to their default vanilla weights.", "Load Vanilla", (GenericButtonHandler)obj4)); object obj5 = <>c.<>9__6_4; if (obj5 == null) { GenericButtonHandler val5 = delegate { if (WeightSyncManager.IsClient()) { LogHelper.LogInfo("Using HOST'S weight configuration (synced from server)"); } else { NetworkManager singleton = NetworkManager.Singleton; if (singleton != null && singleton.IsHost) { LogHelper.LogInfo("You are the HOST - your weights are synced to all clients"); } else { LogHelper.LogInfo("Not in multiplayer - using your LOCAL weight configuration"); } } }; <>c.<>9__6_4 = val5; obj5 = (object)val5; } LethalConfigManager.AddConfigItem((BaseConfigItem)new GenericButtonConfigItem("General", "Network Sync Status", "Check if using host's weights or local configuration.", "Check Status", (GenericButtonHandler)obj5)); LogHelper.LogDebug("LethalConfig integration fully initialized with all features."); } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static void RegisterWeightSlider(ConfigEntry<float> configEntry, ItemCategory category, float minValue = 0.1f, float maxValue = 500f) { if (!IsAvailable) { return; } try { RegisterWeightSliderInternal(configEntry, category, minValue, maxValue); } catch (Exception ex) { LogHelper.LogWarning("Failed to register slider for '" + ((ConfigEntryBase)configEntry).Definition.Key + "': " + ex.Message); } } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] private static void RegisterWeightSliderInternal(ConfigEntry<float> configEntry, ItemCategory category, float minValue, float maxValue) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown FloatSliderOptions val = new FloatSliderOptions(); ((BaseRangeOptions<float>)val).Min = minValue; ((BaseRangeOptions<float>)val).Max = maxValue; ((BaseOptions)val).RequiresRestart = false; LethalConfigManager.AddConfigItem((BaseConfigItem)new FloatSliderConfigItem(configEntry, val)); LogHelper.LogVerbose("Registered LethalConfig slider for '" + ((ConfigEntryBase)configEntry).Definition.Key + "'"); } public static string GetCategorySection(ItemCategory category) { return category switch { ItemCategory.Scrap => "Scrap Items", ItemCategory.Equipment => "Equipment", ItemCategory.Store => "Store Items", ItemCategory.Modded => "Modded Items", _ => "Item Weights", }; } } public enum ModLogLevel { None, Minimal, Normal, Verbose } public static class LogHelper { private static ManualLogSource _logger; private static ConfigEntry<ModLogLevel> _logLevel; private static ConfigEntry<bool> _enableFileLogging; private static string _logDirectory; private static string _currentLogFile; private static readonly object _fileLock = new object(); private const int MaxLogFiles = 5; private const long MaxLogFileSize = 1048576L; public static ModLogLevel CurrentLogLevel => _logLevel?.Value ?? ModLogLevel.Normal; public static void Initialize(ManualLogSource logger, ConfigFile config) { _logger = logger; _logLevel = config.Bind<ModLogLevel>("Logging", "LogLevel", ModLogLevel.Normal, "Logging level:\n- None: No logs\n- Minimal: Only errors and warnings\n- Normal: Basic information (default)\n- Verbose: All details including per-item weight changes"); _enableFileLogging = config.Bind<bool>("Logging", "Enable File Logging", false, "Enable logging to file. Logs are saved in BepInEx/plugins/WeightsRebalanced/logs/"); _logDirectory = Path.Combine(Paths.PluginPath, "WeightsRebalanced", "logs"); if (_enableFileLogging.Value) { InitializeFileLogging(); } } private static void InitializeFileLogging() { try { if (!Directory.Exists(_logDirectory)) { Directory.CreateDirectory(_logDirectory); } string text = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"); _currentLogFile = Path.Combine(_logDirectory, "WeightsRebalanced_" + text + ".log"); RotateLogs(); WriteToFile($"=== WeightsRebalanced Log Started at {DateTime.Now:yyyy-MM-dd HH:mm:ss} ==="); } catch (Exception ex) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)("Failed to initialize file logging: " + ex.Message)); } } } private static void RotateLogs() { try { string[] files = Directory.GetFiles(_logDirectory, "WeightsRebalanced_*.log"); if (files.Length >= 5) { Array.Sort(files, (string a, string b) => File.GetCreationTime(a).CompareTo(File.GetCreationTime(b))); int num = files.Length - 5 + 1; for (int i = 0; i < num; i++) { File.Delete(files[i]); } } } catch (Exception ex) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)("Failed to rotate log files: " + ex.Message)); } } } private static void WriteToFile(string message) { ConfigEntry<bool> enableFileLogging = _enableFileLogging; if (enableFileLogging == null || !enableFileLogging.Value || string.IsNullOrEmpty(_currentLogFile)) { return; } lock (_fileLock) { try { if (File.Exists(_currentLogFile) && new FileInfo(_currentLogFile).Length >= 1048576) { InitializeFileLogging(); } string text = DateTime.Now.ToString("HH:mm:ss.fff"); File.AppendAllText(_currentLogFile, "[" + text + "] " + message + Environment.NewLine); } catch { } } } public static void LogError(string message) { if (CurrentLogLevel >= ModLogLevel.Minimal) { ManualLogSource logger = _logger; if (logger != null) { logger.LogError((object)message); } WriteToFile("[ERROR] " + message); } } public static void LogWarning(string message) { if (CurrentLogLevel >= ModLogLevel.Minimal) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)message); } WriteToFile("[WARN] " + message); } } public static void LogInfo(string message) { if (CurrentLogLevel >= ModLogLevel.Normal) { ManualLogSource logger = _logger; if (logger != null) { logger.LogInfo((object)message); } WriteToFile("[INFO] " + message); } } public static void LogDebug(string message) { if (CurrentLogLevel >= ModLogLevel.Verbose) { ManualLogSource logger = _logger; if (logger != null) { logger.LogDebug((object)message); } WriteToFile("[DEBUG] " + message); } } public static void LogVerbose(string message) { if (CurrentLogLevel >= ModLogLevel.Verbose) { ManualLogSource logger = _logger; if (logger != null) { logger.LogInfo((object)("[VERBOSE] " + message)); } WriteToFile("[VERBOSE] " + message); } } } [BepInPlugin("com.weights.rebalanced", "Weights Rebalanced", "2.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string ModGUID = "com.weights.rebalanced"; public const string ModName = "Weights Rebalanced"; public const string ModVersion = "2.0.0"; private Harmony _harmony; public static Plugin Instance { get; private set; } public static ManualLogSource Log { get; private set; } public static ConfigFile ConfigInstance { get; private set; } public static Dictionary<string, ConfigEntry<float>> ItemWeights { get; private set; } = new Dictionary<string, ConfigEntry<float>>(); public static Dictionary<string, float> DefaultItemWeights { get; private set; } = new Dictionary<string, float>(); public static Dictionary<string, float> CurrentItemWeightsKg { get; private set; } = new Dictionary<string, float>(); public static ConfigEntry<bool> EnableWeightModifications { get; private set; } private void Awake() { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; ConfigInstance = ((BaseUnityPlugin)this).Config; LogHelper.Initialize(((BaseUnityPlugin)this).Logger, ((BaseUnityPlugin)this).Config); ItemClassifier.Initialize(); PresetManager.Initialize(); EnableWeightModifications = ConfigInstance.Bind<bool>("General", "Enable Weight Modifications", true, "Global toggle to enable or disable all weight modifications. Set to false to use vanilla weights."); LogHelper.LogInfo("Weights Rebalanced v2.0.0 is loading..."); _harmony = new Harmony("com.weights.rebalanced"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); LethalConfigIntegration.Initialize(); ConfigWatcher.Initialize(); LogHelper.LogInfo("Weights Rebalanced loaded successfully!"); LogHelper.LogInfo($"Log level: {LogHelper.CurrentLogLevel}"); LogHelper.LogInfo("Weight modifications: " + (EnableWeightModifications.Value ? "Enabled" : "Disabled")); } private static string SanitizeConfigKey(string name) { if (string.IsNullOrEmpty(name)) { return "Unknown"; } string input = Regex.Replace(name, "[\\n\\t\\\\\"\\'\\[\\]]", ""); input = Regex.Replace(input, "\\s+", " ").Trim(); if (string.IsNullOrWhiteSpace(input)) { LogHelper.LogWarning("Item '" + name + "' has no valid characters, using hash as config key."); return $"Item_{name.GetHashCode():X8}"; } if (input != name) { LogHelper.LogDebug("Item name sanitized: '" + name + "' -> '" + input + "'"); } return input; } public static float GetItemWeight(string itemName, float defaultWeight, ItemCategory category = ItemCategory.Scrap) { //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown defaultWeight = (float)Math.Round(defaultWeight, 1); if (!DefaultItemWeights.ContainsKey(itemName)) { DefaultItemWeights[itemName] = defaultWeight; } if (!EnableWeightModifications.Value) { CurrentItemWeightsKg[itemName] = defaultWeight; return defaultWeight; } string text = SanitizeConfigKey(itemName); if (!ItemWeights.ContainsKey(itemName)) { string categorySection = LethalConfigIntegration.GetCategorySection(category); ItemWeights[itemName] = ConfigInstance.Bind<float>(categorySection, text, defaultWeight, new ConfigDescription("Weight of '" + text + "' in kilograms.\n" + $"Vanilla weight: {defaultWeight:F1} kg\n" + $"Valid range: {0.1f}-{500f} kg", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 500f), Array.Empty<object>())); LethalConfigIntegration.RegisterWeightSlider(ItemWeights[itemName], category); } float value = ItemWeights[itemName].Value; value = ConfigValidator.ClampWeight(value, itemName); if (value != ItemWeights[itemName].Value) { ItemWeights[itemName].Value = value; } CurrentItemWeightsKg[itemName] = value; return value; } public static void ResetAllWeights() { int num = 0; foreach (KeyValuePair<string, ConfigEntry<float>> itemWeight in ItemWeights) { if (DefaultItemWeights.TryGetValue(itemWeight.Key, out var value)) { itemWeight.Value.Value = value; CurrentItemWeightsKg[itemWeight.Key] = value; num++; } } LogHelper.LogInfo($"Reset {num} item weights to default values."); } public static void ResetItemWeight(string itemName) { if (ItemWeights.TryGetValue(itemName, out var value) && DefaultItemWeights.TryGetValue(itemName, out var value2)) { value.Value = value2; CurrentItemWeightsKg[itemName] = value2; LogHelper.LogDebug($"Reset '{itemName}' weight to {value2} kg."); } } public static float GameWeightToKg(float gameWeight) { return (gameWeight - 1f) * 100f * 0.453592f; } public static float KgToGameWeight(float kg) { float num = kg / 0.453592f; return 1f + num / 100f; } } public static class SafetyHelpers { public static bool ValidateItem(Item item, out string errorMessage) { errorMessage = null; if ((Object)(object)item == (Object)null) { errorMessage = "Item is null"; return false; } if (string.IsNullOrEmpty(item.itemName)) { errorMessage = $"Item has no name (InstanceID: {((Object)item).GetInstanceID()})"; return false; } if (item.weight < 0f) { errorMessage = $"Item '{item.itemName}' has negative weight: {item.weight}"; return false; } return true; } public static T SafeExecute<T>(Func<T> action, T defaultValue, string context) { try { return action(); } catch (Exception ex) { LogHelper.LogError("Error in " + context + ": " + ex.Message + "\n" + ex.StackTrace); return defaultValue; } } public static void SafeExecute(Action action, string context) { try { action(); } catch (Exception ex) { LogHelper.LogError("Error in " + context + ": " + ex.Message + "\n" + ex.StackTrace); } } } } namespace WeightsRebalanced.Presets { [Serializable] public class WeightPreset { public string PresetName { get; set; } public string Description { get; set; } public string CreatedDate { get; set; } public string ModVersion { get; set; } public Dictionary<string, float> ItemWeights { get; set; } = new Dictionary<string, float>(); public WeightPreset() { CreatedDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); ModVersion = "2.0.0"; } } public static class PresetManager { private static string _presetsDirectory; public static void Initialize() { _presetsDirectory = Path.Combine(Paths.ConfigPath, "WeightsRebalanced", "Presets"); if (!Directory.Exists(_presetsDirectory)) { Directory.CreateDirectory(_presetsDirectory); LogHelper.LogInfo("Created presets directory: " + _presetsDirectory); } } public static bool SavePreset(string presetName, string description = "") { try { WeightPreset weightPreset = new WeightPreset { PresetName = presetName, Description = description }; foreach (KeyValuePair<string, ConfigEntry<float>> itemWeight in Plugin.ItemWeights) { weightPreset.ItemWeights[itemWeight.Key] = itemWeight.Value.Value; } string path = SanitizeFileName(presetName) + ".txt"; string text = Path.Combine(_presetsDirectory, path); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# Preset: " + weightPreset.PresetName); stringBuilder.AppendLine("# Description: " + weightPreset.Description); stringBuilder.AppendLine("# Created: " + weightPreset.CreatedDate); stringBuilder.AppendLine("# ModVersion: " + weightPreset.ModVersion); stringBuilder.AppendLine(); foreach (KeyValuePair<string, float> itemWeight2 in weightPreset.ItemWeights) { stringBuilder.AppendLine($"{itemWeight2.Key}={itemWeight2.Value:F1}"); } File.WriteAllText(text, stringBuilder.ToString()); LogHelper.LogInfo($"Saved preset '{presetName}' with {weightPreset.ItemWeights.Count} items to {text}"); return true; } catch (Exception ex) { LogHelper.LogError("Failed to save preset '" + presetName + "': " + ex.Message); return false; } } public static bool LoadPreset(string presetName, bool applyImmediately = true) { try { string path = SanitizeFileName(presetName) + ".txt"; string text = Path.Combine(_presetsDirectory, path); if (!File.Exists(text)) { LogHelper.LogWarning("Preset file not found: " + text); return false; } WeightPreset weightPreset = new WeightPreset { PresetName = presetName }; string[] array = File.ReadAllLines(text); foreach (string text2 in array) { if (string.IsNullOrWhiteSpace(text2) || text2.StartsWith("#")) { continue; } string[] array2 = text2.Split('='); if (array2.Length == 2) { string key = array2[0].Trim(); if (float.TryParse(array2[1].Trim(), out var result)) { weightPreset.ItemWeights[key] = result; } } } if (weightPreset.ItemWeights.Count == 0) { LogHelper.LogError("Invalid preset file: " + text); return false; } if (applyImmediately) { ApplyPreset(weightPreset); } LogHelper.LogInfo($"Loaded preset '{weightPreset.PresetName}' with {weightPreset.ItemWeights.Count} items"); return true; } catch (Exception ex) { LogHelper.LogError("Failed to load preset '" + presetName + "': " + ex.Message); return false; } } private static void ApplyPreset(WeightPreset preset) { int num = 0; int num2 = 0; foreach (KeyValuePair<string, float> itemWeight in preset.ItemWeights) { string key = itemWeight.Key; float value = ConfigValidator.ClampWeight(itemWeight.Value, key); if (Plugin.ItemWeights.TryGetValue(key, out var value2)) { value2.Value = value; Plugin.CurrentItemWeightsKg[key] = value; num++; } else { num2++; } } LogHelper.LogInfo($"Applied preset: {num} items updated, {num2} items not yet loaded"); } public static List<string> GetAvailablePresets() { List<string> list = new List<string>(); try { if (Directory.Exists(_presetsDirectory)) { string[] files = Directory.GetFiles(_presetsDirectory, "*.txt"); for (int i = 0; i < files.Length; i++) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(files[i]); list.Add(fileNameWithoutExtension); } } } catch (Exception ex) { LogHelper.LogError("Failed to get preset list: " + ex.Message); } return list; } public static bool ExportPreset(string presetName, string destinationPath) { try { string path = SanitizeFileName(presetName) + ".txt"; string text = Path.Combine(_presetsDirectory, path); if (!File.Exists(text)) { LogHelper.LogWarning("Preset not found: " + presetName); return false; } File.Copy(text, destinationPath, overwrite: true); LogHelper.LogInfo("Exported preset to " + destinationPath); return true; } catch (Exception ex) { LogHelper.LogError("Failed to export preset: " + ex.Message); return false; } } public static bool ImportPreset(string sourcePath) { try { if (!File.Exists(sourcePath)) { LogHelper.LogWarning("Import file not found: " + sourcePath); return false; } string[] array = File.ReadAllLines(sourcePath); string text = "ImportedPreset"; int num = 0; string[] array2 = array; foreach (string text2 in array2) { if (text2.StartsWith("# Preset:")) { text = text2.Substring(9).Trim(); } else if (!string.IsNullOrWhiteSpace(text2) && !text2.StartsWith("#") && text2.Contains("=")) { num++; } } if (num == 0) { LogHelper.LogError("Invalid preset format"); return false; } string path = SanitizeFileName(text) + ".txt"; string destFileName = Path.Combine(_presetsDirectory, path); File.Copy(sourcePath, destFileName, overwrite: true); LogHelper.LogInfo($"Imported preset '{text}' with {num} items"); return true; } catch (Exception ex) { LogHelper.LogError("Failed to import preset: " + ex.Message); return false; } } private static string SanitizeFileName(string fileName) { char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); string text = fileName; char[] array = invalidFileNameChars; foreach (char oldChar in array) { text = text.Replace(oldChar, '_'); } return text; } } } namespace WeightsRebalanced.Patches { [HarmonyPatch] public class ItemSpawnPatches { private static HashSet<int> _modifiedItems = new HashSet<int>(); [HarmonyPatch(typeof(RoundManager), "SpawnScrapInLevel")] [HarmonyPrefix] public static void SpawnScrapInLevel_Prefix(RoundManager __instance) { if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.currentLevel == (Object)null) { return; } foreach (SpawnableItemWithRarity item in __instance.currentLevel.spawnableScrap) { if (!((Object)(object)item?.spawnableItem == (Object)null)) { ModifyItemWeight(item.spawnableItem); } } } [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPostfix] public static void StartOfRound_Awake_Postfix(StartOfRound __instance) { if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.allItemsList == (Object)null) { return; } CacheStoreItems(); int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; foreach (Item items in __instance.allItemsList.itemsList) { if ((Object)(object)items != (Object)null) { ItemCategory itemCategory = DetermineItemCategory(items); ModifyItemWeight(items); switch (itemCategory) { case ItemCategory.Scrap: num++; break; case ItemCategory.Equipment: num2++; break; case ItemCategory.Store: num3++; break; case ItemCategory.Modded: num4++; break; } } } LogHelper.LogInfo($"Modified weights: {num} scrap, {num2} equipment, {num3} store, {num4} modded items."); } private static void CacheStoreItems() { CategoryDetector.CacheStoreItems(); } private static void ModifyItemWeight(Item itemProperties) { if (!SafetyHelpers.ValidateItem(itemProperties, out var errorMessage)) { LogHelper.LogWarning("Skipping invalid item: " + errorMessage); return; } SafetyHelpers.SafeExecute(delegate { int instanceID = ((Object)itemProperties).GetInstanceID(); if (!_modifiedItems.Contains(instanceID)) { string itemName = itemProperties.itemName; float weight = itemProperties.weight; float num = Plugin.GameWeightToKg(weight); ItemCategory itemCategory = DetermineItemCategory(itemProperties); float itemWeight = Plugin.GetItemWeight(itemName, Mathf.Max(0.1f, num), itemCategory); float num2 = Plugin.KgToGameWeight(itemWeight); float num3 = Plugin.GameWeightToKg(num2); itemProperties.weight = num2; _modifiedItems.Add(instanceID); LogHelper.LogInfo($"[{itemCategory}] '{itemName}':"); LogHelper.LogInfo($" Original: {weight:F3} game weight = {num:F2} kg"); LogHelper.LogInfo($" Config: {itemWeight:F2} kg"); LogHelper.LogInfo($" New: {num2:F3} game weight"); LogHelper.LogInfo($" Verify: {num2:F3} game weight = {num3:F2} kg"); if (Mathf.Abs(num3 - itemWeight) > 0.01f) { LogHelper.LogWarning($" WARNING: Conversion mismatch! Config {itemWeight:F2} kg != Verify {num3:F2} kg"); } } }, "ModifyItemWeight"); } private static ItemCategory DetermineItemCategory(Item item) { return CategoryDetector.DetermineCategory(item); } [HarmonyPatch(typeof(StartOfRound), "ResetShip")] [HarmonyPostfix] public static void ResetShip_Postfix() { _modifiedItems.Clear(); } } [HarmonyPatch] public class NetworkPatches { [CompilerGenerated] private sealed class <DelaySyncToClients>d__3 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DelaySyncToClients>d__3(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(2f); <>1__state = 1; return true; case 1: <>1__state = -1; if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsHost) { foreach (ulong connectedClientsId in NetworkManager.Singleton.ConnectedClientsIds) { if (connectedClientsId != NetworkManager.Singleton.LocalClientId) { LogHelper.LogDebug($"Syncing weights to client {connectedClientsId}"); WeightSyncManager.OnClientConnected(connectedClientsId); } } } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [HarmonyPatch(typeof(NetworkManager), "StartHost")] [HarmonyPostfix] public static void StartHost_Postfix() { LogHelper.LogInfo("Host started - initializing weight sync manager"); WeightSyncManager.Initialize(); } [HarmonyPatch(typeof(NetworkManager), "StartClient")] [HarmonyPostfix] public static void StartClient_Postfix() { LogHelper.LogInfo("Client started - initializing weight sync manager"); WeightSyncManager.Initialize(); } [HarmonyPatch(typeof(StartOfRound), "Start")] [HarmonyPostfix] public static void StartOfRound_Start_Postfix(StartOfRound __instance) { if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsHost) { ((MonoBehaviour)__instance).StartCoroutine(DelaySyncToClients()); } } [IteratorStateMachine(typeof(<DelaySyncToClients>d__3))] private static IEnumerator DelaySyncToClients() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <DelaySyncToClients>d__3(0); } [HarmonyPatch(typeof(NetworkManager), "Shutdown")] [HarmonyPrefix] public static void Shutdown_Prefix() { if (WeightSyncManager.IsClient()) { LogHelper.LogInfo("Disconnected from host - restoring original weights"); WeightSyncManager.RestoreOriginalWeights(); } } } [HarmonyPatch] public class ScanNodePatches { private static readonly Regex PoundRegex = new Regex("(\\d+(?:\\.\\d+)?)\\s*lb", RegexOptions.IgnoreCase); [HarmonyPatch(typeof(HUDManager), "AssignNewNodes")] [HarmonyPostfix] public static void AssignNewNodes_Postfix(HUDManager __instance) { if (__instance.scanElements == null) { return; } for (int i = 0; i < __instance.scanElements.Length; i++) { RectTransform val = __instance.scanElements[i]; if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeSelf) { continue; } Text[] componentsInChildren = ((Component)val).GetComponentsInChildren<Text>(); foreach (Text val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)null && !string.IsNullOrEmpty(val2.text)) { val2.text = ConvertPoundsToKg(val2.text); } } } } private static string ConvertPoundsToKg(string text) { if (string.IsNullOrEmpty(text) || text.Contains("kg")) { return text; } return PoundRegex.Replace(text, delegate(Match match) { if (float.TryParse(match.Groups[1].Value, out var result)) { float num = result * 0.453592f; return $"{num:F1} kg"; } return match.Value; }); } } [HarmonyPatch] public class WeightPatches { private static readonly Regex WeightRegex = new Regex("(\\d+(?:[.,]\\d+)?)\\s*lb", RegexOptions.IgnoreCase); private static int _lastInventoryHash = 0; private static float _lastCachedWeight = 0f; [HarmonyPatch(typeof(HUDManager), "Update")] [HarmonyPostfix] public static void HUDManager_Update_Postfix(HUDManager __instance) { if ((Object)(object)__instance?.weightCounter == (Object)null) { return; } PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if (!((Object)(object)val == (Object)null) && ((NetworkBehaviour)val).IsOwner) { int num = CalculateInventoryHash(val); if (num != _lastInventoryHash || ((TMP_Text)__instance.weightCounter).text.Contains("lb")) { _lastInventoryHash = num; _lastCachedWeight = GetPlayerCarryWeightKg(val); ((TMP_Text)__instance.weightCounter).text = $"{_lastCachedWeight:F1} kg"; LogHelper.LogVerbose($"[HUD] Updated weight counter: {_lastCachedWeight:F2} kg displayed as '{((TMP_Text)__instance.weightCounter).text}'"); } } } private static int CalculateInventoryHash(PlayerControllerB player) { if (player?.ItemSlots == null) { return 0; } int num = 17; GrabbableObject[] itemSlots = player.ItemSlots; foreach (GrabbableObject val in itemSlots) { num = num * 31 + ((val != null) ? ((Object)val).GetInstanceID() : 0); } return num; } [HarmonyPatch(typeof(PlayerControllerB), "GrabObjectClientRpc")] [HarmonyPostfix] public static void GrabObject_Postfix(PlayerControllerB __instance) { UpdateWeightDisplay(__instance); } [HarmonyPatch(typeof(PlayerControllerB), "DiscardHeldObject")] [HarmonyPostfix] public static void DiscardObject_Postfix(PlayerControllerB __instance) { UpdateWeightDisplay(__instance); } private static void UpdateWeightDisplay(PlayerControllerB player) { if (!((Object)(object)player == (Object)null) && ((NetworkBehaviour)player).IsOwner) { HUDManager instance = HUDManager.Instance; if ((Object)(object)instance?.weightCounter != (Object)null) { float playerCarryWeightKg = GetPlayerCarryWeightKg(player); ((TMP_Text)instance.weightCounter).text = $"{playerCarryWeightKg:F1} kg"; } } } [HarmonyPatch(typeof(HUDManager), "DisplayNewScrapFound")] [HarmonyPostfix] public static void DisplayNewScrapFound_Postfix(HUDManager __instance) { if (!((Object)(object)__instance == (Object)null) && (Object)(object)__instance.totalValueText != (Object)null) { string text = ((TMP_Text)__instance.totalValueText).text; if (!string.IsNullOrEmpty(text) && text.Contains("lb")) { ((TMP_Text)__instance.totalValueText).text = ConvertWeightText(text); } } } public static string ConvertWeightText(string text) { if (string.IsNullOrEmpty(text) || text.Contains("kg")) { return text; } return WeightRegex.Replace(text, delegate(Match match) { if (float.TryParse(match.Groups[1].Value.Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { float num = result * 0.453592f; return $"{num:F1} kg"; } return match.Value; }); } public static float GetPlayerCarryWeightKg(PlayerControllerB player) { if ((Object)(object)player == (Object)null) { return 0f; } float num = 0f; GrabbableObject[] itemSlots = player.ItemSlots; foreach (GrabbableObject val in itemSlots) { if ((Object)(object)val != (Object)null && (Object)(object)val.itemProperties != (Object)null) { string itemName = val.itemProperties.itemName; float num2 = 0f; if (Plugin.CurrentItemWeightsKg.TryGetValue(itemName, out var value)) { num2 = value; LogHelper.LogVerbose($"[HUD] '{itemName}': Using config weight {value:F2} kg (game weight: {val.itemProperties.weight:F3})"); } else { num2 = Plugin.GameWeightToKg(val.itemProperties.weight); LogHelper.LogVerbose($"[HUD] '{itemName}': Fallback conversion from game weight {val.itemProperties.weight:F3} = {num2:F2} kg"); } num += num2; } } LogHelper.LogVerbose($"[HUD] Total carry weight: {num:F2} kg"); return num; } } } namespace WeightsRebalanced.Networking { public static class WeightSyncManager { [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__OnReceiveWeightSync; } private const string CustomMessageName = "WeightsRebalanced_SyncWeights"; private static bool _isInitialized = false; private static bool _isSyncing = false; private static Dictionary<string, float> _originalWeights = new Dictionary<string, float>(); public static void Initialize() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown if (_isInitialized) { return; } _isInitialized = true; try { CustomMessagingManager customMessagingManager = NetworkManager.Singleton.CustomMessagingManager; object obj = <>O.<0>__OnReceiveWeightSync; if (obj == null) { HandleNamedMessageDelegate val = OnReceiveWeightSync; <>O.<0>__OnReceiveWeightSync = val; obj = (object)val; } customMessagingManager.RegisterNamedMessageHandler("WeightsRebalanced_SyncWeights", (HandleNamedMessageDelegate)obj); LogHelper.LogInfo("Weight synchronization network handler registered"); } catch (Exception ex) { LogHelper.LogError("Failed to register network handler: " + ex.Message); } } public static void OnClientConnected(ulong clientId) { if (IsHost()) { LogHelper.LogInfo($"Sending weight sync to client {clientId}"); SendWeightsToClient(clientId); } } private static void SendWeightsToClient(ulong clientId) { //IL_001e: 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_0044: Unknown result type (might be due to invalid IL or missing references) try { byte[] array = SerializeWeights(); FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(array.Length + 4, (Allocator)2, -1); try { int num = array.Length; ((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteBytesSafe(array, -1, 0); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("WeightsRebalanced_SyncWeights", clientId, val, (NetworkDelivery)4); } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } LogHelper.LogDebug($"Sent {array.Length} bytes of weight data to client {clientId}"); } catch (Exception ex) { LogHelper.LogError($"Failed to send weights to client {clientId}: {ex.Message}"); } } public static void BroadcastWeightUpdate(string itemName, float weightKg) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (!IsHost()) { return; } try { byte[] array = SerializeSingleWeight(itemName, weightKg); FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(array.Length + 4, (Allocator)2, -1); try { int num = array.Length; ((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteBytesSafe(array, -1, 0); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessageToAll("WeightsRebalanced_SyncWeights", val, (NetworkDelivery)2); } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } LogHelper.LogDebug("Broadcast weight update for '" + itemName + "' to all clients"); } catch (Exception ex) { LogHelper.LogError("Failed to broadcast weight update: " + ex.Message); } } private static void OnReceiveWeightSync(ulong senderId, FastBufferReader reader) { //IL_001e: 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) if (_isSyncing) { LogHelper.LogWarning("Already syncing weights, ignoring duplicate message"); return; } _isSyncing = true; try { int num = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives)); byte[] data = new byte[num]; ((FastBufferReader)(ref reader)).ReadBytesSafe(ref data, num, 0); DeserializeAndApplyWeights(data); LogHelper.LogInfo($"Received and applied {num} bytes of weight data from host"); } catch (Exception ex) { LogHelper.LogError("Failed to receive weight sync: " + ex.Message); } finally { _isSyncing = false; } } private static byte[] SerializeWeights() { using MemoryStream memoryStream = new MemoryStream(); using BinaryWriter binaryWriter = new BinaryWriter(memoryStream); binaryWriter.Write((byte)1); binaryWriter.Write("2.0.0"); binaryWriter.Write(Plugin.ItemWeights.Count); foreach (KeyValuePair<string, ConfigEntry<float>> itemWeight in Plugin.ItemWeights) { binaryWriter.Write(itemWeight.Key); binaryWriter.Write(itemWeight.Value.Value); } return memoryStream.ToArray(); } private static byte[] SerializeSingleWeight(string itemName, float weightKg) { using MemoryStream memoryStream = new MemoryStream(); using BinaryWriter binaryWriter = new BinaryWriter(memoryStream); binaryWriter.Write((byte)2); binaryWriter.Write(itemName); binaryWriter.Write(weightKg); return memoryStream.ToArray(); } private static void DeserializeAndApplyWeights(byte[] data) { using MemoryStream input = new MemoryStream(data); using BinaryReader binaryReader = new BinaryReader(input); switch (binaryReader.ReadByte()) { case 1: { string arg = binaryReader.ReadString(); int num = binaryReader.ReadInt32(); LogHelper.LogInfo($"Receiving full weight sync from host (version {arg}, {num} items)"); Dictionary<string, float> dictionary = new Dictionary<string, float>(); for (int i = 0; i < num; i++) { string key = binaryReader.ReadString(); float value = binaryReader.ReadSingle(); dictionary[key] = value; } ApplyReceivedWeights(dictionary); break; } case 2: { string itemName = binaryReader.ReadString(); float weightKg = binaryReader.ReadSingle(); ApplySingleWeight(itemName, weightKg); break; } } } private static void ApplyReceivedWeights(Dictionary<string, float> weights) { int num = 0; foreach (KeyValuePair<string, float> weight in weights) { ApplySingleWeight(weight.Key, weight.Value); num++; } LogHelper.LogInfo($"Applied {num} synced weights from host (local config overridden for this session)"); } private static void ApplySingleWeight(string itemName, float weightKg) { weightKg = ConfigValidator.ClampWeight(weightKg, itemName); Plugin.CurrentItemWeightsKg[itemName] = weightKg; if (Plugin.ItemWeights.TryGetValue(itemName, out var value)) { if (!_originalWeights.ContainsKey(itemName)) { _originalWeights[itemName] = value.Value; } value.Value = weightKg; } UpdateLiveItemWeight(itemName, weightKg); } private static void UpdateLiveItemWeight(string itemName, float weightKg) { GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>(); int num = 0; GrabbableObject[] array2 = array; foreach (GrabbableObject val in array2) { if ((Object)(object)val?.itemProperties != (Object)null && val.itemProperties.itemName == itemName) { float weight = Plugin.KgToGameWeight(weightKg); val.itemProperties.weight = weight; num++; } } if (num > 0) { LogHelper.LogDebug($"Updated {num} live instances of '{itemName}'"); } } public static void RestoreOriginalWeights() { if (_originalWeights.Count == 0) { return; } LogHelper.LogInfo($"Restoring {_originalWeights.Count} original weight values"); foreach (KeyValuePair<string, float> originalWeight in _originalWeights) { if (Plugin.ItemWeights.TryGetValue(originalWeight.Key, out var value)) { value.Value = originalWeight.Value; } } _originalWeights.Clear(); } public static bool IsHost() { if ((Object)(object)NetworkManager.Singleton != (Object)null) { return NetworkManager.Singleton.IsHost; } return false; } public static bool IsClient() { if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsClient) { return !NetworkManager.Singleton.IsHost; } return false; } } } namespace WeightsRebalanced.ItemDetection { public static class CategoryDetector { private static HashSet<string> _storeItemNames = new HashSet<string>(); public static ItemCategory DetermineCategory(Item item) { if ((Object)(object)item == (Object)null) { return ItemCategory.Scrap; } if (ItemClassifier.GetItemOrigin(item) == ItemOrigin.Modded) { return ItemCategory.Modded; } if (item.isScrap) { return ItemCategory.Scrap; } if (IsStoreItem(item)) { return ItemCategory.Store; } return ItemCategory.Equipment; } private static bool IsStoreItem(Item item) { if (_storeItemNames.Contains(item.itemName)) { return true; } Terminal val = Object.FindObjectOfType<Terminal>(); if (val?.buyableItemsList != null) { Item[] buyableItemsList = val.buyableItemsList; for (int i = 0; i < buyableItemsList.Length; i++) { if ((Object)(object)buyableItemsList[i] == (Object)(object)item) { _storeItemNames.Add(item.itemName); return true; } } } return false; } public static void CacheStoreItems() { _storeItemNames.Clear(); Terminal val = Object.FindObjectOfType<Terminal>(); if (val?.buyableItemsList == null) { return; } Item[] buyableItemsList = val.buyableItemsList; foreach (Item val2 in buyableItemsList) { if ((Object)(object)val2 != (Object)null && !string.IsNullOrEmpty(val2.itemName)) { _storeItemNames.Add(val2.itemName); } } LogHelper.LogDebug($"Cached {_storeItemNames.Count} store items dynamically"); } } public static class DiagnosticCommands { public static void PrintAllItemsWithOrigin() { StartOfRound val = Object.FindObjectOfType<StartOfRound>(); if (val?.allItemsList?.itemsList != null) { LogHelper.LogInfo("=== Item Detection Diagnostics ==="); int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; int num6 = 0; int num7 = 0; foreach (Item items in val.allItemsList.itemsList) { if (!((Object)(object)items == (Object)null)) { ItemOrigin itemOrigin = ItemClassifier.GetItemOrigin(items); ItemCategory itemCategory = CategoryDetector.DetermineCategory(items); float num8 = Plugin.GameWeightToKg(items.weight); LogHelper.LogInfo($"[{itemOrigin}] [{itemCategory}] {items.itemName} (weight: {num8:F2} kg)"); switch (itemOrigin) { case ItemOrigin.Vanilla: num++; break; case ItemOrigin.Modded: num2++; break; case ItemOrigin.Unknown: num3++; break; } switch (itemCategory) { case ItemCategory.Scrap: num4++; break; case ItemCategory.Equipment: num5++; break; case ItemCategory.Store: num6++; break; case ItemCategory.Modded: num7++; break; } } } LogHelper.LogInfo("\n=== Summary ==="); LogHelper.LogInfo($"Origins: {num} vanilla, {num2} modded, {num3} unknown"); LogHelper.LogInfo($"Categories: {num4} scrap, {num5} equipment, {num6} store, {num7} modded"); LogHelper.LogInfo(ItemClassifier.GetDiagnostics()); } else { LogHelper.LogWarning("Could not find StartOfRound or items list"); } } } public enum ItemOrigin { Vanilla, Modded, Unknown } public static class ItemClassifier { private static Assembly _vanillaAssembly; private static HashSet<string> _knownVanillaItems = new HashSet<string>(); private static HashSet<string> _knownModdedItems = new HashSet<string>(); private static Dictionary<int, ItemOrigin> _itemOriginCache = new Dictionary<int, ItemOrigin>(); public static void Initialize() { _vanillaAssembly = typeof(StartOfRound).Assembly; LogHelper.LogInfo("Vanilla assembly identified: " + _vanillaAssembly.GetName().Name); } public static ItemOrigin GetItemOrigin(Item item) { if ((Object)(object)item == (Object)null) { return ItemOrigin.Unknown; } int instanceID = ((Object)item).GetInstanceID(); if (_itemOriginCache.TryGetValue(instanceID, out var value)) { return value; } ItemOrigin itemOrigin = DetermineOriginInternal(item); _itemOriginCache[instanceID] = itemOrigin; return itemOrigin; } private static ItemOrigin DetermineOriginInternal(Item item) { try { Assembly assembly = ((object)item).GetType().Assembly; if (assembly == _vanillaAssembly) { _knownVanillaItems.Add(item.itemName); LogHelper.LogVerbose("Detected vanilla item via assembly: " + item.itemName); return ItemOrigin.Vanilla; } if (assembly != null && assembly != _vanillaAssembly) { _knownModdedItems.Add(item.itemName); LogHelper.LogVerbose("Detected modded item via assembly: " + item.itemName + " (from " + assembly.GetName().Name + ")"); return ItemOrigin.Modded; } } catch (Exception ex) { LogHelper.LogDebug("Assembly check failed for '" + item.itemName + "': " + ex.Message); } if (_knownVanillaItems.Contains(item.itemName)) { return ItemOrigin.Vanilla; } if (_knownModdedItems.Contains(item.itemName)) { return ItemOrigin.Modded; } LogHelper.LogDebug("Could not determine origin for '" + item.itemName + "', assuming modded"); return ItemOrigin.Modded; } public static string GetDiagnostics() { return $"Known Vanilla Items: {_knownVanillaItems.Count}\n" + $"Known Modded Items: {_knownModdedItems.Count}\n" + $"Cache Size: {_itemOriginCache.Count}"; } public static void ClearCache() { _itemOriginCache.Clear(); } } } namespace WeightsRebalanced.HotReload { public static class ConfigWatcher { private static bool _initialized; public static void Initialize() { if (!_initialized) { _initialized = true; Plugin.ConfigInstance.SettingChanged += OnConfigChanged; LogHelper.LogDebug("Config hot reload watcher initialized"); } } private static void OnConfigChanged(object sender, SettingChangedEventArgs e) { if (IsWeightSetting(e.ChangedSetting)) { string key = e.ChangedSetting.Definition.Key; float num = (float)e.ChangedSetting.BoxedValue; LogHelper.LogDebug($"Config changed: {key} = {num:F1} kg"); UpdateLiveItems(key, num); if (WeightSyncManager.IsHost()) { WeightSyncManager.BroadcastWeightUpdate(key, num); } } } private static bool IsWeightSetting(ConfigEntryBase setting) { string section = setting.Definition.Section; if (!section.Contains("Items") && !section.Contains("Equipment") && !section.Contains("Store")) { return section.Contains("Modded"); } return true; } private static void UpdateLiveItems(string itemName, float newWeightKg) { GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>(); int num = 0; GrabbableObject[] array2 = array; foreach (GrabbableObject val in array2) { if ((Object)(object)val?.itemProperties != (Object)null && val.itemProperties.itemName == itemName) { float weight = Plugin.KgToGameWeight(newWeightKg); val.itemProperties.weight = weight; num++; } } if (num > 0) { LogHelper.LogInfo($"Hot-reloaded weight for {num} instances of '{itemName}' to {newWeightKg:F1} kg"); } } } }