Decompiled source of LightMyFire v1.1.0

plugins/LightMyFire/LightMyFire.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using TMPro;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("LightMyFire")]
[assembly: AssemblyFileVersion("1.1.0")]
[assembly: AssemblyCompany("R4V9N1")]
[assembly: AssemblyDescription("Created by R4V9N1")]
[assembly: AssemblyProduct("LightMyFire")]
[assembly: AssemblyCopyright("Created by R4V9N1")]
[assembly: AssemblyMetadata("Creator", "Created by R4V9N1")]
[assembly: AssemblyVersion("1.1.0.0")]
namespace LightMyFire;

public sealed class LightMyFireBarrel : MonoBehaviour
{
	private struct PendingReservation
	{
		public int Amount;

		public long RequesterPeer;

		public ZDOID FireplaceId;

		public long ReservedAtNetworkTicks;
	}

	private const string RpcRequestFuel = "R4V9N1_LightMyFire_RequestFuel";

	private const string RpcAckApplied = "R4V9N1_LightMyFire_AckApplied";

	private const string RpcRefundFuel = "R4V9N1_LightMyFire_RefundFuel";

	internal const int MaxRequestPerTransaction = 50;

	private const float ReservationTimeoutSeconds = 30f;

	private const string ReservationStateZdoKey = "R4V9N1_LightMyFire_PendingReservations";

	private static readonly List<LightMyFireBarrel> ActiveBarrels = new List<LightMyFireBarrel>();

	private ZNetView _nview;

	private Container _container;

	private Inventory _inventory;

	[SerializeField]
	private string _fuelItemName;

	private bool _rpcRegistered;

	private bool _inventoryHooksRegistered;

	private bool _runtimeInitialized;

	private bool _sanitizingInventory;

	private bool _ownershipStateInitialized;

	private bool _wasOwner;

	private readonly Dictionary<long, PendingReservation> _pendingReservations = new Dictionary<long, PendingReservation>();

	private float _nextReservationSweep;

	internal string FuelItemName
	{
		get
		{
			EnsureConfiguration();
			return _fuelItemName;
		}
	}

	internal void Configure(string fuelItemName)
	{
		_fuelItemName = fuelItemName;
	}

	private void Awake()
	{
		_nview = ((Component)this).GetComponent<ZNetView>();
		_container = ((Component)this).GetComponent<Container>();
		EnsureConfiguration();
	}

	private void Start()
	{
		TryInitializeRuntime();
	}

	private void Update()
	{
		if (!_runtimeInitialized)
		{
			TryInitializeRuntime();
		}
		else
		{
			RefreshOwnershipState();
		}
	}

	private bool TryInitializeRuntime()
	{
		EnsureConfiguration();
		if ((Object)(object)_nview == (Object)null)
		{
			_nview = ((Component)this).GetComponent<ZNetView>();
		}
		if ((Object)(object)_container == (Object)null)
		{
			_container = ((Component)this).GetComponent<Container>();
		}
		if ((Object)(object)_container == (Object)null)
		{
			return false;
		}
		if (_inventory == null)
		{
			_inventory = _container.GetInventory();
		}
		if (_inventory != null && !_inventoryHooksRegistered)
		{
			Inventory inventory = _inventory;
			inventory.m_onChanged = (Action)Delegate.Combine(inventory.m_onChanged, new Action(OnInventoryChanged));
			LightMyFireItemFilter.RegisterFilteredInventory(_inventory, _fuelItemName);
			_inventoryHooksRegistered = true;
		}
		if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || _nview.GetZDO() == null || _inventory == null)
		{
			return false;
		}
		if (!_rpcRegistered)
		{
			_nview.Register<long, ZDOID, int>("R4V9N1_LightMyFire_RequestFuel", (Action<long, long, ZDOID, int>)RPC_RequestFuel);
			_nview.Register<long>("R4V9N1_LightMyFire_AckApplied", (Action<long, long>)RPC_AckApplied);
			_nview.Register<long, int>("R4V9N1_LightMyFire_RefundFuel", (Action<long, long, int>)RPC_RefundFuel);
			_rpcRegistered = true;
		}
		if (!ActiveBarrels.Contains(this))
		{
			ActiveBarrels.Add(this);
		}
		RefreshOwnershipState();
		_runtimeInitialized = true;
		LightMyFirePlugin.LogBarrelRuntimeReady(((Object)((Component)this).gameObject).name, _fuelItemName, GetFuelCount());
		return true;
	}

	private void EnsureConfiguration()
	{
		if (string.IsNullOrEmpty(_fuelItemName))
		{
			if (((Object)((Component)this).gameObject).name.IndexOf("ResinBarrel", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				_fuelItemName = "$item_resin";
			}
			else if (((Object)((Component)this).gameObject).name.IndexOf("WoodBarrel", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				_fuelItemName = "$item_wood";
			}
			else
			{
				_fuelItemName = "$item_coal";
			}
		}
	}

	private void OnDestroy()
	{
		if (_inventory != null && _inventoryHooksRegistered)
		{
			Inventory inventory = _inventory;
			inventory.m_onChanged = (Action)Delegate.Remove(inventory.m_onChanged, new Action(OnInventoryChanged));
			LightMyFireItemFilter.UnregisterFilteredInventory(_inventory);
			_inventoryHooksRegistered = false;
		}
		_inventory = null;
		_runtimeInitialized = false;
		_rpcRegistered = false;
		_ownershipStateInitialized = false;
		_wasOwner = false;
		_pendingReservations.Clear();
		ActiveBarrels.Remove(this);
	}

	private void OnInventoryChanged()
	{
		if (!_sanitizingInventory)
		{
			EjectInvalidItems();
		}
	}

	internal void EjectInvalidItems()
	{
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.IsOwner() || _inventory == null)
		{
			return;
		}
		EnsureConfiguration();
		List<ItemData> allItems = _inventory.GetAllItems();
		if (allItems == null || allItems.Count == 0)
		{
			return;
		}
		List<ItemData> list = null;
		for (int i = 0; i < allItems.Count; i++)
		{
			ItemData val = allItems[i];
			if (val != null && val.m_shared != null && !string.Equals(val.m_shared.m_name, _fuelItemName, StringComparison.Ordinal))
			{
				if (list == null)
				{
					list = new List<ItemData>();
				}
				list.Add(val);
			}
		}
		if (list == null)
		{
			return;
		}
		_sanitizingInventory = true;
		try
		{
			for (int j = 0; j < list.Count; j++)
			{
				ItemData val2 = list[j];
				_inventory.RemoveItem(val2);
				ItemDrop.DropItem(val2, val2.m_stack, ((Component)this).transform.position + Vector3.up * 0.5f, ((Component)this).transform.rotation);
			}
		}
		finally
		{
			_sanitizingInventory = false;
		}
		LightMyFirePlugin.LogInvalidItemEjection(list.Count, ((Object)((Component)this).gameObject).name);
	}

	internal void SweepStaleReservations()
	{
		if (_pendingReservations.Count == 0 || (Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.IsOwner())
		{
			return;
		}
		float realtimeSinceStartup = Time.realtimeSinceStartup;
		if (realtimeSinceStartup < _nextReservationSweep)
		{
			return;
		}
		_nextReservationSweep = realtimeSinceStartup + 5f;
		long networkTicks = GetNetworkTicks();
		List<long> list = null;
		foreach (KeyValuePair<long, PendingReservation> pendingReservation in _pendingReservations)
		{
			if (TimeSpan.FromTicks(Math.Max(0L, networkTicks - pendingReservation.Value.ReservedAtNetworkTicks)).TotalSeconds >= 30.0)
			{
				if (list == null)
				{
					list = new List<long>();
				}
				list.Add(pendingReservation.Key);
			}
		}
		if (list == null)
		{
			return;
		}
		for (int i = 0; i < list.Count; i++)
		{
			long key = list[i];
			if (_pendingReservations.TryGetValue(key, out var value))
			{
				_pendingReservations.Remove(key);
				RefundLocally(value.Amount);
			}
		}
		PersistReservations();
	}

	private static long GetNetworkTicks()
	{
		if (!((Object)(object)ZNet.instance == (Object)null))
		{
			return ZNet.instance.GetTime().Ticks;
		}
		return DateTime.UtcNow.Ticks;
	}

	private void RefreshOwnershipState()
	{
		bool flag = (Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.IsOwner();
		if (!_ownershipStateInitialized || flag != _wasOwner)
		{
			_ownershipStateInitialized = true;
			_wasOwner = flag;
			_pendingReservations.Clear();
			if (flag)
			{
				LoadPersistedReservations();
			}
		}
	}

	private void LoadPersistedReservations()
	{
		//IL_013a: Unknown result type (might be due to invalid IL or missing references)
		//IL_013f: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.IsOwner())
		{
			return;
		}
		ZDO zDO = _nview.GetZDO();
		if (zDO == null)
		{
			return;
		}
		string text = zDO.GetString("R4V9N1_LightMyFire_PendingReservations", string.Empty);
		if (string.IsNullOrEmpty(text))
		{
			return;
		}
		string[] array = text.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
		for (int i = 0; i < array.Length; i++)
		{
			string[] array2 = array[i].Split(new char[1] { '|' });
			if (array2.Length == 6 && long.TryParse(array2[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && int.TryParse(array2[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2) && long.TryParse(array2[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result3) && long.TryParse(array2[3], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result4) && uint.TryParse(array2[4], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result5) && long.TryParse(array2[5], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result6) && result2 > 0 && result6 > 0)
			{
				_pendingReservations[result] = new PendingReservation
				{
					Amount = result2,
					RequesterPeer = result3,
					FireplaceId = new ZDOID(result4, result5),
					ReservedAtNetworkTicks = result6
				};
			}
		}
	}

	private void PersistReservations()
	{
		if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.IsOwner())
		{
			return;
		}
		ZDO zDO = _nview.GetZDO();
		if (zDO == null)
		{
			return;
		}
		if (_pendingReservations.Count == 0)
		{
			zDO.Set("R4V9N1_LightMyFire_PendingReservations", string.Empty);
			return;
		}
		StringBuilder stringBuilder = new StringBuilder();
		foreach (KeyValuePair<long, PendingReservation> pendingReservation in _pendingReservations)
		{
			if (stringBuilder.Length > 0)
			{
				stringBuilder.Append(';');
			}
			PendingReservation value = pendingReservation.Value;
			stringBuilder.Append(pendingReservation.Key.ToString(CultureInfo.InvariantCulture)).Append('|').Append(value.Amount.ToString(CultureInfo.InvariantCulture))
				.Append('|')
				.Append(value.RequesterPeer.ToString(CultureInfo.InvariantCulture))
				.Append('|')
				.Append(((ZDOID)(ref value.FireplaceId)).UserID.ToString(CultureInfo.InvariantCulture))
				.Append('|')
				.Append(((ZDOID)(ref value.FireplaceId)).ID.ToString(CultureInfo.InvariantCulture))
				.Append('|')
				.Append(value.ReservedAtNetworkTicks.ToString(CultureInfo.InvariantCulture));
		}
		zDO.Set("R4V9N1_LightMyFire_PendingReservations", stringBuilder.ToString());
	}

	private bool CanReceiveRequest(Vector3 targetPosition, float rangeSqr)
	{
		//IL_0063: 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)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)this == (Object)null || !((Behaviour)this).isActiveAndEnabled)
		{
			return false;
		}
		if (!_runtimeInitialized && !TryInitializeRuntime())
		{
			return false;
		}
		if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.HasOwner() || (Object)(object)_container == (Object)null)
		{
			return false;
		}
		Vector3 val = ((Component)this).transform.position - targetPosition;
		return ((Vector3)(ref val)).sqrMagnitude <= rangeSqr;
	}

	internal int GetFuelCount()
	{
		EnsureConfiguration();
		if (_inventory == null && (Object)(object)_container != (Object)null)
		{
			_inventory = _container.GetInventory();
		}
		if (_inventory != null)
		{
			return _inventory.CountItems(_fuelItemName, -1, false);
		}
		return 0;
	}

	private int RemoveFuelLocally(int requested)
	{
		if (requested <= 0 || _inventory == null)
		{
			return 0;
		}
		int num = _inventory.CountItems(_fuelItemName, -1, false);
		int num2 = Math.Min(num, requested);
		if (num2 <= 0)
		{
			return 0;
		}
		_inventory.RemoveItem(_fuelItemName, num2, -1, false);
		int num3 = _inventory.CountItems(_fuelItemName, -1, false);
		return Mathf.Clamp(num - num3, 0, num2);
	}

	private void RefundLocally(int amount)
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
		if (amount <= 0 || _inventory == null)
		{
			return;
		}
		EnsureConfiguration();
		string fuelPrefabName = LightMyFirePlugin.GetFuelPrefabName(_fuelItemName);
		int num = _inventory.CountItems(_fuelItemName, -1, false);
		_inventory.AddItem(fuelPrefabName, amount, 1, 0, 0L, string.Empty, new Vector2i(-1, -1), false, false, false);
		int num2 = Mathf.Clamp(_inventory.CountItems(_fuelItemName, -1, false) - num, 0, amount);
		int num3 = amount - num2;
		if (num3 > 0)
		{
			GameObject val = (((Object)(object)ObjectDB.instance == (Object)null) ? null : ObjectDB.instance.GetItemPrefab(fuelPrefabName));
			ItemDrop val2 = (((Object)(object)val == (Object)null) ? null : val.GetComponent<ItemDrop>());
			if ((Object)(object)val2 != (Object)null && val2.m_itemData != null)
			{
				ItemData obj = val2.m_itemData.Clone();
				obj.m_stack = num3;
				ItemDrop.DropItem(obj, num3, ((Component)this).transform.position + Vector3.up * 0.5f, ((Component)this).transform.rotation);
			}
		}
	}

	private void RPC_RequestFuel(long sender, long transactionId, ZDOID fireplaceId, int requestedAmount)
	{
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0106: Unknown result type (might be due to invalid IL or missing references)
		//IL_010b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		if (!LightMyFirePlugin.IsEnabled() || (Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.IsOwner() || _inventory == null || _pendingReservations.ContainsKey(transactionId) || ZDOMan.instance == null)
		{
			return;
		}
		ZDO zDO = ZDOMan.instance.GetZDO(fireplaceId);
		if (zDO == null || zDO.GetOwner() != sender)
		{
			return;
		}
		float feedRange = LightMyFirePlugin.GetFeedRange();
		Vector3 val = ((Component)this).transform.position - zDO.GetPosition();
		if (((Vector3)(ref val)).sqrMagnitude > feedRange * feedRange)
		{
			return;
		}
		int num = Mathf.Clamp(requestedAmount, 0, 50);
		if (num > 0)
		{
			EnsureConfiguration();
			int num2 = RemoveFuelLocally(num);
			if (num2 <= 0)
			{
				LightMyFireFeeder.SendGrant(transactionId, GetZdoId(), fireplaceId, 0);
				return;
			}
			_pendingReservations[transactionId] = new PendingReservation
			{
				Amount = num2,
				RequesterPeer = sender,
				FireplaceId = fireplaceId,
				ReservedAtNetworkTicks = GetNetworkTicks()
			};
			PersistReservations();
			LightMyFireFeeder.SendGrant(transactionId, GetZdoId(), fireplaceId, num2);
		}
	}

	private void RPC_AckApplied(long sender, long transactionId)
	{
		if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner() && _pendingReservations.TryGetValue(transactionId, out var value) && sender == value.RequesterPeer)
		{
			_pendingReservations.Remove(transactionId);
			PersistReservations();
		}
	}

	private void RPC_RefundFuel(long sender, long transactionId, int amount)
	{
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner() && _pendingReservations.TryGetValue(transactionId, out var value))
		{
			bool flag = sender == value.RequesterPeer;
			if (!flag && ZDOMan.instance != null)
			{
				ZDO zDO = ZDOMan.instance.GetZDO(value.FireplaceId);
				flag = zDO != null && zDO.GetOwner() == sender;
			}
			if (flag)
			{
				_pendingReservations.Remove(transactionId);
				int amount2 = Mathf.Clamp(amount, 0, value.Amount);
				RefundLocally(amount2);
				PersistReservations();
			}
		}
	}

	internal ZDOID GetZdoId()
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		return (((Object)(object)_nview == (Object)null) ? null : _nview.GetZDO())?.m_uid ?? ZDOID.None;
	}

	internal bool SendRequestFuel(long transactionId, ZDOID fireplaceId, int requestedAmount)
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.HasOwner())
		{
			return false;
		}
		_nview.InvokeRPC("R4V9N1_LightMyFire_RequestFuel", new object[3]
		{
			transactionId,
			fireplaceId,
			Mathf.Clamp(requestedAmount, 0, 50)
		});
		return true;
	}

	internal void SendAckApplied(long transactionId)
	{
		if ((Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.HasOwner())
		{
			_nview.InvokeRPC("R4V9N1_LightMyFire_AckApplied", new object[1] { transactionId });
		}
	}

	internal void SendRefundFuel(long transactionId, int amount)
	{
		if ((Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.HasOwner() && amount > 0)
		{
			_nview.InvokeRPC("R4V9N1_LightMyFire_RefundFuel", new object[2] { transactionId, amount });
		}
	}

	internal static LightMyFireBarrel FindByZdoId(ZDOID id)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		if (id == ZDOID.None)
		{
			return null;
		}
		for (int num = ActiveBarrels.Count - 1; num >= 0; num--)
		{
			LightMyFireBarrel lightMyFireBarrel = ActiveBarrels[num];
			if ((Object)(object)lightMyFireBarrel == (Object)null)
			{
				ActiveBarrels.RemoveAt(num);
			}
			else if (lightMyFireBarrel.GetZdoId() == id)
			{
				return lightMyFireBarrel;
			}
		}
		return null;
	}

	internal static bool TryFindActiveMatchingBarrels(string fuelItemName, List<LightMyFireBarrel> results)
	{
		results.Clear();
		for (int num = ActiveBarrels.Count - 1; num >= 0; num--)
		{
			LightMyFireBarrel lightMyFireBarrel = ActiveBarrels[num];
			if ((Object)(object)lightMyFireBarrel == (Object)null)
			{
				ActiveBarrels.RemoveAt(num);
			}
			else
			{
				lightMyFireBarrel.EnsureConfiguration();
				if (string.Equals(lightMyFireBarrel._fuelItemName, fuelItemName, StringComparison.Ordinal))
				{
					results.Add(lightMyFireBarrel);
				}
			}
		}
		return results.Count > 0;
	}

	internal bool IsWithinRange(Vector3 targetPosition, float rangeSqr)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		return CanReceiveRequest(targetPosition, rangeSqr);
	}

	internal static bool AnyActiveBarrels()
	{
		for (int num = ActiveBarrels.Count - 1; num >= 0; num--)
		{
			if ((Object)(object)ActiveBarrels[num] == (Object)null)
			{
				ActiveBarrels.RemoveAt(num);
			}
		}
		return ActiveBarrels.Count > 0;
	}

	internal static bool HasActiveBarrels()
	{
		for (int num = ActiveBarrels.Count - 1; num >= 0; num--)
		{
			if ((Object)(object)ActiveBarrels[num] == (Object)null)
			{
				ActiveBarrels.RemoveAt(num);
			}
		}
		if (ActiveBarrels.Count == 0)
		{
			LightMyFireBarrel[] array = Object.FindObjectsByType<LightMyFireBarrel>((FindObjectsInactive)0, (FindObjectsSortMode)0);
			foreach (LightMyFireBarrel lightMyFireBarrel in array)
			{
				if ((Object)(object)lightMyFireBarrel != (Object)null)
				{
					lightMyFireBarrel.TryInitializeRuntime();
				}
			}
		}
		return ActiveBarrels.Count > 0;
	}

	internal static void TickMaintenance()
	{
		for (int num = ActiveBarrels.Count - 1; num >= 0; num--)
		{
			LightMyFireBarrel lightMyFireBarrel = ActiveBarrels[num];
			if ((Object)(object)lightMyFireBarrel == (Object)null)
			{
				ActiveBarrels.RemoveAt(num);
			}
			else
			{
				lightMyFireBarrel.SweepStaleReservations();
			}
		}
	}

	internal static void EjectInvalidItemsFromOwnedBarrels()
	{
		for (int num = ActiveBarrels.Count - 1; num >= 0; num--)
		{
			LightMyFireBarrel lightMyFireBarrel = ActiveBarrels[num];
			if ((Object)(object)lightMyFireBarrel == (Object)null)
			{
				ActiveBarrels.RemoveAt(num);
			}
			else
			{
				lightMyFireBarrel.EjectInvalidItems();
			}
		}
	}
}
internal static class LightMyFireFeeder
{
	private struct OutboundState
	{
		public LightMyFireBarrel CurrentBarrel;

		public ZDOID FireplaceId;

		public int RemainingAmount;

		public List<LightMyFireBarrel> Candidates;

		public int NextCandidateIndex;

		public float SentAtRealtime;
	}

	private readonly struct BarrelDistance
	{
		public readonly LightMyFireBarrel Barrel;

		public readonly float DistanceSqr;

		public BarrelDistance(LightMyFireBarrel barrel, float distanceSqr)
		{
			Barrel = barrel;
			DistanceSqr = distanceSqr;
		}
	}

	internal const string RpcGrantFuel = "R4V9N1_LightMyFire_GrantFuel";

	private const float OutboundRequestTimeoutSeconds = 20f;

	private static readonly Dictionary<long, OutboundState> PendingOutbound = new Dictionary<long, OutboundState>();

	private static readonly List<OutboundState> DeferredSmelterRequests = new List<OutboundState>();

	private static readonly HashSet<ZDOID> LightsAwaitingResponse = new HashSet<ZDOID>();

	private const float SmelterDelaySeconds = 30f;

	private static float _smelterReleaseAt;

	private static readonly HashSet<ZDOID> FireplacesAwaitingResponse = new HashSet<ZDOID>();

	private static long _txCounter;

	private const float SmelterFuelRetrySeconds = 10f;

	private static readonly Dictionary<ZDOID, float> NextSmelterFuelAttempt = new Dictionary<ZDOID, float>();

	internal static void TickDeferred()
	{
		if (DeferredSmelterRequests.Count > 0 && Time.realtimeSinceStartup >= _smelterReleaseAt)
		{
			FlushDeferredSmelterRequests();
		}
	}

	private static long NextTransactionId()
	{
		long uID = ZNet.GetUID();
		_txCounter++;
		return (uID << 20) ^ (_txCounter & 0xFFFFF);
	}

	internal static void PruneStaleOutbound()
	{
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		if (PendingOutbound.Count == 0)
		{
			return;
		}
		float realtimeSinceStartup = Time.realtimeSinceStartup;
		List<long> list = null;
		foreach (KeyValuePair<long, OutboundState> item in PendingOutbound)
		{
			if (realtimeSinceStartup - item.Value.SentAtRealtime >= 20f)
			{
				if (list == null)
				{
					list = new List<long>();
				}
				list.Add(item.Key);
			}
		}
		if (list == null)
		{
			return;
		}
		for (int i = 0; i < list.Count; i++)
		{
			if (PendingOutbound.TryGetValue(list[i], out var value))
			{
				PendingOutbound.Remove(list[i]);
				if (!TrySendNextRequest(value))
				{
					MarkResolved(value.FireplaceId);
				}
			}
		}
	}

	private static void MarkResolved(ZDOID targetId)
	{
		//IL_0005: 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)
		FireplacesAwaitingResponse.Remove(targetId);
		LightsAwaitingResponse.Remove(targetId);
		FlushDeferredSmelterRequests();
	}

	private static void FlushDeferredSmelterRequests()
	{
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		if (LightsAwaitingResponse.Count > 0 || DeferredSmelterRequests.Count == 0 || Time.realtimeSinceStartup < _smelterReleaseAt)
		{
			return;
		}
		List<OutboundState> list = new List<OutboundState>(DeferredSmelterRequests);
		DeferredSmelterRequests.Clear();
		for (int i = 0; i < list.Count; i++)
		{
			if (!FireplacesAwaitingResponse.Contains(list[i].FireplaceId))
			{
				TrySendNextRequest(list[i]);
			}
		}
	}

	internal static void OnSmelterUpdate(Smelter smelter)
	{
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: Unknown result type (might be due to invalid IL or missing references)
		//IL_014a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0171: Unknown result type (might be due to invalid IL or missing references)
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		//IL_0178: Unknown result type (might be due to invalid IL or missing references)
		//IL_017d: Unknown result type (might be due to invalid IL or missing references)
		//IL_021c: Unknown result type (might be due to invalid IL or missing references)
		//IL_021d: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)smelter == (Object)null || smelter.m_maxFuel <= 0 || !LightMyFirePlugin.IsEnabled() || !LightMyFireBarrel.AnyActiveBarrels())
		{
			return;
		}
		ZNetView smelterView = LightMyFireOreFeeder.GetSmelterView(smelter);
		if ((Object)(object)smelterView == (Object)null || !smelterView.IsValid() || !smelterView.IsOwner())
		{
			return;
		}
		ZDO zDO = smelterView.GetZDO();
		float num = zDO.GetFloat(ZDOVars.s_fuel, 0f);
		float num2 = Mathf.Max((float)smelter.m_maxFuel * 0.25f, (float)smelter.m_fuelPerProduct * 2f);
		ZDOID uid = zDO.m_uid;
		if (num > num2 || LightsAwaitingResponse.Count > 0 || FireplacesAwaitingResponse.Contains(uid) || (NextSmelterFuelAttempt.TryGetValue(uid, out var value) && Time.realtimeSinceStartup < value))
		{
			return;
		}
		if (!string.Equals(LightMyFirePlugin.GetSupportedFuelItemName(smelter), "$item_coal", StringComparison.Ordinal))
		{
			NextSmelterFuelAttempt[uid] = float.MaxValue;
			return;
		}
		NextSmelterFuelAttempt[uid] = Time.realtimeSinceStartup + 10f;
		int num3 = Mathf.FloorToInt((float)smelter.m_maxFuel - num + 0.001f);
		List<LightMyFireBarrel> list = new List<LightMyFireBarrel>();
		if (num3 <= 0 || !LightMyFireBarrel.TryFindActiveMatchingBarrels("$item_coal", list))
		{
			return;
		}
		float feedRange = LightMyFirePlugin.GetFeedRange();
		Vector3 position = ((Component)smelter).transform.position;
		List<BarrelDistance> list2 = new List<BarrelDistance>();
		for (int i = 0; i < list.Count; i++)
		{
			if (list[i].IsWithinRange(position, feedRange * feedRange))
			{
				LightMyFireBarrel barrel = list[i];
				Vector3 val = ((Component)list[i]).transform.position - position;
				list2.Add(new BarrelDistance(barrel, ((Vector3)(ref val)).sqrMagnitude));
			}
		}
		if (list2.Count != 0)
		{
			list2.Sort(delegate(BarrelDistance left, BarrelDistance right)
			{
				float distanceSqr = left.DistanceSqr;
				return distanceSqr.CompareTo(right.DistanceSqr);
			});
			List<LightMyFireBarrel> list3 = new List<LightMyFireBarrel>(list2.Count);
			for (int num4 = 0; num4 < list2.Count; num4++)
			{
				list3.Add(list2[num4].Barrel);
			}
			TrySendNextRequest(new OutboundState
			{
				CurrentBarrel = null,
				FireplaceId = uid,
				RemainingAmount = num3,
				Candidates = list3,
				NextCandidateIndex = 0,
				SentAtRealtime = 0f
			});
		}
	}

	internal static void ScanAndRequestRefills()
	{
		//IL_0132: Unknown result type (might be due to invalid IL or missing references)
		//IL_0137: Unknown result type (might be due to invalid IL or missing references)
		//IL_0153: Unknown result type (might be due to invalid IL or missing references)
		//IL_01df: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0215: Unknown result type (might be due to invalid IL or missing references)
		//IL_021a: Unknown result type (might be due to invalid IL or missing references)
		//IL_021c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0221: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_0310: Unknown result type (might be due to invalid IL or missing references)
		//IL_032e: Unknown result type (might be due to invalid IL or missing references)
		PruneStaleOutbound();
		if (!LightMyFireBarrel.HasActiveBarrels())
		{
			return;
		}
		Fireplace[] array = (Fireplace[])(((object)Object.FindObjectsByType<Fireplace>((FindObjectsInactive)0, (FindObjectsSortMode)0)) ?? ((object)new Fireplace[0]));
		Smelter[] array2 = (Smelter[])(((object)Object.FindObjectsByType<Smelter>((FindObjectsInactive)0, (FindObjectsSortMode)0)) ?? ((object)new Smelter[0]));
		CookingStation[] array3 = (CookingStation[])(((object)Object.FindObjectsByType<CookingStation>((FindObjectsInactive)0, (FindObjectsSortMode)0)) ?? ((object)new CookingStation[0]));
		DeferredSmelterRequests.Clear();
		_smelterReleaseAt = Time.realtimeSinceStartup + 30f;
		if (array.Length == 0 && array2.Length == 0 && array3.Length == 0)
		{
			LightMyFirePlugin.LogScanSummary(0, 0, 0, 0, 0, 0);
			return;
		}
		List<Component> list = new List<Component>(array.Length + array2.Length + array3.Length);
		list.AddRange((IEnumerable<Component>)(object)array);
		list.AddRange((IEnumerable<Component>)(object)array2);
		list.AddRange((IEnumerable<Component>)(object)array3);
		int num = 0;
		int num2 = 0;
		int num3 = 0;
		int num4 = 0;
		int num5 = 0;
		float feedRange = LightMyFirePlugin.GetFeedRange();
		float rangeSqr = feedRange * feedRange;
		List<LightMyFireBarrel> list2 = new List<LightMyFireBarrel>();
		List<BarrelDistance> list3 = new List<BarrelDistance>();
		for (int i = 0; i < list.Count; i++)
		{
			Component val = list[i];
			bool flag = val is Fireplace;
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			ZNetView val2 = ResolveNetworkView(val);
			if ((Object)(object)val2 == (Object)null || !val2.IsValid() || !val2.IsOwner())
			{
				continue;
			}
			num++;
			ZDO zDO = val2.GetZDO();
			if (zDO == null)
			{
				continue;
			}
			ZDOID uid = zDO.m_uid;
			if ((val is CookingStation && LightMyFireAutoFuelToggle.IsAutoFuelOff(zDO)) || FireplacesAwaitingResponse.Contains(uid) || !TryGetFuelInfo(val, out var fuelItemName, out var maxFuel))
			{
				continue;
			}
			num2++;
			if (val is Smelter && LightMyFireOreFeeder.SmelterHookActive && string.Equals(fuelItemName, "$item_coal", StringComparison.Ordinal))
			{
				continue;
			}
			float num6 = zDO.GetFloat(ZDOVars.s_fuel, 0f);
			int num7 = Mathf.FloorToInt(maxFuel - num6 + 0.001f);
			if (num7 <= 0)
			{
				continue;
			}
			num3++;
			if (!LightMyFireBarrel.TryFindActiveMatchingBarrels(fuelItemName, list2))
			{
				continue;
			}
			Vector3 position = val.transform.position;
			list3.Clear();
			for (int j = 0; j < list2.Count; j++)
			{
				LightMyFireBarrel lightMyFireBarrel = list2[j];
				if (lightMyFireBarrel.IsWithinRange(position, rangeSqr))
				{
					Vector3 val3 = ((Component)lightMyFireBarrel).transform.position - position;
					list3.Add(new BarrelDistance(lightMyFireBarrel, ((Vector3)(ref val3)).sqrMagnitude));
				}
			}
			if (list3.Count == 0)
			{
				continue;
			}
			num4++;
			list3.Sort(delegate(BarrelDistance left, BarrelDistance right)
			{
				float distanceSqr = left.DistanceSqr;
				return distanceSqr.CompareTo(right.DistanceSqr);
			});
			List<LightMyFireBarrel> list4 = new List<LightMyFireBarrel>(list3.Count);
			for (int num8 = 0; num8 < list3.Count; num8++)
			{
				list4.Add(list3[num8].Barrel);
			}
			OutboundState outboundState = new OutboundState
			{
				CurrentBarrel = null,
				FireplaceId = uid,
				RemainingAmount = num7,
				Candidates = list4,
				NextCandidateIndex = 0,
				SentAtRealtime = 0f
			};
			if (!flag)
			{
				DeferredSmelterRequests.Add(outboundState);
				continue;
			}
			LightsAwaitingResponse.Add(uid);
			if (TrySendNextRequest(outboundState))
			{
				num5++;
			}
			else
			{
				LightsAwaitingResponse.Remove(uid);
			}
		}
		FlushDeferredSmelterRequests();
		LightMyFirePlugin.LogScanSummary(list.Count, num, num2, num3, num4, num5);
	}

	private static bool TrySendNextRequest(OutboundState state)
	{
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		if (state.Candidates == null || state.RemainingAmount <= 0)
		{
			return false;
		}
		while (state.NextCandidateIndex < state.Candidates.Count)
		{
			LightMyFireBarrel lightMyFireBarrel = state.Candidates[state.NextCandidateIndex];
			state.NextCandidateIndex++;
			if (!((Object)(object)lightMyFireBarrel == (Object)null))
			{
				int num = Mathf.Min(state.RemainingAmount, 50);
				if (num <= 0)
				{
					return false;
				}
				long num2 = NextTransactionId();
				state.CurrentBarrel = lightMyFireBarrel;
				state.SentAtRealtime = Time.realtimeSinceStartup;
				PendingOutbound[num2] = state;
				FireplacesAwaitingResponse.Add(state.FireplaceId);
				if (lightMyFireBarrel.SendRequestFuel(num2, state.FireplaceId, num))
				{
					return true;
				}
				PendingOutbound.Remove(num2);
				FireplacesAwaitingResponse.Remove(state.FireplaceId);
			}
		}
		return false;
	}

	internal static void SendGrant(long transactionId, ZDOID barrelId, ZDOID fireplaceId, int grantedAmount)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		if (ZRoutedRpc.instance == null || ZDOMan.instance == null)
		{
			return;
		}
		ZDO zDO = ZDOMan.instance.GetZDO(fireplaceId);
		if (zDO != null)
		{
			long owner = zDO.GetOwner();
			if (owner != 0L)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(owner, "R4V9N1_LightMyFire_GrantFuel", new object[4] { transactionId, barrelId, fireplaceId, grantedAmount });
			}
		}
	}

	internal static void RPC_GrantFuel(long sender, long transactionId, ZDOID barrelId, ZDOID fireplaceId, int grantedAmount)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		OutboundState value;
		bool num = PendingOutbound.TryGetValue(transactionId, out value);
		LightMyFireBarrel lightMyFireBarrel = (num ? value.CurrentBarrel : LightMyFireBarrel.FindByZdoId(barrelId));
		if (!num)
		{
			if (grantedAmount > 0)
			{
				RefundToBarrel(lightMyFireBarrel, transactionId, grantedAmount);
			}
			return;
		}
		PendingOutbound.Remove(transactionId);
		if (grantedAmount <= 0)
		{
			if (!TrySendNextRequest(value))
			{
				MarkResolved(value.FireplaceId);
			}
			return;
		}
		int num2 = TryApplyFuelToFireplace(fireplaceId, grantedAmount);
		int num3 = grantedAmount - num2;
		if (num3 > 0)
		{
			RefundToBarrel(lightMyFireBarrel, transactionId, num3);
		}
		else if ((Object)(object)lightMyFireBarrel != (Object)null)
		{
			lightMyFireBarrel.SendAckApplied(transactionId);
		}
		if (num2 <= 0 || num3 > 0)
		{
			MarkResolved(value.FireplaceId);
			return;
		}
		value.RemainingAmount = Math.Max(0, value.RemainingAmount - num2);
		if (value.RemainingAmount <= 0 || !TrySendNextRequest(value))
		{
			MarkResolved(value.FireplaceId);
		}
	}

	private static void RefundToBarrel(LightMyFireBarrel barrel, long transactionId, int amount)
	{
		if ((Object)(object)barrel != (Object)null && amount > 0)
		{
			barrel.SendRefundFuel(transactionId, amount);
		}
	}

	private static int TryApplyFuelToFireplace(ZDOID fireplaceId, int grantedAmount)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)ZNetScene.instance == (Object)null)
		{
			return 0;
		}
		GameObject val = ZNetScene.instance.FindInstance(fireplaceId);
		if ((Object)(object)val == (Object)null)
		{
			return 0;
		}
		Component val2 = (Component)(object)val.GetComponent<Fireplace>();
		if ((Object)(object)val2 == (Object)null)
		{
			val2 = (Component)(object)val.GetComponentInChildren<Fireplace>(true);
		}
		if ((Object)(object)val2 == (Object)null)
		{
			val2 = (Component)(object)val.GetComponent<Smelter>();
		}
		if ((Object)(object)val2 == (Object)null)
		{
			val2 = (Component)(object)val.GetComponentInChildren<Smelter>(true);
		}
		if ((Object)(object)val2 == (Object)null)
		{
			val2 = (Component)(object)val.GetComponent<CookingStation>();
		}
		if ((Object)(object)val2 == (Object)null)
		{
			val2 = (Component)(object)val.GetComponentInChildren<CookingStation>(true);
		}
		ZNetView val3 = ResolveNetworkView(val2);
		if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || !val3.IsValid() || !val3.IsOwner() || !TryGetFuelInfo(val2, out var fuelItemName, out var maxFuel))
		{
			return 0;
		}
		ZDO zDO = val3.GetZDO();
		if (zDO == null || (val2 is CookingStation && LightMyFireAutoFuelToggle.IsAutoFuelOff(zDO)))
		{
			return 0;
		}
		float num = zDO.GetFloat(ZDOVars.s_fuel, 0f);
		int num2 = Mathf.Clamp(Mathf.FloorToInt(maxFuel - num + 0.001f), 0, 50);
		int num3 = Mathf.Min(grantedAmount, num2);
		if (num3 <= 0)
		{
			return 0;
		}
		zDO.Set(ZDOVars.s_fuel, Mathf.Clamp(num + (float)num3, 0f, maxFuel));
		LightMyFirePlugin.LogTransfer(num3, fuelItemName, GetTargetDisplayName(val2));
		return num3;
	}

	private static bool TryGetFuelInfo(Component target, out string fuelItemName, out float maxFuel)
	{
		fuelItemName = null;
		maxFuel = 0f;
		Fireplace val = (Fireplace)(object)((target is Fireplace) ? target : null);
		if ((Object)(object)val != (Object)null)
		{
			fuelItemName = LightMyFirePlugin.GetSupportedFuelItemName(val);
			maxFuel = val.m_maxFuel;
			return fuelItemName != null;
		}
		Smelter val2 = (Smelter)(object)((target is Smelter) ? target : null);
		if ((Object)(object)val2 != (Object)null)
		{
			fuelItemName = LightMyFirePlugin.GetSupportedFuelItemName(val2);
			maxFuel = val2.m_maxFuel;
			return fuelItemName != null;
		}
		CookingStation val3 = (CookingStation)(object)((target is CookingStation) ? target : null);
		if ((Object)(object)val3 != (Object)null)
		{
			fuelItemName = LightMyFirePlugin.GetSupportedFuelItemName(val3);
			maxFuel = val3.m_maxFuel;
			return fuelItemName != null;
		}
		return false;
	}

	private static string GetTargetDisplayName(Component target)
	{
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		Fireplace val = (Fireplace)(object)((target is Fireplace) ? target : null);
		if ((Object)(object)val != (Object)null)
		{
			return val.GetHoverName();
		}
		string text = ((target is Smelter) ? ((Smelter)target).m_name : ((target is CookingStation) ? ((CookingStation)target).m_name : ((Object)target.gameObject).name));
		if (Localization.instance == null)
		{
			return text;
		}
		return Localization.instance.Localize(text);
	}

	private static ZNetView ResolveNetworkView(Component fireplace)
	{
		if ((Object)(object)fireplace == (Object)null)
		{
			return null;
		}
		ZNetView component = fireplace.GetComponent<ZNetView>();
		if ((Object)(object)component != (Object)null)
		{
			return component;
		}
		component = fireplace.GetComponentInParent<ZNetView>();
		if ((Object)(object)component != (Object)null)
		{
			return component;
		}
		return fireplace.GetComponentInChildren<ZNetView>(true);
	}
}
internal static class LightMyFireItemFilter
{
	private static readonly ConditionalWeakTable<Inventory, StrongBox<string>> FilteredInventories = new ConditionalWeakTable<Inventory, StrongBox<string>>();

	internal static void RegisterFilteredInventory(Inventory inventory, string fuelItemName)
	{
		if (inventory != null && !string.IsNullOrEmpty(fuelItemName))
		{
			if (FilteredInventories.TryGetValue(inventory, out var value))
			{
				value.Value = fuelItemName;
			}
			else
			{
				FilteredInventories.Add(inventory, new StrongBox<string>(fuelItemName));
			}
		}
	}

	internal static void UnregisterFilteredInventory(Inventory inventory)
	{
		if (inventory != null)
		{
			FilteredInventories.Remove(inventory);
		}
	}

	internal static bool TryGetExpectedFuel(Inventory inventory, out string fuelItemName)
	{
		fuelItemName = null;
		if (inventory == null)
		{
			return false;
		}
		if (!FilteredInventories.TryGetValue(inventory, out var value) || value == null || string.IsNullOrEmpty(value.Value))
		{
			return false;
		}
		fuelItemName = value.Value;
		return true;
	}

	internal static bool IsRejected(Inventory inventory, ItemData item)
	{
		if (!TryGetExpectedFuel(inventory, out var fuelItemName) || item == null || item.m_shared == null)
		{
			return false;
		}
		return !IsAcceptedFuelName(fuelItemName, item.m_shared.m_name);
	}

	internal static bool IsRejectedInvocation(Inventory inventory, MethodBase method, object[] args, out string rejectedItemName, out string expectedFuelName)
	{
		rejectedItemName = null;
		expectedFuelName = null;
		if (!TryGetExpectedFuel(inventory, out expectedFuelName) || method == null || args == null)
		{
			return false;
		}
		ParameterInfo[] parameters = method.GetParameters();
		foreach (object obj in args)
		{
			if (obj == null)
			{
				continue;
			}
			ItemData val = (ItemData)((obj is ItemData) ? obj : null);
			if (val != null && val.m_shared != null)
			{
				string name = val.m_shared.m_name;
				if (!IsAcceptedFuelName(expectedFuelName, name))
				{
					rejectedItemName = name;
					return true;
				}
				continue;
			}
			ItemDrop val2 = (ItemDrop)((obj is ItemDrop) ? obj : null);
			if ((Object)(object)val2 != (Object)null && val2.m_itemData != null && val2.m_itemData.m_shared != null)
			{
				string name2 = val2.m_itemData.m_shared.m_name;
				if (!IsAcceptedFuelName(expectedFuelName, name2))
				{
					rejectedItemName = name2;
					return true;
				}
				continue;
			}
			GameObject val3 = (GameObject)((obj is GameObject) ? obj : null);
			if (!((Object)(object)val3 != (Object)null))
			{
				continue;
			}
			ItemDrop component = val3.GetComponent<ItemDrop>();
			if ((Object)(object)component != (Object)null && component.m_itemData != null && component.m_itemData.m_shared != null)
			{
				string name3 = component.m_itemData.m_shared.m_name;
				if (!IsAcceptedFuelName(expectedFuelName, name3))
				{
					rejectedItemName = name3;
					return true;
				}
			}
		}
		if (string.Equals(method.Name, "AddItem", StringComparison.Ordinal) || string.Equals(method.Name, "CanAddItem", StringComparison.Ordinal))
		{
			int num = Math.Min(parameters.Length, args.Length);
			for (int j = 0; j < num; j++)
			{
				if (parameters[j].ParameterType != typeof(string) || !(args[j] is string))
				{
					continue;
				}
				string text = (parameters[j].Name ?? string.Empty).ToLowerInvariant();
				if (!text.Contains("crafter") && !text.Contains("player") && !text.Contains("creator") && (text == "name" || text.Contains("item") || text.Contains("prefab") || text.Contains("shared")))
				{
					string text2 = (string)args[j];
					if (IsAcceptedFuelName(expectedFuelName, text2))
					{
						break;
					}
					rejectedItemName = text2;
					return true;
				}
			}
		}
		if (IsBulkMoveMethod(method.Name))
		{
			foreach (object obj2 in args)
			{
				Inventory val4 = (Inventory)((obj2 is Inventory) ? obj2 : null);
				if (val4 == null || val4 == inventory)
				{
					continue;
				}
				List<ItemData> allItems = val4.GetAllItems();
				if (allItems == null)
				{
					continue;
				}
				for (int l = 0; l < allItems.Count; l++)
				{
					ItemData val5 = allItems[l];
					if (val5 != null && val5.m_shared != null)
					{
						string name4 = val5.m_shared.m_name;
						if (!IsAcceptedFuelName(expectedFuelName, name4))
						{
							rejectedItemName = name4;
							return true;
						}
					}
				}
			}
		}
		return false;
	}

	private static bool IsBulkMoveMethod(string methodName)
	{
		if (!string.Equals(methodName, "MoveAll", StringComparison.Ordinal) && !string.Equals(methodName, "MoveInventoryToThis", StringComparison.Ordinal))
		{
			return string.Equals(methodName, "MoveAllToThis", StringComparison.Ordinal);
		}
		return true;
	}

	internal static bool IsAcceptedFuelName(string expectedFuelName, string actualItemName)
	{
		if (string.IsNullOrEmpty(expectedFuelName) || string.IsNullOrEmpty(actualItemName))
		{
			return false;
		}
		if (string.Equals(expectedFuelName, actualItemName, StringComparison.Ordinal))
		{
			return true;
		}
		if (string.Equals(expectedFuelName, "R4V9N1_LightMyFire_Ore", StringComparison.Ordinal))
		{
			return LightMyFirePlugin.IsSmeltableOreName(actualItemName);
		}
		if (string.Equals(expectedFuelName, "$item_coal", StringComparison.Ordinal))
		{
			return string.Equals(actualItemName, "Coal", StringComparison.OrdinalIgnoreCase);
		}
		if (string.Equals(expectedFuelName, "$item_resin", StringComparison.Ordinal))
		{
			return string.Equals(actualItemName, "Resin", StringComparison.OrdinalIgnoreCase);
		}
		if (string.Equals(expectedFuelName, "$item_wood", StringComparison.Ordinal))
		{
			return string.Equals(actualItemName, "Wood", StringComparison.OrdinalIgnoreCase);
		}
		return false;
	}
}
internal static class LightMyFireHarmonyPatches
{
	private static class InventoryItemGatePatch
	{
		public static bool Prefix(Inventory __instance, MethodBase __originalMethod, object[] __args)
		{
			if (!LightMyFireItemFilter.IsRejectedInvocation(__instance, __originalMethod, __args, out var rejectedItemName, out var expectedFuelName))
			{
				return true;
			}
			LightMyFirePlugin.LogRejectedInsertion(expectedFuelName, rejectedItemName, (__originalMethod == null) ? "Inventory" : __originalMethod.Name);
			return false;
		}
	}

	private static Harmony _harmony;

	internal static void Apply(ManualLogSource log)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Expected O, but got Unknown
		_harmony = new Harmony("r4v9n1.lightmyfire");
		PatchCurrentInventoryEntryPoints(log);
		_harmony.CreateClassProcessor(typeof(CookingStationAutoFuelInteractPatch)).Patch();
		_harmony.CreateClassProcessor(typeof(CookingStationAutoFuelHoverPatch)).Patch();
		_harmony.CreateClassProcessor(typeof(FuelBarrelStackAllPatch)).Patch();
		try
		{
			_harmony.CreateClassProcessor(typeof(SmelterOreFeedPatch)).Patch();
			LightMyFireOreFeeder.SmelterHookActive = true;
			log.LogInfo((object)"[LightMyFire] Ore Chests feed smelters from Smelter.UpdateSmelter (once per second, owner only).");
		}
		catch (Exception ex)
		{
			log.LogWarning((object)("[LightMyFire] Could not hook Smelter.UpdateSmelter (" + ex.Message + "); Ore Chests fall back to a once-a-minute refill."));
		}
		InventoryLinkWoodBarrelCompat.TryPatch(_harmony, log);
	}

	internal static void Unpatch()
	{
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
			_harmony = null;
		}
	}

	private static void PatchCurrentInventoryEntryPoints(ManualLogSource log)
	{
		//IL_0112: Unknown result type (might be due to invalid IL or missing references)
		//IL_0120: Expected O, but got Unknown
		int num = 0;
		HashSet<MethodBase> hashSet = new HashSet<MethodBase>();
		List<MethodInfo> declaredMethods = AccessTools.GetDeclaredMethods(typeof(Inventory));
		for (int i = 0; i < declaredMethods.Count; i++)
		{
			MethodInfo methodInfo = declaredMethods[i];
			if (methodInfo == null || hashSet.Contains(methodInfo) || !IsInsertionOrCheckMethod(methodInfo.Name))
			{
				continue;
			}
			ParameterInfo[] parameters = methodInfo.GetParameters();
			bool flag = false;
			for (int j = 0; j < parameters.Length; j++)
			{
				Type parameterType = parameters[j].ParameterType;
				if (typeof(ItemData).IsAssignableFrom(parameterType) || typeof(ItemDrop).IsAssignableFrom(parameterType) || typeof(GameObject).IsAssignableFrom(parameterType) || parameterType == typeof(string) || (IsBulkMoveMethod(methodInfo.Name) && typeof(Inventory).IsAssignableFrom(parameterType)))
				{
					flag = true;
					break;
				}
			}
			if (flag)
			{
				try
				{
					_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(InventoryItemGatePatch), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					hashSet.Add(methodInfo);
					num++;
				}
				catch (Exception ex)
				{
					log.LogWarning((object)("[LightMyFire] Could not patch current Inventory method " + Describe(methodInfo) + ": " + ex.Message));
				}
			}
		}
		if (num > 0)
		{
			log.LogInfo((object)("[LightMyFire] Strict fuel-only item filter attached to " + num + " current Inventory insertion/check method(s)."));
		}
		else
		{
			log.LogWarning((object)"[LightMyFire] No compatible Inventory insertion methods were found to patch. Owner-side barrel sanitation remains active as a safety net.");
		}
	}

	private static bool IsInsertionOrCheckMethod(string methodName)
	{
		if (!string.Equals(methodName, "AddItem", StringComparison.Ordinal) && !string.Equals(methodName, "CanAddItem", StringComparison.Ordinal) && !string.Equals(methodName, "MoveItemToThis", StringComparison.Ordinal))
		{
			return IsBulkMoveMethod(methodName);
		}
		return true;
	}

	private static bool IsBulkMoveMethod(string methodName)
	{
		if (!string.Equals(methodName, "MoveAll", StringComparison.Ordinal) && !string.Equals(methodName, "MoveInventoryToThis", StringComparison.Ordinal))
		{
			return string.Equals(methodName, "MoveAllToThis", StringComparison.Ordinal);
		}
		return true;
	}

	private static string Describe(MethodInfo method)
	{
		ParameterInfo[] parameters = method.GetParameters();
		string[] array = new string[parameters.Length];
		for (int i = 0; i < parameters.Length; i++)
		{
			array[i] = parameters[i].ParameterType.Name;
		}
		return method.Name + "(" + string.Join(", ", array) + ")";
	}
}
public sealed class LightMyFireOreChest : MonoBehaviour
{
	private struct PendingReservation
	{
		public int Amount;

		public string ItemPrefabName;

		public long RequesterPeer;

		public ZDOID SmelterId;

		public long ReservedAtNetworkTicks;
	}

	private const string RpcRequestOre = "R4V9N1_LightMyFire_RequestOre";

	private const string RpcAckOre = "R4V9N1_LightMyFire_AckOre";

	private const string RpcRefundOre = "R4V9N1_LightMyFire_RefundOre";

	internal const int MaxRequestPerTransaction = 50;

	private const float ReservationTimeoutSeconds = 30f;

	private const string ReservationStateZdoKey = "R4V9N1_LightMyFire_PendingOreReservations";

	private static readonly List<LightMyFireOreChest> ActiveChests = new List<LightMyFireOreChest>();

	private ZNetView _nview;

	private Container _container;

	private Inventory _inventory;

	private bool _rpcRegistered;

	private bool _inventoryHooksRegistered;

	private bool _runtimeInitialized;

	private bool _sanitizingInventory;

	private bool _ownershipStateInitialized;

	private bool _wasOwner;

	private readonly Dictionary<long, PendingReservation> _pendingReservations = new Dictionary<long, PendingReservation>();

	private float _nextReservationSweep;

	private void Awake()
	{
		_nview = ((Component)this).GetComponent<ZNetView>();
		_container = ((Component)this).GetComponent<Container>();
	}

	private void Start()
	{
		TryInitializeRuntime();
	}

	private void Update()
	{
		if (!_runtimeInitialized)
		{
			TryInitializeRuntime();
		}
		else
		{
			RefreshOwnershipState();
		}
	}

	private bool TryInitializeRuntime()
	{
		if ((Object)(object)_nview == (Object)null)
		{
			_nview = ((Component)this).GetComponent<ZNetView>();
		}
		if ((Object)(object)_container == (Object)null)
		{
			_container = ((Component)this).GetComponent<Container>();
		}
		if ((Object)(object)_container == (Object)null)
		{
			return false;
		}
		if (_inventory == null)
		{
			_inventory = _container.GetInventory();
		}
		if (_inventory != null && !_inventoryHooksRegistered)
		{
			Inventory inventory = _inventory;
			inventory.m_onChanged = (Action)Delegate.Combine(inventory.m_onChanged, new Action(OnInventoryChanged));
			LightMyFireItemFilter.RegisterFilteredInventory(_inventory, "R4V9N1_LightMyFire_Ore");
			_inventoryHooksRegistered = true;
		}
		if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || _nview.GetZDO() == null || _inventory == null)
		{
			return false;
		}
		if (!_rpcRegistered)
		{
			_nview.Register<long, ZDOID, int, string>("R4V9N1_LightMyFire_RequestOre", (Method<long, ZDOID, int, string>)RPC_RequestOre);
			_nview.Register<long>("R4V9N1_LightMyFire_AckOre", (Action<long, long>)RPC_AckOre);
			_nview.Register<long, int>("R4V9N1_LightMyFire_RefundOre", (Action<long, long, int>)RPC_RefundOre);
			_rpcRegistered = true;
		}
		if (!ActiveChests.Contains(this))
		{
			ActiveChests.Add(this);
		}
		RefreshOwnershipState();
		_runtimeInitialized = true;
		LightMyFirePlugin.LogOreChestRuntimeReady(((Object)((Component)this).gameObject).name);
		return true;
	}

	private void OnDestroy()
	{
		if (_inventory != null && _inventoryHooksRegistered)
		{
			Inventory inventory = _inventory;
			inventory.m_onChanged = (Action)Delegate.Remove(inventory.m_onChanged, new Action(OnInventoryChanged));
			LightMyFireItemFilter.UnregisterFilteredInventory(_inventory);
			_inventoryHooksRegistered = false;
		}
		_inventory = null;
		_runtimeInitialized = false;
		_rpcRegistered = false;
		_ownershipStateInitialized = false;
		_wasOwner = false;
		_pendingReservations.Clear();
		ActiveChests.Remove(this);
	}

	private void OnInventoryChanged()
	{
		if (!_sanitizingInventory)
		{
			EjectInvalidItems();
		}
	}

	internal void EjectInvalidItems()
	{
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00de: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.IsOwner() || _inventory == null || !LightMyFirePlugin.IsSmeltableOreListReady())
		{
			return;
		}
		List<ItemData> allItems = _inventory.GetAllItems();
		if (allItems == null || allItems.Count == 0)
		{
			return;
		}
		List<ItemData> list = null;
		for (int i = 0; i < allItems.Count; i++)
		{
			ItemData val = allItems[i];
			if (val != null && val.m_shared != null && !LightMyFirePlugin.IsSmeltableOreName(val.m_shared.m_name))
			{
				if (list == null)
				{
					list = new List<ItemData>();
				}
				list.Add(val);
			}
		}
		if (list == null)
		{
			return;
		}
		_sanitizingInventory = true;
		try
		{
			for (int j = 0; j < list.Count; j++)
			{
				ItemData val2 = list[j];
				_inventory.RemoveItem(val2);
				ItemDrop.DropItem(val2, val2.m_stack, ((Component)this).transform.position + Vector3.up * 0.5f, ((Component)this).transform.rotation);
			}
		}
		finally
		{
			_sanitizingInventory = false;
		}
		LightMyFirePlugin.LogInvalidItemEjection(list.Count, ((Object)((Component)this).gameObject).name);
	}

	internal void SweepStaleReservations()
	{
		if (_pendingReservations.Count == 0 || (Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.IsOwner())
		{
			return;
		}
		float realtimeSinceStartup = Time.realtimeSinceStartup;
		if (realtimeSinceStartup < _nextReservationSweep)
		{
			return;
		}
		_nextReservationSweep = realtimeSinceStartup + 5f;
		long networkTicks = GetNetworkTicks();
		List<long> list = null;
		foreach (KeyValuePair<long, PendingReservation> pendingReservation in _pendingReservations)
		{
			if (TimeSpan.FromTicks(Math.Max(0L, networkTicks - pendingReservation.Value.ReservedAtNetworkTicks)).TotalSeconds >= 30.0)
			{
				if (list == null)
				{
					list = new List<long>();
				}
				list.Add(pendingReservation.Key);
			}
		}
		if (list == null)
		{
			return;
		}
		for (int i = 0; i < list.Count; i++)
		{
			if (_pendingReservations.TryGetValue(list[i], out var value))
			{
				_pendingReservations.Remove(list[i]);
				RefundLocally(value.ItemPrefabName, value.Amount);
			}
		}
		PersistReservations();
	}

	private static long GetNetworkTicks()
	{
		if (!((Object)(object)ZNet.instance == (Object)null))
		{
			return ZNet.instance.GetTime().Ticks;
		}
		return DateTime.UtcNow.Ticks;
	}

	private void RefreshOwnershipState()
	{
		bool flag = (Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.IsOwner();
		if (!_ownershipStateInitialized || flag != _wasOwner)
		{
			_ownershipStateInitialized = true;
			_wasOwner = flag;
			_pendingReservations.Clear();
			if (flag)
			{
				LoadPersistedReservations();
			}
		}
	}

	private void LoadPersistedReservations()
	{
		//IL_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_015a: Unknown result type (might be due to invalid IL or missing references)
		ZDO val = (((Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.IsOwner()) ? null : _nview.GetZDO());
		if (val == null)
		{
			return;
		}
		string text = val.GetString("R4V9N1_LightMyFire_PendingOreReservations", string.Empty);
		if (string.IsNullOrEmpty(text))
		{
			return;
		}
		string[] array = text.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
		for (int i = 0; i < array.Length; i++)
		{
			string[] array2 = array[i].Split(new char[1] { '|' });
			if (array2.Length == 7 && long.TryParse(array2[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && int.TryParse(array2[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2) && !string.IsNullOrEmpty(array2[2]) && long.TryParse(array2[3], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result3) && long.TryParse(array2[4], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result4) && uint.TryParse(array2[5], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result5) && long.TryParse(array2[6], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result6) && result2 > 0 && result6 > 0)
			{
				_pendingReservations[result] = new PendingReservation
				{
					Amount = result2,
					ItemPrefabName = array2[2],
					RequesterPeer = result3,
					SmelterId = new ZDOID(result4, result5),
					ReservedAtNetworkTicks = result6
				};
			}
		}
	}

	private void PersistReservations()
	{
		ZDO val = (((Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.IsOwner()) ? null : _nview.GetZDO());
		if (val == null)
		{
			return;
		}
		if (_pendingReservations.Count == 0)
		{
			val.Set("R4V9N1_LightMyFire_PendingOreReservations", string.Empty);
			return;
		}
		StringBuilder stringBuilder = new StringBuilder();
		foreach (KeyValuePair<long, PendingReservation> pendingReservation in _pendingReservations)
		{
			if (stringBuilder.Length > 0)
			{
				stringBuilder.Append(';');
			}
			PendingReservation value = pendingReservation.Value;
			stringBuilder.Append(pendingReservation.Key.ToString(CultureInfo.InvariantCulture)).Append('|').Append(value.Amount.ToString(CultureInfo.InvariantCulture))
				.Append('|')
				.Append(value.ItemPrefabName)
				.Append('|')
				.Append(value.RequesterPeer.ToString(CultureInfo.InvariantCulture))
				.Append('|')
				.Append(((ZDOID)(ref value.SmelterId)).UserID.ToString(CultureInfo.InvariantCulture))
				.Append('|')
				.Append(((ZDOID)(ref value.SmelterId)).ID.ToString(CultureInfo.InvariantCulture))
				.Append('|')
				.Append(value.ReservedAtNetworkTicks.ToString(CultureInfo.InvariantCulture));
		}
		val.Set("R4V9N1_LightMyFire_PendingOreReservations", stringBuilder.ToString());
	}

	private int RemoveOreLocally(HashSet<string> acceptedPrefabNames, int requested, out string itemPrefabName, out bool cheated)
	{
		itemPrefabName = null;
		cheated = false;
		if (requested <= 0 || _inventory == null)
		{
			return 0;
		}
		List<ItemData> allItems = _inventory.GetAllItems();
		ItemData val = null;
		for (int i = 0; i < allItems.Count; i++)
		{
			ItemData val2 = allItems[i];
			if (val2 != null && val2.m_shared != null && !((Object)(object)val2.m_dropPrefab == (Object)null) && acceptedPrefabNames.Contains(((Object)val2.m_dropPrefab).name) && (val == null || val2.m_gridPos.y < val.m_gridPos.y || (val2.m_gridPos.y == val.m_gridPos.y && val2.m_gridPos.x < val.m_gridPos.x)))
			{
				val = val2;
			}
		}
		if (val == null)
		{
			return 0;
		}
		string name = val.m_shared.m_name;
		itemPrefabName = ((Object)val.m_dropPrefab).name;
		for (int j = 0; j < allItems.Count; j++)
		{
			ItemData val3 = allItems[j];
			if (val3 != null && val3.m_shared != null && val3.m_cheated && string.Equals(val3.m_shared.m_name, name, StringComparison.Ordinal))
			{
				cheated = true;
				break;
			}
		}
		int num = _inventory.CountItems(name, -1, false);
		int num2 = Math.Min(num, requested);
		if (num2 <= 0)
		{
			return 0;
		}
		_inventory.RemoveItem(name, num2, -1, false);
		int num3 = _inventory.CountItems(name, -1, false);
		return Mathf.Clamp(num - num3, 0, num2);
	}

	private void RefundLocally(string itemPrefabName, int amount)
	{
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		if (amount <= 0 || _inventory == null || string.IsNullOrEmpty(itemPrefabName))
		{
			return;
		}
		GameObject val = (((Object)(object)ObjectDB.instance == (Object)null) ? null : ObjectDB.instance.GetItemPrefab(itemPrefabName));
		ItemDrop val2 = (((Object)(object)val == (Object)null) ? null : val.GetComponent<ItemDrop>());
		if (!((Object)(object)val2 == (Object)null) && val2.m_itemData != null && val2.m_itemData.m_shared != null)
		{
			string name = val2.m_itemData.m_shared.m_name;
			int num = _inventory.CountItems(name, -1, false);
			_inventory.AddItem(itemPrefabName, amount, 1, 0, 0L, string.Empty, new Vector2i(-1, -1), false, false, false);
			int num2 = _inventory.CountItems(name, -1, false);
			int num3 = amount - Mathf.Clamp(num2 - num, 0, amount);
			if (num3 > 0)
			{
				ItemData obj = val2.m_itemData.Clone();
				obj.m_stack = num3;
				ItemDrop.DropItem(obj, num3, ((Component)this).transform.position + Vector3.up * 0.5f, ((Component)this).transform.rotation);
			}
		}
	}

	private void RPC_RequestOre(long sender, long transactionId, ZDOID smelterId, int requestedAmount, string acceptedPrefabNames)
	{
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_024e: Unknown result type (might be due to invalid IL or missing references)
		//IL_024f: Unknown result type (might be due to invalid IL or missing references)
		//IL_026f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0274: Unknown result type (might be due to invalid IL or missing references)
		//IL_0210: Unknown result type (might be due to invalid IL or missing references)
		//IL_0215: Unknown result type (might be due to invalid IL or missing references)
		if (!LightMyFirePlugin.IsEnabled() || (Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.IsOwner() || _inventory == null || ZDOMan.instance == null || _pendingReservations.ContainsKey(transactionId))
		{
			LightMyFirePlugin.LogOreDiagnostic("Ore request ignored by '" + ((Object)((Component)this).gameObject).name + "': disabled, not the owner, or a duplicate.");
			return;
		}
		ZDO zDO = ZDOMan.instance.GetZDO(smelterId);
		if (zDO == null || zDO.GetOwner() != sender)
		{
			LightMyFirePlugin.LogOreDiagnostic("Ore request ignored: the asking peer " + sender + " does not own that smelter (owner " + ((zDO == null) ? "unknown" : zDO.GetOwner().ToString(CultureInfo.InvariantCulture)) + ").");
			return;
		}
		float oreFeedRange = LightMyFirePlugin.GetOreFeedRange();
		Vector3 val = ((Component)this).transform.position - zDO.GetPosition();
		if (((Vector3)(ref val)).sqrMagnitude > oreFeedRange * oreFeedRange)
		{
			LightMyFirePlugin.LogOreDiagnostic("Ore request ignored: the smelter is farther than " + oreFeedRange.ToString("0.#", CultureInfo.InvariantCulture) + " m.");
			return;
		}
		int num = Mathf.Clamp(requestedAmount, 0, 50);
		HashSet<string> hashSet = ParseAccepted(acceptedPrefabNames);
		string itemPrefabName = null;
		bool cheated = false;
		int num2 = ((num > 0 && hashSet.Count != 0) ? RemoveOreLocally(hashSet, num, out itemPrefabName, out cheated) : 0);
		LightMyFirePlugin.LogOreDiagnostic("Ore Chest '" + ((Object)((Component)this).gameObject).name + "' holds " + _inventory.GetAllItems().Count + " stack(s); granting " + num2 + " " + (itemPrefabName ?? "(nothing)") + " for request of " + num + " (accepted: " + hashSet.Count + " type(s)).");
		if (num2 <= 0)
		{
			LightMyFireOreFeeder.SendGrant(transactionId, GetZdoId(), smelterId, string.Empty, 0, cheated: false);
			return;
		}
		_pendingReservations[transactionId] = new PendingReservation
		{
			Amount = num2,
			ItemPrefabName = itemPrefabName,
			RequesterPeer = sender,
			SmelterId = smelterId,
			ReservedAtNetworkTicks = GetNetworkTicks()
		};
		PersistReservations();
		LightMyFireOreFeeder.SendGrant(transactionId, GetZdoId(), smelterId, itemPrefabName, num2, cheated);
	}

	private static HashSet<string> ParseAccepted(string acceptedPrefabNames)
	{
		HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
		if (string.IsNullOrEmpty(acceptedPrefabNames))
		{
			return hashSet;
		}
		string[] array = acceptedPrefabNames.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
		for (int i = 0; i < array.Length; i++)
		{
			if (LightMyFirePlugin.IsSmeltableOreName(array[i]))
			{
				hashSet.Add(array[i]);
			}
		}
		return hashSet;
	}

	private void RPC_AckOre(long sender, long transactionId)
	{
		if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner() && _pendingReservations.TryGetValue(transactionId, out var value) && sender == value.RequesterPeer)
		{
			_pendingReservations.Remove(transactionId);
			PersistReservations();
		}
	}

	private void RPC_RefundOre(long sender, long transactionId, int amount)
	{
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner() && _pendingReservations.TryGetValue(transactionId, out var value))
		{
			bool flag = sender == value.RequesterPeer;
			if (!flag && ZDOMan.instance != null)
			{
				ZDO zDO = ZDOMan.instance.GetZDO(value.SmelterId);
				flag = zDO != null && zDO.GetOwner() == sender;
			}
			if (flag)
			{
				_pendingReservations.Remove(transactionId);
				RefundLocally(value.ItemPrefabName, Mathf.Clamp(amount, 0, value.Amount));
				PersistReservations();
			}
		}
	}

	internal ZDOID GetZdoId()
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		return (((Object)(object)_nview == (Object)null) ? null : _nview.GetZDO())?.m_uid ?? ZDOID.None;
	}

	internal bool SendRequestOre(long transactionId, ZDOID smelterId, int requestedAmount, string acceptedPrefabNames)
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.HasOwner())
		{
			return false;
		}
		_nview.InvokeRPC("R4V9N1_LightMyFire_RequestOre", new object[4]
		{
			transactionId,
			smelterId,
			Mathf.Clamp(requestedAmount, 0, 50),
			acceptedPrefabNames ?? string.Empty
		});
		return true;
	}

	internal void SendAckOre(long transactionId)
	{
		if ((Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.HasOwner())
		{
			_nview.InvokeRPC("R4V9N1_LightMyFire_AckOre", new object[1] { transactionId });
		}
	}

	internal void SendRefundOre(long transactionId, int amount)
	{
		if ((Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.HasOwner() && amount > 0)
		{
			_nview.InvokeRPC("R4V9N1_LightMyFire_RefundOre", new object[2] { transactionId, amount });
		}
	}

	internal bool IsReadyWithinRange(Vector3 targetPosition, float rangeSqr)
	{
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)this == (Object)null || !((Behaviour)this).isActiveAndEnabled || (!_runtimeInitialized && !TryInitializeRuntime()))
		{
			return false;
		}
		if ((Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.HasOwner() && (Object)(object)_container != (Object)null)
		{
			Vector3 val = ((Component)this).transform.position - targetPosition;
			return ((Vector3)(ref val)).sqrMagnitude <= rangeSqr;
		}
		return false;
	}

	internal static LightMyFireOreChest FindByZdoId(ZDOID id)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		if (id == ZDOID.None)
		{
			return null;
		}
		for (int num = ActiveChests.Count - 1; num >= 0; num--)
		{
			LightMyFireOreChest lightMyFireOreChest = ActiveChests[num];
			if ((Object)(object)lightMyFireOreChest == (Object)null)
			{
				ActiveChests.RemoveAt(num);
			}
			else if (lightMyFireOreChest.GetZdoId() == id)
			{
				return lightMyFireOreChest;
			}
		}
		return null;
	}

	internal static void GetActiveChests(List<LightMyFireOreChest> results)
	{
		results.Clear();
		for (int num = ActiveChests.Count - 1; num >= 0; num--)
		{
			if ((Object)(object)ActiveChests[num] == (Object)null)
			{
				ActiveChests.RemoveAt(num);
			}
			else
			{
				results.Add(ActiveChests[num]);
			}
		}
	}

	internal static bool AnyActiveChests()
	{
		for (int num = ActiveChests.Count - 1; num >= 0; num--)
		{
			if ((Object)(object)ActiveChests[num] == (Object)null)
			{
				ActiveChests.RemoveAt(num);
			}
		}
		return ActiveChests.Count > 0;
	}

	internal static bool HasActiveChests()
	{
		for (int num = ActiveChests.Count - 1; num >= 0; num--)
		{
			if ((Object)(object)ActiveChests[num] == (Object)null)
			{
				ActiveChests.RemoveAt(num);
			}
		}
		if (ActiveChests.Count == 0)
		{
			LightMyFireOreChest[] array = Object.FindObjectsByType<LightMyFireOreChest>((FindObjectsInactive)0, (FindObjectsSortMode)0);
			for (int i = 0; i < array.Length; i++)
			{
				if ((Object)(object)array[i] != (Object)null)
				{
					array[i].TryInitializeRuntime();
				}
			}
		}
		return ActiveChests.Count > 0;
	}

	internal static void TickMaintenance()
	{
		for (int num = ActiveChests.Count - 1; num >= 0; num--)
		{
			LightMyFireOreChest lightMyFireOreChest = ActiveChests[num];
			if ((Object)(object)lightMyFireOreChest == (Object)null)
			{
				ActiveChests.RemoveAt(num);
			}
			else
			{
				lightMyFireOreChest.SweepStaleReservations();
				lightMyFireOreChest.EjectInvalidItems();
			}
		}
	}
}
internal static class LightMyFireOreFeeder
{
	private sealed class OutboundState
	{
		public LightMyFireOreChest CurrentChest;

		public ZDOID SmelterId;

		public int RemainingAmount;

		public int AppliedAmount;

		public string AcceptedPrefabNames;

		public List<LightMyFireOreChest> Candidates;

		public int NextCandidateIndex;

		public float SentAtRealtime;
	}

	internal const string RpcGrantOre = "R4V9N1_LightMyFire_GrantOre";

	private const float OutboundRequestTimeoutSeconds = 20f;

	private const float EmptyRetrySeconds = 5f;

	private const int RefillAtOrBelow = 2;

	private static readonly MethodInfo QueueOreMethod = AccessTools.Method(typeof(Smelter), "QueueOre", new Type[2]
	{
		typeof(string),
		typeof(bool)
	}, (Type[])null);

	private static readonly MethodInfo IsItemAllowedMethod = AccessTools.Method(typeof(Smelter), "IsItemAllowed", new Type[1] { typeof(string) }, (Type[])null);

	private static readonly FieldRef<Smelter, ZNetView> SmelterView = AccessTools.FieldRefAccess<Smelter, ZNetView>("m_nview");

	internal static bool SmelterHookActive;

	private static readonly Dictionary<long, OutboundState> PendingOutbound = new Dictionary<long, OutboundState>();

	private static readonly HashSet<ZDOID> SmeltersAwaitingResponse = new HashSet<ZDOID>();

	private static readonly Dictionary<ZDOID, float> NextAttempt = new Dictionary<ZDOID, float>();

	private static readonly Dictionary<ZDOID, float> NextStatusLog = new Dictionary<ZDOID, float>();

	private static readonly List<LightMyFireOreChest> ChestBuffer = new List<LightMyFireOreChest>();

	private static long _txCounter;

	private static bool _warnedMissingQueueOre;

	internal static ZNetView GetSmelterView(Smelter smelter)
	{
		if (!((Object)(object)smelter == (Object)null))
		{
			return SmelterView.Invoke(smelter);
		}
		return null;
	}

	private static long NextTransactionId()
	{
		long uID = ZNet.GetUID();
		_txCounter++;
		return (uID << 20) ^ (0x80000 | (_txCounter & 0x7FFFF));
	}

	internal static void OnSmelterUpdate(Smelter smelter)
	{
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_0123: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)smelter == (Object)null || smelter.m_maxOre <= 0 || !LightMyFirePlugin.IsEnabled() || !LightMyFireOreChest.AnyActiveChests())
		{
			return;
		}
		ZNetView val = SmelterView.Invoke(smelter);
		if ((Object)(object)val == (Object)null || !val.IsValid() || !val.IsOwner())
		{
			return;
		}
		ZDO zDO = val.GetZDO();
		int num = zDO.GetInt(ZDOVars.s_queued, 0);
		int num2 = smelter.m_maxOre - num;
		ZDOID uid = zDO.m_uid;
		bool flag = SmeltersAwaitingResponse.Contains(uid);
		float value;
		bool flag2 = NextAttempt.TryGetValue(uid, out value) && Time.realtimeSinceStartup < value;
		if (num2 <= 0 || num > 2 || flag || flag2)
		{
			if (LightMyFirePlugin.IsDiagnosticsEnabled())
			{
				LogStatus(smelter, uid, num, flag, flag2 ? (value - Time.realtimeSinceStartup) : 0f);
			}
		}
		else if (!string.Equals(LightMyFirePlugin.GetSupportedFuelItemName(smelter), "$item_coal", StringComparison.Ordinal))
		{
			NextAttempt[uid] = float.MaxValue;
		}
		else if (QueueOreMethod == null || IsItemAllowedMethod == null)
		{
			if (!_warnedMissingQueueOre)
			{
				_warnedMissingQueueOre = true;
				LightMyFirePlugin.LogWarning("Valheim's Smelter.QueueOre/IsItemAllowed were not found; the Ore Chest cannot feed smelters in this game version.");
			}
		}
		else
		{
			StartRequest(smelter, uid, num2);
		}
	}

	private static void LogStatus(Smelter smelter, ZDOID id, int queued, bool awaiting, float cooldownLeft)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		float realtimeSinceStartup = Time.realtimeSinceStartup;
		if (!NextStatusLog.TryGetValue(id, out var value) || !(realtimeSinceStartup < value))
		{
			NextStatusLog[id] = realtimeSinceStartup + 15f;
			LightMyFirePlugin.LogOreDiagnostic(DescribeStation(smelter) + " queue " + queued + "/" + smelter.m_maxOre + (awaiting ? "; waiting for a chest answer" : string.Empty) + ((cooldownLeft > 0f) ? ("; retry in " + cooldownLeft.ToString("0") + " s") : string.Empty) + ((queued > 2) ? ("; refills at " + 2 + " or fewer") : string.Empty) + ".");
		}
	}

	internal static void ScanAndRequestOre()
	{
		PruneStaleOutbound();
		if (LightMyFireOreChest.HasActiveChests())
		{
			Smelter[] array = Object.FindObjectsByType<Smelter>((FindObjectsInactive)0, (FindObjectsSortMode)0);
			int num = 0;
			while (array != null && num < array.Length)
			{
				OnSmelterUpdate(array[num]);
				num++;
			}
		}
	}

	private static void StartRequest(Smelter smelter, ZDOID smelterId, int missing)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0122: Unknown result type (might be due to invalid IL or missing references)
		//IL_0123: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: 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)
		float oreFeedRange = LightMyFirePlugin.GetOreFeedRange();
		float rangeSqr = oreFeedRange * oreFeedRange;
		Vector3 position = ((Component)smelter).transform.position;
		LightMyFireOreChest.GetActiveChests(ChestBuffer);
		List<LightMyFireOreChest> list = null;
		List<float> list2 = null;
		for (int i = 0; i < ChestBuffer.Count; i++)
		{
			LightMyFireOreChest lightMyFireOreChest = ChestBuffer[i];
			if (lightMyFireOreChest.IsReadyWithinRange(position, rangeSqr))
			{
				if (list == null)
				{
					list = new List<LightMyFireOreChest>();
					list2 = new List<float>();
				}
				Vector3 val = ((Component)lightMyFireOreChest).transform.position - position;
				float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
				int j;
				for (j = 0; j < list2.Count && list2[j] <= sqrMagnitude; j++)
				{
				}
				list.Insert(j, lightMyFireOreChest);
				list2.Insert(j, sqrMagnitude);
			}
		}
		if (list == null)
		{
			NextAttempt[smelterId] = Time.realtimeSinceStartup + 5f;
			LightMyFirePlugin.LogOreDiagnostic("No Ore Chest within " + oreFeedRange.ToString("0.#") + " m of " + DescribeStation(smelter) + ".");
			return;
		}
		OutboundState outboundState = new OutboundState
		{
			SmelterId = smelterId,
			RemainingAmount = missing,
			AcceptedPrefabNames = GetAcceptedPrefabNames(smelter),
			Candidates = list,
			NextCandidateIndex = 0
		};
		LightMyFirePlugin.LogOreDiagnostic(DescribeStation(smelter) + " needs " + missing + " ore; asking " + list.Count + " Ore Chest(s) for: " + outboundState.AcceptedPrefabNames + ".");
		if (!TrySendNextRequest(outboundState))
		{
			FinishRound(outboundState);
		}
	}

	internal static void PruneStaleOutbound()
	{
		if (PendingOutbound.Count == 0)
		{
			return;
		}
		float realtimeSinceStartup = Time.realtimeSinceStartup;
		List<long> list = null;
		foreach (KeyValuePair<long, OutboundState> item in PendingOutbound)
		{
			if (realtimeSinceStartup - item.Value.SentAtRealtime >= 20f)
			{
				if (list == null)
				{
					list = new List<long>();
				}
				list.Add(item.Key);
			}
		}
		if (list == null)
		{
			return;
		}
		for (int i = 0; i < list.Count; i++)
		{
			if (PendingOutbound.TryGetValue(list[i], out var value))
			{
				PendingOutbound.Remove(list[i]);
				LightMyFirePlugin.LogOreDiagnostic("Ore Chest did not answer within " + 20f + " s; trying the next chest.");
				value.NextCandidateIndex++;
				if (!TrySendNextRequest(value))
				{
					FinishRound(value);
				}
			}
		}
	}

	private static void FinishRound(OutboundState state)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		SmeltersAwaitingResponse.Remove(state.SmelterId);
		if (state.AppliedAmount > 0)
		{
			NextAttempt.Remove(state.SmelterId);
		}
		else
		{
			NextAttempt[state.SmelterId] = Time.realtimeSinceStartup + 5f;
		}
	}

	private static string GetAcceptedPrefabNames(Smelter smelter)
	{
		List<string> list = new List<string>();
		if (smelter.m_conversion != null)
		{
			for (int i = 0; i < smelter.m_conversion.Count; i++)
			{
				ItemConversion val = smelter.m_conversion[i];
				if (val != null && (Object)(object)val.m_from != (Object)null && !list.Contains(((Object)((Component)val.m_from).gameObject).name))
				{
					list.Add(((Object)((Component)val.m_from).gameObject).name);
				}
			}
		}
		return string.Join(",", list.ToArray());
	}

	private static bool TrySendNextRequest(OutboundState state)
	{
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		if (state.Candidates == null || state.RemainingAmount <= 0)
		{
			return false;
		}
		while (state.NextCandidateIndex < state.Candidates.Count)
		{
			LightMyFireOreChest lightMyFireOreChest = state.Candidates[state.NextCandidateIndex];
			if ((Object)(object)lightMyFireOreChest == (Object)null)
			{
				state.NextCandidateIndex++;
				continue;
			}
			int requestedAmount = Mathf.Min(state.RemainingAmount, 50);
			long num = NextTransactionId();
			state.CurrentChest = lightMyFireOreChest;
			state.SentAtRealtime = Time.realtimeSinceStartup;
			PendingOutbound[num] = state;
			SmeltersAwaitingResponse.Add(state.SmelterId);
			if (!lightMyFireOreChest.SendRequestOre(num, state.SmelterId, requestedAmount, state.AcceptedPrefabNames))
			{
				PendingOutbound.Remove(num);
				SmeltersAwaitingResponse.Remove(state.SmelterId);
				state.NextCandidateIndex++;
				continue;
			}
			return true;
		}
		return false;
	}

	internal static void SendGrant(long transactionId, ZDOID chestId, ZDOID smelterId, string itemPrefabName, int amount, bool cheated)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		if (ZRoutedRpc.instance != null && ZDOMan.instance != null)
		{
			ZDO zDO = ZDOMan.instance.GetZDO(smelterId);
			long num = ((zDO == null) ? 0 : zDO.GetOwner());
			if (num == 0L)
			{
				LightMyFirePlugin.LogOreDiagnostic("Ore grant not sent: the smelter has no owner right now.");
				return;
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(num, "R4V9N1_LightMyFire_GrantOre", new object[6]
			{
				transactionId,
				chestId,
				smelterId,
				itemPrefabName ?? string.Empty,
				amount,
				cheated
			});
		}
	}

	internal static void RPC_GrantOre(long sender, long transactionId, ZDOID chestId, ZDOID smelterId, string itemPrefabName, int grantedAmount, bool cheated)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		OutboundState value;
		bool num = PendingOutbound.TryGetValue(transactionId, out value);
		LightMyFireOreChest lightMyFireOreChest = (num ? value.CurrentChest : LightMyFireOreChest.FindByZdoId(chestId));
		if (!num)
		{
			LightMyFirePlugin.LogOreDiagnostic("Late or unknown ore grant (" + grantedAmount + " " + itemPrefabName + "); returned to the chest.");
			if (grantedAmount > 0 && (Object)(object)lightMyFireOreChest != (Object)null)
			{
				lightMyFireOreChest.SendRefundOre(transactionId, grantedAmount);
			}
			return;
		}
		PendingOutbound.Remove(transactionId);
		if (grantedAmount <= 0)
		{
			LightMyFirePlugin.LogOreDiagnostic("Ore Chest had no ore this station takes.");
			value.NextCandidateIndex++;
			if (!TrySendNextRequest(value))
			{
				FinishRound(value);
			}
			return;
		}
		int num2 = TryQueueOre(smelterId, itemPrefabName, grantedAmount, cheated);
		int num3 = grantedAmount - num2;
		if ((Object)(object)lightMyFireOreChest != (Object)null)
		{
			if (num3 > 0)
			{
				lightMyFireOreChest.SendRefundOre(transactionId, num3);
			}
			else
			{
				lightMyFireOreChest.SendAckOre(transactionId);
			}
		}
		value.AppliedAmount += num2;
		value.RemainingAmount = Math.Max(0, value.RemainingAmount - num2);
		if (num2 <= 0 || num3 > 0 || value.RemainingAmount <= 0 || !TrySendNextRequest(value))
		{
			FinishRound(value);
		}
	}

	private static int TryQueueOre(ZDOID smelterId, string itemPrefabName, int grantedAmount, bool cheated)
	{
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)ZNetScene.instance == (Object)null || string.IsNullOrEmpty(itemPrefabName) || QueueOreMethod == null || IsItemAllowedMethod == null)
		{
			return 0;
		}
		GameObject val = ZNetScene.instance.FindInstance(smelterId);
		Smelter val2 = (((Object)(object)val == (Object)null) ? null : val.GetComponent<Smelter>());
		if ((Object)(object)val != (Object)null && (Object)(object)val2 == (Object)null)
		{
			val2 = val.GetComponentInChildren<Smelter>(true);
		}
		ZNetView val3 = (((Object)(object)val2 == (Object)null) ? null : SmelterView.Invoke(val2));
		ZDO val4 = (((Object)(object)val3 == (Object)null || !val3.IsValid() || !val3.IsOwner()) ? null : val3.GetZDO());
		if (val4 == null)
		{
			LightMyFirePlugin.LogOreDiagnostic("Granted " + grantedAmount + " " + itemPrefabName + " returned: the smelter is no longer loaded or owned here.");
			return 0;
		}
		if (!(bool)IsItemAllowedMethod.Invoke(val2, new object[1] { itemPrefabName }))
		{
			LightMyFirePlugin.LogOreDiagnostic("Granted " + itemPrefabName + " returned: " + DescribeStation(val2) + " does not take it.");
			return 0;
		}
		int num = Mathf.Clamp(val2.m_maxOre - val4.GetInt(ZDOVars.s_queued, 0), 0, 50);
		int num2 = Mathf.Min(grantedAmount, num);
		object[] parameters = new object[2] { itemPrefabName, cheated };
		for (int i = 0; i < num2; i++)
		{
			QueueOreMethod.Invoke(val2, parameters);
		}
		if (num2 > 0)
		{
			LightMyFirePlugin.LogOreTransfer(num2, itemPrefabName, DescribeStation(val2));
		}
		return num2;
	}

	private static string DescribeStation(Smelter smelter)
	{
		if (Localization.instance == null)
		{
			return smelter.m_name;
		}
		return Localization.instance.Localize(smelter.m_name);
	}
}
[HarmonyPatch]
internal static class SmelterOreFeedPatch
{
	private static MethodBase TargetMethod()
	{
		return AccessTools.Method(typeof(Smelter), "UpdateSmelter", Type.EmptyTypes, (Type[])null);
	}

	private static void Postfix(Smelter __instance)
	{
		LightMyFireOreFeeder.OnSmelterUpdate(__instance);
		LightMyFireFeeder.OnSmelterUpdate(__instance);
	}
}
public sealed class LightMyFireOreLabel : MonoBehaviour
{
	internal const string LabelName = "R4V9N1_LightMyFire_OreLabel";

	internal const string Runes = "ᛟᚱᛖ";

	private const float SurfaceGap = 0.003f;

	private void Start()
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Invalid comparison between Unknown and I4
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		if ((int)SystemInfo.graphicsDeviceType == 4)
		{
			((Behaviour)this).enabled = false;
			return;
		}
		Transform val = ((Component)this).transform.Find("R4V9N1_LightMyFire_OreLabel");
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		Vector3 forward = ((Component)this).transform.forward;
		Vector3 val2 = ((Component)this).transform.TransformPoint(new Vector3(val.localPosition.x, val.localPosition.y, val.localPosition.z - 1f));
		Ray val3 = default(Ray);
		((Ray)(ref val3))..ctor(val2, forward);
		float num = float.MaxValue;
		Collider[] componentsInChildren = ((Component)this).GetComponentsInChildren<Collider>(false);
		RaycastHit val4 = default(RaycastHit);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			if ((Object)(object)componentsInChildren[i] != (Object)null && componentsInChildren[i].enabled && !componentsInChildren[i].isTrigger && componentsInChildren[i].Raycast(val3, ref val4, 2f) && ((RaycastHit)(ref val4)).distance < num)
			{
				num = ((RaycastHit)(ref val4)).distance;
			}
		}
		if (num < float.MaxValue)
		{
			val.position = val2 + forward * (num - 0.003f);
		}
	}

	internal static bool Attach(GameObject prefab, float centreHeight, float frontZ, float width)
	{
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0136: Unknown result type (might be due to invalid IL or missing references)
		//IL_0158: Unknown result type (might be due to invalid IL or missing references)
		//IL_0169: Unknown result type (might be due to invalid IL or missing references)
		GameObject prefab2 = PrefabManager.Instance.GetPrefab("sign");
		Sign val = (((Object)(object)prefab2 == (Object)null) ? null : prefab2.GetComponent<Sign>());
		TextMeshProUGUI val2 = (((Object)(object)val == (Object)null) ? null : val.m_textWidget);
		Canvas val3 = (((Object)(object)val2 == (Object)null) ? null : ((Component)val2).GetComponentInParent<Canvas>(true));
		if ((Object)(object)prefab == (Object)null || (Object)(object)val3 == (Object)null)
		{
			return false;
		}
		GameObject val4 = Object.Instantiate<GameObject>(((Component)val3).gameObject, prefab.transform, false);
		((Object)val4).name = "R4V9N1_LightMyFire_OreLabel";
		val4.transform.localPosition = new Vector3(0f, centreHeight, frontZ - 0.003f);
		val4.transform.localRotation = Quaternion.identity;
		val4.transform.localScale = Vector3.one;
		TextMeshProUGUI componentInChildren = val4.GetComponentInChildren<TextMeshProUGUI>(true);
		if ((Object)(object)componentInChildren == (Object)null)
		{
			Object.Destroy((Object)(object)val4);
			return false;
		}
		((TMP_Text)componentInChildren).text = "ᛟᚱᛖ";
		((Graphic)componentInChildren).color = Color.black;
		((TMP_Text)componentInChildren).enableAutoSizing = false;
		((TMP_Text)componentInChildren).fontSize = 5f;
		((TMP_Text)componentInChildren).alignment = (TextAlignmentOptions)514;
		((TMP_Text)componentInChildren).textWrappingMode = (TextWrappingModes)0;
		((Graphic)componentInChildren).raycastTarget = false;
		RectTransform rectTransform = ((TMP_Text)componentInChildren).rectTransform;
		float num = Mathf.Max(0.0001f, Mathf.Abs(((TMP_Text)componentInChildren).transform.localScale.x));
		rectTransform.sizeDelta = new Vector2(width / num, 0.3f / num);
		((TMP_Text)componentInChildren).transform.localPosition = Vector3.zero;
		if ((Object)(object)prefab.GetComponent<LightMyFireOreLabel>() == (Object)null)
		{
			prefab.AddComponent<LightMyFireOreLabel>();
		}
		return true;
	}
}
internal static class LightMyFireAutoFuelToggle
{
	internal const string AutoFuelOffKey = "R4V9N1_LightMyFire_AutoFuelOff";

	internal static bool IsAutoFuelOff(ZDO zdo)
	{
		if (zdo != null)
		{
			return zdo.GetBool("R4V9N1_LightMyFire_AutoFuelOff", false);
		}
		return false;
	}

	internal static ZNetView GetView(CookingStation station)
	{
		if ((Object)(object)station == (Object)null)
		{
			return null;
		}
		ZNetView component = ((Component)station).GetComponent<ZNetView>();
		if (!((Object)(object)component != (Object)null))
		{
			return ((Component)station).GetComponentInParent<ZNetView>();
		}
		return component;
	}
}
[HarmonyPatch(typeof(CookingStation), "Interact")]
internal static class CookingStationAutoFuelInteractPatch
{
	private static bool Prefix(CookingStation __instance, Humanoid user, bool hold, bool alt, ref bool __result)
	{
		if (!alt || hold || LightMyFirePlugin.GetSupportedFuelItemName(__instance) == null)
		{
			return true;
		}
		ZNetView view = LightMyFireAutoFuelToggle.GetView(__instance);
		if ((Object)(object)view == (Object)null || !view.IsValid() || view.GetZDO() == null)
		{
			return true;
		}
		if (!view.IsOwner())
		{
			view.ClaimOwnership();
		}
		bool flag = !LightMyFireAutoFuelToggle.IsAutoFuelOff(view.GetZDO());
		view.GetZDO().Set("R4V9N1_LightMyFire_AutoFuelOff", flag);
		if ((Object)(object)user != (Object)null)
		{
			((Character)user).Message((MessageType)2, flag ? "LightMyFire auto-fuel: Off" : "LightMyFire auto-fuel: On", 0, (Sprite)null, false);
		}
		__result = true;
		return false;
	}
}
[HarmonyPatch(typeof(CookingStation), "GetHoverText")]
internal static class CookingStationAutoFuelHoverPatch
{
	private static void Postfix(CookingStation __instance, ref string __result)
	{
		if (!string.IsNullOrEmpty(__result) && LightMyFirePlugin.GetSupportedFuelItemName(__instance) != null)
		{
			ZNetView view = LightMyFireAutoFuelToggle.GetView(__instance);
			if (!((Object)(object)view == (Object)null) && view.IsValid())
			{
				bool flag = LightMyFireAutoFuelToggle.IsAutoFuelOff(view.GetZDO());
				__result = __result + "\n[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>] LightMyFire auto-fuel: " + (flag ? "Off" : "On");
			}
		}
	}
}
internal static class InventoryLinkWoodBarrelCompat
{
	internal static void TryPatch(Harmony harmony, ManualLogSource log)
	{
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Expected O, but got Unknown
		Type type = AccessTools.TypeByName("InventoryLink.InventoryLinkPlugin");
		if (type == null)
		{
			return;
		}
		MethodInfo methodInfo = AccessTools.Method(type, "IsReservedAutomationContainer", new Type[1] { typeof(Container) }, (Type[])null);
		if (methodInfo == null || methodInfo.ReturnType != typeof(bool))
		{
			if (log != null)
			{
				log.LogWarning((object)"InventoryLink found, but its barrel-exclusion check changed; the Wood Barrel is not excluded from InventoryLink.");
			}
			return;
		}
		harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(InventoryLinkWoodBarrelCompat), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		if (log != null)
		{
			log.LogInfo((object)"InventoryLink found: the Wood Barrel and the Ore Chest are excluded from its material pulls.");
		}
	}

	private static void Postfix(Container container, ref bool __result)
	{
		if (!__result && !((Object)(object)container == (Object)null) && !((Object)(object)((Component)container).gameObject == (Object)null))
		{
			string text = ((Object)((Component)container).gameObject).name ?? string.Empty;
			if (text.StartsWith("R4V9N1_LightMyFireWoodBarrel", StringComparison.Ordinal) || text.StartsWith("R4V9N1_LightMyFireOreChest", StringComparison.Ordinal))
			{
				__result = true;
			}
		}
	}
}
[HarmonyPatch(typeof(Inventory), "StackAll")]
internal static class FuelBarrelStackAllPatch
{
	private static bool Prefix(Inventory __instance, Inventory fromInventory, bool message, ref int __result)
	{
		if (fromInventory == null || fromInventory == __instance || !LightMyFireItemFilter.TryGetExpectedFuel(__instance, out var fuelItemName))
		{
			return true;
		}
		int num = CountAccepted(__instance, fuelItemName);
		List<ItemData> list = new List<ItemData>(fromInventory.GetAllItems());
		for (int i = 0; i < list.Count; i++)
		{
			ItemData val = list[i];
			if (val != null && val.m_shared != null && LightMyFireItemFilter.IsAcceptedFuelName(fuelItemName, val.m_shared.m_name) && (!((Object)(object)Player.m_localPlayer != (Object)null) || !((Humanoid)Player.m_localPlayer).IsItemEquiped(val)) && __instance.AddItem(val))
			{
				fromInventory.RemoveItem(val);
			}
		}
		int num2 = CountAccepted(__instance, fuelItemName) - num;
		if (message && (Object)(object)Player.m_localPlayer != (Object)null)
		{
			((Character)Player.m_localPlayer).Message((MessageType)2, (num2 > 0) ? ("$msg_stackall " + num2) : "$msg_stackall_none", 0, (Sprite)null, false);
		}
		__result = num2;
		return false;
	}

	private static int CountAccepted(Inventory inventory, string fuelItemName)
	{
		int num = 0;
		List<ItemData> allItems = inventory.GetAllItems();
		for (int i = 0; i < allItems.Count; i++)
		{
			if (allItems[i] != null && allItems[i].m_shared != null && LightMyFireItemFilter.IsAcceptedFuelName(fuelItemName, allItems[i].m_shared.m_name))
			{
				num += allItems[i].m_stack;
			}
		}
		return num;
	}
}
[BepInPlugin("r4v9n1.lightmyfire", "LightMyFire", "1.1.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
public sealed class LightMyFirePlugin : BaseUnityPlugin
{
	public const string PluginGuid = "r4v9n1.lightmyfire";

	public const string PluginName = "LightMyFire";

	public const string PluginVersion = "1.1.0";

	public const string CreatorCredit = "Created by R4V9N1";

	internal const string CoalItemName = "$item_coal";

	internal const string ResinItemName = "$item_resin";

	internal const string WoodItemName = "$item_wood";

	internal const string CoalBarrelPrefabName = "R4V9N1_LightMyFireCoalBarrel";

	internal const string ResinBarrelPrefabName = "R4V9N1_LightMyFireResinBarrel";

	internal const string WoodBarrelPrefabName = "R4V9N1_LightMyFireWoodBarrel";

	internal const string OreChestPrefabName = "R4V9N1_LightMyFireOreChest";

	internal const string OreChestFilterToken = "R4V9N1_LightMyFire_Ore";

	private const string OreChestBasePrefabName = "piece_chest";

	private const string CoalItemPrefabName = "Coal";

	private const string ResinItemPrefabName = "Resin";

	private const string WoodItemPrefabName = "Wood";

	private static ConfigEntry<bool> _enabled;