Decompiled source of WeightsRebalanced v2.1.0

plugins/WeightsRebalanced.dll

Decompiled 2 months ago
using 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.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
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 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("2.1.0.0")]
[assembly: AssemblyInformationalVersion("2.1.0")]
[assembly: AssemblyProduct("WeightsRebalanced")]
[assembly: AssemblyTitle("WeightsRebalanced")]
[assembly: AssemblyVersion("2.1.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 WeightsRebalanced
{
	public static class ConfigValidator
	{
		public const float MinWeight = 0f;

		public const float MaxWeight = 500f;

		public static float ClampWeight(float value, string itemName = null)
		{
			float num = Mathf.Clamp(value, 0f, 500f);
			if (num != value && itemName != null)
			{
				LogHelper.LogWarning($"Weight for '{itemName}' clamped from {value:F1} to {num:F1} kg (valid range: {0f}-{500f} kg)");
			}
			return num;
		}
	}
	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__5_0;

			public static GenericButtonHandler <>9__5_1;

			public static GenericButtonHandler <>9__5_2;

			public static GenericButtonHandler <>9__5_3;

			public static GenericButtonHandler <>9__5_4;

			internal void <InitializeInternal>b__5_0()
			{
				Plugin.ResetAllWeights();
			}

			internal void <InitializeInternal>b__5_1()
			{
				DiagnosticCommands.PrintAllItemsWithOrigin();
			}

			internal void <InitializeInternal>b__5_2()
			{
				DiagnosticCommands.PrintNetworkStatus();
			}

			internal void <InitializeInternal>b__5_3()
			{
				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__5_4()
			{
				Plugin.ResetAllWeights();
			}
		}

		private static bool? _isAvailable;

		private static bool _initialized;

		public static bool IsAvailable
		{
			get
			{
				bool valueOrDefault = _isAvailable == true;
				if (!_isAvailable.HasValue)
				{
					valueOrDefault = Chainloader.PluginInfos.ContainsKey("ainavt.lc.lethalconfig");
					_isAvailable = valueOrDefault;
				}
				return _isAvailable.Value;
			}
		}

		public static void Initialize()
		{
			if (_initialized || !IsAvailable)
			{
				if (!IsAvailable)
				{
					LogHelper.LogInfo("LethalConfig not found - mod works without the GUI.");
				}
				return;
			}
			_initialized = true;
			try
			{
				InitializeInternal();
				LogHelper.LogInfo("LethalConfig detected - GUI integration enabled.");
			}
			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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Expected O, but got Unknown
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Expected O, but got Unknown
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Expected O, but got Unknown
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Expected O, but got Unknown
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Expected O, but got Unknown
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Expected O, but got Unknown
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Expected O, but got Unknown
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Expected O, but got Unknown
			LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(Plugin.EnableWeightModifications, new BoolCheckBoxOptions
			{
				RequiresRestart = false
			}));
			LethalConfigManager.AddConfigItem((BaseConfigItem)(object)new EnumDropDownConfigItem<WeightUnit>(Plugin.DisplayUnit, new EnumDropDownOptions
			{
				RequiresRestart = false
			}));
			AddMultiplierSlider(Plugin.GlobalMultiplier);
			AddMultiplierSlider(Plugin.ScrapMultiplier);
			AddMultiplierSlider(Plugin.EquipmentMultiplier);
			AddMultiplierSlider(Plugin.StoreMultiplier);
			AddMultiplierSlider(Plugin.ModdedMultiplier);
			object obj = <>c.<>9__5_0;
			if (obj == null)
			{
				GenericButtonHandler val = delegate
				{
					Plugin.ResetAllWeights();
				};
				<>c.<>9__5_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__5_1;
			if (obj2 == null)
			{
				GenericButtonHandler val2 = delegate
				{
					DiagnosticCommands.PrintAllItemsWithOrigin();
				};
				<>c.<>9__5_1 = val2;
				obj2 = (object)val2;
			}
			LethalConfigManager.AddConfigItem((BaseConfigItem)new GenericButtonConfigItem("General", "Diagnostic: Print Item Detection", "Prints all items with detected origin (vanilla/modded), category and weights to the log.", "Print Diagnostics", (GenericButtonHandler)obj2));
			object obj3 = <>c.<>9__5_2;
			if (obj3 == null)
			{
				GenericButtonHandler val3 = delegate
				{
					DiagnosticCommands.PrintNetworkStatus();
				};
				<>c.<>9__5_2 = val3;
				obj3 = (object)val3;
			}
			LethalConfigManager.AddConfigItem((BaseConfigItem)new GenericButtonConfigItem("General", "Network Sync Status", "Check if using host's weights or local configuration.", "Check Status", (GenericButtonHandler)obj3));
			object obj4 = <>c.<>9__5_3;
			if (obj4 == null)
			{
				GenericButtonHandler val4 = 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__5_3 = val4;
				obj4 = (object)val4;
			}
			LethalConfigManager.AddConfigItem((BaseConfigItem)new GenericButtonConfigItem("Presets", "Save Current as Preset", "Save your current weight configuration as a preset named with the current timestamp.", "Save Preset", (GenericButtonHandler)obj4));
			object obj5 = <>c.<>9__5_4;
			if (obj5 == null)
			{
				GenericButtonHandler val5 = delegate
				{
					Plugin.ResetAllWeights();
				};
				<>c.<>9__5_4 = val5;
				obj5 = (object)val5;
			}
			LethalConfigManager.AddConfigItem((BaseConfigItem)new GenericButtonConfigItem("Presets", "Load Vanilla Weights", "Reset all items to their default vanilla weights.", "Load Vanilla", (GenericButtonHandler)obj5));
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		private static void AddMultiplierSlider(ConfigEntry<float> entry)
		{
			//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_0011: Expected O, but got Unknown
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			FloatSliderOptions val = new FloatSliderOptions();
			((BaseRangeOptions<float>)val).Min = 0f;
			((BaseRangeOptions<float>)val).Max = 10f;
			((BaseOptions)val).RequiresRestart = false;
			LethalConfigManager.AddConfigItem((BaseConfigItem)new FloatSliderConfigItem(entry, val));
		}

		public static void RegisterWeightSlider(ConfigEntry<float> configEntry, ItemCategory category)
		{
			if (!IsAvailable)
			{
				return;
			}
			try
			{
				RegisterWeightSliderInternal(configEntry);
			}
			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)
		{
			//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_0011: Expected O, but got Unknown
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			FloatSliderOptions val = new FloatSliderOptions();
			((BaseRangeOptions<float>)val).Min = 0f;
			((BaseRangeOptions<float>)val).Max = 500f;
			((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 static class LogHelper
	{
		private static ManualLogSource _logger;

		private static ConfigEntry<ModLogLevel> _logLevel;

		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");
		}

		public static void LogError(string message)
		{
			if (CurrentLogLevel >= ModLogLevel.Minimal)
			{
				ManualLogSource logger = _logger;
				if (logger != null)
				{
					logger.LogError((object)message);
				}
			}
		}

		public static void LogWarning(string message)
		{
			if (CurrentLogLevel >= ModLogLevel.Minimal)
			{
				ManualLogSource logger = _logger;
				if (logger != null)
				{
					logger.LogWarning((object)message);
				}
			}
		}

		public static void LogInfo(string message)
		{
			if (CurrentLogLevel >= ModLogLevel.Normal)
			{
				ManualLogSource logger = _logger;
				if (logger != null)
				{
					logger.LogInfo((object)message);
				}
			}
		}

		public static void LogDebug(string message)
		{
			if (CurrentLogLevel >= ModLogLevel.Verbose)
			{
				ManualLogSource logger = _logger;
				if (logger != null)
				{
					logger.LogDebug((object)message);
				}
			}
		}

		public static void LogVerbose(string message)
		{
			if (CurrentLogLevel >= ModLogLevel.Verbose)
			{
				ManualLogSource logger = _logger;
				if (logger != null)
				{
					logger.LogInfo((object)("[VERBOSE] " + message));
				}
			}
		}
	}
	public enum ModLogLevel
	{
		None,
		Minimal,
		Normal,
		Verbose
	}
	[BepInPlugin("com.weights.rebalanced", "Weights Rebalanced", "2.1.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.1.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; } = new Dictionary<string, ConfigEntry<float>>();

		public static Dictionary<string, float> DefaultItemWeightsKg { get; } = new Dictionary<string, float>();

		public static Dictionary<string, float> CurrentItemWeightsKg { get; } = new Dictionary<string, float>();

		public static Dictionary<string, string> ConfigKeyToItemName { get; } = new Dictionary<string, string>();

		public static Dictionary<string, ItemCategory> ItemCategories { get; } = new Dictionary<string, ItemCategory>();

		public static ConfigEntry<bool> EnableWeightModifications { get; private set; }

		public static ConfigEntry<WeightUnit> DisplayUnit { get; private set; }

		public static ConfigEntry<float> GlobalMultiplier { get; private set; }

		public static ConfigEntry<float> ScrapMultiplier { get; private set; }

		public static ConfigEntry<float> EquipmentMultiplier { get; private set; }

		public static ConfigEntry<float> StoreMultiplier { get; private set; }

		public static ConfigEntry<float> ModdedMultiplier { get; private set; }

		private void Awake()
		{
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected O, but got Unknown
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected O, but got Unknown
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Expected O, but got Unknown
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Expected O, but got Unknown
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Expected O, but got Unknown
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: 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 = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enable Weight Modifications", true, "Global toggle to enable or disable all weight modifications. Set to false to use vanilla weights.");
			DisplayUnit = ((BaseUnityPlugin)this).Config.Bind<WeightUnit>("General", "Display Unit", WeightUnit.Kilograms, "Unit used by the HUD weight counter: Kilograms, Pounds (vanilla) or Both.");
			GlobalMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Multipliers", "Global Weight Multiplier", 1f, new ConfigDescription("Multiplies the weight of ALL items on top of their configured values.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			ScrapMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Multipliers", "Scrap Multiplier", 1f, new ConfigDescription("Extra multiplier applied to scrap items.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			EquipmentMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Multipliers", "Equipment Multiplier", 1f, new ConfigDescription("Extra multiplier applied to equipment.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			StoreMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Multipliers", "Store Items Multiplier", 1f, new ConfigDescription("Extra multiplier applied to store items.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			ModdedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Multipliers", "Modded Items Multiplier", 1f, new ConfigDescription("Extra multiplier applied to modded items.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			LogHelper.LogInfo("Weights Rebalanced v2.1.0 is loading...");
			_harmony = new Harmony("com.weights.rebalanced");
			_harmony.PatchAll(Assembly.GetExecutingAssembly());
			LethalConfigIntegration.Initialize();
			ConfigWatcher.Initialize();
			LogHelper.LogInfo(string.Format("{0} loaded successfully! (log level: {1}, modifications: {2})", "Weights Rebalanced", LogHelper.CurrentLogLevel, 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))
			{
				return $"Item_{name.GetHashCode():X8}";
			}
			return input;
		}

		public static float GetEffectiveWeightKg(string itemName, float vanillaKg, ItemCategory category)
		{
			vanillaKg = (float)Math.Round(vanillaKg, 2);
			if (!DefaultItemWeightsKg.ContainsKey(itemName))
			{
				DefaultItemWeightsKg[itemName] = vanillaKg;
			}
			ItemCategories[itemName] = category;
			EnsureConfigEntry(itemName, vanillaKg, category);
			if (WeightSyncManager.TryGetSyncedWeight(itemName, out var weightKg))
			{
				return weightKg;
			}
			if (!EnableWeightModifications.Value)
			{
				return vanillaKg;
			}
			return ConfigValidator.ClampWeight(ConfigValidator.ClampWeight(ItemWeights[itemName].Value, itemName) * GlobalMultiplier.Value * GetCategoryMultiplier(category));
		}

		private static void EnsureConfigEntry(string itemName, float vanillaKg, ItemCategory category)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			if (!ItemWeights.ContainsKey(itemName))
			{
				string text = SanitizeConfigKey(itemName);
				string categorySection = LethalConfigIntegration.GetCategorySection(category);
				ItemWeights[itemName] = ConfigInstance.Bind<float>(categorySection, text, vanillaKg, new ConfigDescription($"Weight of '{text}' in kilograms.\nVanilla weight: {vanillaKg:F1} kg\nValid range: {0f}-{500f} kg", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 500f), Array.Empty<object>()));
				ConfigKeyToItemName[text] = itemName;
				LethalConfigIntegration.RegisterWeightSlider(ItemWeights[itemName], category);
			}
		}

		public static float GetCategoryMultiplier(ItemCategory category)
		{
			return category switch
			{
				ItemCategory.Scrap => ScrapMultiplier.Value, 
				ItemCategory.Equipment => EquipmentMultiplier.Value, 
				ItemCategory.Store => StoreMultiplier.Value, 
				ItemCategory.Modded => ModdedMultiplier.Value, 
				_ => 1f, 
			};
		}

		public static void ResetAllWeights()
		{
			int num = 0;
			ConfigWatcher.Suppress = true;
			try
			{
				foreach (KeyValuePair<string, ConfigEntry<float>> itemWeight in ItemWeights)
				{
					if (DefaultItemWeightsKg.TryGetValue(itemWeight.Key, out var value))
					{
						itemWeight.Value.Value = value;
						num++;
					}
				}
			}
			finally
			{
				ConfigWatcher.Suppress = false;
			}
			WeightApplier.ApplyAllItems();
			WeightSyncManager.BroadcastFullSyncIfHost();
			LogHelper.LogInfo($"Reset {num} item weights to vanilla values.");
		}
	}
	public static class WeightApplier
	{
		private static readonly Dictionary<int, float> _originalGameWeights = new Dictionary<int, float>();

		public static void ApplyAllItems()
		{
			if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)StartOfRound.Instance.allItemsList == (Object)null)
			{
				return;
			}
			Dictionary<Item, float> dictionary = null;
			int num = 0;
			foreach (Item items in StartOfRound.Instance.allItemsList.itemsList)
			{
				float num2 = (((Object)(object)items != (Object)null) ? items.weight : 0f);
				if (!ApplyToItem(items))
				{
					continue;
				}
				num++;
				if (!Mathf.Approximately(num2, items.weight))
				{
					if (dictionary == null)
					{
						dictionary = new Dictionary<Item, float>();
					}
					dictionary[items] = items.weight - num2;
				}
			}
			if (dictionary != null)
			{
				AdjustCarriedWeights(dictionary);
			}
			LogHelper.LogDebug($"Applied weights to {num} items ({dictionary?.Count ?? 0} changed).");
		}

		public static bool ApplyToItem(Item item)
		{
			if ((Object)(object)item == (Object)null || string.IsNullOrEmpty(item.itemName))
			{
				return false;
			}
			int instanceID = ((Object)item).GetInstanceID();
			if (!_originalGameWeights.TryGetValue(instanceID, out var value))
			{
				value = item.weight;
				_originalGameWeights[instanceID] = value;
			}
			float num = WeightMath.GameWeightToKg(value);
			ItemCategory itemCategory = CategoryDetector.DetermineCategory(item);
			float effectiveWeightKg = Plugin.GetEffectiveWeightKg(item.itemName, num, itemCategory);
			float num2 = WeightMath.KgToGameWeight(effectiveWeightKg);
			if (!Mathf.Approximately(item.weight, num2))
			{
				LogHelper.LogVerbose($"[{itemCategory}] '{item.itemName}': {WeightMath.GameWeightToKg(item.weight):F2} kg -> {effectiveWeightKg:F2} kg (vanilla {num:F2} kg)");
				item.weight = num2;
			}
			Plugin.CurrentItemWeightsKg[item.itemName] = effectiveWeightKg;
			return true;
		}

		private static void AdjustCarriedWeights(Dictionary<Item, float> weightDeltas)
		{
			if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null)
			{
				return;
			}
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if ((Object)(object)val == (Object)null || val.ItemSlots == null)
				{
					continue;
				}
				float num = 0f;
				GrabbableObject[] itemSlots = val.ItemSlots;
				foreach (GrabbableObject val2 in itemSlots)
				{
					if ((Object)(object)val2 != (Object)null && (Object)(object)val2.itemProperties != (Object)null && weightDeltas.TryGetValue(val2.itemProperties, out var value))
					{
						num += value;
					}
				}
				if (num != 0f)
				{
					val.carryWeight = Mathf.Max(1f, val.carryWeight + num);
					LogHelper.LogDebug($"Adjusted carry weight of '{val.playerUsername}' by {num:F3} (held items changed).");
				}
			}
		}

		public static bool TryGetVanillaKg(Item item, out float vanillaKg)
		{
			if ((Object)(object)item != (Object)null && _originalGameWeights.TryGetValue(((Object)item).GetInstanceID(), out var value))
			{
				vanillaKg = WeightMath.GameWeightToKg(value);
				return true;
			}
			vanillaKg = 0f;
			return false;
		}
	}
	public static class WeightMath
	{
		public const float LbPerGameWeight = 105f;

		public const float KgPerLb = 0.45359236f;

		public static float GameWeightToKg(float gameWeight)
		{
			return Mathf.Max(0f, gameWeight - 1f) * 105f * 0.45359236f;
		}

		public static float KgToGameWeight(float kg)
		{
			return 1f + Mathf.Max(0f, kg) / 0.45359236f / 105f;
		}

		public static float GameWeightToLb(float gameWeight)
		{
			return Mathf.Max(0f, gameWeight - 1f) * 105f;
		}
	}
	public enum WeightUnit
	{
		Kilograms,
		Pounds,
		Both
	}
}
namespace WeightsRebalanced.Presets
{
	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;
				}
				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(string.Format(CultureInfo.InvariantCulture, "{0}={1:F1}", itemWeight2.Key, itemWeight2.Value));
				}
				string text = Path.Combine(_presetsDirectory, SanitizeFileName(presetName) + ".txt");
				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)
		{
			try
			{
				string text = Path.Combine(_presetsDirectory, SanitizeFileName(presetName) + ".txt");
				if (!File.Exists(text))
				{
					LogHelper.LogWarning("Preset file not found: " + text);
					return false;
				}
				Dictionary<string, float> dictionary = new Dictionary<string, float>();
				string[] array = File.ReadAllLines(text);
				foreach (string text2 in array)
				{
					if (!string.IsNullOrWhiteSpace(text2) && !text2.StartsWith("#"))
					{
						string[] array2 = text2.Split('=');
						if (array2.Length == 2 && float.TryParse(array2[1].Trim().Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
						{
							dictionary[array2[0].Trim()] = result;
						}
					}
				}
				if (dictionary.Count == 0)
				{
					LogHelper.LogError("Invalid preset file: " + text);
					return false;
				}
				ApplyPreset(dictionary);
				LogHelper.LogInfo($"Loaded preset '{presetName}' with {dictionary.Count} items.");
				return true;
			}
			catch (Exception ex)
			{
				LogHelper.LogError("Failed to load preset '" + presetName + "': " + ex.Message);
				return false;
			}
		}

		private static void ApplyPreset(Dictionary<string, float> weights)
		{
			int num = 0;
			int num2 = 0;
			ConfigWatcher.Suppress = true;
			try
			{
				foreach (KeyValuePair<string, float> weight in weights)
				{
					float value = ConfigValidator.ClampWeight(weight.Value, weight.Key);
					if (Plugin.ItemWeights.TryGetValue(weight.Key, out var value2))
					{
						value2.Value = value;
						num++;
					}
					else
					{
						num2++;
					}
				}
			}
			finally
			{
				ConfigWatcher.Suppress = false;
			}
			WeightApplier.ApplyAllItems();
			WeightSyncManager.BroadcastFullSyncIfHost();
			LogHelper.LogInfo($"Applied preset: {num} items updated, {num2} items not currently loaded.");
		}

		public static List<string> GetAvailablePresets()
		{
			List<string> list = new List<string>();
			try
			{
				if (Directory.Exists(_presetsDirectory))
				{
					string[] files = Directory.GetFiles(_presetsDirectory, "*.txt");
					foreach (string path in files)
					{
						list.Add(Path.GetFileNameWithoutExtension(path));
					}
				}
			}
			catch (Exception ex)
			{
				LogHelper.LogError("Failed to list presets: " + ex.Message);
			}
			return list;
		}

		private static string SanitizeFileName(string fileName)
		{
			char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
			foreach (char oldChar in invalidFileNameChars)
			{
				fileName = fileName.Replace(oldChar, '_');
			}
			return fileName;
		}
	}
	[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.1.0";
		}
	}
}
namespace WeightsRebalanced.Patches
{
	[HarmonyPatch]
	internal static class ItemSpawnPatches
	{
		[HarmonyPatch(typeof(StartOfRound), "Awake")]
		[HarmonyPostfix]
		private static void StartOfRound_Awake_Postfix()
		{
			CategoryDetector.CacheStoreItems();
			ItemClassifier.RefreshModdedItems();
			WeightApplier.ApplyAllItems();
			LogSummary();
		}

		[HarmonyPatch(typeof(RoundManager), "SpawnScrapInLevel")]
		[HarmonyPrefix]
		private static void SpawnScrapInLevel_Prefix()
		{
			WeightApplier.ApplyAllItems();
		}

		private static void LogSummary()
		{
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			using (Dictionary<string, ItemCategory>.ValueCollection.Enumerator enumerator = Plugin.ItemCategories.Values.GetEnumerator())
			{
				while (enumerator.MoveNext())
				{
					switch (enumerator.Current)
					{
					case ItemCategory.Scrap:
						num++;
						break;
					case ItemCategory.Equipment:
						num2++;
						break;
					case ItemCategory.Store:
						num3++;
						break;
					case ItemCategory.Modded:
						num4++;
						break;
					}
				}
			}
			LogHelper.LogInfo($"Weights applied: {num} scrap, {num2} equipment, {num3} store, {num4} modded items.");
		}
	}
	[HarmonyPatch]
	internal static class NetworkPatches
	{
		[HarmonyPatch(typeof(NetworkManager), "StartHost")]
		[HarmonyPostfix]
		private static void StartHost_Postfix()
		{
			WeightSyncManager.OnSessionStarted();
		}

		[HarmonyPatch(typeof(NetworkManager), "StartClient")]
		[HarmonyPostfix]
		private static void StartClient_Postfix()
		{
			WeightSyncManager.OnSessionStarted();
		}

		[HarmonyPatch(typeof(NetworkManager), "Shutdown")]
		[HarmonyPrefix]
		private static void Shutdown_Prefix()
		{
			WeightSyncManager.OnSessionShutdown();
		}
	}
	[HarmonyPatch]
	internal static class WeightPatches
	{
		[HarmonyPatch(typeof(HUDManager), "UpdateWeightCounter")]
		[HarmonyPostfix]
		private static void UpdateWeightCounter_Postfix(HUDManager __instance)
		{
			if (Plugin.DisplayUnit.Value != WeightUnit.Pounds && !((Object)(object)__instance.weightCounter == (Object)null))
			{
				PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController;
				if (!((Object)(object)val == (Object)null))
				{
					float num = Mathf.Clamp(val.carryWeight - 1f, 0f, 100f) * 105f;
					float num2 = num * 0.45359236f;
					((TMP_Text)__instance.weightCounter).text = ((Plugin.DisplayUnit.Value == WeightUnit.Both) ? $"{num2:F1} kg ({Mathf.RoundToInt(num)} lb)" : $"{num2:F1} kg");
				}
			}
		}
	}
}
namespace WeightsRebalanced.Networking
{
	public static class WeightSyncManager
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__OnReceiveMessage;

			public static Action<ulong> <1>__OnClientConnected;
		}

		private const string MessageName = "WeightsRebalanced_SyncWeights";

		private const byte FullSyncMessage = 1;

		private const byte SingleWeightMessage = 2;

		private static readonly Dictionary<string, float> _syncedOverrides = new Dictionary<string, float>();

		private static bool _clientConnectedHooked;

		public static bool HasOverrides => _syncedOverrides.Count > 0;

		public static bool TryGetSyncedWeight(string itemName, out float weightKg)
		{
			return _syncedOverrides.TryGetValue(itemName, out weightKg);
		}

		public static void OnSessionStarted()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton == (Object)null)
			{
				return;
			}
			try
			{
				CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager;
				if (customMessagingManager != null)
				{
					object obj = <>O.<0>__OnReceiveMessage;
					if (obj == null)
					{
						HandleNamedMessageDelegate val = OnReceiveMessage;
						<>O.<0>__OnReceiveMessage = val;
						obj = (object)val;
					}
					customMessagingManager.RegisterNamedMessageHandler("WeightsRebalanced_SyncWeights", (HandleNamedMessageDelegate)obj);
				}
				LogHelper.LogInfo("Weight sync message handler registered for this session.");
			}
			catch (Exception ex)
			{
				LogHelper.LogError("Failed to register weight sync handler: " + ex.Message);
			}
			if (singleton.IsHost && !_clientConnectedHooked)
			{
				singleton.OnClientConnectedCallback += OnClientConnected;
				_clientConnectedHooked = true;
			}
		}

		public static void OnSessionShutdown()
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if (_clientConnectedHooked && (Object)(object)singleton != (Object)null)
			{
				singleton.OnClientConnectedCallback -= OnClientConnected;
				_clientConnectedHooked = false;
			}
			if (_syncedOverrides.Count > 0)
			{
				LogHelper.LogInfo($"Disconnected - dropping {_syncedOverrides.Count} synced weights, restoring local configuration.");
				_syncedOverrides.Clear();
				WeightApplier.ApplyAllItems();
			}
		}

		private static void OnClientConnected(ulong clientId)
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if (!((Object)(object)singleton == (Object)null) && singleton.IsHost && clientId != singleton.LocalClientId)
			{
				LogHelper.LogInfo($"Client {clientId} connected - sending weight sync.");
				SendMessage(SerializeFullSync(), clientId);
			}
		}

		public static void BroadcastFullSyncIfHost()
		{
			if (IsHost())
			{
				SendMessageToAllClients(SerializeFullSync());
			}
		}

		public static void BroadcastSingleWeightIfHost(string itemName, float weightKg)
		{
			if (IsHost())
			{
				SendMessageToAllClients(SerializeSingleWeight(itemName, weightKg));
			}
		}

		private static void SendMessageToAllClients(byte[] payload)
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton == (Object)null)
			{
				return;
			}
			foreach (ulong connectedClientsId in singleton.ConnectedClientsIds)
			{
				if (connectedClientsId != singleton.LocalClientId)
				{
					SendMessage(payload, connectedClientsId);
				}
			}
		}

		private unsafe static void SendMessage(byte[] payload, ulong clientId)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				FastBufferWriter val = default(FastBufferWriter);
				((FastBufferWriter)(ref val))..ctor(payload.Length + 4, (Allocator)2, -1);
				try
				{
					int num = payload.Length;
					((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
					((FastBufferWriter)(ref val)).WriteBytesSafe(payload, -1, 0);
					NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("WeightsRebalanced_SyncWeights", clientId, val, (NetworkDelivery)4);
					LogHelper.LogDebug($"Sent {payload.Length} bytes of weight data to client {clientId}.");
				}
				finally
				{
					((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
				}
			}
			catch (Exception ex)
			{
				LogHelper.LogError($"Failed to send weight sync to client {clientId}: {ex.Message}");
			}
		}

		private static void OnReceiveMessage(ulong senderId, FastBufferReader reader)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (IsHost())
			{
				return;
			}
			try
			{
				int num = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
				byte[] payload = new byte[num];
				((FastBufferReader)(ref reader)).ReadBytesSafe(ref payload, num, 0);
				DeserializeAndApply(payload);
			}
			catch (Exception ex)
			{
				LogHelper.LogError("Failed to process weight sync: " + ex.Message);
			}
		}

		private static byte[] SerializeFullSync()
		{
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
			binaryWriter.Write((byte)1);
			binaryWriter.Write("2.1.0");
			binaryWriter.Write(Plugin.CurrentItemWeightsKg.Count);
			foreach (KeyValuePair<string, float> item in Plugin.CurrentItemWeightsKg)
			{
				binaryWriter.Write(item.Key);
				binaryWriter.Write(item.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 DeserializeAndApply(byte[] payload)
		{
			using MemoryStream input = new MemoryStream(payload);
			using BinaryReader binaryReader = new BinaryReader(input);
			switch (binaryReader.ReadByte())
			{
			case 1:
			{
				string arg = binaryReader.ReadString();
				int num2 = binaryReader.ReadInt32();
				LogHelper.LogInfo($"Receiving full weight sync from host (mod version {arg}, {num2} items).");
				for (int i = 0; i < num2; i++)
				{
					string key = binaryReader.ReadString();
					float value = binaryReader.ReadSingle();
					_syncedOverrides[key] = ConfigValidator.ClampWeight(value);
				}
				WeightApplier.ApplyAllItems();
				LogHelper.LogInfo($"Applied {num2} synced weights (local config file untouched).");
				break;
			}
			case 2:
			{
				string text = binaryReader.ReadString();
				float num = ConfigValidator.ClampWeight(binaryReader.ReadSingle());
				_syncedOverrides[text] = num;
				WeightApplier.ApplyAllItems();
				LogHelper.LogDebug($"Applied synced weight update: '{text}' = {num:F1} kg.");
				break;
			}
			}
		}

		public static bool IsHost()
		{
			if ((Object)(object)NetworkManager.Singleton != (Object)null)
			{
				return NetworkManager.Singleton.IsHost;
			}
			return false;
		}

		public static bool IsSyncedClient()
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton != (Object)null && singleton.IsClient)
			{
				return !singleton.IsHost;
			}
			return false;
		}
	}
}
namespace WeightsRebalanced.ItemDetection
{
	public static class CategoryDetector
	{
		private static readonly 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 (_storeItemNames.Contains(item.itemName))
			{
				return ItemCategory.Store;
			}
			return ItemCategory.Equipment;
		}

		public static void CacheStoreItems()
		{
			Terminal val = Object.FindObjectOfType<Terminal>();
			if ((Object)(object)val == (Object)null || val.buyableItemsList == null)
			{
				return;
			}
			_storeItemNames.Clear();
			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.");
		}
	}
	public static class DiagnosticCommands
	{
		public static void PrintAllItemsWithOrigin()
		{
			LogHelper.LogInfo("=== Item Detection Diagnostics ===");
			LogHelper.LogInfo(ItemClassifier.GetDiagnostics());
			if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)StartOfRound.Instance.allItemsList == (Object)null)
			{
				LogHelper.LogInfo("Item list not available yet (start or join a game first).");
				return;
			}
			foreach (Item items in StartOfRound.Instance.allItemsList.itemsList)
			{
				if (!((Object)(object)items == (Object)null) && !string.IsNullOrEmpty(items.itemName))
				{
					ItemOrigin itemOrigin = ItemClassifier.GetItemOrigin(items);
					ItemCategory itemCategory = CategoryDetector.DetermineCategory(items);
					float vanillaKg;
					string text = (WeightApplier.TryGetVanillaKg(items, out vanillaKg) ? $"{vanillaKg:F1} kg" : "?");
					float num = WeightMath.GameWeightToKg(items.weight);
					LogHelper.LogInfo($"[{itemOrigin}/{itemCategory}] '{items.itemName}': vanilla {text}, current {num:F1} kg");
				}
			}
			LogHelper.LogInfo("=== End of diagnostics ===");
		}

		public static void PrintNetworkStatus()
		{
			if (WeightSyncManager.IsSyncedClient())
			{
				LogHelper.LogInfo(WeightSyncManager.HasOverrides ? "Using HOST'S weight configuration (synced from server)." : "Connected as client, but no sync received yet - using LOCAL configuration.");
			}
			else if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.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.");
			}
		}
	}
	public static class ItemClassifier
	{
		private static readonly HashSet<string> _moddedItemNames = new HashSet<string>();

		private static bool _lethalLibChecked;

		private static Type _lethalLibItems;

		public static void Initialize()
		{
			LogHelper.LogDebug("Item classifier initialized (LethalLib lookup happens lazily).");
		}

		public static void RefreshModdedItems()
		{
			if (!_lethalLibChecked)
			{
				_lethalLibChecked = true;
				_lethalLibItems = Type.GetType("LethalLib.Modules.Items, LethalLib");
				LogHelper.LogInfo((_lethalLibItems != null) ? "LethalLib detected - modded items will be classified via its registration lists." : "LethalLib not present - all items will be treated as vanilla unless registered later.");
			}
			if (_lethalLibItems == null)
			{
				return;
			}
			_moddedItemNames.Clear();
			string[] array = new string[3] { "scrapItems", "shopItems", "plainItems" };
			foreach (string text in array)
			{
				try
				{
					FieldInfo field = _lethalLibItems.GetField(text, BindingFlags.Static | BindingFlags.Public);
					if (field == null || !(field.GetValue(null) is IEnumerable enumerable))
					{
						continue;
					}
					foreach (object item in enumerable)
					{
						if (item != null)
						{
							object? obj = item.GetType().GetField("item", BindingFlags.Instance | BindingFlags.Public)?.GetValue(item);
							Item val = (Item)((obj is Item) ? obj : null);
							if (val != null && !string.IsNullOrEmpty(val.itemName))
							{
								_moddedItemNames.Add(val.itemName);
							}
						}
					}
				}
				catch (Exception ex)
				{
					LogHelper.LogDebug("Failed to read LethalLib list '" + text + "': " + ex.Message);
				}
			}
			LogHelper.LogInfo($"Detected {_moddedItemNames.Count} modded items via LethalLib.");
		}

		public static ItemOrigin GetItemOrigin(Item item)
		{
			if ((Object)(object)item == (Object)null || string.IsNullOrEmpty(item.itemName))
			{
				return ItemOrigin.Unknown;
			}
			if (!_moddedItemNames.Contains(item.itemName))
			{
				return ItemOrigin.Vanilla;
			}
			return ItemOrigin.Modded;
		}

		public static string GetDiagnostics()
		{
			return $"LethalLib present: {_lethalLibItems != null}\nKnown modded items: {_moddedItemNames.Count}";
		}
	}
	public enum ItemOrigin
	{
		Unknown,
		Vanilla,
		Modded
	}
}
namespace WeightsRebalanced.HotReload
{
	public static class ConfigWatcher
	{
		private static bool _initialized;

		public static bool Suppress { get; set; }

		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 (Suppress)
			{
				return;
			}
			string section = e.ChangedSetting.Definition.Section;
			string key = e.ChangedSetting.Definition.Key;
			if (Plugin.ConfigKeyToItemName.TryGetValue(key, out var value) && IsWeightSection(section))
			{
				LogHelper.LogDebug($"Config changed: '{value}' = {(float)e.ChangedSetting.BoxedValue:F1} kg");
				WeightApplier.ApplyAllItems();
				if (Plugin.CurrentItemWeightsKg.TryGetValue(value, out var value2))
				{
					WeightSyncManager.BroadcastSingleWeightIfHost(value, value2);
				}
			}
			else if (section == "Multipliers" || key == "Enable Weight Modifications")
			{
				LogHelper.LogDebug("Config changed: " + section + "/" + key + " - reapplying all weights.");
				WeightApplier.ApplyAllItems();
				WeightSyncManager.BroadcastFullSyncIfHost();
			}
		}

		private static bool IsWeightSection(string section)
		{
			switch (section)
			{
			default:
				return section == "Item Weights";
			case "Scrap Items":
			case "Equipment":
			case "Store Items":
			case "Modded Items":
				return true;
			}
		}
	}
}