929 lines
27 KiB
C#
929 lines
27 KiB
C#
using BepInEx;
|
|
using BepInEx.Configuration;
|
|
using UnityEngine;
|
|
using System.Collections.Generic;
|
|
|
|
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
|
|
)]
|
|
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<float> _radius;
|
|
private ConfigEntry<float> _checkInterval;
|
|
private ConfigEntry<float> _refillBelowPercent;
|
|
|
|
private ConfigEntry<bool> _useNearbyContainers;
|
|
private ConfigEntry<float> _containerRadius;
|
|
|
|
private ConfigEntry<bool> _refillToMax;
|
|
private ConfigEntry<int> _refillAmount;
|
|
private ConfigEntry<bool> _fillCampfires;
|
|
private ConfigEntry<bool> _fillHearths;
|
|
private ConfigEntry<bool> _fillStandingTorches;
|
|
private ConfigEntry<bool> _fillWallTorches;
|
|
private ConfigEntry<bool> _fillBraziers;
|
|
private ConfigEntry<bool> _fillBonfires;
|
|
private ConfigEntry<bool> _fillOtherFireplaces;
|
|
private ConfigEntry<int> _keepFuelReserve;
|
|
private ConfigEntry<FuelSourcePriority> _fuelSourcePriority;
|
|
private ConfigEntry<bool> _onlyRefillOwnPieces;
|
|
private ConfigEntry<KeyboardShortcut> _toggleHotkey;
|
|
private ConfigEntry<ModLogLevel> _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."
|
|
);
|
|
|
|
_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."
|
|
);
|
|
|
|
Logger.LogInfo("Auto Refill Fires loaded!");
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (_toggleHotkey.Value.IsDown())
|
|
{
|
|
_modEnabled = !_modEnabled;
|
|
|
|
// Reload config when turning the mod OFF
|
|
if (!_modEnabled)
|
|
{
|
|
try
|
|
{
|
|
Config.Reload();
|
|
LogInfo("Configuration reloaded.");
|
|
}
|
|
catch (System.Exception ex)
|
|
{
|
|
LogError($"Failed to reload configuration: {ex}");
|
|
}
|
|
}
|
|
|
|
string status = _modEnabled
|
|
? "Auto Refill Fires: ENABLED"
|
|
: "Auto Refill Fires: DISABLED";
|
|
|
|
Player player = Player.m_localPlayer;
|
|
|
|
if (player != null)
|
|
{
|
|
player.Message(
|
|
MessageHud.MessageType.Center,
|
|
status
|
|
);
|
|
}
|
|
|
|
LogInfo(status);
|
|
}
|
|
|
|
if (!_modEnabled)
|
|
return;
|
|
|
|
if (Time.time < _nextCheckTime)
|
|
return;
|
|
|
|
_nextCheckTime = Time.time + _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
|
|
{
|
|
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<Fireplace>(
|
|
FindObjectsInactive.Exclude,
|
|
FindObjectsSortMode.None
|
|
);
|
|
|
|
Container[] containers = null;
|
|
|
|
if (_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 > _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:
|
|
*
|
|
* 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
|
|
);
|
|
}
|
|
|
|
LogDebug("Scan end.");
|
|
}
|
|
|
|
private bool IsOwnPiece(Player player, Fireplace fireplace)
|
|
{
|
|
Piece piece = fireplace.GetComponent<Piece>();
|
|
|
|
if (piece == null)
|
|
piece = fireplace.GetComponentInParent<Piece>();
|
|
|
|
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<ZNetView>();
|
|
|
|
if (nview == null)
|
|
nview = fireplace.GetComponentInParent<ZNetView>();
|
|
|
|
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,
|
|
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,
|
|
Fireplace fireplace,
|
|
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(
|
|
fireplace,
|
|
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(
|
|
fireplace,
|
|
fuelName,
|
|
requestedAmount - consumed,
|
|
containers
|
|
);
|
|
}
|
|
}
|
|
|
|
LogDebug(
|
|
$"Fuel request result: " +
|
|
$"fuel='{fuelName}', " +
|
|
$"requested={requestedAmount}, " +
|
|
$"consumed={consumed}"
|
|
);
|
|
|
|
return consumed;
|
|
}
|
|
|
|
private int ConsumeFuelFromNearbyContainers(
|
|
Fireplace fireplace,
|
|
string fuelName,
|
|
int requestedAmount,
|
|
Container[] containers)
|
|
{
|
|
if (requestedAmount <= 0)
|
|
return 0;
|
|
|
|
if (containers == null || containers.Length == 0)
|
|
{
|
|
LogDebug("Container scan: no loaded containers available.");
|
|
return 0;
|
|
}
|
|
|
|
List<ContainerCandidate> candidates =
|
|
new List<ContainerCandidate>();
|
|
|
|
foreach (Container container in containers)
|
|
{
|
|
if (container == null)
|
|
continue;
|
|
|
|
float distance = Vector3.Distance(
|
|
fireplace.transform.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)
|
|
);
|
|
|
|
LogDebug(
|
|
$"Container candidates: " +
|
|
$"fuel='{fuelName}', " +
|
|
$"usable={candidates.Count}, " +
|
|
$"radius={_containerRadius.Value:0.0}m"
|
|
);
|
|
|
|
int consumed = 0;
|
|
int containersUsed = 0;
|
|
|
|
foreach (ContainerCandidate candidate in candidates)
|
|
{
|
|
if (consumed >= requestedAmount)
|
|
break;
|
|
|
|
Container container =
|
|
candidate.Container;
|
|
|
|
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;
|
|
|
|
int remainingNeeded =
|
|
requestedAmount - consumed;
|
|
|
|
int amountToTake =
|
|
Mathf.Min(
|
|
remainingNeeded,
|
|
usableFuel
|
|
);
|
|
|
|
if (amountToTake <= 0)
|
|
continue;
|
|
|
|
inventory.RemoveItem(
|
|
fuelName,
|
|
amountToTake
|
|
);
|
|
|
|
consumed += amountToTake;
|
|
containersUsed++;
|
|
|
|
LogDebug(
|
|
$"Container '{container.name}' " +
|
|
$"({candidate.Distance:0.0}m): " +
|
|
$"consumed={amountToTake}x {fuelName}, " +
|
|
$"before={availableFuel}, " +
|
|
$"remaining={availableFuel - amountToTake}"
|
|
);
|
|
}
|
|
|
|
if (consumed <= 0)
|
|
{
|
|
LogDebug(
|
|
$"Container result: no usable '{fuelName}' found."
|
|
);
|
|
}
|
|
else
|
|
{
|
|
LogDebug(
|
|
$"Container result: " +
|
|
$"consumed={consumed}x {fuelName}, " +
|
|
$"containersUsed={containersUsed}"
|
|
);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
} |