From 073d20ff285f4e5069d8e34a4aebeb05c9201f5c Mon Sep 17 00:00:00 2001 From: LabodiDavid Date: Sun, 6 Sep 2026 14:32:27 +0200 Subject: [PATCH] Refactored into separated components --- AutoRefillFires.csproj | 24 +- Configuration/FuelSourcePriority.cs | 8 + Configuration/ModConfig.cs | 61 ++ Configuration/ModLogLevel.cs | 11 + Fuel/FuelManager.cs | 169 +++++ Logging/ModLogger.cs | 40 + Models/ContainerCandidate.cs | 8 + Models/FireplaceCandidate.cs | 9 + Plugin.cs | 1056 +-------------------------- Refill/FireplaceRefiller.cs | 195 +++++ Refill/HotTubRefiller.cs | 127 ++++ Refill/RefillManager.cs | 112 +++ 12 files changed, 761 insertions(+), 1059 deletions(-) create mode 100644 Configuration/FuelSourcePriority.cs create mode 100644 Configuration/ModConfig.cs create mode 100644 Configuration/ModLogLevel.cs create mode 100644 Fuel/FuelManager.cs create mode 100644 Logging/ModLogger.cs create mode 100644 Models/ContainerCandidate.cs create mode 100644 Models/FireplaceCandidate.cs create mode 100644 Refill/FireplaceRefiller.cs create mode 100644 Refill/HotTubRefiller.cs create mode 100644 Refill/RefillManager.cs diff --git a/AutoRefillFires.csproj b/AutoRefillFires.csproj index 78c024a..2ca9e7f 100644 --- a/AutoRefillFires.csproj +++ b/AutoRefillFires.csproj @@ -6,7 +6,7 @@ AutoRefillFires latest - 1.1.0 + 1.2.0 D:\SteamLibrary\steamapps\common\Valheim Default @@ -60,11 +60,7 @@ - + @@ -84,21 +80,13 @@ - + - + - + - + diff --git a/Configuration/FuelSourcePriority.cs b/Configuration/FuelSourcePriority.cs new file mode 100644 index 0000000..898c51f --- /dev/null +++ b/Configuration/FuelSourcePriority.cs @@ -0,0 +1,8 @@ +namespace AutoRefillFires +{ + public enum FuelSourcePriority + { + PlayerFirst, + ContainersFirst + } +} diff --git a/Configuration/ModConfig.cs b/Configuration/ModConfig.cs new file mode 100644 index 0000000..41bf103 --- /dev/null +++ b/Configuration/ModConfig.cs @@ -0,0 +1,61 @@ +using BepInEx.Configuration; +using UnityEngine; + +namespace AutoRefillFires +{ + internal class ModConfig + { + public ConfigEntry Radius { get; } + public ConfigEntry CheckInterval { get; } + public ConfigEntry RefillBelowPercent { get; } + + public ConfigEntry UseNearbyContainers { get; } + public ConfigEntry ContainerRadius { get; } + + public ConfigEntry RefillToMax { get; } + public ConfigEntry RefillAmount { get; } + + public ConfigEntry FillCampfires { get; } + public ConfigEntry FillHearths { get; } + public ConfigEntry FillStandingTorches { get; } + public ConfigEntry FillWallTorches { get; } + public ConfigEntry FillBraziers { get; } + public ConfigEntry FillBonfires { get; } + public ConfigEntry FillHotTubs { get; } + public ConfigEntry FillOtherFireplaces { get; } + + public ConfigEntry KeepFuelReserve { get; } + public ConfigEntry FuelSourcePriority { get; } + + public ConfigEntry OnlyRefillOwnPieces { get; } + public ConfigEntry ToggleHotkey { get; } + public ConfigEntry LogLevel { get; } + + public ModConfig(ConfigFile config) + { + Radius = config.Bind("General", "Radius", 20f, "Refill fireplaces within this radius around the player."); + CheckInterval = config.Bind("General", "CheckInterval", 3f, "How often fireplaces are checked, in seconds."); + RefillBelowPercent = config.Bind("General", "RefillBelowPercent", 0.75f, "Refill when fuel drops below this percentage."); + RefillToMax = config.Bind("General", "RefillToMax", true, "If true, refill fireplaces to maximum fuel. If false, add only RefillAmount fuel."); + RefillAmount = config.Bind("General", "RefillAmount", 5, "Amount of fuel to add when RefillToMax is false."); + + UseNearbyContainers = config.Bind("Containers", "UseNearbyContainers", false, "Allow plugin to take fuel from nearby containers."); + ContainerRadius = config.Bind("Containers", "ContainerRadius", 10f, "Maximum distance from the fireplace to search for containers."); + + FillCampfires = config.Bind("Fireplace Types", "FillCampfires", true, "Automatically refill campfires."); + FillHearths = config.Bind("Fireplace Types", "FillHearths", true, "Automatically refill hearths."); + FillStandingTorches = config.Bind("Fireplace Types", "FillStandingTorches", true, "Automatically refill all standing torches, including colored variants."); + FillWallTorches = config.Bind("Fireplace Types", "FillWallTorches", true, "Automatically refill all wall torches, including colored variants."); + FillBraziers = config.Bind("Fireplace Types", "FillBraziers", true, "Automatically refill braziers."); + FillBonfires = config.Bind("Fireplace Types", "FillBonfires", true, "Automatically refill bonfires."); + FillHotTubs = config.Bind("Fireplace Types", "FillHotTubs", true, "Automatically refill hot tubs."); + FillOtherFireplaces = config.Bind("Fireplace Types", "FillOtherFireplaces", true, "Automatically refill unknown or modded Fireplace-based objects."); + + ToggleHotkey = config.Bind("General", "ToggleHotkey", new KeyboardShortcut(KeyCode.F7), "Hotkey used to enable or disable automatic refilling."); + KeepFuelReserve = config.Bind("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("Fuel", "FuelSourcePriority", AutoRefillFires.FuelSourcePriority.PlayerFirst, "Select whether player inventory or nearby containers should be used first."); + OnlyRefillOwnPieces = config.Bind("General", "OnlyRefillOwnPieces", false, "If enabled, only refill fireplaces and torches built by the local player."); + LogLevel = config.Bind("Logging", "LogLevel", ModLogLevel.Info, "Logging verbosity. Available values: None, Error, Warning, Info, Debug."); + } + } +} diff --git a/Configuration/ModLogLevel.cs b/Configuration/ModLogLevel.cs new file mode 100644 index 0000000..30d1b67 --- /dev/null +++ b/Configuration/ModLogLevel.cs @@ -0,0 +1,11 @@ +namespace AutoRefillFires +{ + public enum ModLogLevel + { + None = 0, + Error = 1, + Warning = 2, + Info = 3, + Debug = 4 + } +} diff --git a/Fuel/FuelManager.cs b/Fuel/FuelManager.cs new file mode 100644 index 0000000..b2d6868 --- /dev/null +++ b/Fuel/FuelManager.cs @@ -0,0 +1,169 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace AutoRefillFires +{ + 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 consumed = 0; + + if (_config.FuelSourcePriority.Value == FuelSourcePriority.ContainersFirst) + { + if (_config.UseNearbyContainers.Value && containers != null) + consumed += ConsumeFuelFromNearbyContainers(target, fuelName, requestedAmount - consumed, containers); + + if (consumed < requestedAmount) + consumed += ConsumeFuelFromPlayer(player, fuelName, requestedAmount - consumed); + } + else + { + consumed += ConsumeFuelFromPlayer(player, fuelName, requestedAmount); + + if (_config.UseNearbyContainers.Value && containers != null && consumed < requestedAmount) + consumed += ConsumeFuelFromNearbyContainers(target, fuelName, requestedAmount - consumed, containers); + } + + _log.Debug( + $"Fuel request result: fuel='{fuelName}', " + + $"requested={requestedAmount}, " + + $"consumed={consumed}" + ); + + return consumed; + } + + private int ConsumeFuelFromPlayer(Player player, string fuelName, int requestedAmount) + { + if (requestedAmount <= 0) + return 0; + + Inventory inventory = player.GetInventory(); + + if (inventory == null) + { + _log.Debug("Player inventory is null."); + return 0; + } + + int availableFuel = inventory.CountItems(fuelName); + int usableFuel = Mathf.Max(availableFuel - _config.KeepFuelReserve.Value, 0); + int amountToTake = Mathf.Min(requestedAmount, usableFuel); + + if (amountToTake <= 0) + { + _log.Debug( + $"Player inventory: fuel='{fuelName}', " + + $"available={availableFuel}, " + + $"reserve={_config.KeepFuelReserve.Value}, " + + $"usable=0" + ); + + return 0; + } + + inventory.RemoveItem(fuelName, amountToTake); + + _log.Debug( + $"Player inventory: consumed={amountToTake}x {fuelName}, " + + $"before={availableFuel}, " + + $"remaining={availableFuel - amountToTake}" + ); + + return amountToTake; + } + + private int ConsumeFuelFromNearbyContainers(Transform target, string fuelName, int requestedAmount, Container[] containers) + { + if (requestedAmount <= 0) + return 0; + + if (containers == null || containers.Length == 0) + return 0; + + List candidates = new List(); + + foreach (Container container in containers) + { + if (container == null) + continue; + + float distance = Vector3.Distance(target.position, container.transform.position); + + if (distance > _config.ContainerRadius.Value) + continue; + + Inventory inventory = container.GetInventory(); + + if (inventory == null) + continue; + + int availableFuel = inventory.CountItems(fuelName); + int usableFuel = Mathf.Max(availableFuel - _config.KeepFuelReserve.Value, 0); + + if (usableFuel <= 0) + continue; + + candidates.Add(new ContainerCandidate + { + Container = container, + Distance = distance + }); + } + + candidates.Sort((a, b) => a.Distance.CompareTo(b.Distance)); + + int consumed = 0; + + foreach (ContainerCandidate candidate in candidates) + { + if (consumed >= requestedAmount) + break; + + Inventory inventory = candidate.Container.GetInventory(); + + if (inventory == null) + continue; + + int availableFuel = inventory.CountItems(fuelName); + int usableFuel = Mathf.Max(availableFuel - _config.KeepFuelReserve.Value, 0); + + if (usableFuel <= 0) + continue; + + int amountToTake = Mathf.Min(requestedAmount - consumed, usableFuel); + + inventory.RemoveItem(fuelName, amountToTake); + consumed += amountToTake; + + _log.Debug( + $"Container '{candidate.Container.name}' ({candidate.Distance:0.0}m): " + + $"consumed={amountToTake}x {fuelName}" + ); + } + + return consumed; + } + } +} diff --git a/Logging/ModLogger.cs b/Logging/ModLogger.cs new file mode 100644 index 0000000..438980f --- /dev/null +++ b/Logging/ModLogger.cs @@ -0,0 +1,40 @@ +using BepInEx.Logging; + +namespace AutoRefillFires +{ + 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($"[DEBUG] {message}"); + } + + public void Info(string message) + { + if (_config.LogLevel.Value >= ModLogLevel.Info) + _logger.LogInfo(message); + } + + public void Warning(string message) + { + if (_config.LogLevel.Value >= ModLogLevel.Warning) + _logger.LogWarning(message); + } + + public void Error(string message) + { + if (_config.LogLevel.Value >= ModLogLevel.Error) + _logger.LogError(message); + } + } +} diff --git a/Models/ContainerCandidate.cs b/Models/ContainerCandidate.cs new file mode 100644 index 0000000..601e50c --- /dev/null +++ b/Models/ContainerCandidate.cs @@ -0,0 +1,8 @@ +namespace AutoRefillFires +{ + internal class ContainerCandidate + { + public Container Container; + public float Distance; + } +} diff --git a/Models/FireplaceCandidate.cs b/Models/FireplaceCandidate.cs new file mode 100644 index 0000000..9fb1a0c --- /dev/null +++ b/Models/FireplaceCandidate.cs @@ -0,0 +1,9 @@ +namespace AutoRefillFires +{ + internal class FireplaceCandidate + { + public Fireplace Fireplace; + public float Distance; + public float FuelPercent; + } +} diff --git a/Plugin.cs b/Plugin.cs index 5e6e2b9..942eb90 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -1,222 +1,34 @@ using BepInEx; -using BepInEx.Configuration; -using System.Collections.Generic; using UnityEngine; -using static UnityEngine.GraphicsBuffer; namespace AutoRefillFires { - public enum ModLogLevel - { - None = 0, - Error = 1, - Warning = 2, - Info = 3, - Debug = 4 - } - public enum FuelSourcePriority - { - PlayerFirst, - ContainersFirst - } - - [BepInPlugin( - Plugin.PluginGuid, - Plugin.PluginName, - Plugin.PluginVersion - )] + [BepInPlugin(Plugin.PluginGuid, Plugin.PluginName, Plugin.PluginVersion)] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "simplifydave.autorefillfires"; public const string PluginName = "Auto Refill Fires"; public const string PluginVersion = VersionInfo.Version; - private ConfigEntry _radius; - private ConfigEntry _checkInterval; - private ConfigEntry _refillBelowPercent; + private ModConfig _config; + private ModLogger _log; + private RefillManager _refillManager; - private ConfigEntry _useNearbyContainers; - private ConfigEntry _containerRadius; - - private ConfigEntry _refillToMax; - private ConfigEntry _refillAmount; - private ConfigEntry _fillCampfires; - private ConfigEntry _fillHearths; - private ConfigEntry _fillStandingTorches; - private ConfigEntry _fillWallTorches; - private ConfigEntry _fillBraziers; - private ConfigEntry _fillBonfires; - private ConfigEntry _fillHotTubs; - private ConfigEntry _fillOtherFireplaces; - private ConfigEntry _keepFuelReserve; - private ConfigEntry _fuelSourcePriority; - private ConfigEntry _onlyRefillOwnPieces; - private ConfigEntry _toggleHotkey; - private ConfigEntry _logLevel; private bool _modEnabled = true; - private float _nextCheckTime; - private class ContainerCandidate - { - public Container Container; - public float Distance; - } - private class FireplaceCandidate - { - public Fireplace Fireplace; - public float Distance; - public float FuelPercent; - } - private void Awake() { - _radius = Config.Bind( - "General", - "Radius", - 20f, - "Refill fireplaces within this radius around the player." - ); - - _checkInterval = Config.Bind( - "General", - "CheckInterval", - 3f, - "How often fireplaces are checked, in seconds." - ); - - _refillBelowPercent = Config.Bind( - "General", - "RefillBelowPercent", - 0.75f, - "Refill when fuel drops below this percentage." - ); - - _refillToMax = Config.Bind( - "General", - "RefillToMax", - true, - "If true, refill fireplaces to maximum fuel. If false, add only RefillAmount fuel." - ); - - _refillAmount = Config.Bind( - "General", - "RefillAmount", - 5, - "Amount of fuel to add when RefillToMax is false." - ); - - _useNearbyContainers = Config.Bind( - "Containers", - "UseNearbyContainers", - false, - "Allow plugin to take fuel from nearby containers." - ); - - _containerRadius = Config.Bind( - "Containers", - "ContainerRadius", - 10f, - "Maximum distance from the fireplace to search for containers." - ); - - _fillCampfires = Config.Bind( - "Fireplace Types", - "FillCampfires", - true, - "Automatically refill campfires." - ); - - _fillHearths = Config.Bind( - "Fireplace Types", - "FillHearths", - true, - "Automatically refill hearths." - ); - - _fillStandingTorches = Config.Bind( - "Fireplace Types", - "FillStandingTorches", - true, - "Automatically refill all standing torches, including colored variants." - ); - - _fillWallTorches = Config.Bind( - "Fireplace Types", - "FillWallTorches", - true, - "Automatically refill all wall torches, including colored variants." - ); - - _fillBraziers = Config.Bind( - "Fireplace Types", - "FillBraziers", - true, - "Automatically refill braziers." - ); - - _fillBonfires = Config.Bind( - "Fireplace Types", - "FillBonfires", - true, - "Automatically refill bonfires." - ); - - _fillHotTubs = Config.Bind( - "Fireplace Types", - "FillHotTubs", - true, - "Automatically refill hot tubs." - ); - - _fillOtherFireplaces = Config.Bind( - "Fireplace Types", - "FillOtherFireplaces", - true, - "Automatically refill unknown or modded Fireplace-based objects." - ); - - _toggleHotkey = Config.Bind( - "General", - "ToggleHotkey", - new KeyboardShortcut(KeyCode.F7), - "Hotkey used to enable or disable automatic refilling." - ); - - _keepFuelReserve = Config.Bind( - "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( - "Fuel", - "FuelSourcePriority", - FuelSourcePriority.PlayerFirst, - "Select whether player inventory or nearby containers should be used first." - ); - - _onlyRefillOwnPieces = Config.Bind( - "General", - "OnlyRefillOwnPieces", - false, - "If enabled, only refill fireplaces and torches built by the local player." - ); - - _logLevel = Config.Bind( - "Logging", - "LogLevel", - ModLogLevel.Info, - "Logging verbosity. Available values: None, Error, Warning, Info, Debug." - ); + _config = new ModConfig(Config); + _log = new ModLogger(_config, Logger); + _refillManager = new RefillManager(_config, _log); Logger.LogInfo("Auto Refill Fires loaded!"); } private void Update() { - if (_toggleHotkey.Value.IsDown()) + if (_config.ToggleHotkey.Value.IsDown()) { _modEnabled = !_modEnabled; @@ -226,11 +38,11 @@ namespace AutoRefillFires try { Config.Reload(); - LogInfo("Configuration reloaded."); + _log.Info("Configuration reloaded."); } catch (System.Exception ex) { - LogError($"Failed to reload configuration: {ex}"); + _log.Error($"Failed to reload configuration: {ex}"); } } @@ -241,14 +53,9 @@ namespace AutoRefillFires Player player = Player.m_localPlayer; if (player != null) - { - player.Message( - MessageHud.MessageType.Center, - status - ); - } + player.Message(MessageHud.MessageType.Center, status); - LogInfo(status); + _log.Info(status); } if (!_modEnabled) @@ -257,847 +64,14 @@ namespace AutoRefillFires if (Time.time < _nextCheckTime) return; - _nextCheckTime = Time.time + _checkInterval.Value; + _nextCheckTime = Time.time + _config.CheckInterval.Value; Player localPlayer = Player.m_localPlayer; if (localPlayer == null) return; - RefillNearbyFireplaces(localPlayer); - } - - private bool ShouldRefillFireplace(Fireplace fireplace) - { - string objectName = fireplace.gameObject.name - .Replace("(Clone)", "") - .ToLowerInvariant(); - - bool result; - string matchedRule; - - if (objectName.Contains("fire_pit") || objectName.Contains("firepit")) - { - result = _fillCampfires.Value; - matchedRule = "FillCampfires"; - } - else if (objectName.Contains("hearth")) - { - result = _fillHearths.Value; - matchedRule = "FillHearths"; - } - else if (objectName.Contains("groundtorch")) - { - result = _fillStandingTorches.Value; - matchedRule = "FillStandingTorches"; - } - else if (objectName.Contains("walltorch")) - { - result = _fillWallTorches.Value; - matchedRule = "FillWallTorches"; - } - else if (objectName.Contains("brazier")) - { - result = _fillBraziers.Value; - matchedRule = "FillBraziers"; - } - else if (objectName.Contains("bonfire")) - { - result = _fillBonfires.Value; - matchedRule = "FillBonfires"; - } - else if (objectName.Contains("hottub") || objectName.Contains("hot_tub")) - { - result = _fillHotTubs.Value; - matchedRule = "FillHotTubs"; - } - else - { - result = _fillOtherFireplaces.Value; - matchedRule = "FillOtherFireplaces"; - } - - LogDebug( - $"ShouldRefillFireplace: name='{fireplace.gameObject.name}', " + - $"normalized='{objectName}', matchedRule={matchedRule}, result={result}" - ); - - return result; - } - - private void RefillNearbyFireplaces(Player player) - { - Fireplace[] fireplaces = - Object.FindObjectsByType( - FindObjectsInactive.Exclude, - FindObjectsSortMode.None - ); - - Smelter[] smelters = null; - - if (_fillHotTubs.Value) - { - smelters = - Object.FindObjectsByType( - FindObjectsInactive.Exclude, - FindObjectsSortMode.None - ); - } - - Container[] containers = null; - - if (_useNearbyContainers.Value) - { - containers = - Object.FindObjectsByType( - FindObjectsInactive.Exclude, - FindObjectsSortMode.None - ); - } - - List candidates = - new List(); - - foreach (Fireplace fireplace in fireplaces) - { - if (fireplace == null) - continue; - - float distance = Vector3.Distance( - player.transform.position, - fireplace.transform.position - ); - - if (distance > _radius.Value) - continue; - - ZNetView nview = - fireplace.GetComponent(); - - if (nview == null) - nview = fireplace.GetComponentInParent(); - - if (nview == null || !nview.IsValid()) - continue; - - ZDO zdo = nview.GetZDO(); - - if (zdo == null) - continue; - - float maxFuel = - fireplace.m_maxFuel; - - if (maxFuel <= 0f) - continue; - - float currentFuel = - zdo.GetFloat( - ZDOVars.s_fuel, - 0f - ); - - float fuelPercent = - currentFuel / maxFuel; - - candidates.Add( - new FireplaceCandidate - { - Fireplace = fireplace, - Distance = distance, - FuelPercent = fuelPercent - } - ); - } - - /* - * Priority: - * - * 1. Lowest fuel percentage first - * 2. If equal, nearest fireplace first - */ - candidates.Sort( - (a, b) => - { - int fuelCompare = - a.FuelPercent.CompareTo( - b.FuelPercent - ); - - if (fuelCompare != 0) - return fuelCompare; - - return a.Distance.CompareTo( - b.Distance - ); - } - ); - - LogDebug( - $"Scan start: " + - $"loadedFireplaces={fireplaces.Length}, " + - $"inRange={candidates.Count}, " + - $"loadedContainers={(containers != null ? containers.Length : 0)}, " + - $"radius={_radius.Value:0.0}m" - ); - - foreach (FireplaceCandidate candidate in candidates) - { - LogDebug( - $"Priority: " + - $"name='{candidate.Fireplace.gameObject.name}', " + - $"fuel={candidate.FuelPercent * 100f:0.0}%, " + - $"distance={candidate.Distance:0.0}m" - ); - - TryRefillFireplace( - player, - candidate.Fireplace, - containers - ); - } - - if (_fillHotTubs.Value && smelters != null) - { - RefillNearbyHotTubs( - player, - smelters, - containers - ); - } - - LogDebug("Scan end."); - } - - private void RefillNearbyHotTubs( - Player player, - Smelter[] smelters, - Container[] containers) - { - int hotTubsInRange = 0; - - foreach (Smelter smelter in smelters) - { - if (smelter == null) - continue; - - string objectName = - smelter.gameObject.name - .Replace("(Clone)", "") - .ToLowerInvariant(); - - if (objectName != "piece_bathtub") - continue; - - float distance = Vector3.Distance( - player.transform.position, - smelter.transform.position - ); - - if (distance > _radius.Value) - continue; - - hotTubsInRange++; - - LogDebug( - $"Hot tub in range: " + - $"name='{smelter.gameObject.name}', " + - $"distance={distance:0.0}m" - ); - - TryRefillHotTub( - player, - smelter, - containers - ); - } - - LogDebug( - $"Hot tub scan end: inRange={hotTubsInRange}" - ); - } - - private void TryRefillHotTub( - Player player, - Smelter smelter, - Container[] containers) - { - if (smelter == null) - return; - - ZNetView nview = - smelter.GetComponent(); - - if (nview == null) - nview = smelter.GetComponentInParent(); - - if (nview == null || !nview.IsValid()) - { - LogDebug("Hot tub: invalid ZNetView."); - return; - } - - ZDO zdo = nview.GetZDO(); - - if (zdo == null) - { - LogDebug("Hot tub: ZDO is null."); - return; - } - - if ( - smelter.m_fuelItem == null || - smelter.m_fuelItem.m_itemData == null || - smelter.m_fuelItem.m_itemData.m_shared == null - ) - { - LogDebug("Hot tub: fuel item is null."); - return; - } - - string fuelName = - smelter.m_fuelItem.m_itemData.m_shared.m_name; - - float currentFuel = - zdo.GetFloat( - ZDOVars.s_fuel, - 0f - ); - - float maxFuel = - smelter.m_maxFuel; - - if (maxFuel <= 0f) - return; - - float fuelPercent = - currentFuel / maxFuel; - - LogDebug( - $"Hot tub fuel state: " + - $"fuel='{fuelName}', " + - $"current={currentFuel:0.00}, " + - $"max={maxFuel:0.00}, " + - $"percent={fuelPercent * 100f:0.0}%, " + - $"threshold={_refillBelowPercent.Value * 100f:0.0}%" - ); - - if (fuelPercent >= _refillBelowPercent.Value) - { - LogDebug( - "Skipping hot tub - fuelPercent >= threshold." - ); - - return; - } - - int missingFuel = - Mathf.CeilToInt( - maxFuel - currentFuel - ); - - int requestedFuel = - _refillToMax.Value - ? missingFuel - : Mathf.Min( - _refillAmount.Value, - missingFuel - ); - - if (requestedFuel <= 0) - return; - - LogDebug( - $"Hot tub refill requested: " + - $"missing={missingFuel}, " + - $"requested={requestedFuel}" - ); - - int fuelConsumed = - ConsumeFuel( - player, - smelter.transform, - fuelName, - requestedFuel, - containers - ); - - if (fuelConsumed <= 0) - { - LogDebug( - "Hot tub refill stopped: no usable fuel." - ); - - return; - } - - for (int i = 0; i < fuelConsumed; i++) - { - nview.InvokeRPC( - "RPC_AddFuel", - new object[0] - ); - } - - LogInfo( - $"Refilled hot tub: " + - $"{currentFuel:0.0}/{maxFuel:0.0}, " + - $"fuel={fuelName}, " + - $"added={fuelConsumed}, " + - $"mode={(_refillToMax.Value ? "max" : "fixed")}" - ); - } - - private bool IsOwnPiece(Player player, Fireplace fireplace) - { - Piece piece = fireplace.GetComponent(); - - if (piece == null) - piece = fireplace.GetComponentInParent(); - - if (piece == null) - { - // Unknown/modded fireplace without a Piece component. - // Don't block it. - return true; - } - - return piece.GetCreator() == player.GetPlayerID(); - } - - private void TryRefillFireplace(Player player, Fireplace fireplace, Container[] containers) - { - LogDebug($"TryRefillFireplace START: '{fireplace.gameObject.name}'"); - - if (!ShouldRefillFireplace(fireplace)) - { - LogDebug( - $"Skipping '{fireplace.gameObject.name}' - type/config filter returned false." - ); - return; - } - - if (_onlyRefillOwnPieces.Value && !IsOwnPiece(player, fireplace)) - { - LogDebug( - $"Skipping '{fireplace.gameObject.name}' - not owned by local player." - ); - return; - } - - ZNetView nview = fireplace.GetComponent(); - - if (nview == null) - nview = fireplace.GetComponentInParent(); - - if (nview == null) - { - LogDebug( - $"Skipping '{fireplace.gameObject.name}' - no ZNetView found." - ); - return; - } - - if (!nview.IsValid()) - { - LogDebug( - $"Skipping '{fireplace.gameObject.name}' - ZNetView is not valid." - ); - return; - } - - ZDO zdo = nview.GetZDO(); - - if (zdo == null) - { - LogDebug( - $"Skipping '{fireplace.gameObject.name}' - ZDO is null." - ); - return; - } - - if (fireplace.m_fuelItem == null) - { - LogDebug( - $"Skipping '{fireplace.gameObject.name}' - m_fuelItem is null." - ); - return; - } - - float currentFuel = zdo.GetFloat(ZDOVars.s_fuel, 0f); - float maxFuel = fireplace.m_maxFuel; - - if (maxFuel <= 0f) - { - LogDebug( - $"Skipping '{fireplace.gameObject.name}' - maxFuel <= 0 ({maxFuel})." - ); - return; - } - - float fuelPercent = currentFuel / maxFuel; - - LogDebug( - $"Fuel state for '{fireplace.gameObject.name}': " + - $"currentFuel={currentFuel:0.0}, maxFuel={maxFuel:0.0}, " + - $"fuelPercent={fuelPercent:0.00}, threshold={_refillBelowPercent.Value:0.00}" - ); - - if (fuelPercent >= _refillBelowPercent.Value) - { - LogDebug( - $"Skipping '{fireplace.gameObject.name}' - fuelPercent >= threshold." - ); - return; - } - - string fuelName = - fireplace.m_fuelItem.m_itemData.m_shared.m_name; - - int missingFuel = - Mathf.CeilToInt(maxFuel - currentFuel); - - if (missingFuel <= 0) - { - LogDebug( - $"Skipping '{fireplace.gameObject.name}' - missingFuel <= 0 ({missingFuel})." - ); - return; - } - - int requestedFuel; - - if (_refillToMax.Value) - { - requestedFuel = missingFuel; - } - else - { - requestedFuel = Mathf.Min( - Mathf.Max(_refillAmount.Value, 0), - missingFuel - ); - } - - LogDebug( - $"Refill request for '{fireplace.gameObject.name}': " + - $"fuel='{fuelName}', missingFuel={missingFuel}, requestedFuel={requestedFuel}, " + - $"refillMode={(_refillToMax.Value ? "max" : "fixed")}" - ); - - if (requestedFuel <= 0) - { - LogDebug( - $"Skipping '{fireplace.gameObject.name}' - requestedFuel <= 0." - ); - return; - } - - int fuelAdded = 0; - - int fuelConsumed = ConsumeFuel( - player, - fireplace.transform, - fuelName, - requestedFuel, - containers - ); - - if (fuelConsumed <= 0) - { - LogDebug( - $"No usable fuel found for '{fireplace.gameObject.name}'." - ); - - return; - } - - for (int i = 0; i < fuelConsumed; i++) - { - nview.InvokeRPC( - "RPC_AddFuel", - new object[0] - ); - } - - LogInfo( - $"Refilled {fireplace.name}: " + - $"{currentFuel:0.0}/{maxFuel:0.0}, " + - $"fuel={fuelName}, " + - $"added={fuelConsumed}, " + - $"mode={(_refillToMax.Value ? "max" : "fixed")}" - ); - - if (fuelAdded > 0) - { - LogInfo( - $"Refilled {fireplace.name}: " + - $"{currentFuel:0.0}/{maxFuel:0.0}, " + - $"fuel={fuelName}, " + - $"added={fuelAdded}, " + - $"mode={(_refillToMax.Value ? "max" : "fixed")}" - ); - } - } - - private int ConsumeFuelFromPlayer(Player player, string fuelName, int requestedAmount) - { - if (requestedAmount <= 0) - return 0; - - Inventory inventory = player.GetInventory(); - - if (inventory == null) - { - LogDebug("Player inventory is null."); - return 0; - } - - int availableFuel = - inventory.CountItems(fuelName); - - int usableFuel = - Mathf.Max( - availableFuel - _keepFuelReserve.Value, - 0 - ); - - int amountToTake = - Mathf.Min( - requestedAmount, - usableFuel - ); - - if (amountToTake <= 0) - { - LogDebug( - $"Player inventory: fuel='{fuelName}', " + - $"available={availableFuel}, " + - $"reserve={_keepFuelReserve.Value}, " + - $"usable=0" - ); - - return 0; - } - - inventory.RemoveItem( - fuelName, - amountToTake - ); - - LogDebug( - $"Player inventory: consumed={amountToTake}x {fuelName}, " + - $"before={availableFuel}, " + - $"remaining={availableFuel - amountToTake}" - ); - - return amountToTake; - } - - private int ConsumeFuel( - Player player, - Transform target, - string fuelName, - int requestedAmount, - Container[] containers) - { - if (requestedAmount <= 0) - return 0; - - LogDebug( - $"Fuel request: " + - $"fuel='{fuelName}', " + - $"requested={requestedAmount}, " + - $"priority={_fuelSourcePriority.Value}, " + - $"containers={_useNearbyContainers.Value}, " + - $"reserve={_keepFuelReserve.Value}" - ); - - int consumed = 0; - - if (_fuelSourcePriority.Value == FuelSourcePriority.ContainersFirst) - { - if (_useNearbyContainers.Value && containers != null) - { - consumed += ConsumeFuelFromNearbyContainers( - target, - fuelName, - requestedAmount - consumed, - containers - ); - } - - if (consumed < requestedAmount) - { - consumed += ConsumeFuelFromPlayer( - player, - fuelName, - requestedAmount - consumed - ); - } - } - else - { - consumed += ConsumeFuelFromPlayer( - player, - fuelName, - requestedAmount - ); - - if ( - _useNearbyContainers.Value && - containers != null && - consumed < requestedAmount - ) - { - consumed += ConsumeFuelFromNearbyContainers( - target, - fuelName, - requestedAmount - consumed, - containers - ); - } - } - - LogDebug( - $"Fuel request result: " + - $"fuel='{fuelName}', " + - $"requested={requestedAmount}, " + - $"consumed={consumed}" - ); - - return consumed; - } - - private int ConsumeFuelFromNearbyContainers( - Transform target, - string fuelName, - int requestedAmount, - Container[] containers) - { - if (requestedAmount <= 0) - return 0; - - if (containers == null || containers.Length == 0) - return 0; - - List candidates = - new List(); - - foreach (Container container in containers) - { - if (container == null) - continue; - - float distance = Vector3.Distance( - target.position, - container.transform.position - ); - - if (distance > _containerRadius.Value) - continue; - - Inventory inventory = - container.GetInventory(); - - if (inventory == null) - continue; - - int availableFuel = - inventory.CountItems(fuelName); - - int usableFuel = - Mathf.Max( - availableFuel - _keepFuelReserve.Value, - 0 - ); - - if (usableFuel <= 0) - continue; - - candidates.Add( - new ContainerCandidate - { - Container = container, - Distance = distance - } - ); - } - - candidates.Sort( - (a, b) => a.Distance.CompareTo(b.Distance) - ); - - int consumed = 0; - - foreach (ContainerCandidate candidate in candidates) - { - if (consumed >= requestedAmount) - break; - - Inventory inventory = - candidate.Container.GetInventory(); - - if (inventory == null) - continue; - - int availableFuel = - inventory.CountItems(fuelName); - - int usableFuel = - Mathf.Max( - availableFuel - _keepFuelReserve.Value, - 0 - ); - - if (usableFuel <= 0) - continue; - - int amountToTake = - Mathf.Min( - requestedAmount - consumed, - usableFuel - ); - - inventory.RemoveItem( - fuelName, - amountToTake - ); - - consumed += amountToTake; - - LogDebug( - $"Container '{candidate.Container.name}' " + - $"({candidate.Distance:0.0}m): " + - $"consumed={amountToTake}x {fuelName}" - ); - } - - return consumed; - } - - private void LogDebug(string message) - { - if (_logLevel.Value >= ModLogLevel.Debug) - Logger.LogInfo($"[DEBUG] {message}"); - } - - private void LogInfo(string message) - { - if (_logLevel.Value >= ModLogLevel.Info) - Logger.LogInfo(message); - } - - private void LogWarning(string message) - { - if (_logLevel.Value >= ModLogLevel.Warning) - Logger.LogWarning(message); - } - - private void LogError(string message) - { - if (_logLevel.Value >= ModLogLevel.Error) - Logger.LogError(message); + _refillManager.Run(localPlayer); } } -} \ No newline at end of file +} diff --git a/Refill/FireplaceRefiller.cs b/Refill/FireplaceRefiller.cs new file mode 100644 index 0000000..dc6f3f4 --- /dev/null +++ b/Refill/FireplaceRefiller.cs @@ -0,0 +1,195 @@ +using UnityEngine; + +namespace AutoRefillFires +{ + 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: '{fireplace.gameObject.name}'"); + + if (!ShouldRefillFireplace(fireplace)) + { + _log.Debug($"Skipping '{fireplace.gameObject.name}' - type/config filter returned false."); + return; + } + + if (_config.OnlyRefillOwnPieces.Value && !IsOwnPiece(player, fireplace)) + { + _log.Debug($"Skipping '{fireplace.gameObject.name}' - not owned by local player."); + return; + } + + ZNetView nview = fireplace.GetComponent(); + + if (nview == null) + nview = fireplace.GetComponentInParent(); + + if (nview == null) + { + _log.Debug($"Skipping '{fireplace.gameObject.name}' - no ZNetView found."); + return; + } + + if (!nview.IsValid()) + { + _log.Debug($"Skipping '{fireplace.gameObject.name}' - ZNetView is not valid."); + return; + } + + ZDO zdo = nview.GetZDO(); + + if (zdo == null) + { + _log.Debug($"Skipping '{fireplace.gameObject.name}' - ZDO is null."); + return; + } + + if (fireplace.m_fuelItem == null || fireplace.m_fuelItem.m_itemData == null || fireplace.m_fuelItem.m_itemData.m_shared == null) + { + _log.Debug($"Skipping '{fireplace.gameObject.name}' - fuel item is null."); + return; + } + + float currentFuel = zdo.GetFloat(ZDOVars.s_fuel, 0f); + float maxFuel = fireplace.m_maxFuel; + + if (maxFuel <= 0f) + { + _log.Debug($"Skipping '{fireplace.gameObject.name}' - maxFuel <= 0 ({maxFuel})."); + return; + } + + float fuelPercent = currentFuel / maxFuel; + + _log.Debug( + $"Fuel state for '{fireplace.gameObject.name}': " + + $"currentFuel={currentFuel:0.0}, maxFuel={maxFuel:0.0}, " + + $"fuelPercent={fuelPercent:0.00}, threshold={_config.RefillBelowPercent.Value:0.00}" + ); + + if (fuelPercent >= _config.RefillBelowPercent.Value) + { + _log.Debug($"Skipping '{fireplace.gameObject.name}' - fuelPercent >= threshold."); + return; + } + + string fuelName = fireplace.m_fuelItem.m_itemData.m_shared.m_name; + int missingFuel = Mathf.CeilToInt(maxFuel - currentFuel); + + if (missingFuel <= 0) + { + _log.Debug($"Skipping '{fireplace.gameObject.name}' - missingFuel <= 0 ({missingFuel})."); + return; + } + + int requestedFuel = _config.RefillToMax.Value + ? missingFuel + : Mathf.Min(Mathf.Max(_config.RefillAmount.Value, 0), missingFuel); + + _log.Debug( + $"Refill request for '{fireplace.gameObject.name}': " + + $"fuel='{fuelName}', missingFuel={missingFuel}, requestedFuel={requestedFuel}, " + + $"refillMode={(_config.RefillToMax.Value ? "max" : "fixed")}" + ); + + if (requestedFuel <= 0) + { + _log.Debug($"Skipping '{fireplace.gameObject.name}' - requestedFuel <= 0."); + return; + } + + int fuelConsumed = _fuelManager.ConsumeFuel(player, fireplace.transform, fuelName, requestedFuel, containers); + + if (fuelConsumed <= 0) + { + _log.Debug($"No usable fuel found for '{fireplace.gameObject.name}'."); + return; + } + + for (int i = 0; i < fuelConsumed; i++) + nview.InvokeRPC("RPC_AddFuel", new object[0]); + + _log.Info( + $"Refilled {fireplace.name}: {currentFuel:0.0}/{maxFuel:0.0}, " + + $"fuel={fuelName}, added={fuelConsumed}, " + + $"mode={(_config.RefillToMax.Value ? "max" : "fixed")}" + ); + } + + private bool ShouldRefillFireplace(Fireplace fireplace) + { + string objectName = fireplace.gameObject.name.Replace("(Clone)", "").ToLowerInvariant(); + + bool result; + string matchedRule; + + if (objectName.Contains("fire_pit") || objectName.Contains("firepit")) + { + result = _config.FillCampfires.Value; + matchedRule = "FillCampfires"; + } + else if (objectName.Contains("hearth")) + { + result = _config.FillHearths.Value; + matchedRule = "FillHearths"; + } + else if (objectName.Contains("groundtorch")) + { + result = _config.FillStandingTorches.Value; + matchedRule = "FillStandingTorches"; + } + else if (objectName.Contains("walltorch")) + { + result = _config.FillWallTorches.Value; + matchedRule = "FillWallTorches"; + } + else if (objectName.Contains("brazier")) + { + result = _config.FillBraziers.Value; + matchedRule = "FillBraziers"; + } + else if (objectName.Contains("bonfire")) + { + result = _config.FillBonfires.Value; + matchedRule = "FillBonfires"; + } + else + { + result = _config.FillOtherFireplaces.Value; + matchedRule = "FillOtherFireplaces"; + } + + _log.Debug( + $"ShouldRefillFireplace: name='{fireplace.gameObject.name}', " + + $"normalized='{objectName}', matchedRule={matchedRule}, result={result}" + ); + + return result; + } + + private bool IsOwnPiece(Player player, Fireplace fireplace) + { + Piece piece = fireplace.GetComponent(); + + if (piece == null) + piece = fireplace.GetComponentInParent(); + + if (piece == null) + return true; + + return piece.GetCreator() == player.GetPlayerID(); + } + } +} diff --git a/Refill/HotTubRefiller.cs b/Refill/HotTubRefiller.cs new file mode 100644 index 0000000..8e7bdd3 --- /dev/null +++ b/Refill/HotTubRefiller.cs @@ -0,0 +1,127 @@ +using UnityEngine; + +namespace AutoRefillFires +{ + internal class HotTubRefiller + { + private readonly ModConfig _config; + private readonly FuelManager _fuelManager; + private readonly ModLogger _log; + + public HotTubRefiller(ModConfig config, FuelManager fuelManager, ModLogger log) + { + _config = config; + _fuelManager = fuelManager; + _log = log; + } + + public void RefillNearby(Player player, Smelter[] smelters, Container[] containers) + { + int hotTubsInRange = 0; + + foreach (Smelter smelter in smelters) + { + if (smelter == null) + continue; + + string objectName = smelter.gameObject.name.Replace("(Clone)", "").ToLowerInvariant(); + + if (objectName != "piece_bathtub") + continue; + + float distance = Vector3.Distance(player.transform.position, smelter.transform.position); + + if (distance > _config.Radius.Value) + continue; + + hotTubsInRange++; + + _log.Debug( + $"Hot tub in range: name='{smelter.gameObject.name}', " + + $"distance={distance:0.0}m" + ); + + TryRefillHotTub(player, smelter, containers); + } + + _log.Debug($"Hot tub scan end: inRange={hotTubsInRange}"); + } + + private void TryRefillHotTub(Player player, Smelter smelter, Container[] containers) + { + if (smelter == null) + return; + + ZNetView nview = smelter.GetComponent(); + + if (nview == null) + nview = smelter.GetComponentInParent(); + + if (nview == null || !nview.IsValid()) + { + _log.Debug("Hot tub: invalid ZNetView."); + return; + } + + ZDO zdo = nview.GetZDO(); + + if (zdo == null) + { + _log.Debug("Hot tub: ZDO is null."); + return; + } + + if (smelter.m_fuelItem == 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 fuelName = smelter.m_fuelItem.m_itemData.m_shared.m_name; + float currentFuel = zdo.GetFloat(ZDOVars.s_fuel, 0f); + float maxFuel = smelter.m_maxFuel; + + if (maxFuel <= 0f) + return; + + float fuelPercent = currentFuel / maxFuel; + + _log.Debug( + $"Hot tub fuel state: fuel='{fuelName}', " + + $"current={currentFuel:0.00}, max={maxFuel:0.00}, " + + $"percent={fuelPercent * 100f:0.0}%, threshold={_config.RefillBelowPercent.Value * 100f:0.0}%" + ); + + if (fuelPercent >= _config.RefillBelowPercent.Value) + { + _log.Debug("Skipping hot tub - fuelPercent >= threshold."); + return; + } + + int missingFuel = Mathf.CeilToInt(maxFuel - currentFuel); + int requestedFuel = _config.RefillToMax.Value ? missingFuel : Mathf.Min(_config.RefillAmount.Value, missingFuel); + + if (requestedFuel <= 0) + return; + + _log.Debug($"Hot tub refill requested: missing={missingFuel}, requested={requestedFuel}"); + + int fuelConsumed = _fuelManager.ConsumeFuel(player, smelter.transform, fuelName, requestedFuel, containers); + + if (fuelConsumed <= 0) + { + _log.Debug("Hot tub refill stopped: no usable fuel."); + return; + } + + for (int i = 0; i < fuelConsumed; i++) + nview.InvokeRPC("RPC_AddFuel", new object[0]); + + _log.Info( + $"Refilled hot tub: {currentFuel:0.0}/{maxFuel:0.0}, " + + $"fuel={fuelName}, added={fuelConsumed}, " + + $"mode={(_config.RefillToMax.Value ? "max" : "fixed")}" + ); + } + } +} diff --git a/Refill/RefillManager.cs b/Refill/RefillManager.cs new file mode 100644 index 0000000..2b4aaf8 --- /dev/null +++ b/Refill/RefillManager.cs @@ -0,0 +1,112 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace AutoRefillFires +{ + internal class RefillManager + { + private readonly ModConfig _config; + private readonly FireplaceRefiller _fireplaceRefiller; + private readonly HotTubRefiller _hotTubRefiller; + private readonly ModLogger _log; + + public RefillManager(ModConfig config, ModLogger log) + { + _config = config; + _log = log; + + FuelManager fuelManager = new FuelManager(_config, _log); + _fireplaceRefiller = new FireplaceRefiller(_config, fuelManager, _log); + _hotTubRefiller = new HotTubRefiller(_config, fuelManager, _log); + } + + public void Run(Player player) + { + Fireplace[] fireplaces = Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None); + Smelter[] smelters = null; + + if (_config.FillHotTubs.Value) + smelters = Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None); + + Container[] containers = null; + + if (_config.UseNearbyContainers.Value) + containers = Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None); + + List candidates = new List(); + + foreach (Fireplace fireplace in fireplaces) + { + if (fireplace == null) + continue; + + float distance = Vector3.Distance(player.transform.position, fireplace.transform.position); + + if (distance > _config.Radius.Value) + continue; + + ZNetView nview = fireplace.GetComponent(); + + if (nview == null) + nview = fireplace.GetComponentInParent(); + + if (nview == null || !nview.IsValid()) + continue; + + ZDO zdo = nview.GetZDO(); + + if (zdo == null) + continue; + + float maxFuel = fireplace.m_maxFuel; + + if (maxFuel <= 0f) + continue; + + float currentFuel = zdo.GetFloat(ZDOVars.s_fuel, 0f); + float fuelPercent = currentFuel / maxFuel; + + candidates.Add(new FireplaceCandidate + { + Fireplace = fireplace, + Distance = distance, + FuelPercent = fuelPercent + }); + } + + // Priority: lowest fuel percentage first, then nearest fireplace. + candidates.Sort((a, b) => + { + int fuelCompare = a.FuelPercent.CompareTo(b.FuelPercent); + + if (fuelCompare != 0) + return fuelCompare; + + return a.Distance.CompareTo(b.Distance); + }); + + _log.Debug( + $"Scan start: loadedFireplaces={fireplaces.Length}, " + + $"inRange={candidates.Count}, " + + $"loadedContainers={(containers != null ? containers.Length : 0)}, " + + $"radius={_config.Radius.Value:0.0}m" + ); + + foreach (FireplaceCandidate candidate in candidates) + { + _log.Debug( + $"Priority: name='{candidate.Fireplace.gameObject.name}', " + + $"fuel={candidate.FuelPercent * 100f:0.0}%, " + + $"distance={candidate.Distance:0.0}m" + ); + + _fireplaceRefiller.TryRefill(player, candidate.Fireplace, containers); + } + + if (_config.FillHotTubs.Value && smelters != null) + _hotTubRefiller.RefillNearby(player, smelters, containers); + + _log.Debug("Scan end."); + } + } +}