Refactored into separated components
This commit is contained in:
+6
-18
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>AutoRefillFires</RootNamespace>
|
||||
<LangVersion>latest</LangVersion>
|
||||
|
||||
<PluginVersion>1.1.0</PluginVersion>
|
||||
<PluginVersion>1.2.0</PluginVersion>
|
||||
|
||||
<ValheimPath>D:\SteamLibrary\steamapps\common\Valheim</ValheimPath>
|
||||
<R2ProfileName>Default</R2ProfileName>
|
||||
@@ -60,11 +60,7 @@
|
||||
</Target>
|
||||
|
||||
<Target Name="GenerateVersionInfo" BeforeTargets="BeforeCompile">
|
||||
<WriteLinesToFile
|
||||
File="$(IntermediateOutputPath)VersionInfo.cs"
|
||||
Overwrite="true"
|
||||
Lines="namespace AutoRefillFires { internal static class VersionInfo { public const string Version = "$(PluginVersion)"%3B } }"
|
||||
/>
|
||||
<WriteLinesToFile File="$(IntermediateOutputPath)VersionInfo.cs" Overwrite="true" Lines="namespace AutoRefillFires { internal static class VersionInfo { public const string Version = "$(PluginVersion)"%3B } }" />
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="$(IntermediateOutputPath)VersionInfo.cs" />
|
||||
@@ -84,21 +80,13 @@
|
||||
<MakeDir Directories="$(PackageRoot)" />
|
||||
<MakeDir Directories="$(PackagePlugins)" />
|
||||
|
||||
<Copy
|
||||
SourceFiles="$(TargetPath)"
|
||||
DestinationFolder="$(PackagePlugins)" />
|
||||
<Copy SourceFiles="$(TargetPath)" DestinationFolder="$(PackagePlugins)" />
|
||||
|
||||
<Copy
|
||||
SourceFiles="$(SolutionDir)Thunderstore\README.md"
|
||||
DestinationFolder="$(PackageRoot)" />
|
||||
<Copy SourceFiles="$(SolutionDir)Thunderstore\README.md" DestinationFolder="$(PackageRoot)" />
|
||||
|
||||
<Copy
|
||||
SourceFiles="$(SolutionDir)Thunderstore\CHANGELOG.md"
|
||||
DestinationFolder="$(PackageRoot)" />
|
||||
<Copy SourceFiles="$(SolutionDir)Thunderstore\CHANGELOG.md" DestinationFolder="$(PackageRoot)" />
|
||||
|
||||
<Copy
|
||||
SourceFiles="$(SolutionDir)Thunderstore\icon.png"
|
||||
DestinationFolder="$(PackageRoot)" />
|
||||
<Copy SourceFiles="$(SolutionDir)Thunderstore\icon.png" DestinationFolder="$(PackageRoot)" />
|
||||
|
||||
<Exec Command="powershell -NoProfile -ExecutionPolicy Bypass -Command "(Get-Content '$(SolutionDir)Thunderstore\manifest.json' -Raw).Replace('__VERSION__', '$(PluginVersion)') | Set-Content '$(PackageRoot)\manifest.json' -Encoding UTF8"" />
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace AutoRefillFires
|
||||
{
|
||||
public enum FuelSourcePriority
|
||||
{
|
||||
PlayerFirst,
|
||||
ContainersFirst
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
using BepInEx.Configuration;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AutoRefillFires
|
||||
{
|
||||
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> FillOtherFireplaces { get; }
|
||||
|
||||
public ConfigEntry<int> KeepFuelReserve { get; }
|
||||
public ConfigEntry<FuelSourcePriority> FuelSourcePriority { get; }
|
||||
|
||||
public ConfigEntry<bool> OnlyRefillOwnPieces { get; }
|
||||
public ConfigEntry<KeyboardShortcut> ToggleHotkey { get; }
|
||||
public ConfigEntry<ModLogLevel> 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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace AutoRefillFires
|
||||
{
|
||||
public enum ModLogLevel
|
||||
{
|
||||
None = 0,
|
||||
Error = 1,
|
||||
Warning = 2,
|
||||
Info = 3,
|
||||
Debug = 4
|
||||
}
|
||||
}
|
||||
@@ -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<ContainerCandidate> candidates = new List<ContainerCandidate>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace AutoRefillFires
|
||||
{
|
||||
internal class ContainerCandidate
|
||||
{
|
||||
public Container Container;
|
||||
public float Distance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace AutoRefillFires
|
||||
{
|
||||
internal class FireplaceCandidate
|
||||
{
|
||||
public Fireplace Fireplace;
|
||||
public float Distance;
|
||||
public float FuelPercent;
|
||||
}
|
||||
}
|
||||
@@ -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<ZNetView>();
|
||||
|
||||
if (nview == null)
|
||||
nview = fireplace.GetComponentInParent<ZNetView>();
|
||||
|
||||
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<Piece>();
|
||||
|
||||
if (piece == null)
|
||||
piece = fireplace.GetComponentInParent<Piece>();
|
||||
|
||||
if (piece == null)
|
||||
return true;
|
||||
|
||||
return piece.GetCreator() == player.GetPlayerID();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<ZNetView>();
|
||||
|
||||
if (nview == null)
|
||||
nview = smelter.GetComponentInParent<ZNetView>();
|
||||
|
||||
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")}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Fireplace>(FindObjectsInactive.Exclude, FindObjectsSortMode.None);
|
||||
Smelter[] smelters = null;
|
||||
|
||||
if (_config.FillHotTubs.Value)
|
||||
smelters = Object.FindObjectsByType<Smelter>(FindObjectsInactive.Exclude, FindObjectsSortMode.None);
|
||||
|
||||
Container[] containers = null;
|
||||
|
||||
if (_config.UseNearbyContainers.Value)
|
||||
containers = Object.FindObjectsByType<Container>(FindObjectsInactive.Exclude, FindObjectsSortMode.None);
|
||||
|
||||
List<FireplaceCandidate> candidates = new List<FireplaceCandidate>();
|
||||
|
||||
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<ZNetView>();
|
||||
|
||||
if (nview == null)
|
||||
nview = fireplace.GetComponentInParent<ZNetView>();
|
||||
|
||||
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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user