Performance refactor, bonfire setting

This commit is contained in:
2026-08-29 13:59:27 +02:00
parent d1d655769d
commit 6fc7a5ffe9
+401 -109
View File
@@ -1,6 +1,7 @@
using BepInEx; using BepInEx;
using BepInEx.Configuration; using BepInEx.Configuration;
using UnityEngine; using UnityEngine;
using System.Collections.Generic;
namespace AutoRefillFires namespace AutoRefillFires
{ {
@@ -43,6 +44,7 @@ namespace AutoRefillFires
private ConfigEntry<bool> _fillStandingTorches; private ConfigEntry<bool> _fillStandingTorches;
private ConfigEntry<bool> _fillWallTorches; private ConfigEntry<bool> _fillWallTorches;
private ConfigEntry<bool> _fillBraziers; private ConfigEntry<bool> _fillBraziers;
private ConfigEntry<bool> _fillBonfires;
private ConfigEntry<bool> _fillOtherFireplaces; private ConfigEntry<bool> _fillOtherFireplaces;
private ConfigEntry<int> _keepFuelReserve; private ConfigEntry<int> _keepFuelReserve;
private ConfigEntry<FuelSourcePriority> _fuelSourcePriority; private ConfigEntry<FuelSourcePriority> _fuelSourcePriority;
@@ -53,6 +55,12 @@ namespace AutoRefillFires
private float _nextCheckTime; private float _nextCheckTime;
private class ContainerCandidate
{
public Container Container;
public float Distance;
}
private void Awake() private void Awake()
{ {
_radius = Config.Bind( _radius = Config.Bind(
@@ -139,6 +147,13 @@ namespace AutoRefillFires
"Automatically refill braziers." "Automatically refill braziers."
); );
_fillBonfires = Config.Bind(
"Fireplace Types",
"FillBonfires",
true,
"Automatically refill bonfires."
);
_fillOtherFireplaces = Config.Bind( _fillOtherFireplaces = Config.Bind(
"Fireplace Types", "Fireplace Types",
"FillOtherFireplaces", "FillOtherFireplaces",
@@ -243,28 +258,51 @@ namespace AutoRefillFires
.Replace("(Clone)", "") .Replace("(Clone)", "")
.ToLowerInvariant(); .ToLowerInvariant();
// Campfire bool result;
if (objectName.Contains("firepit")) string matchedRule;
return _fillCampfires.Value;
// Hearth if (objectName.Contains("fire_pit") || objectName.Contains("firepit"))
if (objectName.Contains("hearth")) {
return _fillHearths.Value; 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";
}
// All standing / ground torches, including colored variants LogDebug(
if (objectName.Contains("groundtorch")) $"ShouldRefillFireplace: name='{fireplace.gameObject.name}', " +
return _fillStandingTorches.Value; $"normalized='{objectName}', matchedRule={matchedRule}, result={result}"
);
// All wall torches, including colored variants return result;
if (objectName.Contains("walltorch"))
return _fillWallTorches.Value;
// Braziers
if (objectName.Contains("brazier"))
return _fillBraziers.Value;
// Unknown / modded Fireplace-based objects
return _fillOtherFireplaces.Value;
} }
private void RefillNearbyFireplaces(Player player) private void RefillNearbyFireplaces(Player player)
@@ -275,6 +313,29 @@ namespace AutoRefillFires
FindObjectsSortMode.None FindObjectsSortMode.None
); );
Container[] containers = null;
// Only scan containers when container usage is actually enabled.
if (_useNearbyContainers.Value)
{
containers =
Object.FindObjectsByType<Container>(
FindObjectsInactive.Exclude,
FindObjectsSortMode.None
);
}
LogDebug(
$"Scan start: " +
$"loadedFireplaces={fireplaces.Length}, " +
$"loadedContainers={(containers != null ? containers.Length : 0)}, " +
$"fireplaceRadius={_radius.Value:0.0}m, " +
$"containerRadius={_containerRadius.Value:0.0}m"
);
int fireplacesInRange = 0;
int refillAttempts = 0;
foreach (Fireplace fireplace in fireplaces) foreach (Fireplace fireplace in fireplaces)
{ {
if (fireplace == null) if (fireplace == null)
@@ -288,8 +349,28 @@ namespace AutoRefillFires
if (distance > _radius.Value) if (distance > _radius.Value)
continue; continue;
TryRefillFireplace(player, fireplace); fireplacesInRange++;
LogDebug(
$"Fireplace in range: " +
$"name='{fireplace.gameObject.name}', " +
$"distance={distance:0.0}m"
);
refillAttempts++;
TryRefillFireplace(
player,
fireplace,
containers
);
} }
LogDebug(
$"Scan end: " +
$"fireplacesInRange={fireplacesInRange}, " +
$"refillAttempts={refillAttempts}"
);
} }
private bool IsOwnPiece(Player player, Fireplace fireplace) private bool IsOwnPiece(Player player, Fireplace fireplace)
@@ -309,13 +390,25 @@ namespace AutoRefillFires
return piece.GetCreator() == player.GetPlayerID(); return piece.GetCreator() == player.GetPlayerID();
} }
private void TryRefillFireplace(Player player, Fireplace fireplace) private void TryRefillFireplace(Player player, Fireplace fireplace, Container[] containers)
{ {
LogDebug($"TryRefillFireplace START: '{fireplace.gameObject.name}'");
if (!ShouldRefillFireplace(fireplace)) if (!ShouldRefillFireplace(fireplace))
{
LogDebug(
$"Skipping '{fireplace.gameObject.name}' - type/config filter returned false."
);
return; return;
}
if (_onlyRefillOwnPieces.Value && !IsOwnPiece(player, fireplace)) if (_onlyRefillOwnPieces.Value && !IsOwnPiece(player, fireplace))
{
LogDebug(
$"Skipping '{fireplace.gameObject.name}' - not owned by local player."
);
return; return;
}
ZNetView nview = fireplace.GetComponent<ZNetView>(); ZNetView nview = fireplace.GetComponent<ZNetView>();
@@ -323,29 +416,65 @@ namespace AutoRefillFires
nview = fireplace.GetComponentInParent<ZNetView>(); nview = fireplace.GetComponentInParent<ZNetView>();
if (nview == null) if (nview == null)
{
LogDebug(
$"Skipping '{fireplace.gameObject.name}' - no ZNetView found."
);
return; return;
}
if (!nview.IsValid()) if (!nview.IsValid())
{
LogDebug(
$"Skipping '{fireplace.gameObject.name}' - ZNetView is not valid."
);
return; return;
}
ZDO zdo = nview.GetZDO(); ZDO zdo = nview.GetZDO();
if (zdo == null) if (zdo == null)
{
LogDebug(
$"Skipping '{fireplace.gameObject.name}' - ZDO is null."
);
return; return;
}
if (fireplace.m_fuelItem == null) if (fireplace.m_fuelItem == null)
{
LogDebug(
$"Skipping '{fireplace.gameObject.name}' - m_fuelItem is null."
);
return; return;
}
float currentFuel = zdo.GetFloat(ZDOVars.s_fuel, 0f); float currentFuel = zdo.GetFloat(ZDOVars.s_fuel, 0f);
float maxFuel = fireplace.m_maxFuel; float maxFuel = fireplace.m_maxFuel;
if (maxFuel <= 0f) if (maxFuel <= 0f)
{
LogDebug(
$"Skipping '{fireplace.gameObject.name}' - maxFuel <= 0 ({maxFuel})."
);
return; return;
}
float fuelPercent = currentFuel / maxFuel; 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) if (fuelPercent >= _refillBelowPercent.Value)
{
LogDebug(
$"Skipping '{fireplace.gameObject.name}' - fuelPercent >= threshold."
);
return; return;
}
string fuelName = string fuelName =
fireplace.m_fuelItem.m_itemData.m_shared.m_name; fireplace.m_fuelItem.m_itemData.m_shared.m_name;
@@ -354,7 +483,12 @@ namespace AutoRefillFires
Mathf.CeilToInt(maxFuel - currentFuel); Mathf.CeilToInt(maxFuel - currentFuel);
if (missingFuel <= 0) if (missingFuel <= 0)
{
LogDebug(
$"Skipping '{fireplace.gameObject.name}' - missingFuel <= 0 ({missingFuel})."
);
return; return;
}
int requestedFuel; int requestedFuel;
@@ -370,30 +504,55 @@ namespace AutoRefillFires
); );
} }
LogDebug(
$"Refill request for '{fireplace.gameObject.name}': " +
$"fuel='{fuelName}', missingFuel={missingFuel}, requestedFuel={requestedFuel}, " +
$"refillMode={(_refillToMax.Value ? "max" : "fixed")}"
);
if (requestedFuel <= 0) if (requestedFuel <= 0)
{
LogDebug(
$"Skipping '{fireplace.gameObject.name}' - requestedFuel <= 0."
);
return; return;
}
int fuelAdded = 0; int fuelAdded = 0;
for (int i = 0; i < requestedFuel; i++) int fuelConsumed = ConsumeFuel(
{ player,
if (!TryConsumeFuel( fireplace,
player, fuelName,
fireplace, requestedFuel,
fuelName containers
)) );
{
break;
}
if (fuelConsumed <= 0)
{
LogDebug(
$"No usable fuel found for '{fireplace.gameObject.name}'."
);
return;
}
for (int i = 0; i < fuelConsumed; i++)
{
nview.InvokeRPC( nview.InvokeRPC(
"RPC_AddFuel", "RPC_AddFuel",
new object[0] new object[0]
); );
fuelAdded++;
} }
LogInfo(
$"Refilled {fireplace.name}: " +
$"{currentFuel:0.0}/{maxFuel:0.0}, " +
$"fuel={fuelName}, " +
$"added={fuelConsumed}, " +
$"mode={(_refillToMax.Value ? "max" : "fixed")}"
);
if (fuelAdded > 0) if (fuelAdded > 0)
{ {
LogInfo( LogInfo(
@@ -406,77 +565,153 @@ namespace AutoRefillFires
} }
} }
private bool TryConsumeFuelFromPlayer(Player player, string fuelName) private int ConsumeFuelFromPlayer(Player player, string fuelName, int requestedAmount)
{ {
if (requestedAmount <= 0)
return 0;
Inventory inventory = player.GetInventory(); Inventory inventory = player.GetInventory();
if (inventory == null) if (inventory == null)
return false; {
LogDebug("Player inventory is null.");
return 0;
}
int availableFuel = int availableFuel =
inventory.CountItems(fuelName); inventory.CountItems(fuelName);
if (availableFuel <= _keepFuelReserve.Value) int usableFuel =
return false; 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( inventory.RemoveItem(
fuelName, fuelName,
1 amountToTake
); );
LogDebug( LogDebug(
$"Fuel {fuelName} taken from player inventory. " + $"Player inventory: consumed={amountToTake}x {fuelName}, " +
$"Remaining: {availableFuel - 1}" $"before={availableFuel}, " +
$"remaining={availableFuel - amountToTake}"
); );
return true; return amountToTake;
} }
private bool TryConsumeFuel(Player player, Fireplace fireplace, string fuelName) 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 (_fuelSourcePriority.Value == FuelSourcePriority.ContainersFirst)
{ {
if (_useNearbyContainers.Value && if (_useNearbyContainers.Value && containers != null)
TryConsumeFuelFromNearbyContainer(
fireplace,
fuelName))
{ {
return true; consumed += ConsumeFuelFromNearbyContainers(
fireplace,
fuelName,
requestedAmount - consumed,
containers
);
} }
return TryConsumeFuelFromPlayer( if (consumed < requestedAmount)
player, {
fuelName consumed += ConsumeFuelFromPlayer(
); player,
fuelName,
requestedAmount - consumed
);
}
} }
else
// PlayerFirst
if (TryConsumeFuelFromPlayer(
player,
fuelName))
{ {
return true; consumed += ConsumeFuelFromPlayer(
player,
fuelName,
requestedAmount
);
if (
_useNearbyContainers.Value &&
containers != null &&
consumed < requestedAmount
)
{
consumed += ConsumeFuelFromNearbyContainers(
fireplace,
fuelName,
requestedAmount - consumed,
containers
);
}
} }
if (!_useNearbyContainers.Value) LogDebug(
return false; $"Fuel request result: " +
$"fuel='{fuelName}', " +
return TryConsumeFuelFromNearbyContainer( $"requested={requestedAmount}, " +
fireplace, $"consumed={consumed}"
fuelName
); );
return consumed;
} }
private bool TryConsumeFuelFromNearbyContainer(Fireplace fireplace, string fuelName) private int ConsumeFuelFromNearbyContainers(
Fireplace fireplace,
string fuelName,
int requestedAmount,
Container[] containers)
{ {
Container[] containers = if (requestedAmount <= 0)
Object.FindObjectsByType<Container>( return 0;
FindObjectsInactive.Exclude,
FindObjectsSortMode.None
);
Container closestContainer = null; if (containers == null || containers.Length == 0)
float closestDistance = float.MaxValue; {
LogDebug("Container scan: no loaded containers available.");
return 0;
}
List<ContainerCandidate> candidates =
new List<ContainerCandidate>();
foreach (Container container in containers) foreach (Container container in containers)
{ {
@@ -500,58 +735,115 @@ namespace AutoRefillFires
int availableFuel = int availableFuel =
inventory.CountItems(fuelName); inventory.CountItems(fuelName);
/* int usableFuel =
* Never use the configured reserve. Mathf.Max(
* availableFuel - _keepFuelReserve.Value,
* Example: 0
* reserve = 10 );
* chest contains 10 -> skip
* chest contains 11 -> usable if (usableFuel <= 0)
*/
if (availableFuel <= _keepFuelReserve.Value)
continue; continue;
if (distance < closestDistance) candidates.Add(
{ new ContainerCandidate
closestDistance = distance; {
closestContainer = container; Container = container,
} Distance = distance
}
);
} }
if (closestContainer == null) candidates.Sort(
return false; (a, b) => a.Distance.CompareTo(b.Distance)
Inventory chestInventory =
closestContainer.GetInventory();
if (chestInventory == null)
return false;
int chestFuel =
chestInventory.CountItems(fuelName);
if (chestFuel <= _keepFuelReserve.Value)
return false;
chestInventory.RemoveItem(
fuelName,
1
); );
LogDebug( LogDebug(
$"Fuel {fuelName} taken from container " + $"Container candidates: " +
$"{closestContainer.name} " + $"fuel='{fuelName}', " +
$"({closestDistance:0.0}m). " + $"usable={candidates.Count}, " +
$"Remaining: {chestFuel - 1}" $"radius={_containerRadius.Value:0.0}m"
); );
return true; 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) private void LogDebug(string message)
{ {
if (_logLevel.Value >= ModLogLevel.Debug) if (_logLevel.Value >= ModLogLevel.Debug)
Logger.LogDebug(message); Logger.LogInfo($"[DEBUG] {message}");
} }
private void LogInfo(string message) private void LogInfo(string message)