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 AutoRefillFires v1.2.3
plugins/AutoRefillFires/AutoRefillFires.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyMetadata("PluginVersion", "1.2.3")] [assembly: AssemblyCompany("AutoRefillFires")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.2.3.0")] [assembly: AssemblyInformationalVersion("1.0.0+6b7cc092e13549b13efa0cf8ef1ef349d7a38f9b")] [assembly: AssemblyProduct("AutoRefillFires")] [assembly: AssemblyTitle("AutoRefillFires")] [assembly: AssemblyVersion("1.2.3.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 AutoRefillFires { public enum FuelSourcePriority { PlayerFirst, ContainersFirst } internal class ModConfig { public ConfigEntry<float> Radius { get; } public ConfigEntry<float> CheckInterval { get; } public ConfigEntry<float> RefillBelowPercent { get; } public ConfigEntry<bool> UseNearbyContainers { get; } public ConfigEntry<float> ContainerRadius { get; } public ConfigEntry<bool> RefillToMax { get; } public ConfigEntry<int> RefillAmount { get; } public ConfigEntry<bool> FillCampfires { get; } public ConfigEntry<bool> FillHearths { get; } public ConfigEntry<bool> FillStandingTorches { get; } public ConfigEntry<bool> FillWallTorches { get; } public ConfigEntry<bool> FillBraziers { get; } public ConfigEntry<bool> FillBonfires { get; } public ConfigEntry<bool> FillHotTubs { get; } public ConfigEntry<bool> FillShieldGenerators { get; } public ConfigEntry<bool> FillResinCandles { get; } public ConfigEntry<bool> FillOtherFireplaces { get; } public ConfigEntry<int> KeepFuelReserve { get; } public ConfigEntry<FuelSourcePriority> FuelSourcePriority { get; } public ConfigEntry<bool> OnlyRefillOwnPieces { get; } public ConfigEntry<bool> AutoRepair { get; } public ConfigEntry<float> RepairBelowPercent { get; } public ConfigEntry<bool> OnlyRepairOwnPieces { get; } public ConfigEntry<KeyboardShortcut> ToggleHotkey { get; } public ConfigEntry<ModLogLevel> LogLevel { get; } public ModConfig(ConfigFile config) { //IL_020a: Unknown result type (might be due to invalid IL or missing references) Radius = config.Bind<float>("General", "Radius", 20f, "Refill and repair supported objects within this radius around the player."); CheckInterval = config.Bind<float>("General", "CheckInterval", 3f, "How often supported objects are checked, in seconds."); RefillBelowPercent = config.Bind<float>("General", "RefillBelowPercent", 0.75f, "Refill when fuel drops below this percentage."); RefillToMax = config.Bind<bool>("General", "RefillToMax", true, "If true, refill fireplaces to maximum fuel. If false, add only RefillAmount fuel."); RefillAmount = config.Bind<int>("General", "RefillAmount", 5, "Amount of fuel to add when RefillToMax is false."); UseNearbyContainers = config.Bind<bool>("Containers", "UseNearbyContainers", false, "Allow plugin to take fuel from nearby containers."); ContainerRadius = config.Bind<float>("Containers", "ContainerRadius", 10f, "Maximum distance from the fireplace to search for containers."); FillCampfires = config.Bind<bool>("Fireplace Types", "FillCampfires", true, "Automatically refill campfires."); FillHearths = config.Bind<bool>("Fireplace Types", "FillHearths", true, "Automatically refill hearths."); FillStandingTorches = config.Bind<bool>("Fireplace Types", "FillStandingTorches", true, "Automatically refill all standing torches, including colored variants."); FillWallTorches = config.Bind<bool>("Fireplace Types", "FillWallTorches", true, "Automatically refill all wall torches, including colored variants."); FillBraziers = config.Bind<bool>("Fireplace Types", "FillBraziers", true, "Automatically refill braziers."); FillBonfires = config.Bind<bool>("Fireplace Types", "FillBonfires", true, "Automatically refill bonfires."); FillHotTubs = config.Bind<bool>("Fireplace Types", "FillHotTubs", true, "Automatically refill hot tubs."); FillShieldGenerators = config.Bind<bool>("Fireplace Types", "FillShieldGenerators", false, "Automatically refill buildable Ashlands shield generators with their accepted fuels. Refill only; does not enable repair."); FillResinCandles = config.Bind<bool>("Fireplace Types", "FillResinCandles", false, "Automatically refill resin candles when a whole fuel unit fits, including toggle-only candles. Preserves the on/off state. Refill only; does not enable repair."); FillOtherFireplaces = config.Bind<bool>("Fireplace Types", "FillOtherFireplaces", true, "Automatically refill unknown or modded Fireplace-based objects."); ToggleHotkey = config.Bind<KeyboardShortcut>("General", "ToggleHotkey", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Hotkey used to enable or disable automatic refilling and repair."); KeepFuelReserve = config.Bind<int>("Fuel", "KeepFuelReserve", 0, "Minimum amount of fuel to keep in the source inventory. 10 means the last 10 Wood/Resin will not be used."); FuelSourcePriority = config.Bind<FuelSourcePriority>("Fuel", "FuelSourcePriority", AutoRefillFires.FuelSourcePriority.PlayerFirst, "Select whether player inventory or nearby containers should be used first."); OnlyRefillOwnPieces = config.Bind<bool>("General", "OnlyRefillOwnPieces", false, "If enabled, only refill fireplaces and torches built by the local player."); AutoRepair = config.Bind<bool>("Repair", "AutoRepair", false, "Automatically repair supported objects whose corresponding Fill* option is enabled."); RepairBelowPercent = config.Bind<float>("Repair", "RepairBelowPercent", 0.75f, "Repair supported objects when their health drops below this percentage. Example: 0.75 = 75%."); OnlyRepairOwnPieces = config.Bind<bool>("Repair", "OnlyRepairOwnPieces", false, "If enabled, only automatically repair supported objects built by the local player."); LogLevel = config.Bind<ModLogLevel>("Logging", "LogLevel", ModLogLevel.Info, "Logging verbosity. Available values: None, Error, Warning, Info, Debug."); } } public enum ModLogLevel { None, Error, Warning, Info, Debug } internal class FuelManager { private readonly ModConfig _config; private readonly ModLogger _log; public FuelManager(ModConfig config, ModLogger log) { _config = config; _log = log; } public int ConsumeFuel(Player player, Transform target, string fuelName, int requestedAmount, Container[] containers) { if (requestedAmount <= 0) { return 0; } _log.Debug("Fuel request: fuel='" + fuelName + "', " + $"requested={requestedAmount}, " + $"priority={_config.FuelSourcePriority.Value}, " + $"containers={_config.UseNearbyContainers.Value}, " + $"reserve={_config.KeepFuelReserve.Value}"); int num = 0; if (_config.FuelSourcePriority.Value == FuelSourcePriority.ContainersFirst) { if (_config.UseNearbyContainers.Value && containers != null) { num += ConsumeFuelFromNearbyContainers(target, fuelName, requestedAmount - num, containers); } if (num < requestedAmount) { num += ConsumeFuelFromPlayer(player, fuelName, requestedAmount - num); } } else { num += ConsumeFuelFromPlayer(player, fuelName, requestedAmount); if (_config.UseNearbyContainers.Value && containers != null && num < requestedAmount) { num += ConsumeFuelFromNearbyContainers(target, fuelName, requestedAmount - num, containers); } } _log.Debug("Fuel request result: fuel='" + fuelName + "', " + $"requested={requestedAmount}, " + $"consumed={num}"); return num; } public int ConsumeFuelOptions(Player player, Transform target, IReadOnlyList<string> fuelNames, Container[] containers) { bool flag = _config.FuelSourcePriority.Value == FuelSourcePriority.ContainersFirst; for (int i = 0; i < 2; i++) { bool flag2 = ((i == 0) ? flag : (!flag)); if (flag2 && (!_config.UseNearbyContainers.Value || containers == null)) { continue; } foreach (string fuelName in fuelNames) { int num = (flag2 ? ConsumeFuelFromNearbyContainers(target, fuelName, 1, containers) : ConsumeFuelFromPlayer(player, fuelName, 1)); if (num > 0) { return num; } } } return 0; } private int ConsumeFuelFromPlayer(Player player, string fuelName, int requestedAmount) { if (requestedAmount <= 0) { return 0; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { _log.Debug("Player inventory is null."); return 0; } int num = inventory.CountItems(fuelName, -1, true); int num2 = Mathf.Max(num - _config.KeepFuelReserve.Value, 0); int num3 = Mathf.Min(requestedAmount, num2); if (num3 <= 0) { _log.Debug("Player inventory: fuel='" + fuelName + "', " + $"available={num}, " + $"reserve={_config.KeepFuelReserve.Value}, " + "usable=0"); return 0; } inventory.RemoveItem(fuelName, num3, -1, true); _log.Debug($"Player inventory: consumed={num3}x {fuelName}, " + $"before={num}, " + $"remaining={num - num3}"); return num3; } private int ConsumeFuelFromNearbyContainers(Transform target, string fuelName, int requestedAmount, Container[] containers) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) if (requestedAmount <= 0) { return 0; } if (containers == null || containers.Length == 0) { return 0; } List<ContainerCandidate> list = new List<ContainerCandidate>(); foreach (Container val in containers) { if ((Object)(object)val == (Object)null) { continue; } float num = Vector3.Distance(target.position, ((Component)val).transform.position); if (num > _config.ContainerRadius.Value) { continue; } Inventory inventory = val.GetInventory(); if (inventory != null) { int num2 = inventory.CountItems(fuelName, -1, true); int num3 = Mathf.Max(num2 - _config.KeepFuelReserve.Value, 0); if (num3 > 0) { list.Add(new ContainerCandidate { Container = val, Distance = num }); } } } list.Sort((ContainerCandidate a, ContainerCandidate b) => a.Distance.CompareTo(b.Distance)); int num4 = 0; foreach (ContainerCandidate item in list) { if (num4 >= requestedAmount) { break; } Inventory inventory2 = item.Container.GetInventory(); if (inventory2 != null) { int num5 = inventory2.CountItems(fuelName, -1, true); int num6 = Mathf.Max(num5 - _config.KeepFuelReserve.Value, 0); if (num6 > 0) { int num7 = Mathf.Min(requestedAmount - num4, num6); inventory2.RemoveItem(fuelName, num7, -1, true); num4 += num7; _log.Debug($"Container '{((Object)item.Container).name}' ({item.Distance:0.0}m): " + $"consumed={num7}x {fuelName}"); } } } return num4; } } internal class ModLogger { private readonly ModConfig _config; private readonly ManualLogSource _logger; public ModLogger(ModConfig config, ManualLogSource logger) { _config = config; _logger = logger; } public void Debug(string message) { if (_config.LogLevel.Value >= ModLogLevel.Debug) { _logger.LogInfo((object)("[DEBUG] " + message)); } } public void Info(string message) { if (_config.LogLevel.Value >= ModLogLevel.Info) { _logger.LogInfo((object)message); } } public void Warning(string message) { if (_config.LogLevel.Value >= ModLogLevel.Warning) { _logger.LogWarning((object)message); } } public void Error(string message) { if (_config.LogLevel.Value >= ModLogLevel.Error) { _logger.LogError((object)message); } } } internal class ContainerCandidate { public Container Container; public float Distance; } internal class FireplaceCandidate { public Fireplace Fireplace; public float Distance; public float FuelPercent; } [BepInPlugin("simplifydave.autorefillfires", "Auto Refill Fires", "1.2.3")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "simplifydave.autorefillfires"; public const string PluginName = "Auto Refill Fires"; public const string PluginVersion = "1.2.3"; private ModConfig _config; private ModLogger _log; private RefillManager _refillManager; private bool _modEnabled = true; private float _nextCheckTime; private void Awake() { _config = new ModConfig(((BaseUnityPlugin)this).Config); _log = new ModLogger(_config, ((BaseUnityPlugin)this).Logger); _refillManager = new RefillManager(_config, _log); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Auto Refill Fires loaded!"); } private void Update() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut value = _config.ToggleHotkey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { _modEnabled = !_modEnabled; if (!_modEnabled) { try { ((BaseUnityPlugin)this).Config.Reload(); _log.Info("Configuration reloaded."); } catch (Exception arg) { _log.Error($"Failed to reload configuration: {arg}"); } } string text = (_modEnabled ? "Auto Refill Fires: ENABLED" : "Auto Refill Fires: DISABLED"); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { ((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false); } _log.Info(text); } if (_modEnabled && !(Time.time < _nextCheckTime)) { _nextCheckTime = Time.time + _config.CheckInterval.Value; Player localPlayer2 = Player.m_localPlayer; if (!((Object)(object)localPlayer2 == (Object)null)) { _refillManager.Run(localPlayer2); } } } } internal class FireplaceRefiller { private readonly ModConfig _config; private readonly FuelManager _fuelManager; private readonly ModLogger _log; public FireplaceRefiller(ModConfig config, FuelManager fuelManager, ModLogger log) { _config = config; _fuelManager = fuelManager; _log = log; } public void TryRefill(Player player, Fireplace fireplace, Container[] containers) { _log.Debug("TryRefillFireplace START: '" + ((Object)((Component)fireplace).gameObject).name + "'"); if (!ShouldRefillFireplace(fireplace)) { _log.Debug("Skipping '" + ((Object)((Component)fireplace).gameObject).name + "' - type/config filter returned false."); return; } if (_config.OnlyRefillOwnPieces.Value && !IsOwnPiece(player, fireplace)) { _log.Debug("Skipping '" + ((Object)((Component)fireplace).gameObject).name + "' - not owned by local player."); return; } ZNetView val = ((Component)fireplace).GetComponent<ZNetView>(); if ((Object)(object)val == (Object)null) { val = ((Component)fireplace).GetComponentInParent<ZNetView>(); } if ((Object)(object)val == (Object)null) { _log.Debug("Skipping '" + ((Object)((Component)fireplace).gameObject).name + "' - no ZNetView found."); return; } if (!val.IsValid()) { _log.Debug("Skipping '" + ((Object)((Component)fireplace).gameObject).name + "' - ZNetView is not valid."); return; } ZDO zDO = val.GetZDO(); if (zDO == null) { _log.Debug("Skipping '" + ((Object)((Component)fireplace).gameObject).name + "' - ZDO is null."); return; } if ((Object)(object)fireplace.m_fuelItem == (Object)null || fireplace.m_fuelItem.m_itemData == null || fireplace.m_fuelItem.m_itemData.m_shared == null) { _log.Debug("Skipping '" + ((Object)((Component)fireplace).gameObject).name + "' - fuel item is null."); return; } float num = zDO.GetFloat(ZDOVars.s_fuel, 0f); float maxFuel = fireplace.m_maxFuel; if (maxFuel <= 0f) { _log.Debug($"Skipping '{((Object)((Component)fireplace).gameObject).name}' - maxFuel <= 0 ({maxFuel})."); return; } float num2 = num / maxFuel; _log.Debug("Fuel state for '" + ((Object)((Component)fireplace).gameObject).name + "': " + $"currentFuel={num:0.0}, maxFuel={maxFuel:0.0}, " + $"fuelPercent={num2:0.00}, threshold={_config.RefillBelowPercent.Value:0.00}"); if (num2 >= _config.RefillBelowPercent.Value) { _log.Debug("Skipping '" + ((Object)((Component)fireplace).gameObject).name + "' - fuelPercent >= threshold."); return; } string name = fireplace.m_fuelItem.m_itemData.m_shared.m_name; int num3 = Mathf.CeilToInt(maxFuel - num); if (num3 <= 0) { _log.Debug($"Skipping '{((Object)((Component)fireplace).gameObject).name}' - missingFuel <= 0 ({num3})."); return; } int num4 = (_config.RefillToMax.Value ? num3 : Mathf.Min(Mathf.Max(_config.RefillAmount.Value, 0), num3)); _log.Debug("Refill request for '" + ((Object)((Component)fireplace).gameObject).name + "': " + $"fuel='{name}', missingFuel={num3}, requestedFuel={num4}, " + "refillMode=" + (_config.RefillToMax.Value ? "max" : "fixed")); if (num4 <= 0) { _log.Debug("Skipping '" + ((Object)((Component)fireplace).gameObject).name + "' - requestedFuel <= 0."); return; } int num5 = _fuelManager.ConsumeFuel(player, ((Component)fireplace).transform, name, num4, containers); if (num5 <= 0) { _log.Debug("No usable fuel found for '" + ((Object)((Component)fireplace).gameObject).name + "'."); return; } for (int i = 0; i < num5; i++) { val.InvokeRPC("RPC_AddFuel", new object[0]); } _log.Info($"Refilled {((Object)fireplace).name}: {num:0.0}/{maxFuel:0.0}, " + $"fuel={name}, added={num5}, " + "mode=" + (_config.RefillToMax.Value ? "max" : "fixed")); } private bool ShouldRefillFireplace(Fireplace fireplace) { string matchedRule; bool flag = FireplaceTypeFilter.IsEnabled(_config, fireplace, out matchedRule); _log.Debug("ShouldRefillFireplace: name='" + ((Object)((Component)fireplace).gameObject).name + "', " + $"matchedRule={matchedRule}, result={flag}"); return flag; } private bool IsOwnPiece(Player player, Fireplace fireplace) { Piece val = ((Component)fireplace).GetComponent<Piece>(); if ((Object)(object)val == (Object)null) { val = ((Component)fireplace).GetComponentInParent<Piece>(); } if ((Object)(object)val == (Object)null) { return true; } return val.GetCreator() == player.GetPlayerID(); } } internal static class FireplaceTypeFilter { public static bool IsEnabled(ModConfig config, Fireplace fireplace, out string matchedRule) { string text = ((Object)((Component)fireplace).gameObject).name.Replace("(Clone)", "").ToLowerInvariant(); if (text.Contains("candle")) { matchedRule = "IgnoredCandle"; return false; } if (text.Contains("fire_pit") || text.Contains("firepit")) { matchedRule = "FillCampfires"; return config.FillCampfires.Value; } if (text.Contains("hearth")) { matchedRule = "FillHearths"; return config.FillHearths.Value; } if (text.Contains("groundtorch")) { matchedRule = "FillStandingTorches"; return config.FillStandingTorches.Value; } if (text.Contains("walltorch")) { matchedRule = "FillWallTorches"; return config.FillWallTorches.Value; } if (text.Contains("brazier")) { matchedRule = "FillBraziers"; return config.FillBraziers.Value; } if (text.Contains("bonfire")) { matchedRule = "FillBonfires"; return config.FillBonfires.Value; } matchedRule = "FillOtherFireplaces"; return config.FillOtherFireplaces.Value; } } internal class HotTubRefiller { private readonly ModConfig _config; private readonly FuelManager _fuelManager; private readonly RepairManager _repairManager; private readonly ModLogger _log; public HotTubRefiller(ModConfig config, FuelManager fuelManager, RepairManager repairManager, ModLogger log) { _config = config; _fuelManager = fuelManager; _repairManager = repairManager; _log = log; } public void RefillNearby(Player player, Smelter[] smelters, Container[] containers) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) int num = 0; foreach (Smelter val in smelters) { if ((Object)(object)val == (Object)null) { continue; } string text = ((Object)((Component)val).gameObject).name.Replace("(Clone)", "").ToLowerInvariant(); if (!(text != "piece_bathtub")) { float num2 = Vector3.Distance(((Component)player).transform.position, ((Component)val).transform.position); if (!(num2 > _config.Radius.Value)) { num++; _log.Debug("Hot tub in range: name='" + ((Object)((Component)val).gameObject).name + "', " + $"distance={num2:0.0}m"); _repairManager.TryRepair(player, (Component)(object)val, "hot tub"); TryRefillHotTub(player, val, containers); } } } _log.Debug($"Hot tub scan end: inRange={num}"); } private void TryRefillHotTub(Player player, Smelter smelter, Container[] containers) { if ((Object)(object)smelter == (Object)null) { return; } ZNetView val = ((Component)smelter).GetComponent<ZNetView>(); if ((Object)(object)val == (Object)null) { val = ((Component)smelter).GetComponentInParent<ZNetView>(); } if ((Object)(object)val == (Object)null || !val.IsValid()) { _log.Debug("Hot tub: invalid ZNetView."); return; } ZDO zDO = val.GetZDO(); if (zDO == null) { _log.Debug("Hot tub: ZDO is null."); return; } if ((Object)(object)smelter.m_fuelItem == (Object)null || smelter.m_fuelItem.m_itemData == null || smelter.m_fuelItem.m_itemData.m_shared == null) { _log.Debug("Hot tub: fuel item is null."); return; } string name = smelter.m_fuelItem.m_itemData.m_shared.m_name; float num = zDO.GetFloat(ZDOVars.s_fuel, 0f); float num2 = smelter.m_maxFuel; if (num2 <= 0f) { return; } float num3 = num / num2; _log.Debug("Hot tub fuel state: fuel='" + name + "', " + $"current={num:0.00}, max={num2:0.00}, " + $"percent={num3 * 100f:0.0}%, threshold={_config.RefillBelowPercent.Value * 100f:0.0}%"); if (num3 >= _config.RefillBelowPercent.Value) { _log.Debug("Skipping hot tub - fuelPercent >= threshold."); return; } int num4 = Mathf.CeilToInt(num2 - num); int num5 = (_config.RefillToMax.Value ? num4 : Mathf.Min(_config.RefillAmount.Value, num4)); if (num5 <= 0) { return; } _log.Debug($"Hot tub refill requested: missing={num4}, requested={num5}"); int num6 = _fuelManager.ConsumeFuel(player, ((Component)smelter).transform, name, num5, containers); if (num6 <= 0) { _log.Debug("Hot tub refill stopped: no usable fuel."); return; } for (int i = 0; i < num6; i++) { val.InvokeRPC("RPC_AddFuel", new object[0]); } _log.Info($"Refilled hot tub: {num:0.0}/{num2:0.0}, " + $"fuel={name}, added={num6}, " + "mode=" + (_config.RefillToMax.Value ? "max" : "fixed")); } } internal static class RefillAmountCalculator { public static int Calculate(float current, float maximum, float threshold, bool toMax, int amount) { if (float.IsNaN(current) || float.IsInfinity(current) || current < 0f || float.IsNaN(maximum) || float.IsInfinity(maximum) || maximum <= 0f || float.IsNaN(threshold) || current >= maximum) { return 0; } threshold = Math.Max(0f, Math.Min(1f, threshold)); if (current / maximum >= threshold) { return 0; } int num = (int)Math.Min(2147483647.0, Math.Floor((double)maximum - (double)current)); return toMax ? num : Math.Min(num, Math.Max(0, amount)); } } internal class RefillManager { private readonly ModConfig _config; private readonly FireplaceRefiller _fireplaceRefiller; private readonly HotTubRefiller _hotTubRefiller; private readonly SpecialRefiller _specialRefiller; private readonly RepairManager _repairManager; private readonly ModLogger _log; public RefillManager(ModConfig config, ModLogger log) { _config = config; _log = log; FuelManager fuelManager = new FuelManager(_config, _log); _specialRefiller = new SpecialRefiller(_config, fuelManager, _log); _fireplaceRefiller = new FireplaceRefiller(_config, fuelManager, _log); _repairManager = new RepairManager(_config, _log); _hotTubRefiller = new HotTubRefiller(_config, fuelManager, _repairManager, _log); } public void Run(Player player) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) Fireplace[] array = Object.FindObjectsByType<Fireplace>((FindObjectsInactive)0, (FindObjectsSortMode)0); Smelter[] array2 = null; if (_config.FillHotTubs.Value) { array2 = Object.FindObjectsByType<Smelter>((FindObjectsInactive)0, (FindObjectsSortMode)0); } Container[] array3 = null; if (_config.UseNearbyContainers.Value) { array3 = Object.FindObjectsByType<Container>((FindObjectsInactive)0, (FindObjectsSortMode)0); } List<FireplaceCandidate> list = new List<FireplaceCandidate>(); Fireplace[] array4 = array; foreach (Fireplace val in array4) { if ((Object)(object)val == (Object)null) { continue; } float num = Vector3.Distance(((Component)player).transform.position, ((Component)val).transform.position); if (num > _config.Radius.Value) { continue; } ZNetView val2 = ((Component)val).GetComponent<ZNetView>(); if ((Object)(object)val2 == (Object)null) { val2 = ((Component)val).GetComponentInParent<ZNetView>(); } if ((Object)(object)val2 == (Object)null || !val2.IsValid()) { continue; } ZDO zDO = val2.GetZDO(); if (zDO != null) { float maxFuel = val.m_maxFuel; if (!(maxFuel <= 0f)) { float num2 = zDO.GetFloat(ZDOVars.s_fuel, 0f); float fuelPercent = num2 / maxFuel; list.Add(new FireplaceCandidate { Fireplace = val, Distance = num, FuelPercent = fuelPercent }); } } } list.Sort(delegate(FireplaceCandidate a, FireplaceCandidate b) { int num3 = a.FuelPercent.CompareTo(b.FuelPercent); return (num3 != 0) ? num3 : a.Distance.CompareTo(b.Distance); }); _log.Debug($"Scan start: loadedFireplaces={array.Length}, " + $"inRange={list.Count}, " + $"loadedContainers={((array3 != null) ? array3.Length : 0)}, " + $"radius={_config.Radius.Value:0.0}m"); foreach (FireplaceCandidate item in list) { _log.Debug("Priority: name='" + ((Object)((Component)item.Fireplace).gameObject).name + "', " + $"fuel={item.FuelPercent * 100f:0.0}%, " + $"distance={item.Distance:0.0}m"); if (SpecialRefiller.IsResinCandle(item.Fireplace)) { _specialRefiller.TryRefillCandle(player, item.Fireplace, array3); continue; } if (FireplaceTypeFilter.IsEnabled(_config, item.Fireplace, out var matchedRule)) { _repairManager.TryRepair(player, (Component)(object)item.Fireplace, matchedRule); } _fireplaceRefiller.TryRefill(player, item.Fireplace, array3); } if (_config.FillHotTubs.Value && array2 != null) { _hotTubRefiller.RefillNearby(player, array2, array3); } if (_config.FillShieldGenerators.Value) { _specialRefiller.RefillShields(player, Object.FindObjectsByType<ShieldGenerator>((FindObjectsInactive)0, (FindObjectsSortMode)0), array3); } _log.Debug("Scan end."); } } internal class SpecialRefiller { private readonly ModConfig _config; private readonly FuelManager _fuelManager; private readonly ModLogger _log; public SpecialRefiller(ModConfig config, FuelManager fuelManager, ModLogger log) { _config = config; _fuelManager = fuelManager; _log = log; } public static bool IsResinCandle(Fireplace fireplace) { return ((Object)((Component)fireplace).gameObject).name.ToLowerInvariant().Contains("candle") && (Object)(object)fireplace.m_fuelItem != (Object)null && ((Object)((Component)fireplace.m_fuelItem).gameObject).name == "Resin"; } public void TryRefillCandle(Player player, Fireplace fireplace, Container[] containers) { _log.Debug($"Candle check: name='{((Object)fireplace).name}', enabled={_config.FillResinCandles.Value}, canRefill={fireplace.m_canRefill}, infiniteFuel={fireplace.m_infiniteFuel}, maxFuel={fireplace.m_maxFuel}"); if (!_config.FillResinCandles.Value) { _log.Debug("Skipping candle - FillResinCandles is disabled."); return; } if (!IsResinCandle(fireplace) || fireplace.m_infiniteFuel) { _log.Debug("Skipping candle - unsupported type or infinite fuel."); return; } string text = fireplace.m_fuelItem.m_itemData?.m_shared?.m_name; if (string.IsNullOrEmpty(text)) { _log.Debug("Skipping candle - missing fuel item data."); return; } TryRefill(player, (Component)(object)fireplace, fireplace.m_maxFuel, fireplace.m_startFuel, new string[1] { text }, containers); } public void RefillShields(Player player, ShieldGenerator[] shields, Container[] containers) { if (!_config.FillShieldGenerators.Value) { return; } foreach (ShieldGenerator val in shields) { if ((Object)(object)val == (Object)null || ((Object)((Component)val).gameObject).name.Replace("(Clone)", "") != "piece_shieldgenerator" || val.m_fuelItems == null) { continue; } List<string> list = new List<string>(); foreach (ItemDrop fuelItem in val.m_fuelItems) { string text = fuelItem?.m_itemData?.m_shared?.m_name; if (!string.IsNullOrEmpty(text) && !list.Contains(text)) { list.Add(text); } } TryRefill(player, (Component)(object)val, val.m_maxFuel, val.m_defaultFuel, list, containers); } } private void TryRefill(Player player, Component target, float maximum, float defaultFuel, IReadOnlyList<string> fuels, Container[] containers) { //IL_0010: 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) if (fuels.Count == 0 || Vector3.Distance(((Component)player).transform.position, target.transform.position) > _config.Radius.Value) { return; } Piece val = target.GetComponent<Piece>() ?? target.GetComponentInParent<Piece>(); if (_config.OnlyRefillOwnPieces.Value && ((Object)(object)val == (Object)null || val.GetCreator() != player.GetPlayerID())) { _log.Debug("Skipping '" + ((Object)target).name + "' - OnlyRefillOwnPieces restriction."); return; } ZNetView val2 = target.GetComponent<ZNetView>() ?? target.GetComponentInParent<ZNetView>(); if ((Object)(object)val2 == (Object)null || !val2.IsValid()) { _log.Debug("Skipping '" + ((Object)target).name + "' - invalid ZNetView."); return; } ZDO zDO = val2.GetZDO(); float num = zDO.GetFloat(ZDOVars.s_fuel, defaultFuel); int num2 = RefillAmountCalculator.Calculate(num, maximum, _config.RefillBelowPercent.Value, _config.RefillToMax.Value, _config.RefillAmount.Value); _log.Debug($"Special refill: name='{((Object)target).name}', fuel={num:0.000}/{maximum:0.000}, threshold={_config.RefillBelowPercent.Value:0.00}, requested={num2}"); if (num2 <= 0) { _log.Debug("Skipping special refill - threshold not reached, no whole fuel slot, or fixed amount disabled."); return; } val2.ClaimOwnership(); if (!val2.IsOwner()) { return; } int num3 = 0; for (int i = 0; i < num2; i++) { if (!val2.IsValid()) { break; } if (!val2.IsOwner()) { break; } float num4 = zDO.GetFloat(ZDOVars.s_fuel, defaultFuel); if (RefillAmountCalculator.Calculate(num4, maximum, 1f, toMax: true, 1) <= 0 || _fuelManager.ConsumeFuelOptions(player, target.transform, fuels, containers) == 0) { break; } val2.InvokeRPC("RPC_AddFuel", new object[0]); if (zDO.GetFloat(ZDOVars.s_fuel, defaultFuel) <= num4) { _log.Error("Fuel was not applied to '" + ((Object)target).name + "'; stopping this refill."); break; } num3++; } if (num3 > 0) { _log.Info($"Refilled {((Object)target).name}: added={num3}, fuel={zDO.GetFloat(ZDOVars.s_fuel, defaultFuel):0.00}/{maximum:0.00}"); } } } internal class RepairManager { private readonly ModConfig _config; private readonly ModLogger _log; public RepairManager(ModConfig config, ModLogger log) { _config = config; _log = log; } public void TryRepair(Player player, Component target, string label) { if (!_config.AutoRepair.Value || (Object)(object)target == (Object)null) { return; } if (_config.OnlyRepairOwnPieces.Value && !IsOwnPiece(player, target)) { _log.Debug("Skipping repair for '" + ((Object)target.gameObject).name + "' - not owned by local player."); return; } WearNTear val = target.GetComponent<WearNTear>(); if ((Object)(object)val == (Object)null) { val = target.GetComponentInParent<WearNTear>(); } if ((Object)(object)val == (Object)null) { _log.Debug("Skipping repair for '" + ((Object)target.gameObject).name + "' - no WearNTear found."); return; } ZNetView val2 = ((Component)val).GetComponent<ZNetView>(); if ((Object)(object)val2 == (Object)null) { val2 = ((Component)val).GetComponentInParent<ZNetView>(); } if ((Object)(object)val2 == (Object)null || !val2.IsValid()) { _log.Debug("Skipping repair for '" + ((Object)target.gameObject).name + "' - invalid ZNetView."); return; } ZDO zDO = val2.GetZDO(); if (zDO == null) { _log.Debug("Skipping repair for '" + ((Object)target.gameObject).name + "' - ZDO is null."); return; } float health = val.m_health; if (health <= 0f) { _log.Debug($"Skipping repair for '{((Object)target.gameObject).name}' - max health <= 0 ({health})."); return; } float num = zDO.GetFloat(ZDOVars.s_health, health); float num2 = num / health; float num3 = Mathf.Clamp01(_config.RepairBelowPercent.Value); _log.Debug("Repair state: type=" + label + ", name='" + ((Object)target.gameObject).name + "', " + $"health={num:0.0}/{health:0.0} ({num2 * 100f:0.0}%), " + $"threshold={num3 * 100f:0.0}%"); if (!(num2 >= num3)) { if (val.Repair()) { _log.Info("Repaired " + label + ": " + ((Object)target.gameObject).name + ", " + $"{num:0.0}/{health:0.0} ({num2 * 100f:0.0}% -> 100%)"); } else { _log.Debug("Repair request for '" + ((Object)target.gameObject).name + "' returned false."); } } } private static bool IsOwnPiece(Player player, Component target) { Piece val = target.GetComponent<Piece>(); if ((Object)(object)val == (Object)null) { val = target.GetComponentInParent<Piece>(); } if ((Object)(object)val == (Object)null) { return true; } return val.GetCreator() == player.GetPlayerID(); } } internal static class VersionInfo { public const string Version = "1.2.3"; } }