Decompiled source of MySix Lights v1.0.2

MySix.Lights.dll

Decompiled 22 minutes ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using HarmonyLib;
using MySix.Core;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace MySix
{
	internal static class SuiteVersion
	{
		public const string Value = "1.0.2";
	}
}
namespace MySix.Lights
{
	[HarmonyPatch(typeof(Container), "Awake")]
	public static class ContainerRegistry
	{
		private static readonly List<Container> Loaded = new List<Container>();

		public static int KnownContainers => Loaded.Count;

		private static void Postfix(Container __instance)
		{
			Loaded.Add(__instance);
			if (Loaded.Count > 1024)
			{
				Live();
			}
		}

		internal static List<Container> Live()
		{
			for (int num = Loaded.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)Loaded[num] == (Object)null)
				{
					Loaded.RemoveAt(num);
				}
			}
			return Loaded;
		}
	}
	public static class ChestFeed
	{
		private struct Starvation
		{
			public float RetryAt;

			public bool Announced;
		}

		public static Setting<float> Range;

		private const float DefaultRange = 100f;

		private const float RetrySeconds = 10f;

		private static readonly Dictionary<ZDOID, Starvation> Starved = new Dictionary<ZDOID, Starvation>();

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

		private static readonly Func<Container, long, bool> CheckAccess = AccessTools.MethodDelegate<Func<Container, long, bool>>(AccessTools.Method(typeof(Container), "CheckAccess", (Type[])null, (Type[])null), (object)null, false);

		private static readonly Func<Container, bool> ReloadContents = AccessTools.MethodDelegate<Func<Container, bool>>(AccessTools.Method(typeof(Container), "Load", (Type[])null, (Type[])null), (object)null, false);

		internal static void TopUp(Fireplace fire, ZDO zdo)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: 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_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			if (zdo.GetInt(ZDOVars.s_state, 1) != 1)
			{
				return;
			}
			float num = zdo.GetFloat(ZDOVars.s_fuel, 0f);
			if (num >= 1f || (Object)(object)fire.m_fuelItem == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)Game.instance == (Object)null)
			{
				return;
			}
			Starved.TryGetValue(zdo.m_uid, out var value);
			if (Time.realtimeSinceStartup < value.RetryAt)
			{
				return;
			}
			string name = fire.m_fuelItem.m_itemData.m_shared.m_name;
			Container val = NearestWithFuel(((Component)fire).transform.position, name, Game.instance.GetPlayerProfile().GetPlayerID());
			if ((Object)(object)val != (Object)null && TakeOne(val, name))
			{
				Starved.Remove(zdo.m_uid);
				zdo.Set(ZDOVars.s_fuel, num + 1f);
				CorePlugin.Log.LogInfo((object)("Lights: " + Named((Component)(object)fire) + " " + At(((Component)fire).transform.position) + " took 1 " + name + " from " + Named((Component)(object)val) + " " + At(((Component)val).transform.position)));
				return;
			}
			if (!value.Announced && num <= 0f)
			{
				value.Announced = true;
				CorePlugin.Log.LogInfo((object)("Lights: " + Named((Component)(object)fire) + " " + At(((Component)fire).transform.position) + " has gone out; " + $"no {name} in any container within {CurrentRange():0} metres"));
			}
			value.RetryAt = Time.realtimeSinceStartup + 10f;
			Starved[zdo.m_uid] = value;
			if (Starved.Count > 256)
			{
				Starved.Clear();
			}
		}

		private static Container NearestWithFuel(Vector3 firePosition, string fuelItem, long playerID)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			float num = CurrentRange();
			float num2 = num * num;
			Container result = null;
			foreach (Container item in ContainerRegistry.Live())
			{
				Vector3 val = ((Component)item).transform.position - firePosition;
				float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
				if (!(sqrMagnitude >= num2))
				{
					ZNetView val2 = ContainerNView.Invoke(item);
					if (!((Object)(object)val2 == (Object)null) && val2.IsValid() && val2.GetZDO().GetInt(ZDOVars.s_inUse, 0) != 1 && !item.m_autoDestroyEmpty && MayUse(item, playerID) && item.GetInventory().CountItems(fuelItem, -1, false) > 0)
					{
						result = item;
						num2 = sqrMagnitude;
					}
				}
			}
			return result;
		}

		private static bool MayUse(Container container, long playerID)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (!CheckAccess(container, playerID))
			{
				return false;
			}
			if (container.m_checkGuardStone)
			{
				return PrivateArea.CheckAccess(((Component)container).transform.position, 0f, false, false);
			}
			return true;
		}

		private static bool TakeOne(Container container, string fuelItem)
		{
			if (!Compat.TakeOwnership(ContainerNView.Invoke(container).GetZDO()))
			{
				return false;
			}
			ReloadContents(container);
			Inventory inventory = container.GetInventory();
			if (inventory.CountItems(fuelItem, -1, false) <= 0)
			{
				return false;
			}
			inventory.RemoveItem(fuelItem, 1, -1, false);
			return true;
		}

		private static float CurrentRange()
		{
			if (Range != null)
			{
				return Mathf.Max(0f, Range.Value);
			}
			return 100f;
		}

		private static string Named(Component c)
		{
			return ((Object)c).name.Replace("(Clone)", "");
		}

		private static string At(Vector3 p)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			return $"({p.x:0}, {p.y:0}, {p.z:0})";
		}
	}
	public enum LightMode
	{
		Vanilla,
		Infinite,
		ChestFed
	}
	[HarmonyPatch(typeof(Fireplace), "UpdateFireplace")]
	public static class FireplacePatch
	{
		public static Setting<LightMode> Mode;

		public static Setting<bool> PlayerBuiltOnly;

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

		private static readonly string[] CraftingComponents = new string[5] { "CraftingStation", "CookingStation", "Smelter", "Fermenter", "Incinerator" };

		private static readonly Dictionary<int, bool> IsLightByPrefab = new Dictionary<int, bool>();

		public static int KnownLightTypes => IsLightByPrefab.Count;

		private static void Prefix(Fireplace __instance)
		{
			LightMode lightMode = ((Mode != null) ? Mode.Value : LightMode.Vanilla);
			if (lightMode == LightMode.Vanilla)
			{
				return;
			}
			ZNetView val = NView.Invoke(__instance);
			if ((Object)(object)val == (Object)null || !val.IsValid() || !val.IsOwner())
			{
				return;
			}
			ZDO zDO = val.GetZDO();
			if (!IsManagedLight(__instance, zDO.GetPrefab()) || (PlayerBuiltOnly != null && PlayerBuiltOnly.Value && zDO.GetLong(ZDOVars.s_creator, 0L) == 0L))
			{
				return;
			}
			if (lightMode == LightMode.Infinite)
			{
				if (zDO.GetFloat(ZDOVars.s_fuel, 0f) < __instance.m_maxFuel)
				{
					zDO.Set(ZDOVars.s_fuel, __instance.m_maxFuel);
				}
				zDO.Set(ZDOVars.s_lastTime, ZNet.instance.GetTime().Ticks);
			}
			else
			{
				ChestFeed.TopUp(__instance, zDO);
			}
		}

		private static bool IsManagedLight(Fireplace fire, int prefabHash)
		{
			if (IsLightByPrefab.TryGetValue(prefabHash, out var value))
			{
				return value;
			}
			value = true;
			if (fire.m_infiniteFuel || fire.m_secPerFuel <= 0f)
			{
				value = false;
			}
			else if ((Object)(object)((Component)fire).GetComponent<Piece>() == (Object)null)
			{
				value = false;
			}
			else
			{
				string[] craftingComponents = CraftingComponents;
				foreach (string text in craftingComponents)
				{
					if ((Object)(object)((Component)fire).GetComponent(text) != (Object)null)
					{
						value = false;
						break;
					}
				}
			}
			IsLightByPrefab[prefabHash] = value;
			if (value)
			{
				CorePlugin.Log.LogInfo((object)("Lights: " + ((Object)fire).name.Replace("(Clone)", "") + " counts as a light"));
			}
			return value;
		}
	}
	[BepInPlugin("com.mysix.lights", "MySix Lights", "1.0.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class LightsPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.mysix.lights";

		public const string PluginName = "MySix Lights";

		public const string PluginVersion = "1.0.2";

		private const int RequiredCoreApi = 1;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			if (CorePlugin.RequireApi("MySix Lights", 1))
			{
				FireplacePatch.Mode = Settings.Register<LightMode>("MySix Lights", ((BaseUnityPlugin)this).Config.Bind<LightMode>("Lights", "Mode", LightMode.Infinite, "Infinite: torches, braziers, campfires and hearths never run out. ChestFed: they burn real fuel taken from containers in range and go out when there is none. Vanilla: normal fuel use. Crafting fires (kilns, smelters, ovens...) always use fuel normally."), (Scope)0, (string)null);
				FireplacePatch.PlayerBuiltOnly = Settings.Register<bool>("MySix Lights", ((BaseUnityPlugin)this).Config.Bind<bool>("Lights", "PlayerBuiltOnly", true, "Only lights a player built. Torches in dungeons and abandoned villages keep burning down."), (Scope)0, (string)null);
				ChestFeed.Range = Settings.Register<float>("MySix Lights", ((BaseUnityPlugin)this).Config.Bind<float>("Lights", "ContainerRange", 100f, "ChestFed mode only: how far, in metres, a light will reach for its fuel. Containers you could not open yourself, and ones a ward protects, are never used."), (Scope)0, (string)null);
				_harmony = new Harmony("com.mysix.lights");
				_harmony.PatchAll(typeof(LightsPlugin).Assembly);
				((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} {1} loaded; mode {2}", "MySix Lights", "1.0.2", FireplacePatch.Mode.Value));
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}