Decompiled source of AutoOven v1.0.7

AutoOven.dll

Decompiled 8 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using ConditionalConfigSync;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("MrGay")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("AutoOven")]
[assembly: AssemblyTitle("AutoOven")]
[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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 AutoOven
{
	[BepInPlugin("mrgay.autoven", "Auto Oven", "1.0.7")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class AutoOvenPlugin : BaseUnityPlugin
	{
		private sealed class OvenSlots
		{
			public static bool HasFreeSlot(CookingStation oven)
			{
				return FindFreeSlot(oven) >= 0;
			}

			public static int FindFreeSlot(CookingStation oven)
			{
				for (int i = 0; i < oven.m_slots.Length; i++)
				{
					if (!TryGetSlot(oven, i, out string _, out object _))
					{
						return i;
					}
				}
				return -1;
			}

			public static bool SlotContainsItem(CookingStation oven, int slot, string itemName)
			{
				if (TryGetSlot(oven, slot, out string itemName2, out object _))
				{
					return itemName2 == itemName;
				}
				return false;
			}

			public static bool TryTakeFinished(CookingStation oven, out ItemData? item, out int slot)
			{
				item = null;
				slot = -1;
				for (int i = 0; i < oven.m_slots.Length; i++)
				{
					if (TryGetSlot(oven, i, out string itemName, out object status) && !(status?.ToString() != "Done"))
					{
						GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(itemName);
						ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
						if (!((Object)(object)val == (Object)null))
						{
							item = val.m_itemData.Clone();
							item.m_stack = 1;
							slot = i;
							return true;
						}
					}
				}
				return false;
			}

			public static bool RemoveFinished(CookingStation oven, int slot)
			{
				ZNetView component = ((Component)oven).GetComponent<ZNetView>();
				if ((Object)(object)component == (Object)null || !component.IsValid())
				{
					return false;
				}
				component.ClaimOwnership();
				MethodInfo method = ((object)oven).GetType().GetMethod("SetSlot", BindingFlags.Instance | BindingFlags.NonPublic);
				if (method == null)
				{
					return false;
				}
				object obj = Enum.Parse(method.GetParameters()[3].ParameterType, "NotDone");
				method.Invoke(oven, new object[5] { slot, "", 0f, obj, false });
				((object)oven).GetType().GetMethod("RPC_SetSlotVisual", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(oven, new object[3] { 0L, slot, "" });
				return true;
			}

			public static bool ContainsItem(CookingStation oven, string itemName)
			{
				for (int i = 0; i < oven.m_slots.Length; i++)
				{
					if (TryGetSlot(oven, i, out string itemName2, out object _) && itemName2 == itemName)
					{
						return true;
					}
				}
				return false;
			}

			private static bool TryGetSlot(CookingStation oven, int slot, out string itemName, out object? status)
			{
				itemName = "";
				status = null;
				MethodInfo method = ((object)oven).GetType().GetMethod("GetSlot", BindingFlags.Instance | BindingFlags.NonPublic);
				if (method == null)
				{
					return false;
				}
				object[] array = new object[5] { slot, null, 0f, null, false };
				method.Invoke(oven, array);
				itemName = (array[1] as string) ?? "";
				status = array[3];
				return itemName.Length > 0;
			}
		}

		public const string PluginGuid = "mrgay.autoven";

		public const string PluginName = "Auto Oven";

		public const string PluginVersion = "1.0.7";

		private readonly List<CookingStation> ovens = new List<CookingStation>();

		private ConfigEntry<float> scanDistance;

		private ConfigEntry<float> scanInterval;

		private ConfigEntry<bool> enforceServerConfigSync;

		private ConfigEntry<bool> logScanSummary;

		private ConfigEntry<bool> enableAutoFueling;

		private ConfigSync configSync;

		private float nextScan;

		private bool adapterWarningLogged;

		private int scanCount;

		private void Awake()
		{
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Expected O, but got Unknown
			scanDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Automation", "distance", 10f, "Maximum distance in meters between an oven and a chest used for input or output.");
			scanInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Automation", "interval", 3f, "Seconds between server-side oven scans.");
			enforceServerConfigSync = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enforce_Server_Config_Sync", true, "When enabled, the server controls the automation settings for connected clients.");
			logScanSummary = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Log_Scan_Summary", false, "When enabled, periodically log the number of active ovens found by Auto Oven.");
			enableAutoFueling = ((BaseUnityPlugin)this).Config.Bind<bool>("Automation", "Enable_Auto_Fueling", false, "When enabled, nearby chests supply the oven's configured fuel item automatically.");
			configSync = new ConfigSync("mrgay.autoven")
			{
				DisplayName = "Auto Oven",
				CurrentVersion = "1.0.7",
				MinimumRequiredVersion = "1.0.7",
				ModRequired = true
			};
			((ConditionalConfigSync)configSync).AllowClientConfigUpdatesWhenUnlocked = true;
			((ConditionalConfigSync)configSync).AddLockingConfigEntry<bool>(enforceServerConfigSync);
			((ConditionalConfigSync)configSync).AddConfigEntry<bool>(logScanSummary, (ConfigSyncMode)0);
			((ConditionalConfigSync)configSync).AddConfigEntry<bool>(enableAutoFueling, (ConfigSyncMode)0);
			((ConditionalConfigSync)configSync).AddConfigEntry<float>(scanDistance, (ConfigSyncMode)1, true);
			((ConditionalConfigSync)configSync).AddConfigEntry<float>(scanInterval, (ConfigSyncMode)1, true);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Auto Oven 1.0.7 loaded. Automation runs on the server only.");
		}

		private void Update()
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && !(Time.time < nextScan))
			{
				nextScan = Time.time + Mathf.Max(0.25f, scanInterval.Value);
				ScanOvens();
			}
		}

		private void ScanOvens()
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			scanCount++;
			ovens.Clear();
			ovens.AddRange(Object.FindObjectsOfType<CookingStation>());
			foreach (CookingStation oven in ovens)
			{
				if (!((Object)(object)oven == (Object)null) && ((Behaviour)oven).isActiveAndEnabled)
				{
					List<Container> chests = FindNearbyChests(((Component)oven).transform.position);
					UnloadFinishedItems(oven, chests);
					if (enableAutoFueling.Value)
					{
						FuelOven(oven, chests);
					}
					LoadBakeableItems(oven, chests);
				}
			}
			if (logScanSummary.Value && scanCount % 20 == 0)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"Scan {scanCount}: found {ovens.Count} active ovens.");
			}
			UnloadFinishedPersistedOvens();
		}

		private void UnloadFinishedPersistedOvens()
		{
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			if (ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
			{
				CookingStation component = prefab.GetComponent<CookingStation>();
				if ((Object)(object)component == (Object)null)
				{
					continue;
				}
				List<ZDO> list = new List<ZDO>();
				int num = 0;
				while (ZDOMan.instance.GetAllZDOsWithPrefabIterative(((Object)prefab).name, list, ref num))
				{
				}
				foreach (ZDO item in list)
				{
					if (ZNetScene.instance.HaveInstance(item))
					{
						continue;
					}
					for (int i = 0; i < component.m_slots.Length; i++)
					{
						string text = item.GetString("slot" + i, "");
						if (text.Length != 0 && item.GetInt("slotstatus" + i, 0) == 1)
						{
							GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(text);
							ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
							if ((Object)(object)val != (Object)null)
							{
								ItemDrop.DropItem(val.m_itemData.Clone(), 1, item.GetPosition() + Vector3.up, Quaternion.identity);
							}
							item.Set("slot" + i, "");
							item.Set("slot" + i, 0f);
							item.Set("slotstatus" + i, 0);
							ZDOMan.instance.SetDirtySector(item);
						}
					}
				}
			}
		}

		private List<Container> FindNearbyChests(Vector3 position)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			return (from container in Object.FindObjectsOfType<Container>()
				where (Object)(object)container != (Object)null && ((Behaviour)container).isActiveAndEnabled
				select new
				{
					Container = container,
					Distance = Vector3.Distance(position, ((Component)container).transform.position)
				} into entry
				where entry.Distance <= Mathf.Max(0f, scanDistance.Value)
				orderby entry.Distance
				select entry.Container).ToList();
		}

		private void LoadBakeableItems(CookingStation oven, List<Container> chests)
		{
			bool flag;
			do
			{
				flag = false;
				foreach (Container chest in chests)
				{
					if (!OvenSlots.HasFreeSlot(oven))
					{
						return;
					}
					foreach (ItemData item in chest.GetInventory().GetAllItems().ToList())
					{
						if (!OvenSlots.HasFreeSlot(oven))
						{
							return;
						}
						if (TryAddToOven(oven, chest, item))
						{
							flag = true;
						}
					}
				}
			}
			while (flag);
		}

		private void FuelOven(CookingStation oven, List<Container> chests)
		{
			ItemDrop fuelItem = oven.m_fuelItem;
			if ((Object)(object)fuelItem == (Object)null || oven.m_maxFuel <= 0)
			{
				return;
			}
			MethodInfo method = ((object)oven).GetType().GetMethod("GetFuel", BindingFlags.Instance | BindingFlags.NonPublic);
			MethodInfo method2 = ((object)oven).GetType().GetMethod("RPC_AddFuel", BindingFlags.Instance | BindingFlags.NonPublic);
			ZNetView component = ((Component)oven).GetComponent<ZNetView>();
			if (method == null || method2 == null || (Object)(object)component == (Object)null || !component.IsValid())
			{
				LogAdapterWarning("CookingStation fuel API or ZNetView was not found.");
				return;
			}
			string name = fuelItem.m_itemData.m_shared.m_name;
			while (Convert.ToSingle(method.Invoke(oven, null)) < (float)oven.m_maxFuel)
			{
				bool flag = false;
				foreach (Container chest in chests)
				{
					Inventory inventory = chest.GetInventory();
					ItemData item = inventory.GetItem(name, -1, false);
					if (item != null && ClaimContainerOwnership(chest))
					{
						component.ClaimOwnership();
						float num = Convert.ToSingle(method.Invoke(oven, null));
						method2.Invoke(oven, new object[1] { 0L });
						if (!(Convert.ToSingle(method.Invoke(oven, null)) <= num))
						{
							inventory.RemoveItem(item, 1);
							flag = true;
							break;
						}
					}
				}
				if (!flag)
				{
					break;
				}
			}
		}

		private void UnloadFinishedItems(CookingStation oven, List<Container> chests)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//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_0083: Unknown result type (might be due to invalid IL or missing references)
			int slot;
			do
			{
				if (OvenSlots.TryTakeFinished(oven, out ItemData item, out slot))
				{
					Container val = ((IEnumerable<Container>)chests).FirstOrDefault((Func<Container, bool>)((Container chest) => chest.GetInventory().HaveItem(item.m_shared.m_name, true)));
					if (val == null)
					{
						val = chests.FirstOrDefault();
					}
					if (!((Object)(object)val != (Object)null) || !ClaimContainerOwnership(val) || !val.GetInventory().AddItem(item))
					{
						ItemDrop.DropItem(item, item.m_stack, ((Component)oven).transform.position + Vector3.up, Quaternion.identity);
					}
					continue;
				}
				break;
			}
			while (OvenSlots.RemoveFinished(oven, slot));
		}

		private bool TryAddToOven(CookingStation oven, Container chest, ItemData item)
		{
			try
			{
				Inventory inventory = chest.GetInventory();
				ZNetView component = ((Component)oven).GetComponent<ZNetView>();
				if ((Object)(object)component == (Object)null || !component.IsValid())
				{
					LogAdapterWarning("CookingStation has no valid ZNetView.");
					return false;
				}
				string itemName = ((Object)item.m_dropPrefab).name;
				if (!oven.m_conversion.Any((ItemConversion conversion) => (Object)(object)conversion.m_from != (Object)null && ((Object)((Component)conversion.m_from).gameObject).name == itemName))
				{
					return false;
				}
				int num = OvenSlots.FindFreeSlot(oven);
				if (num < 0)
				{
					return false;
				}
				if (!ClaimContainerOwnership(chest))
				{
					return false;
				}
				component.ClaimOwnership();
				MethodInfo method = typeof(CookingStation).GetMethod("RPC_AddItem", BindingFlags.Instance | BindingFlags.NonPublic);
				if (method == null)
				{
					LogAdapterWarning("CookingStation.RPC_AddItem was not found.");
					return false;
				}
				method.Invoke(oven, new object[3] { 0L, itemName, item.m_cheated });
				if (!OvenSlots.SlotContainsItem(oven, num, itemName))
				{
					return false;
				}
				component.InvokeRPC(ZNetView.Everybody, "RPC_SetSlotVisual", new object[2] { num, itemName });
				inventory.RemoveItem(item, 1);
				return true;
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not load " + item.m_shared.m_name + " into an oven: " + ex.GetBaseException().Message));
				return false;
			}
		}

		private static bool ClaimContainerOwnership(Container container)
		{
			ZNetView val = ((Component)container).GetComponent<ZNetView>() ?? ((Component)container).GetComponentInParent<ZNetView>();
			if ((Object)(object)val == (Object)null || !val.IsValid())
			{
				return false;
			}
			val.ClaimOwnership();
			return val.IsOwner();
		}

		private void LogAdapterWarning(string message)
		{
			if (!adapterWarningLogged)
			{
				adapterWarningLogged = true;
				((BaseUnityPlugin)this).Logger.LogWarning((object)(message + " Finished-item automation is disabled for this Valheim build."));
			}
		}
	}
}