Decompiled source of AutoRefillFires v1.2.3

plugins/AutoRefillFires/AutoRefillFires.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyMetadata("PluginVersion", "1.2.3")]
[assembly: AssemblyCompany("AutoRefillFires")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.2.3.0")]
[assembly: AssemblyInformationalVersion("1.0.0+6b7cc092e13549b13efa0cf8ef1ef349d7a38f9b")]
[assembly: AssemblyProduct("AutoRefillFires")]
[assembly: AssemblyTitle("AutoRefillFires")]
[assembly: AssemblyVersion("1.2.3.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace AutoRefillFires
{
	public enum FuelSourcePriority
	{
		PlayerFirst,
		ContainersFirst
	}
	internal class ModConfig
	{
		public ConfigEntry<float> Radius { get; }

		public ConfigEntry<float> CheckInterval { get; }

		public ConfigEntry<float> RefillBelowPercent { get; }

		public ConfigEntry<bool> UseNearbyContainers { get; }

		public ConfigEntry<float> ContainerRadius { get; }

		public ConfigEntry<bool> RefillToMax { get; }

		public ConfigEntry<int> RefillAmount { get; }

		public ConfigEntry<bool> FillCampfires { get; }

		public ConfigEntry<bool> FillHearths { get; }

		public ConfigEntry<bool> FillStandingTorches { get; }

		public ConfigEntry<bool> FillWallTorches { get; }

		public ConfigEntry<bool> FillBraziers { get; }

		public ConfigEntry<bool> FillBonfires { get; }

		public ConfigEntry<bool> FillHotTubs { get; }

		public ConfigEntry<bool> FillShieldGenerators { get; }

		public ConfigEntry<bool> FillResinCandles { get; }

		public ConfigEntry<bool> FillOtherFireplaces { get; }

		public ConfigEntry<int> KeepFuelReserve { get; }

		public ConfigEntry<FuelSourcePriority> FuelSourcePriority { get; }

		public ConfigEntry<bool> OnlyRefillOwnPieces { get; }

		public ConfigEntry<bool> AutoRepair { get; }

		public ConfigEntry<float> RepairBelowPercent { get; }

		public ConfigEntry<bool> OnlyRepairOwnPieces { get; }

		public ConfigEntry<KeyboardShortcut> ToggleHotkey { get; }

		public ConfigEntry<ModLogLevel> LogLevel { get; }

		public ModConfig(ConfigFile config)
		{
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			Radius = config.Bind<float>("General", "Radius", 20f, "Refill and repair supported objects within this radius around the player.");
			CheckInterval = config.Bind<float>("General", "CheckInterval", 3f, "How often supported objects are checked, in seconds.");
			RefillBelowPercent = config.Bind<float>("General", "RefillBelowPercent", 0.75f, "Refill when fuel drops below this percentage.");
			RefillToMax = config.Bind<bool>("General", "RefillToMax", true, "If true, refill fireplaces to maximum fuel. If false, add only RefillAmount fuel.");
			RefillAmount = config.Bind<int>("General", "RefillAmount", 5, "Amount of fuel to add when RefillToMax is false.");
			UseNearbyContainers = config.Bind<bool>("Containers", "UseNearbyContainers", false, "Allow plugin to take fuel from nearby containers.");
			ContainerRadius = config.Bind<float>("Containers", "ContainerRadius", 10f, "Maximum distance from the fireplace to search for containers.");
			FillCampfires = config.Bind<bool>("Fireplace Types", "FillCampfires", true, "Automatically refill campfires.");
			FillHearths = config.Bind<bool>("Fireplace Types", "FillHearths", true, "Automatically refill hearths.");
			FillStandingTorches = config.Bind<bool>("Fireplace Types", "FillStandingTorches", true, "Automatically refill all standing torches, including colored variants.");
			FillWallTorches = config.Bind<bool>("Fireplace Types", "FillWallTorches", true, "Automatically refill all wall torches, including colored variants.");
			FillBraziers = config.Bind<bool>("Fireplace Types", "FillBraziers", true, "Automatically refill braziers.");
			FillBonfires = config.Bind<bool>("Fireplace Types", "FillBonfires", true, "Automatically refill bonfires.");
			FillHotTubs = config.Bind<bool>("Fireplace Types", "FillHotTubs", true, "Automatically refill hot tubs.");
			FillShieldGenerators = config.Bind<bool>("Fireplace Types", "FillShieldGenerators", false, "Automatically refill buildable Ashlands shield generators with their accepted fuels. Refill only; does not enable repair.");
			FillResinCandles = config.Bind<bool>("Fireplace Types", "FillResinCandles", false, "Automatically refill resin candles when a whole fuel unit fits, including toggle-only candles. Preserves the on/off state. Refill only; does not enable repair.");
			FillOtherFireplaces = config.Bind<bool>("Fireplace Types", "FillOtherFireplaces", true, "Automatically refill unknown or modded Fireplace-based objects.");
			ToggleHotkey = config.Bind<KeyboardShortcut>("General", "ToggleHotkey", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Hotkey used to enable or disable automatic refilling and repair.");
			KeepFuelReserve = config.Bind<int>("Fuel", "KeepFuelReserve", 0, "Minimum amount of fuel to keep in the source inventory. 10 means the last 10 Wood/Resin will not be used.");
			FuelSourcePriority = config.Bind<FuelSourcePriority>("Fuel", "FuelSourcePriority", AutoRefillFires.FuelSourcePriority.PlayerFirst, "Select whether player inventory or nearby containers should be used first.");
			OnlyRefillOwnPieces = config.Bind<bool>("General", "OnlyRefillOwnPieces", false, "If enabled, only refill fireplaces and torches built by the local player.");
			AutoRepair = config.Bind<bool>("Repair", "AutoRepair", false, "Automatically repair supported objects whose corresponding Fill* option is enabled.");
			RepairBelowPercent = config.Bind<float>("Repair", "RepairBelowPercent", 0.75f, "Repair supported objects when their health drops below this percentage. Example: 0.75 = 75%.");
			OnlyRepairOwnPieces = config.Bind<bool>("Repair", "OnlyRepairOwnPieces", false, "If enabled, only automatically repair supported objects built by the local player.");
			LogLevel = config.Bind<ModLogLevel>("Logging", "LogLevel", ModLogLevel.Info, "Logging verbosity. Available values: None, Error, Warning, Info, Debug.");
		}
	}
	public enum ModLogLevel
	{
		None,
		Error,
		Warning,
		Info,
		Debug
	}
	internal class FuelManager
	{
		private readonly ModConfig _config;

		private readonly ModLogger _log;

		public FuelManager(ModConfig config, ModLogger log)
		{
			_config = config;
			_log = log;
		}

		public int ConsumeFuel(Player player, Transform target, string fuelName, int requestedAmount, Container[] containers)
		{
			if (requestedAmount <= 0)
			{
				return 0;
			}
			_log.Debug("Fuel request: fuel='" + fuelName + "', " + $"requested={requestedAmount}, " + $"priority={_config.FuelSourcePriority.Value}, " + $"containers={_config.UseNearbyContainers.Value}, " + $"reserve={_config.KeepFuelReserve.Value}");
			int num = 0;
			if (_config.FuelSourcePriority.Value == FuelSourcePriority.ContainersFirst)
			{
				if (_config.UseNearbyContainers.Value && containers != null)
				{
					num += ConsumeFuelFromNearbyContainers(target, fuelName, requestedAmount - num, containers);
				}
				if (num < requestedAmount)
				{
					num += ConsumeFuelFromPlayer(player, fuelName, requestedAmount - num);
				}
			}
			else
			{
				num += ConsumeFuelFromPlayer(player, fuelName, requestedAmount);
				if (_config.UseNearbyContainers.Value && containers != null && num < requestedAmount)
				{
					num += ConsumeFuelFromNearbyContainers(target, fuelName, requestedAmount - num, containers);
				}
			}
			_log.Debug("Fuel request result: fuel='" + fuelName + "', " + $"requested={requestedAmount}, " + $"consumed={num}");
			return num;
		}

		public int ConsumeFuelOptions(Player player, Transform target, IReadOnlyList<string> fuelNames, Container[] containers)
		{
			bool flag = _config.FuelSourcePriority.Value == FuelSourcePriority.ContainersFirst;
			for (int i = 0; i < 2; i++)
			{
				bool flag2 = ((i == 0) ? flag : (!flag));
				if (flag2 && (!_config.UseNearbyContainers.Value || containers == null))
				{
					continue;
				}
				foreach (string fuelName in fuelNames)
				{
					int num = (flag2 ? ConsumeFuelFromNearbyContainers(target, fuelName, 1, containers) : ConsumeFuelFromPlayer(player, fuelName, 1));
					if (num > 0)
					{
						return num;
					}
				}
			}
			return 0;
		}

		private int ConsumeFuelFromPlayer(Player player, string fuelName, int requestedAmount)
		{
			if (requestedAmount <= 0)
			{
				return 0;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory == null)
			{
				_log.Debug("Player inventory is null.");
				return 0;
			}
			int num = inventory.CountItems(fuelName, -1, true);
			int num2 = Mathf.Max(num - _config.KeepFuelReserve.Value, 0);
			int num3 = Mathf.Min(requestedAmount, num2);
			if (num3 <= 0)
			{
				_log.Debug("Player inventory: fuel='" + fuelName + "', " + $"available={num}, " + $"reserve={_config.KeepFuelReserve.Value}, " + "usable=0");
				return 0;
			}
			inventory.RemoveItem(fuelName, num3, -1, true);
			_log.Debug($"Player inventory: consumed={num3}x {fuelName}, " + $"before={num}, " + $"remaining={num - num3}");
			return num3;
		}

		private int ConsumeFuelFromNearbyContainers(Transform target, string fuelName, int requestedAmount, Container[] containers)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			if (requestedAmount <= 0)
			{
				return 0;
			}
			if (containers == null || containers.Length == 0)
			{
				return 0;
			}
			List<ContainerCandidate> list = new List<ContainerCandidate>();
			foreach (Container val in containers)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				float num = Vector3.Distance(target.position, ((Component)val).transform.position);
				if (num > _config.ContainerRadius.Value)
				{
					continue;
				}
				Inventory inventory = val.GetInventory();
				if (inventory != null)
				{
					int num2 = inventory.CountItems(fuelName, -1, true);
					int num3 = Mathf.Max(num2 - _config.KeepFuelReserve.Value, 0);
					if (num3 > 0)
					{
						list.Add(new ContainerCandidate
						{
							Container = val,
							Distance = num
						});
					}
				}
			}
			list.Sort((ContainerCandidate a, ContainerCandidate b) => a.Distance.CompareTo(b.Distance));
			int num4 = 0;
			foreach (ContainerCandidate item in list)
			{
				if (num4 >= requestedAmount)
				{
					break;
				}
				Inventory inventory2 = item.Container.GetInventory();
				if (inventory2 != null)
				{
					int num5 = inventory2.CountItems(fuelName, -1, true);
					int num6 = Mathf.Max(num5 - _config.KeepFuelReserve.Value, 0);
					if (num6 > 0)
					{
						int num7 = Mathf.Min(requestedAmount - num4, num6);
						inventory2.RemoveItem(fuelName, num7, -1, true);
						num4 += num7;
						_log.Debug($"Container '{((Object)item.Container).name}' ({item.Distance:0.0}m): " + $"consumed={num7}x {fuelName}");
					}
				}
			}
			return num4;
		}
	}
	internal class ModLogger
	{
		private readonly ModConfig _config;

		private readonly ManualLogSource _logger;

		public ModLogger(ModConfig config, ManualLogSource logger)
		{
			_config = config;
			_logger = logger;
		}

		public void Debug(string message)
		{
			if (_config.LogLevel.Value >= ModLogLevel.Debug)
			{
				_logger.LogInfo((object)("[DEBUG] " + message));
			}
		}

		public void Info(string message)
		{
			if (_config.LogLevel.Value >= ModLogLevel.Info)
			{
				_logger.LogInfo((object)message);
			}
		}

		public void Warning(string message)
		{
			if (_config.LogLevel.Value >= ModLogLevel.Warning)
			{
				_logger.LogWarning((object)message);
			}
		}

		public void Error(string message)
		{
			if (_config.LogLevel.Value >= ModLogLevel.Error)
			{
				_logger.LogError((object)message);
			}
		}
	}
	internal class ContainerCandidate
	{
		public Container Container;

		public float Distance;
	}
	internal class FireplaceCandidate
	{
		public Fireplace Fireplace;

		public float Distance;

		public float FuelPercent;
	}
	[BepInPlugin("simplifydave.autorefillfires", "Auto Refill Fires", "1.2.3")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "simplifydave.autorefillfires";

		public const string PluginName = "Auto Refill Fires";

		public const string PluginVersion = "1.2.3";

		private ModConfig _config;

		private ModLogger _log;

		private RefillManager _refillManager;

		private bool _modEnabled = true;

		private float _nextCheckTime;

		private void Awake()
		{
			_config = new ModConfig(((BaseUnityPlugin)this).Config);
			_log = new ModLogger(_config, ((BaseUnityPlugin)this).Logger);
			_refillManager = new RefillManager(_config, _log);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Auto Refill Fires loaded!");
		}

		private void Update()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = _config.ToggleHotkey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				_modEnabled = !_modEnabled;
				if (!_modEnabled)
				{
					try
					{
						((BaseUnityPlugin)this).Config.Reload();
						_log.Info("Configuration reloaded.");
					}
					catch (Exception arg)
					{
						_log.Error($"Failed to reload configuration: {arg}");
					}
				}
				string text = (_modEnabled ? "Auto Refill Fires: ENABLED" : "Auto Refill Fires: DISABLED");
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer != (Object)null)
				{
					((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
				}
				_log.Info(text);
			}
			if (_modEnabled && !(Time.time < _nextCheckTime))
			{
				_nextCheckTime = Time.time + _config.CheckInterval.Value;
				Player localPlayer2 = Player.m_localPlayer;
				if (!((Object)(object)localPlayer2 == (Object)null))
				{
					_refillManager.Run(localPlayer2);
				}
			}
		}
	}
	internal class FireplaceRefiller
	{
		private readonly ModConfig _config;

		private readonly FuelManager _fuelManager;

		private readonly ModLogger _log;

		public FireplaceRefiller(ModConfig config, FuelManager fuelManager, ModLogger log)
		{
			_config = config;
			_fuelManager = fuelManager;
			_log = log;
		}

		public void TryRefill(Player player, Fireplace fireplace, Container[] containers)
		{
			_log.Debug("TryRefillFireplace START: '" + ((Object)((Component)fireplace).gameObject).name + "'");
			if (!ShouldRefillFireplace(fireplace))
			{
				_log.Debug("Skipping '" + ((Object)((Component)fireplace).gameObject).name + "' - type/config filter returned false.");
				return;
			}
			if (_config.OnlyRefillOwnPieces.Value && !IsOwnPiece(player, fireplace))
			{
				_log.Debug("Skipping '" + ((Object)((Component)fireplace).gameObject).name + "' - not owned by local player.");
				return;
			}
			ZNetView val = ((Component)fireplace).GetComponent<ZNetView>();
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)fireplace).GetComponentInParent<ZNetView>();
			}
			if ((Object)(object)val == (Object)null)
			{
				_log.Debug("Skipping '" + ((Object)((Component)fireplace).gameObject).name + "' - no ZNetView found.");
				return;
			}
			if (!val.IsValid())
			{
				_log.Debug("Skipping '" + ((Object)((Component)fireplace).gameObject).name + "' - ZNetView is not valid.");
				return;
			}
			ZDO zDO = val.GetZDO();
			if (zDO == null)
			{
				_log.Debug("Skipping '" + ((Object)((Component)fireplace).gameObject).name + "' - ZDO is null.");
				return;
			}
			if ((Object)(object)fireplace.m_fuelItem == (Object)null || fireplace.m_fuelItem.m_itemData == null || fireplace.m_fuelItem.m_itemData.m_shared == null)
			{
				_log.Debug("Skipping '" + ((Object)((Component)fireplace).gameObject).name + "' - fuel item is null.");
				return;
			}
			float num = zDO.GetFloat(ZDOVars.s_fuel, 0f);
			float maxFuel = fireplace.m_maxFuel;
			if (maxFuel <= 0f)
			{
				_log.Debug($"Skipping '{((Object)((Component)fireplace).gameObject).name}' - maxFuel <= 0 ({maxFuel}).");
				return;
			}
			float num2 = num / maxFuel;
			_log.Debug("Fuel state for '" + ((Object)((Component)fireplace).gameObject).name + "': " + $"currentFuel={num:0.0}, maxFuel={maxFuel:0.0}, " + $"fuelPercent={num2:0.00}, threshold={_config.RefillBelowPercent.Value:0.00}");
			if (num2 >= _config.RefillBelowPercent.Value)
			{
				_log.Debug("Skipping '" + ((Object)((Component)fireplace).gameObject).name + "' - fuelPercent >= threshold.");
				return;
			}
			string name = fireplace.m_fuelItem.m_itemData.m_shared.m_name;
			int num3 = Mathf.CeilToInt(maxFuel - num);
			if (num3 <= 0)
			{
				_log.Debug($"Skipping '{((Object)((Component)fireplace).gameObject).name}' - missingFuel <= 0 ({num3}).");
				return;
			}
			int num4 = (_config.RefillToMax.Value ? num3 : Mathf.Min(Mathf.Max(_config.RefillAmount.Value, 0), num3));
			_log.Debug("Refill request for '" + ((Object)((Component)fireplace).gameObject).name + "': " + $"fuel='{name}', missingFuel={num3}, requestedFuel={num4}, " + "refillMode=" + (_config.RefillToMax.Value ? "max" : "fixed"));
			if (num4 <= 0)
			{
				_log.Debug("Skipping '" + ((Object)((Component)fireplace).gameObject).name + "' - requestedFuel <= 0.");
				return;
			}
			int num5 = _fuelManager.ConsumeFuel(player, ((Component)fireplace).transform, name, num4, containers);
			if (num5 <= 0)
			{
				_log.Debug("No usable fuel found for '" + ((Object)((Component)fireplace).gameObject).name + "'.");
				return;
			}
			for (int i = 0; i < num5; i++)
			{
				val.InvokeRPC("RPC_AddFuel", new object[0]);
			}
			_log.Info($"Refilled {((Object)fireplace).name}: {num:0.0}/{maxFuel:0.0}, " + $"fuel={name}, added={num5}, " + "mode=" + (_config.RefillToMax.Value ? "max" : "fixed"));
		}

		private bool ShouldRefillFireplace(Fireplace fireplace)
		{
			string matchedRule;
			bool flag = FireplaceTypeFilter.IsEnabled(_config, fireplace, out matchedRule);
			_log.Debug("ShouldRefillFireplace: name='" + ((Object)((Component)fireplace).gameObject).name + "', " + $"matchedRule={matchedRule}, result={flag}");
			return flag;
		}

		private bool IsOwnPiece(Player player, Fireplace fireplace)
		{
			Piece val = ((Component)fireplace).GetComponent<Piece>();
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)fireplace).GetComponentInParent<Piece>();
			}
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			return val.GetCreator() == player.GetPlayerID();
		}
	}
	internal static class FireplaceTypeFilter
	{
		public static bool IsEnabled(ModConfig config, Fireplace fireplace, out string matchedRule)
		{
			string text = ((Object)((Component)fireplace).gameObject).name.Replace("(Clone)", "").ToLowerInvariant();
			if (text.Contains("candle"))
			{
				matchedRule = "IgnoredCandle";
				return false;
			}
			if (text.Contains("fire_pit") || text.Contains("firepit"))
			{
				matchedRule = "FillCampfires";
				return config.FillCampfires.Value;
			}
			if (text.Contains("hearth"))
			{
				matchedRule = "FillHearths";
				return config.FillHearths.Value;
			}
			if (text.Contains("groundtorch"))
			{
				matchedRule = "FillStandingTorches";
				return config.FillStandingTorches.Value;
			}
			if (text.Contains("walltorch"))
			{
				matchedRule = "FillWallTorches";
				return config.FillWallTorches.Value;
			}
			if (text.Contains("brazier"))
			{
				matchedRule = "FillBraziers";
				return config.FillBraziers.Value;
			}
			if (text.Contains("bonfire"))
			{
				matchedRule = "FillBonfires";
				return config.FillBonfires.Value;
			}
			matchedRule = "FillOtherFireplaces";
			return config.FillOtherFireplaces.Value;
		}
	}
	internal class HotTubRefiller
	{
		private readonly ModConfig _config;

		private readonly FuelManager _fuelManager;

		private readonly RepairManager _repairManager;

		private readonly ModLogger _log;

		public HotTubRefiller(ModConfig config, FuelManager fuelManager, RepairManager repairManager, ModLogger log)
		{
			_config = config;
			_fuelManager = fuelManager;
			_repairManager = repairManager;
			_log = log;
		}

		public void RefillNearby(Player player, Smelter[] smelters, Container[] containers)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			foreach (Smelter val in smelters)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				string text = ((Object)((Component)val).gameObject).name.Replace("(Clone)", "").ToLowerInvariant();
				if (!(text != "piece_bathtub"))
				{
					float num2 = Vector3.Distance(((Component)player).transform.position, ((Component)val).transform.position);
					if (!(num2 > _config.Radius.Value))
					{
						num++;
						_log.Debug("Hot tub in range: name='" + ((Object)((Component)val).gameObject).name + "', " + $"distance={num2:0.0}m");
						_repairManager.TryRepair(player, (Component)(object)val, "hot tub");
						TryRefillHotTub(player, val, containers);
					}
				}
			}
			_log.Debug($"Hot tub scan end: inRange={num}");
		}

		private void TryRefillHotTub(Player player, Smelter smelter, Container[] containers)
		{
			if ((Object)(object)smelter == (Object)null)
			{
				return;
			}
			ZNetView val = ((Component)smelter).GetComponent<ZNetView>();
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)smelter).GetComponentInParent<ZNetView>();
			}
			if ((Object)(object)val == (Object)null || !val.IsValid())
			{
				_log.Debug("Hot tub: invalid ZNetView.");
				return;
			}
			ZDO zDO = val.GetZDO();
			if (zDO == null)
			{
				_log.Debug("Hot tub: ZDO is null.");
				return;
			}
			if ((Object)(object)smelter.m_fuelItem == (Object)null || smelter.m_fuelItem.m_itemData == null || smelter.m_fuelItem.m_itemData.m_shared == null)
			{
				_log.Debug("Hot tub: fuel item is null.");
				return;
			}
			string name = smelter.m_fuelItem.m_itemData.m_shared.m_name;
			float num = zDO.GetFloat(ZDOVars.s_fuel, 0f);
			float num2 = smelter.m_maxFuel;
			if (num2 <= 0f)
			{
				return;
			}
			float num3 = num / num2;
			_log.Debug("Hot tub fuel state: fuel='" + name + "', " + $"current={num:0.00}, max={num2:0.00}, " + $"percent={num3 * 100f:0.0}%, threshold={_config.RefillBelowPercent.Value * 100f:0.0}%");
			if (num3 >= _config.RefillBelowPercent.Value)
			{
				_log.Debug("Skipping hot tub - fuelPercent >= threshold.");
				return;
			}
			int num4 = Mathf.CeilToInt(num2 - num);
			int num5 = (_config.RefillToMax.Value ? num4 : Mathf.Min(_config.RefillAmount.Value, num4));
			if (num5 <= 0)
			{
				return;
			}
			_log.Debug($"Hot tub refill requested: missing={num4}, requested={num5}");
			int num6 = _fuelManager.ConsumeFuel(player, ((Component)smelter).transform, name, num5, containers);
			if (num6 <= 0)
			{
				_log.Debug("Hot tub refill stopped: no usable fuel.");
				return;
			}
			for (int i = 0; i < num6; i++)
			{
				val.InvokeRPC("RPC_AddFuel", new object[0]);
			}
			_log.Info($"Refilled hot tub: {num:0.0}/{num2:0.0}, " + $"fuel={name}, added={num6}, " + "mode=" + (_config.RefillToMax.Value ? "max" : "fixed"));
		}
	}
	internal static class RefillAmountCalculator
	{
		public static int Calculate(float current, float maximum, float threshold, bool toMax, int amount)
		{
			if (float.IsNaN(current) || float.IsInfinity(current) || current < 0f || float.IsNaN(maximum) || float.IsInfinity(maximum) || maximum <= 0f || float.IsNaN(threshold) || current >= maximum)
			{
				return 0;
			}
			threshold = Math.Max(0f, Math.Min(1f, threshold));
			if (current / maximum >= threshold)
			{
				return 0;
			}
			int num = (int)Math.Min(2147483647.0, Math.Floor((double)maximum - (double)current));
			return toMax ? num : Math.Min(num, Math.Max(0, amount));
		}
	}
	internal class RefillManager
	{
		private readonly ModConfig _config;

		private readonly FireplaceRefiller _fireplaceRefiller;

		private readonly HotTubRefiller _hotTubRefiller;

		private readonly SpecialRefiller _specialRefiller;

		private readonly RepairManager _repairManager;

		private readonly ModLogger _log;

		public RefillManager(ModConfig config, ModLogger log)
		{
			_config = config;
			_log = log;
			FuelManager fuelManager = new FuelManager(_config, _log);
			_specialRefiller = new SpecialRefiller(_config, fuelManager, _log);
			_fireplaceRefiller = new FireplaceRefiller(_config, fuelManager, _log);
			_repairManager = new RepairManager(_config, _log);
			_hotTubRefiller = new HotTubRefiller(_config, fuelManager, _repairManager, _log);
		}

		public void Run(Player player)
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			Fireplace[] array = Object.FindObjectsByType<Fireplace>((FindObjectsInactive)0, (FindObjectsSortMode)0);
			Smelter[] array2 = null;
			if (_config.FillHotTubs.Value)
			{
				array2 = Object.FindObjectsByType<Smelter>((FindObjectsInactive)0, (FindObjectsSortMode)0);
			}
			Container[] array3 = null;
			if (_config.UseNearbyContainers.Value)
			{
				array3 = Object.FindObjectsByType<Container>((FindObjectsInactive)0, (FindObjectsSortMode)0);
			}
			List<FireplaceCandidate> list = new List<FireplaceCandidate>();
			Fireplace[] array4 = array;
			foreach (Fireplace val in array4)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				float num = Vector3.Distance(((Component)player).transform.position, ((Component)val).transform.position);
				if (num > _config.Radius.Value)
				{
					continue;
				}
				ZNetView val2 = ((Component)val).GetComponent<ZNetView>();
				if ((Object)(object)val2 == (Object)null)
				{
					val2 = ((Component)val).GetComponentInParent<ZNetView>();
				}
				if ((Object)(object)val2 == (Object)null || !val2.IsValid())
				{
					continue;
				}
				ZDO zDO = val2.GetZDO();
				if (zDO != null)
				{
					float maxFuel = val.m_maxFuel;
					if (!(maxFuel <= 0f))
					{
						float num2 = zDO.GetFloat(ZDOVars.s_fuel, 0f);
						float fuelPercent = num2 / maxFuel;
						list.Add(new FireplaceCandidate
						{
							Fireplace = val,
							Distance = num,
							FuelPercent = fuelPercent
						});
					}
				}
			}
			list.Sort(delegate(FireplaceCandidate a, FireplaceCandidate b)
			{
				int num3 = a.FuelPercent.CompareTo(b.FuelPercent);
				return (num3 != 0) ? num3 : a.Distance.CompareTo(b.Distance);
			});
			_log.Debug($"Scan start: loadedFireplaces={array.Length}, " + $"inRange={list.Count}, " + $"loadedContainers={((array3 != null) ? array3.Length : 0)}, " + $"radius={_config.Radius.Value:0.0}m");
			foreach (FireplaceCandidate item in list)
			{
				_log.Debug("Priority: name='" + ((Object)((Component)item.Fireplace).gameObject).name + "', " + $"fuel={item.FuelPercent * 100f:0.0}%, " + $"distance={item.Distance:0.0}m");
				if (SpecialRefiller.IsResinCandle(item.Fireplace))
				{
					_specialRefiller.TryRefillCandle(player, item.Fireplace, array3);
					continue;
				}
				if (FireplaceTypeFilter.IsEnabled(_config, item.Fireplace, out var matchedRule))
				{
					_repairManager.TryRepair(player, (Component)(object)item.Fireplace, matchedRule);
				}
				_fireplaceRefiller.TryRefill(player, item.Fireplace, array3);
			}
			if (_config.FillHotTubs.Value && array2 != null)
			{
				_hotTubRefiller.RefillNearby(player, array2, array3);
			}
			if (_config.FillShieldGenerators.Value)
			{
				_specialRefiller.RefillShields(player, Object.FindObjectsByType<ShieldGenerator>((FindObjectsInactive)0, (FindObjectsSortMode)0), array3);
			}
			_log.Debug("Scan end.");
		}
	}
	internal class SpecialRefiller
	{
		private readonly ModConfig _config;

		private readonly FuelManager _fuelManager;

		private readonly ModLogger _log;

		public SpecialRefiller(ModConfig config, FuelManager fuelManager, ModLogger log)
		{
			_config = config;
			_fuelManager = fuelManager;
			_log = log;
		}

		public static bool IsResinCandle(Fireplace fireplace)
		{
			return ((Object)((Component)fireplace).gameObject).name.ToLowerInvariant().Contains("candle") && (Object)(object)fireplace.m_fuelItem != (Object)null && ((Object)((Component)fireplace.m_fuelItem).gameObject).name == "Resin";
		}

		public void TryRefillCandle(Player player, Fireplace fireplace, Container[] containers)
		{
			_log.Debug($"Candle check: name='{((Object)fireplace).name}', enabled={_config.FillResinCandles.Value}, canRefill={fireplace.m_canRefill}, infiniteFuel={fireplace.m_infiniteFuel}, maxFuel={fireplace.m_maxFuel}");
			if (!_config.FillResinCandles.Value)
			{
				_log.Debug("Skipping candle - FillResinCandles is disabled.");
				return;
			}
			if (!IsResinCandle(fireplace) || fireplace.m_infiniteFuel)
			{
				_log.Debug("Skipping candle - unsupported type or infinite fuel.");
				return;
			}
			string text = fireplace.m_fuelItem.m_itemData?.m_shared?.m_name;
			if (string.IsNullOrEmpty(text))
			{
				_log.Debug("Skipping candle - missing fuel item data.");
				return;
			}
			TryRefill(player, (Component)(object)fireplace, fireplace.m_maxFuel, fireplace.m_startFuel, new string[1] { text }, containers);
		}

		public void RefillShields(Player player, ShieldGenerator[] shields, Container[] containers)
		{
			if (!_config.FillShieldGenerators.Value)
			{
				return;
			}
			foreach (ShieldGenerator val in shields)
			{
				if ((Object)(object)val == (Object)null || ((Object)((Component)val).gameObject).name.Replace("(Clone)", "") != "piece_shieldgenerator" || val.m_fuelItems == null)
				{
					continue;
				}
				List<string> list = new List<string>();
				foreach (ItemDrop fuelItem in val.m_fuelItems)
				{
					string text = fuelItem?.m_itemData?.m_shared?.m_name;
					if (!string.IsNullOrEmpty(text) && !list.Contains(text))
					{
						list.Add(text);
					}
				}
				TryRefill(player, (Component)(object)val, val.m_maxFuel, val.m_defaultFuel, list, containers);
			}
		}

		private void TryRefill(Player player, Component target, float maximum, float defaultFuel, IReadOnlyList<string> fuels, Container[] containers)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (fuels.Count == 0 || Vector3.Distance(((Component)player).transform.position, target.transform.position) > _config.Radius.Value)
			{
				return;
			}
			Piece val = target.GetComponent<Piece>() ?? target.GetComponentInParent<Piece>();
			if (_config.OnlyRefillOwnPieces.Value && ((Object)(object)val == (Object)null || val.GetCreator() != player.GetPlayerID()))
			{
				_log.Debug("Skipping '" + ((Object)target).name + "' - OnlyRefillOwnPieces restriction.");
				return;
			}
			ZNetView val2 = target.GetComponent<ZNetView>() ?? target.GetComponentInParent<ZNetView>();
			if ((Object)(object)val2 == (Object)null || !val2.IsValid())
			{
				_log.Debug("Skipping '" + ((Object)target).name + "' - invalid ZNetView.");
				return;
			}
			ZDO zDO = val2.GetZDO();
			float num = zDO.GetFloat(ZDOVars.s_fuel, defaultFuel);
			int num2 = RefillAmountCalculator.Calculate(num, maximum, _config.RefillBelowPercent.Value, _config.RefillToMax.Value, _config.RefillAmount.Value);
			_log.Debug($"Special refill: name='{((Object)target).name}', fuel={num:0.000}/{maximum:0.000}, threshold={_config.RefillBelowPercent.Value:0.00}, requested={num2}");
			if (num2 <= 0)
			{
				_log.Debug("Skipping special refill - threshold not reached, no whole fuel slot, or fixed amount disabled.");
				return;
			}
			val2.ClaimOwnership();
			if (!val2.IsOwner())
			{
				return;
			}
			int num3 = 0;
			for (int i = 0; i < num2; i++)
			{
				if (!val2.IsValid())
				{
					break;
				}
				if (!val2.IsOwner())
				{
					break;
				}
				float num4 = zDO.GetFloat(ZDOVars.s_fuel, defaultFuel);
				if (RefillAmountCalculator.Calculate(num4, maximum, 1f, toMax: true, 1) <= 0 || _fuelManager.ConsumeFuelOptions(player, target.transform, fuels, containers) == 0)
				{
					break;
				}
				val2.InvokeRPC("RPC_AddFuel", new object[0]);
				if (zDO.GetFloat(ZDOVars.s_fuel, defaultFuel) <= num4)
				{
					_log.Error("Fuel was not applied to '" + ((Object)target).name + "'; stopping this refill.");
					break;
				}
				num3++;
			}
			if (num3 > 0)
			{
				_log.Info($"Refilled {((Object)target).name}: added={num3}, fuel={zDO.GetFloat(ZDOVars.s_fuel, defaultFuel):0.00}/{maximum:0.00}");
			}
		}
	}
	internal class RepairManager
	{
		private readonly ModConfig _config;

		private readonly ModLogger _log;

		public RepairManager(ModConfig config, ModLogger log)
		{
			_config = config;
			_log = log;
		}

		public void TryRepair(Player player, Component target, string label)
		{
			if (!_config.AutoRepair.Value || (Object)(object)target == (Object)null)
			{
				return;
			}
			if (_config.OnlyRepairOwnPieces.Value && !IsOwnPiece(player, target))
			{
				_log.Debug("Skipping repair for '" + ((Object)target.gameObject).name + "' - not owned by local player.");
				return;
			}
			WearNTear val = target.GetComponent<WearNTear>();
			if ((Object)(object)val == (Object)null)
			{
				val = target.GetComponentInParent<WearNTear>();
			}
			if ((Object)(object)val == (Object)null)
			{
				_log.Debug("Skipping repair for '" + ((Object)target.gameObject).name + "' - no WearNTear found.");
				return;
			}
			ZNetView val2 = ((Component)val).GetComponent<ZNetView>();
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = ((Component)val).GetComponentInParent<ZNetView>();
			}
			if ((Object)(object)val2 == (Object)null || !val2.IsValid())
			{
				_log.Debug("Skipping repair for '" + ((Object)target.gameObject).name + "' - invalid ZNetView.");
				return;
			}
			ZDO zDO = val2.GetZDO();
			if (zDO == null)
			{
				_log.Debug("Skipping repair for '" + ((Object)target.gameObject).name + "' - ZDO is null.");
				return;
			}
			float health = val.m_health;
			if (health <= 0f)
			{
				_log.Debug($"Skipping repair for '{((Object)target.gameObject).name}' - max health <= 0 ({health}).");
				return;
			}
			float num = zDO.GetFloat(ZDOVars.s_health, health);
			float num2 = num / health;
			float num3 = Mathf.Clamp01(_config.RepairBelowPercent.Value);
			_log.Debug("Repair state: type=" + label + ", name='" + ((Object)target.gameObject).name + "', " + $"health={num:0.0}/{health:0.0} ({num2 * 100f:0.0}%), " + $"threshold={num3 * 100f:0.0}%");
			if (!(num2 >= num3))
			{
				if (val.Repair())
				{
					_log.Info("Repaired " + label + ": " + ((Object)target.gameObject).name + ", " + $"{num:0.0}/{health:0.0} ({num2 * 100f:0.0}% -> 100%)");
				}
				else
				{
					_log.Debug("Repair request for '" + ((Object)target.gameObject).name + "' returned false.");
				}
			}
		}

		private static bool IsOwnPiece(Player player, Component target)
		{
			Piece val = target.GetComponent<Piece>();
			if ((Object)(object)val == (Object)null)
			{
				val = target.GetComponentInParent<Piece>();
			}
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			return val.GetCreator() == player.GetPlayerID();
		}
	}
	internal static class VersionInfo
	{
		public const string Version = "1.2.3";
	}
}