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.4.2
ExhaustedBatteries.dll
Decompiled 2 weeks agousing System; using System.Collections; 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+94f676050750c60ae337e4d70b57fb451c4822b0")] [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 EmptyTeleporterEffects { [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__OnHostMimicReq; public static HandleNamedMessageDelegate <1>__OnHostCurseReq; } private const string MimicReqMsg = "ExhaustedBatteries_MimicReq"; private const string CurseReqMsg = "ExhaustedBatteries_CurseReq"; private static MethodInfo spawnEnemy; private static bool spawnEnemyResolved; private static bool IsHost { get { if ((Object)(object)NetworkManager.Singleton != (Object)null) { return NetworkManager.Singleton.IsServer; } return false; } } internal static void OnLocalConnect() { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null) { return; } CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager; string[] array = new string[2] { "ExhaustedBatteries_MimicReq", "ExhaustedBatteries_CurseReq" }; foreach (string text in array) { try { customMessagingManager.UnregisterNamedMessageHandler(text); } catch { } } if (singleton.IsServer) { object obj2 = <>O.<0>__OnHostMimicReq; if (obj2 == null) { HandleNamedMessageDelegate val = OnHostMimicReq; <>O.<0>__OnHostMimicReq = val; obj2 = (object)val; } customMessagingManager.RegisterNamedMessageHandler("ExhaustedBatteries_MimicReq", (HandleNamedMessageDelegate)obj2); object obj3 = <>O.<1>__OnHostCurseReq; if (obj3 == null) { HandleNamedMessageDelegate val2 = OnHostCurseReq; <>O.<1>__OnHostCurseReq = val2; obj3 = (object)val2; } customMessagingManager.RegisterNamedMessageHandler("ExhaustedBatteries_CurseReq", (HandleNamedMessageDelegate)obj3); } TeleporterCurse.Reset(); } internal static void RequestMimic(Vector3 pos) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) if (IsHost) { SpawnMimic(pos); } else { SendVector("ExhaustedBatteries_MimicReq", pos); } } private static void OnHostMimicReq(ulong sender, FastBufferReader reader) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (IsHost && ((FastBufferReader)(ref reader)).TryBeginRead(12)) { Vector3 pos = default(Vector3); ((FastBufferReader)(ref reader)).ReadValueSafe(ref pos); SpawnMimic(pos); } } private static void SpawnMimic(Vector3 pos) { //IL_008c: Unknown result type (might be due to invalid IL or missing references) try { RoundManager instance = RoundManager.Instance; if ((Object)(object)instance == (Object)null) { return; } EnemyType val = FindMaskedType(instance); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"[Mimic] no Masked enemy type on this moon, nothing spawned."); return; } if (!spawnEnemyResolved) { spawnEnemyResolved = true; spawnEnemy = AccessTools.Method(typeof(RoundManager), "SpawnEnemyGameObject", (Type[])null, (Type[])null); } if (spawnEnemy == null) { Plugin.Log.LogWarning((object)"[Mimic] SpawnEnemyGameObject not found."); return; } spawnEnemy.Invoke(instance, new object[4] { pos, 0f, -1, val }); if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)"[Mimic] depleted teleporter beamed a mimic aboard."); } } catch (Exception arg) { Plugin.Log.LogError((object)$"[Mimic] spawn failed: {arg}"); } } private static EnemyType FindMaskedType(RoundManager rm) { SelectableLevel currentLevel = rm.currentLevel; if ((Object)(object)currentLevel == (Object)null) { return null; } List<SpawnableEnemyWithRarity>[] array = new List<SpawnableEnemyWithRarity>[3] { currentLevel.Enemies, currentLevel.OutsideEnemies, currentLevel.DaytimeEnemies }; foreach (List<SpawnableEnemyWithRarity> list in array) { if (list == null) { continue; } foreach (SpawnableEnemyWithRarity item in list) { EnemyType val = item?.enemyType; if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(val.enemyName) && val.enemyName.IndexOf("masked", StringComparison.OrdinalIgnoreCase) >= 0) { return val; } } } return null; } internal static void RequestCurse() { if (IsHost) { TeleporterCurse.Arm(); } else { SendEmpty("ExhaustedBatteries_CurseReq"); } } private static void OnHostCurseReq(ulong sender, FastBufferReader reader) { if (IsHost) { TeleporterCurse.Arm(); } } private unsafe static void SendVector(string msg, Vector3 pos) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(12, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe(ref pos); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage(msg, 0uL, val, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private unsafe static void SendEmpty(string msg) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(1, (Allocator)2, -1); try { NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage(msg, 0uL, val, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } } internal static class TeleporterCurse { private static int roundsLeft; private static bool[] wasInShip = new bool[0]; private static float nextAllowedFire; private static MethodInfo getInversePos; private static MethodInfo teleportOutClientRpc; private static bool resolved; private static bool IsHost { get { if ((Object)(object)NetworkManager.Singleton != (Object)null) { return NetworkManager.Singleton.IsServer; } return false; } } internal static void Reset() { roundsLeft = 0; wasInShip = new bool[0]; nextAllowedFire = 0f; } internal static void Arm() { if (IsHost && Plugin.EmptyInverseTeleporterCurse.Value) { int num = Mathf.Min(Plugin.CurseMinRounds.Value, Plugin.CurseMaxRounds.Value); int num2 = Mathf.Max(Plugin.CurseMinRounds.Value, Plugin.CurseMaxRounds.Value); roundsLeft = Random.Range(num, num2 + 1); nextAllowedFire = Time.time + 3f; SnapshotPresence(); Plugin.Log.LogInfo((object)$"[Curse] inverse teleporter cursed: {roundsLeft} round(s) armed."); } } internal static void Tick() { try { if (roundsLeft <= 0 || !IsHost || !ConfigSync.IsActive) { return; } PlayerControllerB[] array = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.allPlayerScripts : null); if (array == null || array.Length == 0) { return; } if (wasInShip.Length != array.Length) { SnapshotPresence(); return; } bool flag = false; for (int i = 0; i < array.Length; i++) { PlayerControllerB val = array[i]; if ((Object)(object)val == (Object)null || !val.isPlayerControlled || val.isPlayerDead) { wasInShip[i] = false; continue; } bool isInHangarShipRoom = val.isInHangarShipRoom; if (isInHangarShipRoom && !wasInShip[i]) { flag = true; } wasInShip[i] = isInHangarShipRoom; } if (flag && Time.time >= nextAllowedFire) { nextAllowedFire = Time.time + 5f; FireRound(array); } } catch (Exception arg) { Plugin.Log.LogError((object)$"[Curse] tick error: {arg}"); roundsLeft = 0; } } private static void SnapshotPresence() { PlayerControllerB[] array = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.allPlayerScripts : null); if (array == null) { wasInShip = new bool[0]; return; } wasInShip = new bool[array.Length]; for (int i = 0; i < array.Length; i++) { PlayerControllerB val = array[i]; wasInShip[i] = (Object)(object)val != (Object)null && val.isPlayerControlled && !val.isPlayerDead && val.isInHangarShipRoom; } } private static void FireRound(PlayerControllerB[] players) { //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) ShipTeleporter val = FindInverseTeleporter(); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"[Curse] no inverse teleporter found, curse cleared."); roundsLeft = 0; return; } if (!resolved) { resolved = true; getInversePos = AccessTools.Method(typeof(ShipTeleporter), "GetInverseTelePosition", (Type[])null, (Type[])null); teleportOutClientRpc = AccessTools.Method(typeof(ShipTeleporter), "TeleportPlayerOutClientRpc", (Type[])null, (Type[])null); } if (getInversePos == null || teleportOutClientRpc == null) { Plugin.Log.LogWarning((object)"[Curse] inverse teleport methods not found, curse cleared."); roundsLeft = 0; return; } int num = 0; for (int i = 0; i < players.Length; i++) { PlayerControllerB val2 = players[i]; if (!((Object)(object)val2 == (Object)null) && val2.isPlayerControlled && !val2.isPlayerDead && val2.isInHangarShipRoom) { try { Vector3 val3 = (Vector3)getInversePos.Invoke(val, null); teleportOutClientRpc.Invoke(val, new object[2] { i, val3 }); num++; } catch (Exception arg) { Plugin.Log.LogError((object)$"[Curse] failed to teleport player {i}: {arg}"); } } } roundsLeft--; Plugin.Log.LogInfo((object)$"[Curse] fired on {num} player(s), {roundsLeft} round(s) left."); } private static ShipTeleporter FindInverseTeleporter() { ShipTeleporter[] array = Object.FindObjectsOfType<ShipTeleporter>(); foreach (ShipTeleporter val in array) { if ((Object)(object)val != (Object)null && val.isInverseTeleporter) { return val; } } return null; } } internal static class Loc { internal enum Language { Auto, English, Russian } private static bool resolved; private static bool russian; internal static bool IsRussianResolved => IsRussian; 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 string SignalTranslatorTipHeader { get { if (!IsRussian) { return "Signal Translator"; } 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 string TeleporterTipHeader(bool inverse) { if (!IsRussian) { if (!inverse) { return "Teleporter"; } return "Inverse Teleporter"; } if (!inverse) { return "Телепорт"; } return "Инверсный телепорт"; } } internal enum ChargePool { Charger, Teleporter, InverseTeleporter, SignalTranslator } internal static class ChargerSync { [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__OnHostUsed; public static HandleNamedMessageDelegate <1>__OnHostExplodeReq; public static HandleNamedMessageDelegate <2>__OnClientState; public static HandleNamedMessageDelegate <3>__OnClientExplode; } private const int PoolCount = 4; private const string StateMsg = "ExhaustedBatteries_PoolState"; private const string UsedMsg = "ExhaustedBatteries_PoolUsed"; private const string ExplodeReqMsg = "ExhaustedBatteries_ExplodeReq"; private const string ExplodeMsg = "ExhaustedBatteries_Explode"; private static readonly int[] charges = new int[4]; private static bool IsHost { get { if ((Object)(object)NetworkManager.Singleton != (Object)null) { return NetworkManager.Singleton.IsServer; } return false; } } internal static int Charges => Get(ChargePool.Charger); internal static bool UnlimitedCharger => Unlimited(ChargePool.Charger); internal static int Get(ChargePool pool) { return charges[(int)pool]; } internal static int MaxFor(ChargePool pool) { return pool switch { ChargePool.Charger => Plugin.MaxCharges.Value, ChargePool.Teleporter => Plugin.MaxTeleporterCharges.Value, ChargePool.InverseTeleporter => Plugin.MaxInverseTeleporterCharges.Value, ChargePool.SignalTranslator => Plugin.MaxSignalTranslatorCharges.Value, _ => 0, }; } internal static bool Unlimited(ChargePool pool) { return MaxFor(pool) <= 0; } internal static void OnLocalConnect() { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null) { return; } CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager; Unregister(customMessagingManager); if (singleton.IsServer) { object obj = <>O.<0>__OnHostUsed; if (obj == null) { HandleNamedMessageDelegate val = OnHostUsed; <>O.<0>__OnHostUsed = val; obj = (object)val; } customMessagingManager.RegisterNamedMessageHandler("ExhaustedBatteries_PoolUsed", (HandleNamedMessageDelegate)obj); object obj2 = <>O.<1>__OnHostExplodeReq; if (obj2 == null) { HandleNamedMessageDelegate val2 = OnHostExplodeReq; <>O.<1>__OnHostExplodeReq = val2; obj2 = (object)val2; } customMessagingManager.RegisterNamedMessageHandler("ExhaustedBatteries_ExplodeReq", (HandleNamedMessageDelegate)obj2); for (int i = 0; i < 4; i++) { charges[i] = Mathf.Max(0, MaxFor((ChargePool)i)); } Broadcast(); } else { object obj3 = <>O.<2>__OnClientState; if (obj3 == null) { HandleNamedMessageDelegate val3 = OnClientState; <>O.<2>__OnClientState = val3; obj3 = (object)val3; } customMessagingManager.RegisterNamedMessageHandler("ExhaustedBatteries_PoolState", (HandleNamedMessageDelegate)obj3); object obj4 = <>O.<3>__OnClientExplode; if (obj4 == null) { HandleNamedMessageDelegate val4 = OnClientExplode; <>O.<3>__OnClientExplode = val4; obj4 = (object)val4; } customMessagingManager.RegisterNamedMessageHandler("ExhaustedBatteries_Explode", (HandleNamedMessageDelegate)obj4); } } internal static void OnDisconnect() { Unregister(((Object)(object)NetworkManager.Singleton != (Object)null) ? NetworkManager.Singleton.CustomMessagingManager : null); for (int i = 0; i < 4; i++) { charges[i] = 0; } } private static void Unregister(CustomMessagingManager cmm) { if (cmm == null) { return; } string[] array = new string[4] { "ExhaustedBatteries_PoolState", "ExhaustedBatteries_PoolUsed", "ExhaustedBatteries_ExplodeReq", "ExhaustedBatteries_Explode" }; foreach (string text in array) { try { cmm.UnregisterNamedMessageHandler(text); } catch { } } } internal static void OnLocalUse(ChargePool pool) { if (IsHost) { if (charges[(int)pool] > 0) { charges[(int)pool]--; Broadcast(); } return; } if (charges[(int)pool] > 0) { charges[(int)pool]--; } RefreshTips(); SendPool("ExhaustedBatteries_PoolUsed", 0uL, pool); } internal static void OnLocalCharge() { OnLocalUse(ChargePool.Charger); } internal static void DayReset() { if (!IsHost || !Plugin.ResetChargesEachDay.Value) { return; } for (int i = 0; i < 4; i++) { ChargePool pool = (ChargePool)i; if (!Unlimited(pool)) { charges[i] = ((!Plugin.HardResetEachDay.Value && Plugin.CarryOverUnusedCharges.Value) ? (charges[i] + MaxFor(pool)) : MaxFor(pool)); } } Broadcast(); } internal static void AddFromLightning() { if (IsHost && (0u | (TryAddOne(ChargePool.Charger, Plugin.LightningChargesStation.Value) ? 1u : 0u) | (TryAddOne(ChargePool.Teleporter, Plugin.LightningChargesTeleporter.Value) ? 1u : 0u) | (TryAddOne(ChargePool.InverseTeleporter, Plugin.LightningChargesInverseTeleporter.Value) ? 1u : 0u) | (TryAddOne(ChargePool.SignalTranslator, Plugin.LightningChargesSignalTranslator.Value) ? 1u : 0u)) != 0) { Broadcast(); } } private static bool TryAddOne(ChargePool pool, bool enabled) { if (!enabled || Unlimited(pool)) { return false; } charges[(int)pool]++; if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"[Lightning] +1 {pool} (now {charges[(int)pool]})"); } return true; } internal static void QuotaReset() { if (!IsHost || !Plugin.ResetChargesOnQuota.Value) { return; } for (int i = 0; i < 4; i++) { ChargePool pool = (ChargePool)i; if (!Unlimited(pool)) { charges[i] = MaxFor(pool); } } if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)"[Quota] fulfilled -> all counters refilled"); } Broadcast(); } internal static void TriggerExplosion(Vector3 pos) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) if (IsHost) { BroadcastExplode(pos); } else { SendVector("ExhaustedBatteries_ExplodeReq", 0uL, pos); } } private static void SpawnExplosion(Vector3 pos) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) Landmine.SpawnExplosion(pos + Vector3.down * 0.7f, true, 5.7f, 6.4f, 50, 65f, (GameObject)null, false); } private static void RefreshTips() { ItemChargerPatch.RefreshAllTips(); TeleporterPatch.RefreshAllTips(); } private static void Broadcast() { RefreshTips(); if (!IsHost) { return; } foreach (ulong connectedClientsId in NetworkManager.Singleton.ConnectedClientsIds) { if (connectedClientsId != 0L) { SendState(connectedClientsId); } } } internal static void SendStateTo(ulong clientId) { if (IsHost) { SendState(clientId); } } private unsafe static void SendState(ulong clientId) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(16, (Allocator)2, -1); try { for (int i = 0; i < 4; i++) { int num = charges[i]; ((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives)); } NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("ExhaustedBatteries_PoolState", clientId, val, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private static void BroadcastExplode(Vector3 pos) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) SpawnExplosion(pos); if (!IsHost) { return; } foreach (ulong connectedClientsId in NetworkManager.Singleton.ConnectedClientsIds) { if (connectedClientsId != 0L) { SendVector("ExhaustedBatteries_Explode", connectedClientsId, pos); } } } private static void OnHostUsed(ulong senderId, FastBufferReader reader) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) if (!IsHost || !((FastBufferReader)(ref reader)).TryBeginRead(1)) { return; } byte b = default(byte); ((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b, default(ForPrimitives)); if (b < 4) { if (charges[b] > 0) { charges[b]--; } Broadcast(); } } private static void OnHostExplodeReq(ulong senderId, FastBufferReader reader) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (IsHost && ((FastBufferReader)(ref reader)).TryBeginRead(12)) { Vector3 pos = default(Vector3); ((FastBufferReader)(ref reader)).ReadValueSafe(ref pos); BroadcastExplode(pos); } } private static void OnClientState(ulong _, FastBufferReader reader) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) if (((FastBufferReader)(ref reader)).TryBeginRead(16)) { int num = default(int); for (int i = 0; i < 4; i++) { ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives)); charges[i] = num; } RefreshTips(); } } private static void OnClientExplode(ulong _, FastBufferReader reader) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (((FastBufferReader)(ref reader)).TryBeginRead(12)) { Vector3 pos = default(Vector3); ((FastBufferReader)(ref reader)).ReadValueSafe(ref pos); SpawnExplosion(pos); } } private unsafe static void SendPool(string msg, ulong clientId, ChargePool pool) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) byte b = (byte)pool; FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(1, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe<byte>(ref b, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage(msg, clientId, val, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private unsafe static void SendVector(string msg, ulong clientId, Vector3 pos) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(12, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe(ref pos); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage(msg, clientId, val, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } } 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)."); ChargerSync.SendStateTo(clientId); DischargeSync.ScheduleJoinerResync(); } 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("mt=").Append(Plugin.MaxTeleporterCharges.Value.ToString(CultureInfo.InvariantCulture)).Append('\n'); stringBuilder.Append("mi=").Append(Plugin.MaxInverseTeleporterCharges.Value.ToString(CultureInfo.InvariantCulture)).Append('\n'); stringBuilder.Append("ms=").Append(Plugin.MaxSignalTranslatorCharges.Value.ToString(CultureInfo.InvariantCulture)).Append('\n'); stringBuilder.Append("rd=").Append(Plugin.ResetChargesEachDay.Value).Append('\n'); stringBuilder.Append("co=").Append(Plugin.CarryOverUnusedCharges.Value).Append('\n'); stringBuilder.Append("ex=").Append(Plugin.ExplodeWhenEmpty.Value).Append('\n'); stringBuilder.Append("rq=").Append(Plugin.ResetChargesOnQuota.Value).Append('\n'); stringBuilder.Append("hr=").Append(Plugin.HardResetEachDay.Value).Append('\n'); stringBuilder.Append("em=").Append(Plugin.EmptyTeleporterSpawnsMimic.Value).Append('\n'); stringBuilder.Append("ec=").Append(Plugin.EmptyInverseTeleporterCurse.Value).Append('\n'); stringBuilder.Append("cn=").Append(Plugin.CurseMinRounds.Value.ToString(CultureInfo.InvariantCulture)).Append('\n'); stringBuilder.Append("cx=").Append(Plugin.CurseMaxRounds.Value.ToString(CultureInfo.InvariantCulture)).Append('\n'); stringBuilder.Append("lt=").Append(Plugin.LightningChargesTeleporter.Value).Append('\n'); stringBuilder.Append("lv=").Append(Plugin.LightningChargesInverseTeleporter.Value).Append('\n'); stringBuilder.Append("lg=").Append(Plugin.LightningChargesSignalTranslator.Value).Append('\n'); stringBuilder.Append("li=").Append(Plugin.LightningChargesItems.Value).Append('\n'); stringBuilder.Append("ls=").Append(Plugin.LightningChargesStation.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[1]) { case 'm': { float f4; if (!(key == "gm")) { if (key == "em" && bool.TryParse(val, out var result18)) { Plugin.EmptyTeleporterSpawnsMimic.Value = result18; } } else if (TryF(val, out f4)) { Plugin.GlobalMultiplier.Value = f4; } break; } case 'i': switch (key) { case "ei": { if (bool.TryParse(val, out var result8)) { Plugin.EnableIndividualMultipliers.Value = result8; } break; } case "mi": { if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result9)) { Plugin.MaxInverseTeleporterCharges.Value = result9; } break; } case "li": { if (bool.TryParse(val, out var result7)) { Plugin.LightningChargesItems.Value = result7; } break; } } break; case 'd': switch (key) { case "sd": { if (bool.TryParse(val, out var result2)) { Plugin.SpawnStoreItemsDischarged.Value = result2; } break; } case "rd": { if (bool.TryParse(val, out var result3)) { Plugin.ResetChargesEachDay.Value = result3; } break; } case "fd": { if (bool.TryParse(val, out var result)) { Plugin.EnableFlashlightDimming.Value = result; } break; } } break; case 'c': switch (key) { case "ic": { if (TryF(val, out var f3)) { Plugin.InitialChargeMultiplier.Value = f3; } break; } case "mc": { if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result14)) { Plugin.MaxCharges.Value = result14; } break; } case "ec": { if (bool.TryParse(val, out var result13)) { Plugin.EmptyInverseTeleporterCurse.Value = result13; } break; } } break; case 't': { int result17; if (!(key == "mt")) { if (key == "lt" && bool.TryParse(val, out var result16)) { Plugin.LightningChargesTeleporter.Value = result16; } } else if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out result17)) { Plugin.MaxTeleporterCharges.Value = result17; } break; } case 's': switch (key) { case "ms": { if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result20)) { Plugin.MaxSignalTranslatorCharges.Value = result20; } break; } case "ls": { if (bool.TryParse(val, out var result21)) { Plugin.LightningChargesStation.Value = result21; } break; } case "ds": { if (TryF(val, out var f5)) { Plugin.DimStartCharge.Value = f5; } break; } } break; case 'o': { if (key == "co" && bool.TryParse(val, out var result6)) { Plugin.CarryOverUnusedCharges.Value = result6; } break; } case 'x': { bool result12; if (!(key == "ex")) { if (key == "cx" && int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result11)) { Plugin.CurseMaxRounds.Value = result11; } } else if (bool.TryParse(val, out result12)) { Plugin.ExplodeWhenEmpty.Value = result12; } break; } case 'q': { if (key == "rq" && bool.TryParse(val, out var result4)) { Plugin.ResetChargesOnQuota.Value = result4; } break; } case 'r': { if (key == "hr" && bool.TryParse(val, out var result19)) { Plugin.HardResetEachDay.Value = result19; } break; } case 'n': { if (key == "cn" && int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result15)) { Plugin.CurseMinRounds.Value = result15; } break; } case 'v': { if (key == "lv" && bool.TryParse(val, out var result10)) { Plugin.LightningChargesInverseTeleporter.Value = result10; } break; } case 'g': { if (key == "lg" && bool.TryParse(val, out var result5)) { Plugin.LightningChargesSignalTranslator.Value = result5; } break; } case 'b': { if (key == "mb" && TryF(val, out var f2)) { Plugin.MinBrightness.Value = f2; } break; } case 'e': case 'f': case 'h': case 'j': case 'k': case 'l': case 'p': case 'u': case 'w': 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(); ChargerSync.OnLocalConnect(); EmptyTeleporterEffects.OnLocalConnect(); } } internal static class DischargeSync { private static MethodInfo syncClientRpc; private static FieldInfo isHeldField; private static bool resolved; private static bool IsHost { get { if ((Object)(object)NetworkManager.Singleton != (Object)null) { return NetworkManager.Singleton.IsServer; } return false; } } internal static void Schedule(GrabbableObject obj) { if (IsHost && !((Object)(object)obj == (Object)null) && !((Object)(object)Plugin.Instance == (Object)null)) { ((MonoBehaviour)Plugin.Instance).StartCoroutine(Pulse(obj)); } } internal static void ScheduleJoinerResync() { if (IsHost && !((Object)(object)Plugin.Instance == (Object)null)) { ((MonoBehaviour)Plugin.Instance).StartCoroutine(JoinerResync()); } } private static IEnumerator Pulse(GrabbableObject obj) { float[] array = new float[2] { 1f, 2f }; float[] array2 = array; foreach (float num in array2) { yield return (object)new WaitForSeconds(num); if ((Object)(object)obj == (Object)null || !IsHost) { break; } Battery insertedBattery = obj.insertedBattery; if (insertedBattery == null) { break; } insertedBattery.charge = 0f; insertedBattery.empty = true; Broadcast(obj, 0); } } private static IEnumerator JoinerResync() { yield return (object)new WaitForSeconds(2.5f); if (!IsHost) { yield break; } int num = 0; GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>(); foreach (GrabbableObject val in array) { try { if (!((Object)(object)val == (Object)null) && !((Object)(object)val.itemProperties == (Object)null) && val.itemProperties.requiresBattery && val.insertedBattery != null && !IsHeld(val)) { Broadcast(val, Mathf.Clamp(Mathf.RoundToInt(val.insertedBattery.charge * 100f), 0, 100)); num++; } } catch (Exception arg) { Plugin.Log.LogError((object)$"[Discharge] joiner resync failed for an item: {arg}"); } } if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"[Discharge] joiner resync: pushed {num} battery value(s)."); } } private static void Resolve() { if (!resolved) { resolved = true; syncClientRpc = AccessTools.Method(typeof(GrabbableObject), "SyncBatteryClientRpc", (Type[])null, (Type[])null); isHeldField = AccessTools.Field(typeof(GrabbableObject), "isHeld"); } } private static bool IsHeld(GrabbableObject obj) { Resolve(); if (isHeldField == null) { return false; } try { return (bool)isHeldField.GetValue(obj); } catch { return false; } } private static void Broadcast(GrabbableObject obj, int charge) { Resolve(); if (syncClientRpc == null) { Plugin.Log.LogWarning((object)"[Discharge] SyncBatteryClientRpc not found; clients keep their local value."); return; } try { syncClientRpc.Invoke(obj, new object[1] { charge }); if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"[Discharge] host broadcast charge={charge} for '{obj.itemProperties?.itemName}'"); } } catch (Exception arg) { Plugin.Log.LogError((object)$"[Discharge] broadcast failed: {arg}"); } } } [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<string, float> baseUsages = new Dictionary<string, float>(StringComparer.Ordinal); private static bool reapplying; private static string BaseKey(Item item) { if (!string.IsNullOrEmpty(item.itemName)) { return item.itemName; } return "#" + ((Object)item).GetInstanceID(); } [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; DischargeSync.Schedule(__instance); } 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) { string key = BaseKey(item); if (!baseUsages.TryGetValue(key, out var value)) { value = item.batteryUsage; baseUsages[key] = 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 { private static readonly Dictionary<InteractTrigger, string> baseTips = new Dictionary<InteractTrigger, string>(); [HarmonyPrefix] private static bool Prefix(ItemCharger __instance) { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) if (!ConfigSync.IsActive) { return true; } if (ChargerSync.UnlimitedCharger) { 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 (ChargerSync.Charges > 0) { ChargerSync.OnLocalCharge(); if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"[Charger] charge used, ~{ChargerSync.Charges} left"); } return true; } if (Plugin.ExplodeWhenEmpty.Value) { ChargerSync.TriggerExplosion(((Component)__instance).transform.position); } else if ((Object)(object)HUDManager.Instance != (Object)null) { HUDManager.Instance.DisplayTip(Loc.ChargerTipHeader, Loc.NoChargesLeft, true, false, "LC_Tip1"); } return false; } 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 && !ChargerSync.UnlimitedCharger) { triggerScript.hoverTip = $"{value} [{Mathf.Max(0, ChargerSync.Charges)}]"; } 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), "ShipLeave")] internal static class ChargerTakeoffResetPatch { [HarmonyPostfix] private static void Postfix() { ChargerSync.DayReset(); ItemChargerPatch.RefreshAllTips(); TeleporterPatch.RefreshAllTips(); } } [HarmonyPatch(typeof(StormyWeather), "LightningStrike")] internal static class LightningPatch { [HarmonyPostfix] private static void Postfix(bool useTargetedObject, GrabbableObject ___targetingMetalObject) { if (!ConfigSync.IsActive || !useTargetedObject || !Plugin.LightningChargesItems.Value) { return; } if (!((Object)(object)___targetingMetalObject == (Object)null) && !((Object)(object)___targetingMetalObject.itemProperties == (Object)null) && ___targetingMetalObject.itemProperties.requiresBattery && ___targetingMetalObject.insertedBattery != null) { ___targetingMetalObject.insertedBattery.charge = 1f; ___targetingMetalObject.insertedBattery.empty = false; if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)("[Lightning] charged item '" + ___targetingMetalObject.itemProperties.itemName + "'")); } } } } [HarmonyPatch(typeof(StartOfRound), "PowerSurgeShip")] internal static class ShipLightningRodPatch { [HarmonyPostfix] private static void Postfix() { if (ConfigSync.IsActive) { ChargerSync.AddFromLightning(); if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)"[Lightning] ship lightning rod struck"); } } } } [HarmonyPatch(typeof(TimeOfDay), "SetNewProfitQuota")] internal static class QuotaResetPatch { [HarmonyPostfix] private static void Postfix() { if (ConfigSync.IsActive) { ChargerSync.QuotaReset(); } } } [HarmonyPatch(typeof(Terminal), "RunTerminalEvents")] internal static class SignalTranslatorPatch { [HarmonyPrefix] private static bool Prefix(TerminalNode node) { try { return Check(node); } catch (Exception arg) { Plugin.Log.LogError((object)$"[SignalTranslator] prefix error, allowing vanilla event: {arg}"); return true; } } private static bool Check(TerminalNode node) { if ((Object)(object)node == (Object)null || string.IsNullOrEmpty(node.terminalEvent)) { return true; } if (node.terminalEvent.IndexOf("transmit", StringComparison.OrdinalIgnoreCase) < 0) { return true; } if (!ConfigSync.IsActive) { return true; } if (ChargerSync.Unlimited(ChargePool.SignalTranslator)) { return true; } if (ChargerSync.Get(ChargePool.SignalTranslator) > 0) { ChargerSync.OnLocalUse(ChargePool.SignalTranslator); if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"[SignalTranslator] transmission used, ~{ChargerSync.Get(ChargePool.SignalTranslator)} left"); } return true; } if ((Object)(object)HUDManager.Instance != (Object)null) { HUDManager.Instance.DisplayTip(Loc.SignalTranslatorTipHeader, Loc.NoChargesLeft, true, false, "LC_Tip1"); } return false; } } [HarmonyPatch(typeof(ShipTeleporter), "PressTeleportButtonOnLocalClient")] internal static class TeleporterPatch { private static readonly Dictionary<InteractTrigger, string> baseTips = new Dictionary<InteractTrigger, string>(); private static MethodInfo canUseInverse; private static bool canUseInverseResolved; internal static ChargePool PoolOf(ShipTeleporter t) { if (!t.isInverseTeleporter) { return ChargePool.Teleporter; } return ChargePool.InverseTeleporter; } [HarmonyPrefix] private static bool Prefix(ShipTeleporter __instance, float ___cooldownTime) { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) try { if (!ConfigSync.IsActive) { return true; } ChargePool chargePool = PoolOf(__instance); if (ChargerSync.Unlimited(chargePool)) { return true; } if (___cooldownTime > 0f) { return true; } if (__instance.isInverseTeleporter && !CanUseInverse(__instance)) { return true; } if (ChargerSync.Get(chargePool) > 0) { ChargerSync.OnLocalUse(chargePool); if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"[Teleporter] {chargePool} used, ~{ChargerSync.Get(chargePool)} left"); } return true; } bool isInverseTeleporter = __instance.isInverseTeleporter; if (!isInverseTeleporter && Plugin.EmptyTeleporterSpawnsMimic.Value) { EmptyTeleporterEffects.RequestMimic(((Component)__instance).transform.position); } else if (isInverseTeleporter && Plugin.EmptyInverseTeleporterCurse.Value) { EmptyTeleporterEffects.RequestCurse(); } else if ((Object)(object)HUDManager.Instance != (Object)null) { HUDManager.Instance.DisplayTip(Loc.TeleporterTipHeader(isInverseTeleporter), Loc.NoChargesLeft, true, false, "LC_Tip1"); } return false; } catch (Exception arg) { Plugin.Log.LogError((object)$"[Teleporter] prefix error, allowing vanilla press: {arg}"); return true; } } private static bool CanUseInverse(ShipTeleporter t) { if (!canUseInverseResolved) { canUseInverseResolved = true; canUseInverse = AccessTools.Method(typeof(ShipTeleporter), "CanUseInverseTeleporter", (Type[])null, (Type[])null); } if (canUseInverse == null) { return true; } try { return (bool)canUseInverse.Invoke(t, null); } catch { return true; } } internal static void RefreshTip(ShipTeleporter teleporter) { try { if ((Object)(object)teleporter == (Object)null) { return; } InteractTrigger buttonTrigger = teleporter.buttonTrigger; if (!((Object)(object)buttonTrigger == (Object)null)) { if (!baseTips.TryGetValue(buttonTrigger, out var value)) { value = buttonTrigger.hoverTip; baseTips[buttonTrigger] = value; } ChargePool pool = PoolOf(teleporter); if (ConfigSync.IsActive && !ChargerSync.Unlimited(pool)) { buttonTrigger.hoverTip = $"{value} [{Mathf.Max(0, ChargerSync.Get(pool))}]"; } else { buttonTrigger.hoverTip = value; } } } catch (Exception arg) { Plugin.Log.LogError((object)$"[Teleporter] hover tip error: {arg}"); } } internal static void RefreshAllTips() { ShipTeleporter[] array = Object.FindObjectsOfType<ShipTeleporter>(); for (int i = 0; i < array.Length; i++) { RefreshTip(array[i]); } } } internal static class ModInfo { public const string Guid = "ExhaustedBatteries"; public const string Name = "Exhausted Batteries"; public const string Version = "1.4.2"; } [BepInPlugin("ExhaustedBatteries", "Exhausted Batteries", "1.4.2")] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Log; public const string GeneralSection = "General"; public const string ChargerSection = "ChargingStation"; public const string LightningSection = "Lightning"; public const string TeleporterSection = "Teleporter"; public const string SignalSection = "SignalTranslator"; 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> CarryOverUnusedCharges; public static ConfigEntry<bool> ExplodeWhenEmpty; public static ConfigEntry<bool> ResetChargesOnQuota; public static ConfigEntry<bool> HardResetEachDay; public static ConfigEntry<bool> LightningChargesItems; public static ConfigEntry<bool> LightningChargesStation; public static ConfigEntry<bool> LightningChargesTeleporter; public static ConfigEntry<bool> LightningChargesInverseTeleporter; public static ConfigEntry<bool> LightningChargesSignalTranslator; public static ConfigEntry<int> MaxTeleporterCharges; public static ConfigEntry<int> MaxInverseTeleporterCharges; public static ConfigEntry<bool> EmptyTeleporterSpawnsMimic; public static ConfigEntry<bool> EmptyInverseTeleporterCurse; public static ConfigEntry<int> CurseMinRounds; public static ConfigEntry<int> CurseMaxRounds; public static ConfigEntry<int> MaxSignalTranslatorCharges; 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_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; BindGeneralConfig(); BindChargerConfig(); BindLightningConfig(); BindTeleporterConfig(); BindSignalConfig(); 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.4.2 loaded. " + $"Global={GlobalMultiplier.Value}, Individual={EnableIndividualMultipliers.Value}, " + $"DischargeStore={SpawnStoreItemsDischarged.Value}, MaxCharges={MaxCharges.Value}")); Log.LogInfo((object)string.Format("Language setting={0}, in-game messages will use {1}.", LanguageSetting.Value, Loc.IsRussianResolved ? "Russian" : "English")); } private void Update() { TeleporterCurse.Tick(); } 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 counter refreshes every day (when the ship lands). If false, MaxCharges is a total limit for the whole session."); CarryOverUnusedCharges = ((BaseUnityPlugin)this).Config.Bind<bool>("ChargingStation", "CarryOverUnusedCharges", false, "Requires ResetChargesEachDay = true. If true, charges left unused at the end of a day carry over and add to the next day's allotment (instead of being lost)."); ExplodeWhenEmpty = ((BaseUnityPlugin)this).Config.Bind<bool>("ChargingStation", "ExplodeWhenEmpty", false, "If true, trying to use the charging station when it is out of charges makes it EXPLODE."); HardResetEachDay = ((BaseUnityPlugin)this).Config.Bind<bool>("ChargingStation", "HardResetEachDay", true, "Strict daily reset: on a new day every counter is set exactly back to its maximum and NOTHING from the previous day survives (leftovers and lightning bonuses are discarded). Takes priority over CarryOverUnusedCharges. Requires ResetChargesEachDay = true."); ResetChargesOnQuota = ((BaseUnityPlugin)this).Config.Bind<bool>("ChargingStation", "ResetChargesOnQuota", false, "If true, ALL counters (charging station, both teleporters, signal translator) are refilled to their maximum when the crew fulfils the profit quota and a new quota starts."); } private void BindLightningConfig() { LightningChargesItems = ((BaseUnityPlugin)this).Config.Bind<bool>("Lightning", "LightningChargesItems", false, "If true, a lightning bolt that strikes a battery item fully charges that item. Strikes on the ship/roof do not charge items."); LightningChargesStation = ((BaseUnityPlugin)this).Config.Bind<bool>("Lightning", "LightningChargesStation", false, "If true, when lightning strikes the ship's lightning rod (which happens when you bring a targeted conductive item onto the ship and the ship's power surges / lights flicker), the charging station gains 1 charge."); LightningChargesTeleporter = ((BaseUnityPlugin)this).Config.Bind<bool>("Lightning", "LightningChargesTeleporter", false, "If true, a lightning strike on the ship's lightning rod also adds 1 use to the regular Teleporter."); LightningChargesInverseTeleporter = ((BaseUnityPlugin)this).Config.Bind<bool>("Lightning", "LightningChargesInverseTeleporter", false, "If true, a lightning strike on the ship's lightning rod also adds 1 use to the Inverse Teleporter."); LightningChargesSignalTranslator = ((BaseUnityPlugin)this).Config.Bind<bool>("Lightning", "LightningChargesSignalTranslator", false, "If true, a lightning strike on the ship's lightning rod also adds 1 transmission to the Signal Translator."); } private void BindTeleporterConfig() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Expected O, but got Unknown MaxTeleporterCharges = ((BaseUnityPlugin)this).Config.Bind<int>("Teleporter", "MaxTeleporterCharges", 0, new ConfigDescription("Maximum number of times the regular Teleporter can be used. 0 = unlimited (vanilla). Shares the same daily reset / carry-over settings as the charging station.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>())); MaxInverseTeleporterCharges = ((BaseUnityPlugin)this).Config.Bind<int>("Teleporter", "MaxInverseTeleporterCharges", 0, new ConfigDescription("Maximum number of times the Inverse Teleporter can be used. 0 = unlimited (vanilla).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>())); EmptyTeleporterSpawnsMimic = ((BaseUnityPlugin)this).Config.Bind<bool>("Teleporter", "EmptyTeleporterSpawnsMimic", false, "If true, pressing the regular Teleporter when it is out of charges teleports a MIMIC (Masked) onto the ship instead of a player."); EmptyInverseTeleporterCurse = ((BaseUnityPlugin)this).Config.Bind<bool>("Teleporter", "EmptyInverseTeleporterCurse", false, "If true, pressing the Inverse Teleporter when it is out of charges curses it: the next few times the crew returns to the ship, everyone standing in the ship is flung to a random spot with the vanilla inverse-teleport animation."); CurseMinRounds = ((BaseUnityPlugin)this).Config.Bind<int>("Teleporter", "CurseMinRounds", 2, new ConfigDescription("Minimum number of times the curse fires before it wears off.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), Array.Empty<object>())); CurseMaxRounds = ((BaseUnityPlugin)this).Config.Bind<int>("Teleporter", "CurseMaxRounds", 4, new ConfigDescription("Maximum number of times the curse fires before it wears off.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), Array.Empty<object>())); } private void BindSignalConfig() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown MaxSignalTranslatorCharges = ((BaseUnityPlugin)this).Config.Bind<int>("SignalTranslator", "MaxSignalTranslatorCharges", 0, new ConfigDescription("Maximum number of transmissions the Signal Translator can send. 0 = unlimited (vanilla).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>())); } 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(); TeleporterPatch.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.")); } } } }