Decompiled source of Lamplighter v1.0.0

BepInEx\plugins\Lamplighter\Lamplighter.dll

Decompiled 15 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Lamplighter.Config;
using Lamplighter.Creatures;
using Lamplighter.Pieces;
using Lamplighter.Systems;
using Lamplighter.Visuals;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("Greguru")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © Greguru 2026")]
[assembly: AssemblyDescription("\r\n      A Valheim mod that summons a fire spirit to tend nearby fires and lights.\r\n    ")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Lamplighter")]
[assembly: AssemblyTitle("Lamplighter")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Lamplighter
{
	[BepInPlugin("com.g.lamplighter", "Lamplighter", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[SynchronizationMode(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.g.lamplighter";

		public const string PluginName = "Lamplighter";

		public const string PluginVersion = "1.0.0";

		private void Awake()
		{
			ModConfig.Bind(((BaseUnityPlugin)this).Config);
			LamplighterPiece.Register();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Lamplighter 1.0.0 loaded. The fires of Valheim can be tended.");
		}
	}
}
namespace Lamplighter.Visuals
{
	internal sealed class RangeIndicator : MonoBehaviour
	{
		private const int Segments = 96;

		private const float Width = 0.12f;

		private const float HeightOffset = 0.08f;

		private static readonly FieldInfo PlacementGhostField = AccessTools.Field(typeof(Player), "m_placementGhost");

		private LineRenderer _line;

		private float _lastRadius = -1f;

		private void Awake()
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			_line = ((Component)this).GetComponent<LineRenderer>();
			if ((Object)(object)_line == (Object)null)
			{
				_line = ((Component)this).gameObject.AddComponent<LineRenderer>();
			}
			_line.useWorldSpace = false;
			_line.loop = true;
			_line.positionCount = 96;
			_line.startWidth = 0.12f;
			_line.endWidth = 0.12f;
			((Renderer)_line).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)_line).receiveShadows = false;
			Shader val = Shader.Find("Sprites/Default");
			if ((Object)(object)val != (Object)null)
			{
				((Renderer)_line).material = new Material(val);
			}
			((Renderer)_line).enabled = false;
			RebuildCircle();
		}

		private void Update()
		{
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			if (!ModConfig.ShowRangeWhilePlacing.Value)
			{
				((Renderer)_line).enabled = false;
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || PlacementGhostField == null)
			{
				((Renderer)_line).enabled = false;
				return;
			}
			object? value = PlacementGhostField.GetValue(localPlayer);
			if (!((Object)((value is GameObject) ? value : null) == (Object)(object)((Component)this).gameObject))
			{
				((Renderer)_line).enabled = false;
				return;
			}
			((Renderer)_line).enabled = true;
			if (!Mathf.Approximately(ModConfig.WorkRadius.Value, _lastRadius))
			{
				RebuildCircle();
			}
			Color value2 = ModConfig.WispColor.Value;
			value2.a = 0.85f;
			_line.startColor = value2;
			_line.endColor = value2;
			if ((Object)(object)((Renderer)_line).material != (Object)null)
			{
				((Renderer)_line).material.color = value2;
			}
		}

		private void RebuildCircle()
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			float num = (_lastRadius = ModConfig.WorkRadius.Value);
			for (int i = 0; i < 96; i++)
			{
				float num2 = (float)i * (float)Math.PI * 2f / 96f;
				_line.SetPosition(i, new Vector3(Mathf.Cos(num2) * num, 0.08f, Mathf.Sin(num2) * num));
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)_line != (Object)null && (Object)(object)((Renderer)_line).material != (Object)null)
			{
				Object.Destroy((Object)(object)((Renderer)_line).material);
			}
		}
	}
	internal sealed class ShrineVisuals : MonoBehaviour
	{
		private readonly List<Material> _shrineMaterials = new List<Material>();

		private readonly List<Material> _oozeMaterials = new List<Material>();

		private bool _initialized;

		private bool _subscribed;

		private void Awake()
		{
			Initialize();
		}

		private void OnEnable()
		{
			Initialize();
			ApplyColors();
		}

		private void Initialize()
		{
			if (!_initialized)
			{
				CacheMaterials();
				_initialized = true;
			}
			Subscribe();
			ApplyColors();
		}

		private void CacheMaterials()
		{
			_shrineMaterials.Clear();
			_oozeMaterials.Clear();
			Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<Renderer>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Material[] materials = componentsInChildren[i].materials;
				foreach (Material val in materials)
				{
					if (!((Object)(object)val == (Object)null))
					{
						if (((Object)val).name.StartsWith("WispLure_mat"))
						{
							_shrineMaterials.Add(val);
						}
						else if (((Object)val).name.StartsWith("Ooze_mat"))
						{
							_oozeMaterials.Add(val);
						}
					}
				}
			}
		}

		private void Subscribe()
		{
			if (!_subscribed)
			{
				if (ModConfig.ShrineColor != null)
				{
					ModConfig.ShrineColor.SettingChanged += OnAppearanceChanged;
				}
				if (ModConfig.OozeColor != null)
				{
					ModConfig.OozeColor.SettingChanged += OnAppearanceChanged;
				}
				_subscribed = true;
			}
		}

		private void OnAppearanceChanged(object sender, EventArgs e)
		{
			ApplyColors();
		}

		private void ApplyColors()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			if (ModConfig.ShrineColor != null)
			{
				Color value = ModConfig.ShrineColor.Value;
				foreach (Material shrineMaterial in _shrineMaterials)
				{
					ApplyMaterialColor(shrineMaterial, value);
				}
			}
			if (ModConfig.OozeColor == null)
			{
				return;
			}
			Color value2 = ModConfig.OozeColor.Value;
			foreach (Material oozeMaterial in _oozeMaterials)
			{
				ApplyMaterialColor(oozeMaterial, value2);
			}
		}

		private static void ApplyMaterialColor(Material material, Color color)
		{
			//IL_001d: 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)
			if (!((Object)(object)material == (Object)null))
			{
				if (material.HasProperty("_Color"))
				{
					material.SetColor("_Color", color);
				}
				if (material.HasProperty("_EmissionColor"))
				{
					material.SetColor("_EmissionColor", color);
				}
			}
		}

		private void OnDestroy()
		{
			if (_subscribed)
			{
				if (ModConfig.ShrineColor != null)
				{
					ModConfig.ShrineColor.SettingChanged -= OnAppearanceChanged;
				}
				if (ModConfig.OozeColor != null)
				{
					ModConfig.OozeColor.SettingChanged -= OnAppearanceChanged;
				}
				_subscribed = false;
			}
		}
	}
	internal sealed class WispVisuals : MonoBehaviour
	{
		private Color _lastColor;

		private void Start()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			_lastColor = new Color(-1f, -1f, -1f, -1f);
			ApplyColor();
		}

		private void Update()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (ModConfig.WispColor.Value != _lastColor)
			{
				ApplyColor();
			}
		}

		private void ApplyColor()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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_004a: 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_00b0: 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)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			Color val = (_lastColor = ModConfig.WispColor.Value);
			Light[] componentsInChildren = ((Component)this).GetComponentsInChildren<Light>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].color = val;
			}
			ParticleSystem[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<ParticleSystem>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				MainModule main = componentsInChildren2[i].main;
				((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(val);
			}
			Renderer[] componentsInChildren3 = ((Component)this).GetComponentsInChildren<Renderer>(true);
			for (int i = 0; i < componentsInChildren3.Length; i++)
			{
				Material[] materials = componentsInChildren3[i].materials;
				foreach (Material val2 in materials)
				{
					if (val2.HasProperty("_Color"))
					{
						val2.color = val;
					}
					if (val2.HasProperty("_EmissionColor"))
					{
						val2.SetColor("_EmissionColor", new Color(val.r * 2f, val.g * 2f, val.b * 2f, 1f));
					}
				}
			}
		}
	}
	internal static class WispVisualsFactory
	{
		public static GameObject Prefab { get; private set; }

		public static void Create()
		{
			if ((Object)(object)Prefab != (Object)null)
			{
				return;
			}
			Prefab = PrefabManager.Instance.CreateClonedPrefab("lamplighter_wisp_visual", "LuredWisp");
			if ((Object)(object)Prefab == (Object)null)
			{
				Logger.LogError((object)"Could not clone LuredWisp prefab.");
				return;
			}
			RemoveComponent<ZNetView>();
			RemoveComponent<ZSyncTransform>();
			RemoveComponent<LuredWisp>();
			RemoveComponent<Pickable>();
			RemoveComponent<Rigidbody>();
			Collider[] componentsInChildren = Prefab.GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
			if ((Object)(object)Prefab.GetComponent<WispVisuals>() == (Object)null)
			{
				Prefab.AddComponent<WispVisuals>();
			}
			Prefab.SetActive(false);
			ModConfig.DebugLog("Created Lamplighter wisp visual.");
		}

		private static void RemoveComponent<T>() where T : Component
		{
			T component = Prefab.GetComponent<T>();
			if ((Object)(object)component != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)component);
			}
		}
	}
}
namespace Lamplighter.Systems
{
	internal static class ContainerScanner
	{
		public static Container FindNearestContaining(Vector3 origin, string itemName)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: 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_0058: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(itemName))
			{
				return null;
			}
			float value = ModConfig.WorkRadius.Value;
			float num = value * value;
			Container result = null;
			float num2 = float.MaxValue;
			Container[] array = Object.FindObjectsOfType<Container>();
			foreach (Container val in array)
			{
				if ((Object)(object)val == (Object)null || !((Behaviour)val).isActiveAndEnabled)
				{
					continue;
				}
				Vector3 val2 = ((Component)val).transform.position - origin;
				float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
				if (!(sqrMagnitude > num) && (!(itemName == "$item_wood") || !IsWoodStack(val) || ModConfig.TakeWoodFromWoodStacks.Value))
				{
					Inventory inventory = val.GetInventory();
					if (inventory != null && inventory.CountItems(itemName, -1, true) > 0 && sqrMagnitude < num2)
					{
						result = val;
						num2 = sqrMagnitude;
					}
				}
			}
			return result;
		}

		public static bool IsWoodStack(Container container)
		{
			if ((Object)(object)container == (Object)null)
			{
				return false;
			}
			Piece componentInParent = ((Component)container).GetComponentInParent<Piece>();
			if ((Object)(object)componentInParent == (Object)null)
			{
				return false;
			}
			string name = ((Object)((Component)componentInParent).gameObject).name;
			if (!(name == "wood_stack"))
			{
				return name.StartsWith("wood_stack(");
			}
			return true;
		}
	}
	internal static class FireScanner
	{
		private static readonly FieldInfo NViewField = AccessTools.Field(typeof(Fireplace), "m_nview");

		private static readonly FieldInfo MaxFuelField = AccessTools.Field(typeof(Fireplace), "m_maxFuel");

		private static readonly FieldInfo StartFuelField = AccessTools.Field(typeof(Fireplace), "m_startFuel");

		private static readonly FieldInfo InfiniteFuelField = AccessTools.Field(typeof(Fireplace), "m_infiniteFuel");

		private static readonly FieldInfo FuelItemField = AccessTools.Field(typeof(Fireplace), "m_fuelItem");

		public static Fireplace FindNearestNeedingFuel(Vector3 origin)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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)
			float value = ModConfig.WorkRadius.Value;
			float num = value * value;
			Fireplace result = null;
			float num2 = float.MaxValue;
			Fireplace[] array = Object.FindObjectsOfType<Fireplace>();
			foreach (Fireplace val in array)
			{
				if (IsValidPlacedFireplace(val))
				{
					Vector3 val2 = ((Component)val).transform.position - origin;
					float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
					if (!(sqrMagnitude > num) && NeedsFuel(val) && sqrMagnitude < num2)
					{
						result = val;
						num2 = sqrMagnitude;
					}
				}
			}
			return result;
		}

		public static Fireplace FindNearestServiceable(Vector3 origin, IDictionary<string, int> carriedFuel)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			if (carriedFuel == null || carriedFuel.Count == 0)
			{
				return null;
			}
			float value = ModConfig.WorkRadius.Value;
			float num = value * value;
			Fireplace result = null;
			float num2 = float.MaxValue;
			Fireplace[] array = Object.FindObjectsOfType<Fireplace>();
			foreach (Fireplace val in array)
			{
				if (!IsValidPlacedFireplace(val))
				{
					continue;
				}
				Vector3 val2 = ((Component)val).transform.position - origin;
				float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
				if (!(sqrMagnitude > num) && NeedsFuel(val) && CanAcceptFuel(val))
				{
					string fuelItemName = GetFuelItemName(val);
					if (!string.IsNullOrEmpty(fuelItemName) && carriedFuel.TryGetValue(fuelItemName, out var value2) && value2 > 0 && sqrMagnitude < num2)
					{
						result = val;
						num2 = sqrMagnitude;
					}
				}
			}
			return result;
		}

		public static Dictionary<string, int> GetFuelTypesInRadius(Vector3 origin)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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)
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			float value = ModConfig.WorkRadius.Value;
			float num = value * value;
			Fireplace[] array = Object.FindObjectsOfType<Fireplace>();
			foreach (Fireplace val in array)
			{
				if (!IsValidPlacedFireplace(val))
				{
					continue;
				}
				Vector3 val2 = ((Component)val).transform.position - origin;
				if (((Vector3)(ref val2)).sqrMagnitude > num)
				{
					continue;
				}
				string fuelItemName = GetFuelItemName(val);
				if (!string.IsNullOrEmpty(fuelItemName))
				{
					int fuelStackLimit = GetFuelStackLimit(val);
					if (!dictionary.TryGetValue(fuelItemName, out var value2) || fuelStackLimit > value2)
					{
						dictionary[fuelItemName] = fuelStackLimit;
					}
				}
			}
			return dictionary;
		}

		public static bool NeedsFuel(Fireplace fireplace)
		{
			if (!IsValidPlacedFireplace(fireplace))
			{
				return false;
			}
			if (InfiniteFuelField != null && (bool)InfiniteFuelField.GetValue(fireplace))
			{
				return false;
			}
			float maxFuel = GetMaxFuel(fireplace);
			if (maxFuel <= 0f)
			{
				return false;
			}
			if (GetFuelNeededToMax(fireplace) <= 0)
			{
				return false;
			}
			return GetFuel(fireplace) / maxFuel < ModConfig.RefillThreshold;
		}

		public static bool CanAcceptFuel(Fireplace fireplace)
		{
			if (!IsValidPlacedFireplace(fireplace))
			{
				return false;
			}
			return GetFuelNeededToMax(fireplace) > 0;
		}

		public static int GetFuelNeededToMax(Fireplace fireplace)
		{
			if (!IsValidPlacedFireplace(fireplace))
			{
				return 0;
			}
			float maxFuel = GetMaxFuel(fireplace);
			if (maxFuel <= 0f)
			{
				return 0;
			}
			float fuel = GetFuel(fireplace);
			float num = maxFuel - fuel;
			if (num < 1f)
			{
				return 0;
			}
			return Mathf.Max(0, Mathf.FloorToInt(num + 0.0001f));
		}

		public static float GetMaxFuel(Fireplace fireplace)
		{
			if ((Object)(object)fireplace == (Object)null || MaxFuelField == null)
			{
				return 0f;
			}
			return (float)MaxFuelField.GetValue(fireplace);
		}

		public static float GetFuel(Fireplace fireplace)
		{
			if (!IsValidPlacedFireplace(fireplace))
			{
				return 0f;
			}
			ZNetView networkView = GetNetworkView(fireplace);
			if ((Object)(object)networkView == (Object)null)
			{
				return 0f;
			}
			ZDO zDO = networkView.GetZDO();
			if (zDO == null)
			{
				return 0f;
			}
			float num = zDO.GetFloat("fuel", -1f);
			if (num < 0f)
			{
				num = ((StartFuelField != null) ? ((float)StartFuelField.GetValue(fireplace)) : 0f);
			}
			return num;
		}

		public static string GetFuelItemName(Fireplace fireplace)
		{
			return GetFuelItem(fireplace)?.m_itemData?.m_shared?.m_name;
		}

		public static int GetFuelStackLimit(Fireplace fireplace)
		{
			ItemDrop fuelItem = GetFuelItem(fireplace);
			if (fuelItem?.m_itemData?.m_shared == null)
			{
				return 1;
			}
			return Mathf.Max(1, fuelItem.m_itemData.m_shared.m_maxStackSize);
		}

		public static bool IsValidPlacedFireplace(Fireplace fireplace)
		{
			if ((Object)(object)fireplace == (Object)null || !((Behaviour)fireplace).isActiveAndEnabled || !((Component)fireplace).gameObject.activeInHierarchy)
			{
				return false;
			}
			ZNetView networkView = GetNetworkView(fireplace);
			if ((Object)(object)networkView == (Object)null || !networkView.IsValid())
			{
				return false;
			}
			if (networkView.GetZDO() == null)
			{
				return false;
			}
			return true;
		}

		private static ZNetView GetNetworkView(Fireplace fireplace)
		{
			if ((Object)(object)fireplace == (Object)null || NViewField == null)
			{
				return null;
			}
			object? value = NViewField.GetValue(fireplace);
			return (ZNetView)((value is ZNetView) ? value : null);
		}

		private static ItemDrop GetFuelItem(Fireplace fireplace)
		{
			if ((Object)(object)fireplace == (Object)null || FuelItemField == null)
			{
				return null;
			}
			object? value = FuelItemField.GetValue(fireplace);
			return (ItemDrop)((value is ItemDrop) ? value : null);
		}
	}
	internal static class FuelService
	{
		private static readonly FieldInfo ContainerNViewField = AccessTools.Field(typeof(Container), "m_nview");

		private static readonly FieldInfo FireplaceNViewField = AccessTools.Field(typeof(Fireplace), "m_nview");

		private static readonly MethodInfo InventoryChangedMethod = AccessTools.Method(typeof(Inventory), "Changed", (Type[])null, (Type[])null);

		private static readonly MethodInfo ContainerSaveMethod = AccessTools.Method(typeof(Container), "Save", (Type[])null, (Type[])null);

		private static readonly MethodInfo RemoveItemMethod = AccessTools.Method(typeof(Inventory), "RemoveItem", new Type[1] { typeof(ItemData) }, (Type[])null);

		public static int TakeFuel(Container container, string fuelName, int maximumAmount)
		{
			if ((Object)(object)container == (Object)null || string.IsNullOrEmpty(fuelName) || maximumAmount <= 0)
			{
				return 0;
			}
			Inventory inventory = container.GetInventory();
			if (inventory == null)
			{
				return 0;
			}
			object? obj = ContainerNViewField?.GetValue(container);
			ZNetView val = (ZNetView)((obj is ZNetView) ? obj : null);
			if ((Object)(object)val != (Object)null && val.IsValid() && !val.IsOwner())
			{
				val.ClaimOwnership();
			}
			int num = maximumAmount;
			int num2 = 0;
			foreach (ItemData item in new List<ItemData>(inventory.GetAllItems()))
			{
				if (num <= 0)
				{
					break;
				}
				if (item == null || item.m_shared == null || item.m_shared.m_name != fuelName || item.m_stack <= 0)
				{
					continue;
				}
				int num3 = Mathf.Min(item.m_stack, num);
				if (num3 == item.m_stack)
				{
					if (RemoveItemMethod == null)
					{
						continue;
					}
					RemoveItemMethod.Invoke(inventory, new object[1] { item });
				}
				else
				{
					item.m_stack -= num3;
				}
				num2 += num3;
				num -= num3;
			}
			if (num2 <= 0)
			{
				return 0;
			}
			InventoryChangedMethod?.Invoke(inventory, null);
			ContainerSaveMethod?.Invoke(container, null);
			HandleEmptyWoodStack(container, fuelName);
			ModConfig.DebugLog($"Lamplighter: picked up {num2} x {fuelName}");
			return num2;
		}

		public static int AddFuelToMax(Fireplace fireplace, int availableAmount)
		{
			if ((Object)(object)fireplace == (Object)null || availableAmount <= 0)
			{
				return 0;
			}
			int fuelNeededToMax = FireScanner.GetFuelNeededToMax(fireplace);
			if (fuelNeededToMax <= 0)
			{
				return 0;
			}
			int num = Mathf.Min(fuelNeededToMax, availableAmount);
			object? obj = FireplaceNViewField?.GetValue(fireplace);
			ZNetView val = (ZNetView)((obj is ZNetView) ? obj : null);
			if ((Object)(object)val == (Object)null || !val.IsValid())
			{
				return 0;
			}
			if (!val.IsOwner())
			{
				val.ClaimOwnership();
			}
			for (int i = 0; i < num; i++)
			{
				val.InvokeRPC("RPC_AddFuel", Array.Empty<object>());
			}
			ModConfig.DebugLog($"Lamplighter: delivered {num} fuel to {((Object)fireplace).name}");
			return num;
		}

		private static void HandleEmptyWoodStack(Container container, string fuelName)
		{
			if (!ModConfig.TakeWoodFromWoodStacks.Value || fuelName != "$item_wood" || !ContainerScanner.IsWoodStack(container))
			{
				return;
			}
			Inventory inventory = container.GetInventory();
			if (inventory != null && inventory.CountItems("$item_wood", -1, true) > 0)
			{
				return;
			}
			Piece componentInParent = ((Component)container).GetComponentInParent<Piece>();
			if (!((Object)(object)componentInParent == (Object)null))
			{
				ZNetView component = ((Component)componentInParent).GetComponent<ZNetView>();
				if ((Object)(object)component != (Object)null && component.IsValid() && !component.IsOwner())
				{
					component.ClaimOwnership();
				}
				if ((Object)(object)ZNetScene.instance != (Object)null)
				{
					ZNetScene.instance.Destroy(((Component)componentInParent).gameObject);
				}
			}
		}
	}
}
namespace Lamplighter.Pieces
{
	internal static class LamplighterPiece
	{
		public const string PrefabName = "piece_lamplighter";

		private const string SourcePrefab = "piece_wisplure";

		private static CustomPiece _customPiece;

		public static void Register()
		{
			PrefabManager.OnVanillaPrefabsAvailable += CreatePiece;
		}

		private static void CreatePiece()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			PrefabManager.OnVanillaPrefabsAvailable -= CreatePiece;
			WispVisualsFactory.Create();
			PieceConfig val = new PieceConfig
			{
				Name = "Lamplighter",
				Description = "Summons a fire spirit that tends nearby fires and lights.",
				PieceTable = PieceTables.Hammer,
				Category = PieceCategories.Misc,
				CraftingStation = CraftingStations.Workbench
			};
			val.AddRequirement("Stone", 10, true);
			val.AddRequirement("Resin", 5, true);
			val.AddRequirement("SurtlingCore", 1, true);
			_customPiece = new CustomPiece("piece_lamplighter", "piece_wisplure", val);
			GameObject piecePrefab = _customPiece.PiecePrefab;
			if ((Object)(object)piecePrefab.GetComponent<ShrineVisuals>() == (Object)null)
			{
				piecePrefab.AddComponent<ShrineVisuals>();
			}
			if ((Object)(object)piecePrefab.GetComponent<RangeIndicator>() == (Object)null)
			{
				piecePrefab.AddComponent<RangeIndicator>();
			}
			if ((Object)(object)piecePrefab.GetComponent<LamplighterWisp>() == (Object)null)
			{
				piecePrefab.AddComponent<LamplighterWisp>();
			}
			WispSpawner component = piecePrefab.GetComponent<WispSpawner>();
			if ((Object)(object)component != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)component);
			}
			PieceManager.Instance.AddPiece(_customPiece);
			ModConfig.DebugLog("Registered Lamplighter build piece.");
		}
	}
}
namespace Lamplighter.Creatures
{
	internal sealed class LamplighterWisp : MonoBehaviour, Hoverable
	{
		private enum WispState
		{
			Idle,
			ToChest,
			AtChest,
			ToFire,
			AtFire
		}

		private const float HoverHeight = 1.8f;

		private const float BobAmount = 0.15f;

		private const float BobSpeed = 1.5f;

		private const float DriftAmount = 0.18f;

		private const float DriftSpeed = 0.65f;

		private const float MoveSpeed = 3.5f;

		private const float ChestHoverHeight = 1.1f;

		private const float ChestArrivalDistance = 0.35f;

		private const float FireHoverDistance = 0.8f;

		private const float FireHoverHeight = 0.7f;

		private const float FireArrivalDistance = 0.3f;

		private const float ChestPauseTime = 0.6f;

		private const float FirePauseTime = 0.4f;

		private const float RestingScanInterval = 3f;

		private const float RemoteSyncInterval = 0.5f;

		private const string InventoryZdoKey = "com.g.lamplighter.carried_inventory";

		private const string VisualStateZdoKey = "com.g.lamplighter.visual_state";

		private static readonly FieldInfo ObjectDbItemsField = AccessTools.Field(typeof(ObjectDB), "m_items");

		private GameObject _wisp;

		private ZNetView _nview;

		private WearNTear _wearNTear;

		private Fireplace _targetFire;

		private Container _targetContainer;

		private readonly Dictionary<string, int> _inventory = new Dictionary<string, int>();

		private readonly Dictionary<string, int> _stackLimits = new Dictionary<string, int>();

		private readonly List<string> _restockQueue = new List<string>();

		private int _restockIndex;

		private string _restockFuelName;

		private WispState _state;

		private float _timeOffset;

		private float _nextScanTime;

		private float _stateTimer;

		private bool _isResting;

		private bool _restockDidWork;

		private bool _inventoryReturned;

		private bool _wasOwner;

		private char _remoteVisualMode = 'H';

		private Vector3 _remoteVisualTarget;

		private float _nextRemoteSyncTime;

		private void Start()
		{
			_timeOffset = Random.Range(0f, 100f);
			_nview = ((Component)this).GetComponent<ZNetView>();
			_wearNTear = ((Component)this).GetComponent<WearNTear>();
			if ((Object)(object)_wearNTear != (Object)null)
			{
				WearNTear wearNTear = _wearNTear;
				wearNTear.m_onDestroyed = (Action)Delegate.Combine(wearNTear.m_onDestroyed, new Action(OnShrineDestroyed));
			}
			CreateWisp();
			if ((Object)(object)_nview != (Object)null && _nview.IsValid())
			{
				LoadInventoryFromZdo();
				_wasOwner = _nview.IsOwner();
				if (_wasOwner)
				{
					SaveVisualHome();
				}
				else
				{
					LoadVisualStateFromZdo();
				}
			}
		}

		private void CreateWisp()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_wisp != (Object)null) && !((Object)(object)WispVisualsFactory.Prefab == (Object)null))
			{
				_wisp = Object.Instantiate<GameObject>(WispVisualsFactory.Prefab, ((Component)this).transform);
				((Object)_wisp).name = "LamplighterWisp";
				_wisp.transform.localScale = Vector3.one * 0.65f;
				_wisp.transform.localPosition = new Vector3(0f, 1.8f, 0f);
				_wisp.SetActive(true);
			}
		}

		private void Update()
		{
			if ((Object)(object)_wisp == (Object)null)
			{
				CreateWisp();
				return;
			}
			if ((Object)(object)_nview == (Object)null || !_nview.IsValid())
			{
				MoveHome();
				return;
			}
			bool flag = _nview.IsOwner();
			if (flag != _wasOwner)
			{
				_wasOwner = flag;
				LoadInventoryFromZdo();
				ResetWorkState();
				if (flag)
				{
					SaveVisualHome();
					ModConfig.DebugLog("Lamplighter: acquired network ownership.");
				}
			}
			if (!flag)
			{
				UpdateRemoteVisual();
				return;
			}
			switch (_state)
			{
			case WispState.Idle:
				UpdateIdle();
				break;
			case WispState.ToChest:
				UpdateToChest();
				break;
			case WispState.AtChest:
				UpdateAtChest();
				break;
			case WispState.ToFire:
				UpdateToFire();
				break;
			case WispState.AtFire:
				UpdateAtFire();
				break;
			}
		}

		private void UpdateIdle()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			MoveHome();
			if (!(Time.time < _nextScanTime))
			{
				Fireplace val = FireScanner.FindNearestServiceable(((Component)this).transform.position, _inventory);
				if ((Object)(object)val != (Object)null)
				{
					LeaveResting();
					BeginFireJob(val);
				}
				else if (StartRestockRun())
				{
					LeaveResting();
				}
				else
				{
					EnterResting();
				}
			}
		}

		private void BeginFireJob(Fireplace fireplace)
		{
			//IL_002d: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			if (FireScanner.IsValidPlacedFireplace(fireplace))
			{
				string fuelItemName = FireScanner.GetFuelItemName(fireplace);
				int carried = GetCarried(fuelItemName);
				if (carried > 0)
				{
					_targetFire = fireplace;
					_state = WispState.ToFire;
					Vector3 fireHoverPosition = GetFireHoverPosition(fireplace);
					SaveVisualTarget('F', fireHoverPosition);
					ModConfig.DebugLog($"Lamplighter: servicing {((Object)fireplace).name} with {fuelItemName} ({carried} carried)");
				}
			}
		}

		private bool StartRestockRun()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, int> fuelTypesInRadius = FireScanner.GetFuelTypesInRadius(((Component)this).transform.position);
			if (fuelTypesInRadius.Count == 0)
			{
				return false;
			}
			foreach (KeyValuePair<string, int> item in fuelTypesInRadius)
			{
				_stackLimits[item.Key] = item.Value;
			}
			_restockQueue.Clear();
			_restockIndex = 0;
			_restockDidWork = false;
			foreach (KeyValuePair<string, int> item2 in fuelTypesInRadius)
			{
				string key = item2.Key;
				int value = item2.Value;
				if (GetCarried(key) < value)
				{
					_restockQueue.Add(key);
				}
			}
			if (_restockQueue.Count == 0)
			{
				return false;
			}
			if (!BeginNextRestockFuel())
			{
				return false;
			}
			ModConfig.DebugLog($"Lamplighter: beginning restock run for {_restockQueue.Count} fuel type(s)");
			return true;
		}

		private bool BeginNextRestockFuel()
		{
			_targetContainer = null;
			_restockFuelName = null;
			while (_restockIndex < _restockQueue.Count)
			{
				string text = _restockQueue[_restockIndex];
				_restockIndex++;
				int stackLimit = GetStackLimit(text);
				if (GetCarried(text) < stackLimit)
				{
					_restockFuelName = text;
					if (FindContainerForCurrentFuel())
					{
						return true;
					}
					_restockFuelName = null;
				}
			}
			FinishRestockRun();
			return false;
		}

		private bool FindContainerForCurrentFuel()
		{
			//IL_0033: 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)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(_restockFuelName))
			{
				return false;
			}
			int stackLimit = GetStackLimit(_restockFuelName);
			if (GetCarried(_restockFuelName) >= stackLimit)
			{
				return false;
			}
			Container val = ContainerScanner.FindNearestContaining(((Component)this).transform.position, _restockFuelName);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			_targetContainer = val;
			_state = WispState.ToChest;
			LeaveResting();
			Vector3 chestHoverPosition = GetChestHoverPosition(val);
			SaveVisualTarget('C', chestHoverPosition);
			ModConfig.DebugLog("Lamplighter: fetching " + _restockFuelName + " from " + ((Object)val).name);
			return true;
		}

		private void UpdateToChest()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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_0058: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_targetContainer == (Object)null)
			{
				HandleFailedChest();
				return;
			}
			if (!IsInsideWorkRadius(((Component)_targetContainer).transform.position))
			{
				HandleFailedChest();
				return;
			}
			Vector3 chestHoverPosition = GetChestHoverPosition(_targetContainer);
			MoveWisp(chestHoverPosition);
			if (Vector3.Distance(_wisp.transform.position, chestHoverPosition) <= 0.35f)
			{
				_stateTimer = 0.6f;
				_state = WispState.AtChest;
			}
		}

		private void UpdateAtChest()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_targetContainer == (Object)null || string.IsNullOrEmpty(_restockFuelName))
			{
				HandleFailedChest();
				return;
			}
			Vector3 chestHoverPosition = GetChestHoverPosition(_targetContainer);
			BobAround(chestHoverPosition, 0.08f);
			_stateTimer -= Time.deltaTime;
			if (!(_stateTimer > 0f))
			{
				string restockFuelName = _restockFuelName;
				int stackLimit = GetStackLimit(restockFuelName);
				int carried = GetCarried(restockFuelName);
				int num = Mathf.Max(0, stackLimit - carried);
				int num2 = 0;
				if (num > 0)
				{
					num2 = FuelService.TakeFuel(_targetContainer, restockFuelName, num);
				}
				if (num2 > 0)
				{
					_restockDidWork = true;
					SetCarried(restockFuelName, carried + num2);
					ModConfig.DebugLog($"Lamplighter: carrying {GetCarried(restockFuelName)}/{stackLimit} x {restockFuelName}");
				}
				_targetContainer = null;
				if (GetCarried(restockFuelName) >= stackLimit || !FindContainerForCurrentFuel())
				{
					_restockFuelName = null;
					BeginNextRestockFuel();
				}
			}
		}

		private void HandleFailedChest()
		{
			_targetContainer = null;
			if (!FindContainerForCurrentFuel())
			{
				_restockFuelName = null;
				BeginNextRestockFuel();
			}
		}

		private void FinishRestockRun()
		{
			_targetContainer = null;
			_restockFuelName = null;
			_restockQueue.Clear();
			_restockIndex = 0;
			_state = WispState.Idle;
			SaveVisualHome();
			if (_restockDidWork)
			{
				ModConfig.DebugLog("Lamplighter: restock complete.");
				_nextScanTime = Time.time + 0.25f;
			}
			else
			{
				EnterResting();
			}
		}

		private void UpdateToFire()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_targetFire == (Object)null)
			{
				FinishFireJob();
				return;
			}
			if (!FireScanner.IsValidPlacedFireplace(_targetFire))
			{
				FinishFireJob();
				return;
			}
			if (!IsInsideWorkRadius(((Component)_targetFire).transform.position))
			{
				FinishFireJob();
				return;
			}
			string fuelItemName = FireScanner.GetFuelItemName(_targetFire);
			if (GetCarried(fuelItemName) <= 0)
			{
				FinishFireJob();
				return;
			}
			if (!FireScanner.CanAcceptFuel(_targetFire))
			{
				FinishFireJob();
				return;
			}
			Vector3 fireHoverPosition = GetFireHoverPosition(_targetFire);
			MoveWisp(fireHoverPosition);
			if (Vector3.Distance(_wisp.transform.position, fireHoverPosition) <= 0.3f)
			{
				_stateTimer = 0.4f;
				_state = WispState.AtFire;
			}
		}

		private void UpdateAtFire()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_targetFire == (Object)null || !FireScanner.IsValidPlacedFireplace(_targetFire))
			{
				FinishFireJob();
				return;
			}
			Vector3 fireHoverPosition = GetFireHoverPosition(_targetFire);
			BobAround(fireHoverPosition, 0.08f);
			_stateTimer -= Time.deltaTime;
			if (_stateTimer > 0f)
			{
				return;
			}
			string fuelItemName = FireScanner.GetFuelItemName(_targetFire);
			int carried = GetCarried(fuelItemName);
			if (carried <= 0)
			{
				FinishFireJob();
				return;
			}
			int num = FuelService.AddFuelToMax(_targetFire, carried);
			if (num > 0)
			{
				SetCarried(fuelItemName, carried - num);
				ModConfig.DebugLog($"Lamplighter: {GetCarried(fuelItemName)} x {fuelItemName} remaining");
			}
			FinishFireJob();
		}

		private void FinishFireJob()
		{
			_targetFire = null;
			_state = WispState.Idle;
			SaveVisualHome();
			_nextScanTime = Time.time + 0.15f;
		}

		private void EnterResting()
		{
			_state = WispState.Idle;
			_nextScanTime = Time.time + 3f;
			SaveVisualHome();
			if (!_isResting)
			{
				_isResting = true;
				ModConfig.DebugLog("Lamplighter: resting.");
			}
		}

		private void LeaveResting()
		{
			_isResting = false;
		}

		private void ResetWorkState()
		{
			_targetFire = null;
			_targetContainer = null;
			_restockFuelName = null;
			_restockQueue.Clear();
			_restockIndex = 0;
			_restockDidWork = false;
			_state = WispState.Idle;
			_isResting = false;
			_nextScanTime = Time.time + 0.15f;
		}

		private int GetCarried(string fuelName)
		{
			if (string.IsNullOrEmpty(fuelName))
			{
				return 0;
			}
			if (_inventory.TryGetValue(fuelName, out var value))
			{
				return value;
			}
			return 0;
		}

		private void SetCarried(string fuelName, int amount)
		{
			if (string.IsNullOrEmpty(fuelName))
			{
				return;
			}
			if (amount <= 0)
			{
				if (_inventory.Remove(fuelName))
				{
					SaveInventoryToZdo();
				}
				return;
			}
			int stackLimit = GetStackLimit(fuelName);
			int num = Mathf.Clamp(amount, 0, stackLimit);
			if (!_inventory.TryGetValue(fuelName, out var value) || value != num)
			{
				_inventory[fuelName] = num;
				SaveInventoryToZdo();
			}
		}

		private int GetStackLimit(string fuelName)
		{
			if (_stackLimits.TryGetValue(fuelName, out var value))
			{
				return Mathf.Max(1, value);
			}
			return 1;
		}

		private void SaveInventoryToZdo()
		{
			if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.IsOwner())
			{
				return;
			}
			ZDO zDO = _nview.GetZDO();
			if (zDO == null)
			{
				return;
			}
			StringBuilder stringBuilder = new StringBuilder();
			List<string> list = new List<string>(_inventory.Keys);
			list.Sort(StringComparer.Ordinal);
			foreach (string item in list)
			{
				int carried = GetCarried(item);
				if (carried > 0)
				{
					int stackLimit = GetStackLimit(item);
					string value = Convert.ToBase64String(Encoding.UTF8.GetBytes(item));
					if (stringBuilder.Length > 0)
					{
						stringBuilder.Append(';');
					}
					stringBuilder.Append(value);
					stringBuilder.Append(',');
					stringBuilder.Append(carried);
					stringBuilder.Append(',');
					stringBuilder.Append(stackLimit);
				}
			}
			zDO.Set("com.g.lamplighter.carried_inventory", stringBuilder.ToString());
			ModConfig.DebugLog($"Lamplighter: saved {_inventory.Count} carried fuel type(s).");
		}

		private void LoadInventoryFromZdo()
		{
			if ((Object)(object)_nview == (Object)null || !_nview.IsValid())
			{
				return;
			}
			ZDO zDO = _nview.GetZDO();
			if (zDO == null)
			{
				return;
			}
			string text = zDO.GetString("com.g.lamplighter.carried_inventory", string.Empty);
			_inventory.Clear();
			_stackLimits.Clear();
			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 != 3)
				{
					Logger.LogWarning((object)"Lamplighter: invalid saved inventory entry.");
					continue;
				}
				try
				{
					string text2 = Encoding.UTF8.GetString(Convert.FromBase64String(array2[0]));
					if (!int.TryParse(array2[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || !int.TryParse(array2[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2))
					{
						Logger.LogWarning((object)"Lamplighter: invalid saved inventory amount.");
					}
					else if (!string.IsNullOrEmpty(text2) && result > 0)
					{
						result2 = Mathf.Max(1, result2);
						result = Mathf.Clamp(result, 1, result2);
						_stackLimits[text2] = result2;
						_inventory[text2] = result;
					}
				}
				catch (FormatException)
				{
					Logger.LogWarning((object)"Lamplighter: invalid saved fuel name.");
				}
			}
			ModConfig.DebugLog($"Lamplighter: restored {_inventory.Count} carried fuel type(s).");
		}

		private void SaveVisualHome()
		{
			if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner())
			{
				ZDO zDO = _nview.GetZDO();
				if (zDO != null)
				{
					zDO.Set("com.g.lamplighter.visual_state", "H");
				}
			}
		}

		private void SaveVisualTarget(char mode, Vector3 position)
		{
			//IL_0054: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner())
			{
				ZDO zDO = _nview.GetZDO();
				if (zDO != null)
				{
					string text = string.Format(CultureInfo.InvariantCulture, "{0}|{1:R}|{2:R}|{3:R}", mode, position.x, position.y, position.z);
					zDO.Set("com.g.lamplighter.visual_state", text);
				}
			}
		}

		private void UpdateRemoteVisual()
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time >= _nextRemoteSyncTime)
			{
				_nextRemoteSyncTime = Time.time + 0.5f;
				LoadInventoryFromZdo();
				LoadVisualStateFromZdo();
			}
			if (_remoteVisualMode == 'H')
			{
				MoveHome();
			}
			else
			{
				MoveWisp(_remoteVisualTarget);
			}
		}

		private void LoadVisualStateFromZdo()
		{
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_nview == (Object)null || !_nview.IsValid())
			{
				return;
			}
			ZDO zDO = _nview.GetZDO();
			if (zDO == null)
			{
				return;
			}
			string text = zDO.GetString("com.g.lamplighter.visual_state", "H");
			if (string.IsNullOrEmpty(text) || text == "H")
			{
				_remoteVisualMode = 'H';
				return;
			}
			string[] array = text.Split(new char[1] { '|' });
			if (array.Length != 4 || string.IsNullOrEmpty(array[0]))
			{
				_remoteVisualMode = 'H';
				return;
			}
			if (!float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) || !float.TryParse(array[3], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3))
			{
				_remoteVisualMode = 'H';
				return;
			}
			char c = array[0][0];
			if (c != 'C' && c != 'F')
			{
				_remoteVisualMode = 'H';
				return;
			}
			_remoteVisualMode = c;
			_remoteVisualTarget = new Vector3(result, result2, result3);
		}

		private bool IsInsideWorkRadius(Vector3 position)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			float value = ModConfig.WorkRadius.Value;
			Vector3 val = position - ((Component)this).transform.position;
			return ((Vector3)(ref val)).sqrMagnitude <= value * value;
		}

		private Vector3 GetChestHoverPosition(Container container)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			return ((Component)container).transform.position + Vector3.up * 1.1f;
		}

		private Vector3 GetFireHoverPosition(Fireplace fireplace)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: 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_0038: 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)
			Vector3 position = ((Component)fireplace).transform.position;
			Vector3 val = ((Component)this).transform.position - position;
			val.y = 0f;
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				val = Vector3.right;
			}
			((Vector3)(ref val)).Normalize();
			return position + val * 0.8f + Vector3.up * 0.7f;
		}

		private void MoveWisp(Vector3 destination)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			_wisp.transform.position = Vector3.MoveTowards(_wisp.transform.position, destination, 3.5f * Time.deltaTime);
		}

		private void BobAround(Vector3 center, float amount)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			float num = Time.time + _timeOffset;
			Vector3 destination = center + new Vector3(Mathf.Cos(num * 2f) * amount, Mathf.Sin(num * 2.5f) * amount, Mathf.Sin(num * 2f) * amount);
			MoveWisp(destination);
		}

		private void MoveHome()
		{
			//IL_0013: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			float num = Time.time + _timeOffset;
			Vector3 destination = ((Component)this).transform.position + new Vector3(Mathf.Cos(num * 0.65f) * 0.18f, 1.8f + Mathf.Sin(num * 1.5f) * 0.15f, Mathf.Sin(num * 0.65f) * 0.18f);
			MoveWisp(destination);
		}

		private void OnShrineDestroyed()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: 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)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			if (_inventoryReturned || (Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.IsOwner())
			{
				return;
			}
			_inventoryReturned = true;
			if (_inventory.Count == 0)
			{
				return;
			}
			Vector3 position = ((Component)this).transform.position + Vector3.up * 0.75f;
			foreach (KeyValuePair<string, int> item in new List<KeyValuePair<string, int>>(_inventory))
			{
				if (item.Value > 0)
				{
					DropCarriedItem(item.Key, item.Value, position);
				}
			}
			_inventory.Clear();
			SaveInventoryToZdo();
			ModConfig.DebugLog("Lamplighter: returned carried inventory.");
		}

		private void DropCarriedItem(string sharedName, int amount, Vector3 position)
		{
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ObjectDB.instance == (Object)null || amount <= 0)
			{
				return;
			}
			if (!(ObjectDbItemsField?.GetValue(ObjectDB.instance) is List<GameObject> list))
			{
				Logger.LogWarning((object)$"Lamplighter: couldn't return {amount} x {sharedName}; ObjectDB item list unavailable.");
				return;
			}
			GameObject val = null;
			ItemDrop val2 = null;
			foreach (GameObject item in list)
			{
				if (!((Object)(object)item == (Object)null))
				{
					ItemDrop component = item.GetComponent<ItemDrop>();
					if (!((Object)(object)component == (Object)null) && component.m_itemData != null && component.m_itemData.m_shared != null && !(component.m_itemData.m_shared.m_name != sharedName))
					{
						val = item;
						val2 = component;
						break;
					}
				}
			}
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
			{
				Logger.LogWarning((object)$"Lamplighter: couldn't return {amount} x {sharedName}; item prefab not found.");
				return;
			}
			int num = Mathf.Max(1, val2.m_itemData.m_shared.m_maxStackSize);
			int num2 = amount;
			Vector3 val3 = default(Vector3);
			while (num2 > 0)
			{
				int num3 = Mathf.Min(num2, num);
				ItemData obj = val2.m_itemData.Clone();
				obj.m_dropPrefab = val;
				((Vector3)(ref val3))..ctor(Random.Range(-0.35f, 0.35f), 0f, Random.Range(-0.35f, 0.35f));
				ItemDrop.DropItem(obj, num3, position + val3, Quaternion.Euler(0f, Random.Range(0f, 360f), 0f));
				num2 -= num3;
			}
		}

		public string GetHoverName()
		{
			return "Lamplighter";
		}

		public string GetHoverText()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("<color=orange>Lamplighter</color>");
			stringBuilder.Append("\n");
			stringBuilder.Append("Status: ");
			stringBuilder.Append(GetStatusText());
			stringBuilder.Append("\n");
			if (_inventory.Count == 0)
			{
				stringBuilder.Append("Carrying: Nothing");
				return stringBuilder.ToString();
			}
			stringBuilder.Append("Carrying:");
			List<string> list = new List<string>(_inventory.Keys);
			list.Sort();
			foreach (string item in list)
			{
				int carried = GetCarried(item);
				if (carried > 0)
				{
					int stackLimit = GetStackLimit(item);
					string value = item;
					if (Localization.instance != null)
					{
						value = Localization.instance.Localize(item);
					}
					stringBuilder.Append("\n");
					stringBuilder.Append(value);
					stringBuilder.Append(": ");
					stringBuilder.Append(carried);
					stringBuilder.Append("/");
					stringBuilder.Append(stackLimit);
				}
			}
			return stringBuilder.ToString();
		}

		private string GetStatusText()
		{
			if ((Object)(object)_nview != (Object)null && _nview.IsValid() && !_nview.IsOwner())
			{
				return _remoteVisualMode switch
				{
					'C' => "Restocking", 
					'F' => "Working", 
					_ => "Resting", 
				};
			}
			switch (_state)
			{
			case WispState.ToChest:
			case WispState.AtChest:
				return "Restocking";
			case WispState.ToFire:
			case WispState.AtFire:
				return "Working";
			default:
				if (!_isResting)
				{
					return "Looking for work";
				}
				return "Resting";
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)_wearNTear != (Object)null)
			{
				WearNTear wearNTear = _wearNTear;
				wearNTear.m_onDestroyed = (Action)Delegate.Remove(wearNTear.m_onDestroyed, new Action(OnShrineDestroyed));
			}
		}
	}
}
namespace Lamplighter.Config
{
	internal static class ModConfig
	{
		public static ConfigEntry<float> WorkRadius { get; private set; }

		public static ConfigEntry<int> RefillBelowPercent { get; private set; }

		public static ConfigEntry<Color> WispColor { get; private set; }

		public static ConfigEntry<Color> OozeColor { get; private set; }

		public static ConfigEntry<Color> ShrineColor { get; private set; }

		public static ConfigEntry<bool> TakeWoodFromWoodStacks { get; private set; }

		public static ConfigEntry<bool> DetailedLogging { get; private set; }

		public static ConfigEntry<bool> ShowRangeWhilePlacing { get; private set; }

		public static ConfigEntry<bool> ShowRangeOnHover { get; private set; }

		public static float RefillThreshold => (float)RefillBelowPercent.Value / 100f;

		public static void Bind(ConfigFile config)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			//IL_00b2: 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_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Expected O, but got Unknown
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Expected O, but got Unknown
			WorkRadius = config.Bind<float>("Lamplighter", "Work Radius", 40f, new ConfigDescription("Maximum distance in meters for servicing fires and searching fuel containers.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 100f), new object[1] { AdminOnly() }));
			RefillBelowPercent = config.Bind<int>("Lamplighter", "Refill Below", 25, new ConfigDescription("Refill a fire when its fuel falls below this percentage.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), new object[1] { AdminOnly() }));
			TakeWoodFromWoodStacks = config.Bind<bool>("Lamplighter", "Take Wood From Wood Stacks", true, "Allow the Lamplighter to use placed Wood Stacks as a fuel source.");
			WispColor = config.Bind<Color>("Appearance", "Wisp Color", new Color(1f, 0.25f, 0.03f, 1f), "Color of the Lamplighter fire spirit.");
			OozeColor = config.Bind<Color>("Appearance", "Ooze Color", new Color(1f, 0.25f, 0.03f, 1f), "Color of the glowing flowing material on the Lamplighter shrine.");
			ShrineColor = config.Bind<Color>("Appearance", "Shrine Color", new Color(0.85f, 0.72f, 0.4f, 1f), "Color of the Lamplighter shrine structure.");
			DetailedLogging = config.Bind<bool>("Advanced", "Detailed Logging", false, "Log Lamplighter jobs, fuel transfers, restocking, and other diagnostic activity.");
			ShowRangeWhilePlacing = config.Bind<bool>("Advanced", "Show Range While Placing", true, new ConfigDescription("Show the Lamplighter work radius while placing it.", (AcceptableValueBase)null, new object[1] { Hidden() }));
			ShowRangeOnHover = config.Bind<bool>("Advanced", "Show Range On Hover", false, new ConfigDescription("Show the work radius while hovering over an existing Lamplighter.", (AcceptableValueBase)null, new object[1] { Hidden() }));
		}

		public static void DebugLog(string message)
		{
			if (DetailedLogging != null && DetailedLogging.Value)
			{
				Logger.LogInfo((object)message);
			}
		}

		private static ConfigurationManagerAttributes AdminOnly()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			return new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			};
		}

		private static ConfigurationManagerAttributes Hidden()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			return new ConfigurationManagerAttributes
			{
				Browsable = false
			};
		}
	}
}