Decompiled source of Exhausted Batteries v1.0.0

ExhaustedBatteries.dll

Decompiled 2 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;

[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("ExhaustedBatteries")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+fe06e0258f1397ec38ac6c6dfe6b28fe265d83ae")]
[assembly: AssemblyProduct("Exhausted Batteries")]
[assembly: AssemblyTitle("ExhaustedBatteries")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ExhaustedBatteries
{
	internal static class Loc
	{
		internal enum Language
		{
			Auto,
			English,
			Russian
		}

		private static bool resolved;

		private static bool russian;

		private static bool IsRussian
		{
			get
			{
				if (!resolved)
				{
					Resolve();
				}
				return russian;
			}
		}

		internal static string ChargerTipHeader
		{
			get
			{
				if (!IsRussian)
				{
					return "Charging Station";
				}
				return "Зарядная станция";
			}
		}

		internal static string NoChargesLeft
		{
			get
			{
				if (!IsRussian)
				{
					return "No charges left" + (Plugin.ResetChargesEachDay.Value ? " for today." : ".");
				}
				if (!Plugin.ResetChargesEachDay.Value)
				{
					return "Заряды закончились.";
				}
				return "Заряды на сегодня закончились.";
			}
		}

		internal static void Invalidate()
		{
			resolved = false;
		}

		private static void Resolve()
		{
			resolved = true;
			switch ((Plugin.LanguageSetting != null) ? Plugin.LanguageSetting.Value : Language.Auto)
			{
			case Language.English:
				russian = false;
				break;
			case Language.Russian:
				russian = true;
				break;
			default:
				russian = DetectRussian();
				break;
			}
		}

		private static bool DetectRussian()
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Invalid comparison between Unknown and I4
			try
			{
				foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
				{
					string s = ((pluginInfo.Key != null) ? pluginInfo.Key.ToLowerInvariant() : "");
					PluginInfo value = pluginInfo.Value;
					object obj;
					if (value == null)
					{
						obj = null;
					}
					else
					{
						BepInPlugin metadata = value.Metadata;
						obj = ((metadata != null) ? metadata.Name : null);
					}
					string s2 = ((obj != null) ? pluginInfo.Value.Metadata.Name.ToLowerInvariant() : "");
					if (Marks(s) || Marks(s2))
					{
						return true;
					}
				}
			}
			catch
			{
			}
			try
			{
				if ((int)Application.systemLanguage == 30)
				{
					return true;
				}
			}
			catch
			{
			}
			return false;
		}

		private static bool Marks(string s)
		{
			if (!s.Contains("rtlc") && !s.Contains("rulethal") && !s.Contains("russian") && !s.Contains("русск"))
			{
				return s.Contains("russiantranslation");
			}
			return true;
		}
	}
	internal static class ConfigSync
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__OnHostReceivedRequest;

			public static HandleNamedMessageDelegate <1>__OnClientReceivedConfig;
		}

		private const string RequestMsg = "ExhaustedBatteries_RequestConfig";

		private const string ReceiveMsg = "ExhaustedBatteries_ReceiveConfig";

		private static byte[] localBlob;

		private static byte[] hostBlob;

		internal static bool IsActive { get; private set; }

		internal static bool Applying { get; private set; }

		internal static bool IsSyncedClient => localBlob != null;

		internal static void OnLocalConnect()
		{
			RevertToLocal();
			NetworkManager singleton = NetworkManager.Singleton;
			if (!((Object)(object)singleton == (Object)null))
			{
				if (singleton.IsServer)
				{
					SetupHost();
				}
				else
				{
					SetupClient();
				}
			}
		}

		private static void SetupHost()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			CustomMessagingManager customMessagingManager = NetworkManager.Singleton.CustomMessagingManager;
			SafeUnregister(customMessagingManager);
			object obj = <>O.<0>__OnHostReceivedRequest;
			if (obj == null)
			{
				HandleNamedMessageDelegate val = OnHostReceivedRequest;
				<>O.<0>__OnHostReceivedRequest = val;
				obj = (object)val;
			}
			customMessagingManager.RegisterNamedMessageHandler("ExhaustedBatteries_RequestConfig", (HandleNamedMessageDelegate)obj);
			IsActive = true;
			Plugin.Log.LogInfo((object)"[Sync] Host: local config is authoritative.");
			Plugin.ReapplyAll();
		}

		private unsafe static void SetupClient()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			CustomMessagingManager customMessagingManager = NetworkManager.Singleton.CustomMessagingManager;
			SafeUnregister(customMessagingManager);
			object obj = <>O.<1>__OnClientReceivedConfig;
			if (obj == null)
			{
				HandleNamedMessageDelegate val = OnClientReceivedConfig;
				<>O.<1>__OnClientReceivedConfig = val;
				obj = (object)val;
			}
			customMessagingManager.RegisterNamedMessageHandler("ExhaustedBatteries_ReceiveConfig", (HandleNamedMessageDelegate)obj);
			IsActive = false;
			FastBufferWriter val2 = default(FastBufferWriter);
			((FastBufferWriter)(ref val2))..ctor(4, (Allocator)2, -1);
			try
			{
				customMessagingManager.SendNamedMessage("ExhaustedBatteries_RequestConfig", 0uL, val2, (NetworkDelivery)4);
				Plugin.Log.LogInfo((object)"[Sync] Client: requested host config.");
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val2))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		internal static void RevertToLocal()
		{
			SafeUnregister(((Object)(object)NetworkManager.Singleton != (Object)null) ? NetworkManager.Singleton.CustomMessagingManager : null);
			if (localBlob != null)
			{
				Apply(localBlob);
				localBlob = null;
			}
			hostBlob = null;
			IsActive = false;
		}

		internal static void EnforceHostAuthority()
		{
			if (IsSyncedClient && hostBlob != null)
			{
				Apply(hostBlob);
			}
		}

		private unsafe static void OnHostReceivedRequest(ulong clientId, FastBufferReader reader)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsServer)
			{
				return;
			}
			byte[] array = Serialize();
			int num = array.Length;
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(num + 4, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
				((FastBufferWriter)(ref val)).WriteBytesSafe(array, num, 0);
				NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("ExhaustedBatteries_ReceiveConfig", clientId, val, (NetworkDelivery)4);
				Plugin.Log.LogInfo((object)$"[Sync] Host: sent config to client {clientId} ({num} bytes).");
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private static void OnClientReceivedConfig(ulong _, FastBufferReader reader)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((FastBufferReader)(ref reader)).TryBeginRead(4))
				{
					return;
				}
				int num = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
				if (num >= 0 && ((FastBufferReader)(ref reader)).TryBeginRead(num))
				{
					byte[] data = new byte[num];
					((FastBufferReader)(ref reader)).ReadBytesSafe(ref data, num, 0);
					if (localBlob == null)
					{
						localBlob = Serialize();
					}
					hostBlob = data;
					IsActive = true;
					Apply(data);
					Plugin.ReapplyAll();
					Plugin.Log.LogInfo((object)"[Sync] Client: applied host config.");
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Sync] receive error: {arg}");
			}
		}

		private static void SafeUnregister(CustomMessagingManager cmm)
		{
			if (cmm == null)
			{
				return;
			}
			try
			{
				cmm.UnregisterNamedMessageHandler("ExhaustedBatteries_RequestConfig");
			}
			catch
			{
			}
			try
			{
				cmm.UnregisterNamedMessageHandler("ExhaustedBatteries_ReceiveConfig");
			}
			catch
			{
			}
		}

		private static string F(float v)
		{
			return v.ToString("R", CultureInfo.InvariantCulture);
		}

		private static byte[] Serialize()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("gm=").Append(F(Plugin.GlobalMultiplier.Value)).Append('\n');
			stringBuilder.Append("ei=").Append(Plugin.EnableIndividualMultipliers.Value).Append('\n');
			stringBuilder.Append("sd=").Append(Plugin.SpawnStoreItemsDischarged.Value).Append('\n');
			stringBuilder.Append("ic=").Append(F(Plugin.InitialChargeMultiplier.Value)).Append('\n');
			stringBuilder.Append("mc=").Append(Plugin.MaxCharges.Value.ToString(CultureInfo.InvariantCulture)).Append('\n');
			stringBuilder.Append("rd=").Append(Plugin.ResetChargesEachDay.Value).Append('\n');
			stringBuilder.Append("fd=").Append(Plugin.EnableFlashlightDimming.Value).Append('\n');
			stringBuilder.Append("ds=").Append(F(Plugin.DimStartCharge.Value)).Append('\n');
			stringBuilder.Append("mb=").Append(F(Plugin.MinBrightness.Value)).Append('\n');
			foreach (ConfigEntry<float> itemEntry in Plugin.ItemEntries)
			{
				stringBuilder.Append("i:").Append(((ConfigEntryBase)itemEntry).Definition.Key).Append('=')
					.Append(F(itemEntry.Value))
					.Append('\n');
			}
			return Encoding.UTF8.GetBytes(stringBuilder.ToString());
		}

		private static void Apply(byte[] data)
		{
			Applying = true;
			bool saveOnConfigSet = Plugin.Cfg.SaveOnConfigSet;
			Plugin.Cfg.SaveOnConfigSet = false;
			try
			{
				string[] array = Encoding.UTF8.GetString(data).Split('\n');
				for (int i = 0; i < array.Length; i++)
				{
					string text = array[i].Trim();
					if (text.Length != 0)
					{
						int num = text.IndexOf('=');
						if (num > 0)
						{
							ApplyOne(text.Substring(0, num), text.Substring(num + 1));
						}
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Sync] apply error: {arg}");
			}
			finally
			{
				Plugin.Cfg.SaveOnConfigSet = saveOnConfigSet;
				Applying = false;
			}
		}

		private static void ApplyOne(string key, string val)
		{
			if (key.StartsWith("i:", StringComparison.Ordinal))
			{
				string text = key.Substring(2);
				Plugin.EnsureIndividualEntry(text);
				ConfigEntry<float> val2 = Plugin.FindIndividual(text);
				if (val2 != null && TryF(val, out var f))
				{
					val2.Value = f;
				}
			}
			else
			{
				if (key == null)
				{
					return;
				}
				int length = key.Length;
				if (length != 2)
				{
					return;
				}
				switch (key[0])
				{
				case 'g':
				{
					if (key == "gm" && TryF(val, out var f5))
					{
						Plugin.GlobalMultiplier.Value = f5;
					}
					break;
				}
				case 'e':
				{
					if (key == "ei" && bool.TryParse(val, out var result4))
					{
						Plugin.EnableIndividualMultipliers.Value = result4;
					}
					break;
				}
				case 's':
				{
					if (key == "sd" && bool.TryParse(val, out var result3))
					{
						Plugin.SpawnStoreItemsDischarged.Value = result3;
					}
					break;
				}
				case 'i':
				{
					if (key == "ic" && TryF(val, out var f3))
					{
						Plugin.InitialChargeMultiplier.Value = f3;
					}
					break;
				}
				case 'm':
				{
					int result;
					if (!(key == "mc"))
					{
						if (key == "mb" && TryF(val, out var f4))
						{
							Plugin.MinBrightness.Value = f4;
						}
					}
					else if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out result))
					{
						Plugin.MaxCharges.Value = result;
					}
					break;
				}
				case 'r':
				{
					if (key == "rd" && bool.TryParse(val, out var result5))
					{
						Plugin.ResetChargesEachDay.Value = result5;
					}
					break;
				}
				case 'f':
				{
					if (key == "fd" && bool.TryParse(val, out var result2))
					{
						Plugin.EnableFlashlightDimming.Value = result2;
					}
					break;
				}
				case 'd':
				{
					if (key == "ds" && TryF(val, out var f2))
					{
						Plugin.DimStartCharge.Value = f2;
					}
					break;
				}
				}
			}
		}

		private static bool TryF(string s, out float f)
		{
			return float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out f);
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")]
	internal static class ConfigSyncConnectPatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			ConfigSync.OnLocalConnect();
		}
	}
	[HarmonyPatch(typeof(FlashlightItem), "Update")]
	internal static class FlashlightDimPatch
	{
		private static readonly Dictionary<Light, float> baseIntensities = new Dictionary<Light, float>();

		private static bool loggedOnce;

		[HarmonyPostfix]
		[HarmonyPriority(200)]
		private static void Postfix(FlashlightItem __instance)
		{
			if (!ConfigSync.IsActive || !Plugin.EnableFlashlightDimming.Value)
			{
				return;
			}
			Battery insertedBattery = ((GrabbableObject)__instance).insertedBattery;
			if (insertedBattery != null)
			{
				float num = Brightness(insertedBattery.charge);
				Apply(__instance.flashlightBulb, num);
				Apply(__instance.flashlightBulbGlow, num);
				if (Plugin.VerboseLogging.Value && !loggedOnce)
				{
					loggedOnce = true;
					float num2 = (((Object)(object)__instance.flashlightBulb != (Object)null) ? __instance.flashlightBulb.intensity : (-1f));
					Plugin.Log.LogInfo((object)($"[Flashlight] dimming active: charge={insertedBattery.charge:0.##}, " + $"factor={num:0.##}, bulb.intensity={num2:0.##}"));
				}
			}
		}

		private static void Apply(Light light, float factor)
		{
			if (!((Object)(object)light == (Object)null))
			{
				if (!baseIntensities.TryGetValue(light, out var value) || light.intensity > value)
				{
					value = light.intensity;
					baseIntensities[light] = value;
				}
				light.intensity = value * factor;
			}
		}

		private static float Brightness(float charge)
		{
			float value = Plugin.DimStartCharge.Value;
			float value2 = Plugin.MinBrightness.Value;
			charge = Mathf.Clamp01(charge);
			if (value <= 0f)
			{
				return 1f;
			}
			if (charge >= value)
			{
				return 1f;
			}
			return Mathf.Lerp(value2, 1f, charge / value);
		}

		internal static void OnSettingsChanged()
		{
			if (Plugin.EnableFlashlightDimming.Value)
			{
				return;
			}
			foreach (KeyValuePair<Light, float> baseIntensity in baseIntensities)
			{
				if ((Object)(object)baseIntensity.Key != (Object)null)
				{
					baseIntensity.Key.intensity = baseIntensity.Value;
				}
			}
		}
	}
	[HarmonyPatch(typeof(GrabbableObject), "Start")]
	internal static class GrabbableObjectPatch
	{
		private static readonly Dictionary<Item, float> baseUsages = new Dictionary<Item, float>();

		private static bool reapplying;

		[HarmonyPostfix]
		[HarmonyPriority(200)]
		private static void Postfix(GrabbableObject __instance)
		{
			try
			{
				if (!ConfigSync.IsActive)
				{
					return;
				}
				Item itemProperties = __instance.itemProperties;
				if ((Object)(object)itemProperties == (Object)null || !itemProperties.requiresBattery || __instance.insertedBattery == null || itemProperties.batteryUsage <= 0f)
				{
					return;
				}
				string usedKey;
				bool individual;
				float num = ResolveMultiplier(__instance, itemProperties, out usedKey, out individual);
				float num2 = ApplyCapacity(itemProperties, num);
				Battery insertedBattery = __instance.insertedBattery;
				bool flag = false;
				if (!itemProperties.isScrap && Plugin.SpawnStoreItemsDischarged.Value)
				{
					insertedBattery.charge = 0f;
					insertedBattery.empty = true;
					flag = true;
				}
				else
				{
					float value = Plugin.InitialChargeMultiplier.Value;
					if (Math.Abs(value - 1f) > 0.0001f)
					{
						insertedBattery.charge = Mathf.Clamp01(insertedBattery.charge * value);
						insertedBattery.empty = insertedBattery.charge <= 0f;
					}
				}
				if (Plugin.VerboseLogging.Value)
				{
					Plugin.Log.LogInfo((object)($"[Battery] {Describe(__instance, itemProperties)} | x{num:0.###} " + "(" + (individual ? ("individual:" + usedKey) : "global") + ") | " + $"usage {num2:0.#}s -> {itemProperties.batteryUsage:0.#}s | " + string.Format("charge={0:0.##}{1}", insertedBattery.charge, flag ? " (discharged)" : "")));
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Error applying battery settings: {arg}");
			}
		}

		private static float ApplyCapacity(Item item, float mult)
		{
			if (!baseUsages.TryGetValue(item, out var value))
			{
				value = item.batteryUsage;
				baseUsages[item] = value;
			}
			item.batteryUsage = Mathf.Max(0.01f, value * mult);
			return value;
		}

		internal static void ReapplyAllCapacities()
		{
			if (!ConfigSync.IsActive || reapplying)
			{
				return;
			}
			reapplying = true;
			try
			{
				GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>();
				foreach (GrabbableObject val in array)
				{
					Item val2 = (((Object)(object)val != (Object)null) ? val.itemProperties : null);
					if (!((Object)(object)val2 == (Object)null) && val2.requiresBattery && !(val2.batteryUsage <= 0f))
					{
						string usedKey;
						bool individual;
						float mult = ResolveMultiplier(val, val2, out usedKey, out individual);
						ApplyCapacity(val2, mult);
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Error while re-applying capacities: {arg}");
			}
			finally
			{
				reapplying = false;
			}
		}

		private static float ResolveMultiplier(GrabbableObject obj, Item item, out string usedKey, out bool individual)
		{
			usedKey = null;
			individual = false;
			Plugin.EnsureIndividualEntry(Plugin.SanitizeKey((!string.IsNullOrEmpty(item.itemName)) ? item.itemName : ((object)obj).GetType().Name));
			if (Plugin.EnableIndividualMultipliers.Value)
			{
				foreach (string item2 in CandidateKeys(obj, item))
				{
					ConfigEntry<float> val = Plugin.FindIndividual(item2);
					if (val != null && val.Value >= 0f)
					{
						usedKey = ((ConfigEntryBase)val).Definition.Key;
						individual = true;
						return val.Value;
					}
				}
			}
			return Plugin.GlobalMultiplier.Value;
		}

		private static IEnumerable<string> CandidateKeys(GrabbableObject obj, Item item)
		{
			if (!string.IsNullOrEmpty(item.itemName))
			{
				yield return item.itemName;
			}
			if ((Object)(object)((Component)obj).gameObject != (Object)null)
			{
				string text = ((Object)((Component)obj).gameObject).name.Replace("(Clone)", "").Trim();
				if (!string.IsNullOrEmpty(text))
				{
					yield return text;
				}
			}
			yield return ((object)obj).GetType().Name;
		}

		private static string Describe(GrabbableObject obj, Item item)
		{
			return (string.IsNullOrEmpty(item.itemName) ? "?" : item.itemName) + " " + $"[type={((object)obj).GetType().Name}, scrap={item.isScrap}]";
		}
	}
	[HarmonyPatch(typeof(ItemCharger), "ChargeItem")]
	internal static class ItemChargerPatch
	{
		internal static int chargesUsed;

		private static readonly Dictionary<InteractTrigger, string> baseTips = new Dictionary<InteractTrigger, string>();

		[HarmonyPrefix]
		private static bool Prefix(ItemCharger __instance)
		{
			if (!ConfigSync.IsActive)
			{
				return true;
			}
			int value = Plugin.MaxCharges.Value;
			if (value <= 0)
			{
				return true;
			}
			PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null);
			GrabbableObject val2 = (((Object)(object)val != (Object)null) ? val.currentlyHeldObjectServer : null);
			if ((Object)(object)val2 == (Object)null || (Object)(object)val2.itemProperties == (Object)null || !val2.itemProperties.requiresBattery)
			{
				return true;
			}
			if (chargesUsed >= value)
			{
				if ((Object)(object)HUDManager.Instance != (Object)null)
				{
					HUDManager.Instance.DisplayTip(Loc.ChargerTipHeader, Loc.NoChargesLeft, true, false, "LC_Tip1");
				}
				RefreshTip(__instance);
				return false;
			}
			chargesUsed++;
			if (Plugin.VerboseLogging.Value)
			{
				Plugin.Log.LogInfo((object)$"[Charger] used {chargesUsed}/{value}");
			}
			RefreshTip(__instance);
			return true;
		}

		internal static void RefreshTip(ItemCharger charger)
		{
			if ((Object)(object)charger == (Object)null)
			{
				return;
			}
			InteractTrigger triggerScript = charger.triggerScript;
			if (!((Object)(object)triggerScript == (Object)null))
			{
				if (!baseTips.TryGetValue(triggerScript, out var value))
				{
					value = triggerScript.hoverTip;
					baseTips[triggerScript] = value;
				}
				if (ConfigSync.IsActive && Plugin.MaxCharges.Value > 0)
				{
					int num = Mathf.Max(0, Plugin.MaxCharges.Value - chargesUsed);
					triggerScript.hoverTip = $"{value} [{num}]";
				}
				else
				{
					triggerScript.hoverTip = value;
				}
			}
		}

		internal static void RefreshAllTips()
		{
			ItemCharger[] array = Object.FindObjectsOfType<ItemCharger>();
			for (int i = 0; i < array.Length; i++)
			{
				RefreshTip(array[i]);
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "StartGame")]
	internal static class ChargerDailyResetPatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			if (Plugin.ResetChargesEachDay.Value)
			{
				ItemChargerPatch.chargesUsed = 0;
				if (Plugin.VerboseLogging.Value)
				{
					Plugin.Log.LogInfo((object)"[Charger] daily charges reset.");
				}
			}
			ItemChargerPatch.RefreshAllTips();
		}
	}
	internal static class ModInfo
	{
		public const string Guid = "ExhaustedBatteries";

		public const string Name = "Exhausted Batteries";

		public const string Version = "1.0.0";
	}
	[BepInPlugin("ExhaustedBatteries", "Exhausted Batteries", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		public const string GeneralSection = "General";

		public const string ChargerSection = "ChargingStation";

		public const string FlashlightSection = "Flashlight";

		public const string LocalizationSection = "Localization";

		public const string IndividualSection = "IndividualMultipliers";

		public const string ModdedSection = "ModdedItems";

		public static ConfigEntry<float> GlobalMultiplier;

		public static ConfigEntry<bool> EnableIndividualMultipliers;

		public static ConfigEntry<bool> SpawnStoreItemsDischarged;

		public static ConfigEntry<float> InitialChargeMultiplier;

		public static ConfigEntry<bool> VerboseLogging;

		public static ConfigEntry<int> MaxCharges;

		public static ConfigEntry<bool> ResetChargesEachDay;

		public static ConfigEntry<bool> EnableFlashlightDimming;

		public static ConfigEntry<float> DimStartCharge;

		public static ConfigEntry<float> MinBrightness;

		internal static ConfigEntry<Loc.Language> LanguageSetting;

		private static readonly Dictionary<string, ConfigEntry<float>> normalizedIndex = new Dictionary<string, ConfigEntry<float>>(StringComparer.Ordinal);

		private Harmony harmony;

		public static Plugin Instance { get; private set; }

		internal static ConfigFile Cfg => ((BaseUnityPlugin)Instance).Config;

		internal static IEnumerable<ConfigEntry<float>> ItemEntries => normalizedIndex.Values;

		private void Awake()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			BindGeneralConfig();
			BindChargerConfig();
			BindFlashlightConfig();
			BindLocalizationConfig();
			BindModdedItems();
			ImportExistingIndividualKeys();
			harmony = new Harmony("ExhaustedBatteries");
			harmony.PatchAll();
			((BaseUnityPlugin)this).Config.SettingChanged += delegate
			{
				if (!ConfigSync.Applying)
				{
					ConfigSync.EnforceHostAuthority();
					ReapplyAll();
				}
			};
			Log.LogInfo((object)("Exhausted Batteries v1.0.0 loaded. " + $"Global={GlobalMultiplier.Value}, Individual={EnableIndividualMultipliers.Value}, " + $"DischargeStore={SpawnStoreItemsDischarged.Value}, MaxCharges={MaxCharges.Value}"));
		}

		private void BindGeneralConfig()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			GlobalMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("General", "GlobalMultiplier", 1f, new ConfigDescription("Global battery-capacity multiplier applied to ALL items that use a battery. 1.0 = vanilla, 2.0 = lasts twice as long, 0.5 = half as long.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.001f, 1000f), Array.Empty<object>()));
			EnableIndividualMultipliers = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableIndividualMultipliers", false, "Enable per-item multipliers from [IndividualMultipliers] and [ModdedItems]. A per-item multiplier takes priority over the global one.");
			SpawnStoreItemsDischarged = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SpawnStoreItemsDischarged", true, "Items with a battery bought from the store arrive fully discharged (charge = 0). Does not affect scrap/loot found on the map.");
			InitialChargeMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("General", "InitialChargeMultiplier", 1f, new ConfigDescription("Multiplier for the INITIAL charge of items that are NOT force-discharged (usually loot/scrap). 1.0 = vanilla. Result is clamped to 0..1.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "VerboseLogging", false, "Verbose logging of applied multipliers to the BepInEx console (for debugging).");
		}

		private void BindChargerConfig()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			MaxCharges = ((BaseUnityPlugin)this).Config.Bind<int>("ChargingStation", "MaxCharges", 0, new ConfigDescription("Maximum number of times the ship's charging station can be used. 0 = unlimited (vanilla).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>()));
			ResetChargesEachDay = ((BaseUnityPlugin)this).Config.Bind<bool>("ChargingStation", "ResetChargesEachDay", true, "If true, the charging-station use counter resets every day (when the ship lands). If false, MaxCharges is a total limit for the whole session.");
		}

		private void BindFlashlightConfig()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: 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
			EnableFlashlightDimming = ((BaseUnityPlugin)this).Config.Bind<bool>("Flashlight", "EnableFlashlightDimming", false, "Flashlights get dimmer as their battery drains (separate optional feature, off by default).");
			DimStartCharge = ((BaseUnityPlugin)this).Config.Bind<float>("Flashlight", "DimStartCharge", 1f, new ConfigDescription("Charge fraction (0..1) at/above which the flashlight stays at full brightness. Below it, brightness fades toward MinBrightness as the battery drops to empty. 1.0 = dim across the whole charge range.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			MinBrightness = ((BaseUnityPlugin)this).Config.Bind<float>("Flashlight", "MinBrightness", 0.15f, new ConfigDescription("Brightness fraction (0..1) at empty battery. 0 = almost dark, 1 = no dimming.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		}

		private void BindLocalizationConfig()
		{
			LanguageSetting = ((BaseUnityPlugin)this).Config.Bind<Loc.Language>("Localization", "Language", Loc.Language.Auto, "Language for this mod's in-game messages. Auto = Russian if a Russian localization mod (e.g. RTLC) is loaded or the system language is Russian, otherwise English. The config file itself stays in English.");
		}

		private void BindModdedItems()
		{
			RegisterItemEntry("ModdedItems", "Mapper", "Per-item capacity multiplier for the Mapper (mod: restoremapper). -1 = use GlobalMultiplier.");
			RegisterItemEntry("ModdedItems", "Geigercounter", "Per-item capacity multiplier for the Geiger counter (mod: facilitymeltdown). -1 = use GlobalMultiplier.");
		}

		private ConfigEntry<float> RegisterItemEntry(string section, string key, string description)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			ConfigEntry<float> val = ((BaseUnityPlugin)this).Config.Bind<float>(section, key, -1f, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1f, 1000f), Array.Empty<object>()));
			normalizedIndex[Normalize(key)] = val;
			return val;
		}

		public static void EnsureIndividualEntry(string canonicalKey)
		{
			if (!string.IsNullOrEmpty(canonicalKey) && !normalizedIndex.ContainsKey(Normalize(canonicalKey)))
			{
				Instance.RegisterItemEntry("IndividualMultipliers", canonicalKey, "Per-item capacity multiplier for '" + canonicalKey + "'. -1 = use GlobalMultiplier. Requires EnableIndividualMultipliers = true.");
			}
		}

		internal static void ReapplyAll()
		{
			Loc.Invalidate();
			GrabbableObjectPatch.ReapplyAllCapacities();
			ItemChargerPatch.RefreshAllTips();
			FlashlightDimPatch.OnSettingsChanged();
		}

		public static ConfigEntry<float> FindIndividual(string candidate)
		{
			if (string.IsNullOrEmpty(candidate))
			{
				return null;
			}
			if (!normalizedIndex.TryGetValue(Normalize(candidate), out var value))
			{
				return null;
			}
			return value;
		}

		public static string Normalize(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				return string.Empty;
			}
			return new string(s.Where(char.IsLetterOrDigit).ToArray()).ToLowerInvariant();
		}

		public static string SanitizeKey(string s)
		{
			if (string.IsNullOrWhiteSpace(s))
			{
				return "Unknown";
			}
			StringBuilder stringBuilder = new StringBuilder(s.Length);
			string text = s.Trim();
			foreach (char c in text)
			{
				stringBuilder.Append(("=\n\t\\\"'[]".IndexOf(c) >= 0) ? '_' : c);
			}
			string text2 = stringBuilder.ToString().Trim();
			if (text2.Length != 0)
			{
				return text2;
			}
			return "Unknown";
		}

		private void ImportExistingIndividualKeys()
		{
			try
			{
				if (!(typeof(ConfigFile).GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(((BaseUnityPlugin)this).Config) is IDictionary<ConfigDefinition, string> dictionary))
				{
					return;
				}
				foreach (ConfigDefinition item in dictionary.Keys.ToList())
				{
					if (string.Equals(item.Section, "IndividualMultipliers", StringComparison.Ordinal))
					{
						EnsureIndividualEntry(item.Key);
					}
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Could not import existing [IndividualMultipliers] keys: " + ex.Message + ". Prefer the keys the mod generates automatically."));
			}
		}
	}
}