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 Exhausted Batteries v1.0.0
ExhaustedBatteries.dll
Decompiled 2 hours agousing 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.")); } } } }