Decompiled source of ResinFire v1.2.1

ResinFire.dll

Decompiled 5 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[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("ResinFire")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ResinFire")]
[assembly: AssemblyTitle("ResinFire")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ResinFire
{
	[BepInPlugin("snowfarm.valheim.resinfire", "ResinFire", "1.2.1")]
	public class ResinFirePlugin : BaseUnityPlugin
	{
		public const string Guid = "snowfarm.valheim.resinfire";

		public const string Name = "ResinFire";

		public const string Version = "1.2.1";

		private const string DefaultFuelPrefabs = "piece_brazierceiling01,piece_brazierfloor01,piece_brazierfloor02,piece_groundtorch_blue,piece_groundtorch_green";

		private const string DefaultRefillPrefabs = "piece_brazierceiling01,piece_brazierfloor01,piece_brazierfloor02,piece_groundtorch_blue,piece_groundtorch_green,piece_sconce,piece_groundtorch,piece_groundtorchwood";

		private const string V110FuelPrefabs = "piece_brazierceiling01,piece_brazierfloor01";

		private const string V110RefillPrefabs = "piece_brazierceiling01,piece_brazierfloor01,piece_sconce,piece_groundtorch,piece_groundtorchwood";

		private static ManualLogSource _log;

		private static ConfigEntry<bool> _enabled;

		private static ConfigEntry<string> _fuelItemName;

		private static ConfigEntry<string> _fuelPrefabs;

		private static ConfigEntry<string> _refillPrefabs;

		private static ConfigEntry<float> _radius;

		private static ConfigEntry<float> _interval;

		private static ConfigEntry<bool> _verbose;

		private static readonly List<Fireplace> Fireplaces = new List<Fireplace>();

		private static readonly List<Container> Containers = new List<Container>();

		private static readonly HashSet<string> FuelTargets = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static readonly HashSet<string> RefillTargets = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static ItemDrop _fuelItem;

		private static float _radiusSqr;

		private static bool _loggedNotServer;

		private void Awake()
		{
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Expected O, but got Unknown
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Expected O, but got Unknown
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			_log = ((BaseUnityPlugin)this).Logger;
			_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Enabled", true, "Turn the whole plugin on or off.");
			_fuelItemName = ((BaseUnityPlugin)this).Config.Bind<string>("2 - Fuel", "FuelItem", "Resin", "Item prefab the pieces in FuelPrefabs burn. Use 'Coal' to get vanilla behaviour back.");
			_fuelPrefabs = ((BaseUnityPlugin)this).Config.Bind<string>("2 - Fuel", "FuelPrefabs", "piece_brazierceiling01,piece_brazierfloor01,piece_brazierfloor02,piece_groundtorch_blue,piece_groundtorch_green", "Comma separated prefabs whose fuel item is replaced.");
			_refillPrefabs = ((BaseUnityPlugin)this).Config.Bind<string>("3 - Auto refill", "RefillPrefabs", "piece_brazierceiling01,piece_brazierfloor01,piece_brazierfloor02,piece_groundtorch_blue,piece_groundtorch_green,piece_sconce,piece_groundtorch,piece_groundtorchwood", "Comma separated prefabs that refill themselves from nearby containers.");
			if (_fuelPrefabs.Value == "piece_brazierceiling01,piece_brazierfloor01")
			{
				_fuelPrefabs.Value = "piece_brazierceiling01,piece_brazierfloor01,piece_brazierfloor02,piece_groundtorch_blue,piece_groundtorch_green";
			}
			if (_refillPrefabs.Value == "piece_brazierceiling01,piece_brazierfloor01,piece_sconce,piece_groundtorch,piece_groundtorchwood")
			{
				_refillPrefabs.Value = "piece_brazierceiling01,piece_brazierfloor01,piece_brazierfloor02,piece_groundtorch_blue,piece_groundtorch_green,piece_sconce,piece_groundtorch,piece_groundtorchwood";
			}
			_radius = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Auto refill", "Radius", 30f, new ConfigDescription("Search radius for containers, in meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			_interval = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Auto refill", "Interval", 5f, new ConfigDescription("Seconds between refill checks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), Array.Empty<object>()));
			_verbose = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Diagnostics", "Verbose", false, "Log a summary every cycle and the reason each fire was skipped.");
			ParseList(_fuelPrefabs.Value, FuelTargets);
			ParseList(_refillPrefabs.Value, RefillTargets);
			_radiusSqr = _radius.Value * _radius.Value;
			new Harmony("snowfarm.valheim.resinfire").PatchAll(typeof(ResinFirePlugin));
			((MonoBehaviour)this).StartCoroutine(PrefabLoop());
			((MonoBehaviour)this).StartCoroutine(RefillLoop());
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} {1} loaded. fuel={2}, radius={3}m", "ResinFire", "1.2.1", _fuelItemName.Value, _radius.Value));
			((BaseUnityPlugin)this).Logger.LogInfo((object)("fuel prefabs   : " + string.Join(", ", FuelTargets)));
			((BaseUnityPlugin)this).Logger.LogInfo((object)("refill prefabs : " + string.Join(", ", RefillTargets)));
		}

		private static void ParseList(string value, HashSet<string> target)
		{
			target.Clear();
			string[] array = (value ?? "").Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0)
				{
					target.Add(text);
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Fireplace), "Awake")]
		private static void FireplaceAwake(Fireplace __instance)
		{
			if (!((Object)(object)__instance == (Object)null))
			{
				if (!Fireplaces.Contains(__instance))
				{
					Fireplaces.Add(__instance);
				}
				if ((Object)(object)_fuelItem == (Object)null)
				{
					_fuelItem = ResolveFuelItem();
				}
				if ((Object)(object)_fuelItem != (Object)null && FuelTargets.Contains(PrefabName(((Component)__instance).gameObject)))
				{
					__instance.m_fuelItem = _fuelItem;
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Container), "Awake")]
		private static void ContainerAwake(Container __instance)
		{
			if ((Object)(object)__instance != (Object)null && !Containers.Contains(__instance))
			{
				Containers.Add(__instance);
			}
		}

		private IEnumerator PrefabLoop()
		{
			ZNetScene last = null;
			while (true)
			{
				ZNetScene instance = ZNetScene.instance;
				if ((Object)(object)instance != (Object)null && (Object)(object)instance != (Object)(object)last)
				{
					last = instance;
					ApplyFuelToPrefabs();
				}
				yield return (object)new WaitForSeconds(5f);
			}
		}

		private static void ApplyFuelToPrefabs()
		{
			if (!_enabled.Value)
			{
				return;
			}
			_fuelItem = ResolveFuelItem();
			if ((Object)(object)_fuelItem == (Object)null)
			{
				return;
			}
			foreach (string fuelTarget in FuelTargets)
			{
				GameObject prefab = ZNetScene.instance.GetPrefab(fuelTarget);
				if ((Object)(object)prefab == (Object)null)
				{
					_log.LogWarning((object)("Prefab '" + fuelTarget + "' not found."));
					continue;
				}
				Fireplace componentInChildren = prefab.GetComponentInChildren<Fireplace>(true);
				if ((Object)(object)componentInChildren == (Object)null)
				{
					_log.LogWarning((object)("Prefab '" + fuelTarget + "' has no Fireplace component."));
					continue;
				}
				string text = "?";
				if ((Object)(object)componentInChildren.m_fuelItem != (Object)null && componentInChildren.m_fuelItem.m_itemData != null)
				{
					text = componentInChildren.m_fuelItem.m_itemData.m_shared.m_name;
				}
				componentInChildren.m_fuelItem = _fuelItem;
				_log.LogInfo((object)("'" + fuelTarget + "' now burns " + _fuelItemName.Value + " (was " + text + ")."));
			}
		}

		private static ItemDrop ResolveFuelItem()
		{
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			GameObject itemPrefab = instance.GetItemPrefab(_fuelItemName.Value);
			if (!Object.op_Implicit((Object)(object)itemPrefab))
			{
				return null;
			}
			return itemPrefab.GetComponent<ItemDrop>();
		}

		private IEnumerator RefillLoop()
		{
			while (true)
			{
				yield return (object)new WaitForSeconds(_interval.Value);
				if (!_enabled.Value)
				{
					continue;
				}
				if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
				{
					if (!_loggedNotServer)
					{
						_loggedNotServer = true;
						_log.LogInfo((object)"Not the server: auto refill only runs on the server (this peer will not refill).");
					}
					continue;
				}
				PruneLists();
				int num = 0;
				int num2 = 0;
				int num3 = 0;
				foreach (Fireplace fireplace in Fireplaces)
				{
					try
					{
						string reason;
						bool flag = Refill(fireplace, out reason);
						if (reason != null)
						{
							num++;
							if (reason != "full")
							{
								num2++;
							}
							if (flag)
							{
								num3++;
							}
							if (_verbose.Value && !flag && reason != "full")
							{
								_log.LogInfo((object)(PrefabName(((Component)fireplace).gameObject) + ": skipped (" + reason + ")"));
							}
						}
					}
					catch (Exception ex)
					{
						_log.LogDebug((object)("Refill failed: " + ex.Message));
					}
				}
				if (_verbose.Value && num > 0)
				{
					_log.LogInfo((object)$"cycle: targets={num} empty={num2} refilled={num3} containers={Containers.Count}");
				}
			}
		}

		private static void PruneLists()
		{
			Fireplaces.RemoveAll((Fireplace f) => (Object)(object)f == (Object)null);
			Containers.RemoveAll((Container c) => (Object)(object)c == (Object)null);
		}

		private static bool Refill(Fireplace fireplace, out string reason)
		{
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: 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_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			reason = null;
			if ((Object)(object)fireplace == (Object)null)
			{
				return false;
			}
			if (!RefillTargets.Contains(PrefabName(((Component)fireplace).gameObject)))
			{
				return false;
			}
			if (fireplace.m_infiniteFuel)
			{
				reason = "infinite fuel";
				return false;
			}
			ZNetView component = ((Component)fireplace).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				reason = "no ZNetView";
				return false;
			}
			if (!component.IsOwner())
			{
				component.ClaimOwnership();
				if (!component.IsOwner())
				{
					reason = "fire not owned";
					return false;
				}
			}
			ZDO zDO = component.GetZDO();
			if (zDO == null)
			{
				reason = "no ZDO";
				return false;
			}
			if (zDO.GetInt(ZDOVars.s_state, 1) != 1)
			{
				reason = "switched off";
				return false;
			}
			float maxFuel = fireplace.m_maxFuel;
			if (maxFuel <= 0f)
			{
				reason = "maxFuel 0";
				return false;
			}
			float num = zDO.GetFloat(ZDOVars.s_fuel, 0f);
			if (num >= maxFuel - 0.01f)
			{
				reason = "full";
				return false;
			}
			ItemDrop fuelItem = fireplace.m_fuelItem;
			if ((Object)(object)fuelItem == (Object)null || fuelItem.m_itemData == null)
			{
				reason = "no fuel item";
				return false;
			}
			string name = fuelItem.m_itemData.m_shared.m_name;
			int num2 = Mathf.CeilToInt(maxFuel - num);
			int num3 = 0;
			int num4 = 0;
			Vector3 position = ((Component)fireplace).transform.position;
			foreach (Container container in Containers)
			{
				if (num3 >= num2)
				{
					break;
				}
				if ((Object)(object)container == (Object)null || !((Component)container).gameObject.activeInHierarchy)
				{
					continue;
				}
				Vector3 val = ((Component)container).transform.position - position;
				if (((Vector3)(ref val)).sqrMagnitude > _radiusSqr)
				{
					continue;
				}
				num4++;
				if (!container.IsOwner())
				{
					if (container.IsInUse())
					{
						continue;
					}
					ZNetView component2 = ((Component)container).GetComponent<ZNetView>();
					if ((Object)(object)component2 == (Object)null || !component2.IsValid())
					{
						continue;
					}
					component2.ClaimOwnership();
					if (!container.IsOwner())
					{
						continue;
					}
				}
				Inventory inventory = container.GetInventory();
				if (inventory == null)
				{
					continue;
				}
				int num5 = inventory.CountItems(name, -1, false);
				if (num5 <= 0)
				{
					continue;
				}
				ItemData item = inventory.GetItem(name, -1, false);
				if (item != null)
				{
					int num6 = Mathf.Min(num5, num2 - num3);
					if (inventory.RemoveItem(item, num6))
					{
						num3 += num6;
					}
				}
			}
			if (num3 <= 0)
			{
				reason = ((num4 == 0) ? "no containers in range" : ("no " + name + " in range"));
				return false;
			}
			fireplace.AddFuel((float)num3);
			_log.LogDebug((object)$"Refilled {((Object)((Component)fireplace).gameObject).name} with {num3} x {name}.");
			return true;
		}

		private static string PrefabName(GameObject go)
		{
			if ((Object)(object)go == (Object)null)
			{
				return string.Empty;
			}
			string text = ((Object)go).name;
			int num = text.IndexOf("(Clone)", StringComparison.Ordinal);
			if (num >= 0)
			{
				text = text.Substring(0, num);
			}
			return text.Trim();
		}
	}
}